diff --git a/.config/taplo.toml b/.config/taplo.toml index 2c6ccfb2b34440686764c39ed6db1c73ed940f06..7cbc1b075125ad237f16d5d7dd33b0de7089ac38 100644 --- a/.config/taplo.toml +++ b/.config/taplo.toml @@ -33,3 +33,10 @@ keys = ["build"] [rule.formatting] reorder_arrays = false + +[[rule]] +include = ["Cargo.toml"] +keys = ["workspace.dependencies"] + +[rule.formatting] +reorder_keys = true diff --git a/.github/commands-readme.md b/.github/commands-readme.md index bf0e9e5ed20bb3085e6bbe3e59079372121167b1..793524e056f8e113b0803405f2d5a238a7c7b285 100644 --- a/.github/commands-readme.md +++ b/.github/commands-readme.md @@ -10,6 +10,7 @@ The current available command actions are: - [Command FMT](https://github.com/paritytech/polkadot-sdk/actions/workflows/command-fmt.yml) - [Command Update UI](https://github.com/paritytech/polkadot-sdk/actions/workflows/command-update-ui.yml) +- [Command Sync](https://github.com/paritytech/polkadot-sdk/actions/workflows/command-sync.yml) - [Command Bench](https://github.com/paritytech/polkadot-sdk/actions/workflows/command-bench.yml) - [Command Bench All](https://github.com/paritytech/polkadot-sdk/actions/workflows/command-bench-all.yml) - [Command Bench Overhead](https://github.com/paritytech/polkadot-sdk/actions/workflows/command-bench-overhead.yml) @@ -24,12 +25,36 @@ Each command will have the same two required values, but it could have more. GitHub's official documentation: [Manually running a workflow](https://docs.github.com/en/actions/using-workflows/manually-running-a-workflow) +#### Running from CLI + +You can use [`gh cli`](https://cli.github.com/) to run the commands too. Refers to the [`gh workflow run`](https://cli.github.com/manual/gh_workflow_run) section from the documentation for more information. + ### Number of the Pull Request The number of the pull request. Required so the action can fetch the correct branch and comment if it fails. ## Action configurations +### FMT + +For FMT you only need the PR number. + +You can use the following [`gh cli`](https://cli.github.com/) inside the repo: + +```bash +gh workflow run command-fmt.yml -f pr=1000 +``` + +### Update UI + +For Update UI you only need the PR number. + +You can use the following [`gh cli`](https://cli.github.com/) inside the repo: + +```bash +gh workflow run command-update-ui.yml -f pr=1000 +``` + ### Bench Runs `benchmark pallet` or `benchmark overhead` against your PR and commits back updated weights. @@ -135,6 +160,12 @@ Posible combinations based on the `benchmark` dropdown. - Requires `Runtime Dir` to be `testing` - Requires `Target Directory` to be `cumulus` +You can use the following [`gh cli`](https://cli.github.com/) inside the repo: + +```bash +gh workflow run command-bench.yml -f pr=1000 -f benchmark=polkadot-pallet -f subcommand=pallet -f runtime=rococo -f pallet=pallet_name -f target_dir=polkadot +``` + ### Bench-all This is a wrapper to run `bench` for all pallets. @@ -173,6 +204,12 @@ Posible combinations based on the `benchmark` dropdown. - `people-westend` - Requires `Target Directory` to be `cumulus` +You can use the following [`gh cli`](https://cli.github.com/) inside the repo: + +```bash +gh workflow run command-bench-all.yml -f pr=1000 -f benchmark=pallet -f pallet=pallet_name -f target_dir=polkadot -f runtime=rococo +``` + ### Bench-overhead Run benchmarks overhead and commit back results to PR. @@ -192,6 +229,35 @@ Posible combinations based on the `benchmark` dropdown. - `asset-hub-westend` - Requires `Target directory` to be `cumulus` +You can use the following [`gh cli`](https://cli.github.com/) inside the repo: + +```bash +gh workflow run command-bench-overheard.yml -f pr=1000 -f benchmark=substrate -f runtime=rococo -f target_dir=substrate +``` + +### Sync + +Run sync and commit back results to PR. + +Posible combinations based on the `benchmark` dropdown. + +- `chain` + - Requires one of the following: + - `rococo` + - `westend` +- `sync-type` + - Requires one of the following: + - `warp` + - `full` + - `fast` + - `fast-unsafe` + +You can use the following [`gh cli`](https://cli.github.com/) inside the repo: + +```bash +gh workflow run command-sync.yml -f pr=1000 -f chain=rococo -f sync-type=full +``` + ## How to modify an action If you want to modify an action and test it, you can do by simply pushing your changes and then selecting your branch in the `Use worflow from` option. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3277a6e4607a74b2b59e24fce951e68c8703fcfc..12f81b04d3a1228d3f4533c8e3d34d6935df51c6 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,13 +5,17 @@ updates: directory: '/' labels: ["A1-insubstantial", "R0-silent"] schedule: - interval: daily + interval: weekly + groups: + ci_dependencies: + patterns: + - "*" # Update Rust dependencies: - package-ecosystem: "cargo" directory: "/" labels: ["A1-insubstantial", "R0-silent"] schedule: - interval: "daily" + interval: "weekly" groups: # We assume these crates to be semver abiding and can therefore group them together. known_good_semver: diff --git a/.github/env b/.github/env index 162ce8af7c0ddbc1534b7d1ffb09cff4be012fc7..2e4d5b48100dfb3e976270efd155843e907687a8 100644 --- a/.github/env +++ b/.github/env @@ -1 +1 @@ -IMAGE="docker.io/paritytech/ci-unified:bullseye-1.77.0-2024-04-10-v20240408" \ No newline at end of file +IMAGE="docker.io/paritytech/ci-unified:bullseye-1.77.0-2024-04-10-v202407161507" diff --git a/.github/scripts/check-workspace.py b/.github/scripts/check-workspace.py index 1f8f103e4e157a8c1c804a618652741193ca5a00..d5197100ad253ed18b9a4df255faa88598883f91 100644 --- a/.github/scripts/check-workspace.py +++ b/.github/scripts/check-workspace.py @@ -135,8 +135,12 @@ def check_links(all_crates): if dep_name in all_crates: links.append((name, dep_name)) - if not 'path' in deps[dep]: - broken.append((name, dep_name, "crate must be linked via `path`")) + if name == 'polkadot-sdk': + if not 'path' in deps[dep]: + broken.append((name, dep_name, "crate must use path")) + return + elif not 'workspace' in deps[dep] or not deps[dep]['workspace']: + broken.append((name, dep_name, "crate must use workspace inheritance")) return def check_crate(deps): @@ -154,8 +158,6 @@ def check_links(all_crates): check_crate(manifest) - - links.sort() broken.sort() diff --git a/.github/scripts/common/lib.sh b/.github/scripts/common/lib.sh index f844e962c41def7625fa3d45ae3cbf81ecb57147..33ef2d3e7eda4d6b4b5b7eacc2e3ed2b1a24c29f 100755 --- a/.github/scripts/common/lib.sh +++ b/.github/scripts/common/lib.sh @@ -444,3 +444,16 @@ get_latest_release_tag() { latest_release_tag=$(curl -s -H "$TOKEN" $api_base/paritytech/polkadot-sdk/releases/latest | jq -r '.tag_name') printf $latest_release_tag } + +function get_polkadot_node_version_from_code() { + # list all the files with node version + git grep -e "\(NODE_VERSION[^=]*= \)\".*\"" | + # fetch only the one we need + grep "primitives/src/lib.rs:" | + # Print only the version + awk '{ print $7 }' | + # Remove the quotes + sed 's/"//g' | + # Remove the semicolon + sed 's/;//g' +} diff --git a/.github/scripts/deny-git-deps.py b/.github/scripts/deny-git-deps.py index 4b831c9347f75bdc3c74c80d3af652c37e7ae459..622fc64c488123a153b438af8516f3fa65133776 100644 --- a/.github/scripts/deny-git-deps.py +++ b/.github/scripts/deny-git-deps.py @@ -19,6 +19,7 @@ KNOWN_BAD_GIT_DEPS = { root = sys.argv[1] if len(sys.argv) > 1 else os.getcwd() workspace = Workspace.from_path(root) +errors = [] def check_dep(dep, used_by): if dep.location != DependencyLocation.GIT: @@ -27,14 +28,23 @@ def check_dep(dep, used_by): if used_by in KNOWN_BAD_GIT_DEPS.get(dep.name, []): print(f'๐Ÿคจ Ignoring git dependency {dep.name} in {used_by}') else: - print(f'๐Ÿšซ Found git dependency {dep.name} in {used_by}') - sys.exit(1) + errors.append(f'๐Ÿšซ Found git dependency {dep.name} in {used_by}') # Check the workspace dependencies that can be inherited: for dep in workspace.dependencies: check_dep(dep, "workspace") + if workspace.crates.find_by_name(dep.name): + if dep.location != DependencyLocation.PATH: + errors.append(f'๐Ÿšซ Workspace must use path to link local dependency {dep.name}') + # And the dependencies of each crate: for crate in workspace.crates: for dep in crate.dependencies: check_dep(dep, crate.name) + +if errors: + print('โŒ Found errors:') + for error in errors: + print(error) + sys.exit(1) diff --git a/.github/scripts/update-wishlist-leaderboard.py b/.github/scripts/update-wishlist-leaderboard.py new file mode 100644 index 0000000000000000000000000000000000000000..caa30bec846d6c35320f0112cd6124201b2dccaf --- /dev/null +++ b/.github/scripts/update-wishlist-leaderboard.py @@ -0,0 +1,79 @@ +from github import Github +import re +import os +from datetime import date + +g = Github(os.getenv("GH_TOKEN")) + +# Regex pattern to match wish format: +wish_pattern = re.compile( + r"I wish for:? (https://github\.com/([a-zA-Z0-9_.-]+)/([a-zA-Z0-9_.-]+)/issues/(\d+))" +) + +wishlist_issue = g.get_repo(os.getenv("WISHLIST_REPOSITORY")).get_issue( + int(os.getenv("WISHLIST_ISSUE_NUMBER")) +) +new_leaderboard = ( + "| Feature Request | Summary | Votes | Status |\n| --- | --- | --- | --- |\n" +) +wishes = {} +issue_details = {} + +for comment in wishlist_issue.get_comments(): + # in the comment body, if there is a string `#(\d)`, replace it with + # https://github.com/paritytech/polkadot-sdk/issues/(number) + updated_body = re.sub( + r"#(\d+)", r"https://github.com/paritytech/polkadot-sdk/issues/\1", comment.body + ) + + matches = wish_pattern.findall(updated_body) + for match in matches: + url, org, repo_name, issue_id = match + issue_key = (url, org, repo_name, issue_id) + if issue_key not in wishes: + wishes[issue_key] = [] + + # Get the author and upvoters of the wish comment. + wishes[issue_key].append(comment.user.id) + wishes[issue_key].extend( + [ + reaction.user.id + for reaction in comment.get_reactions() + if reaction.content in ["+1", "heart", "rocket"] + ] + ) + + # Get upvoters of the desired issue. + desired_issue = g.get_repo(f"{org}/{repo_name}").get_issue(int(issue_id)) + wishes[issue_key].extend( + [ + reaction.user.id + for reaction in desired_issue.get_reactions() + if reaction.content in ["+1", "heart", "rocket"] + ] + ) + issue_details[url] = [ + desired_issue.title, + "๐Ÿ‘พ Open" if desired_issue.state == "open" else "โœ…Closed", + ] + +# Count unique wishes - the author of the wish, upvoters of the wish, and upvoters of the desired issue. +for key in wishes: + wishes[key] = len(list(set(wishes[key]))) + +# Sort wishes by count and add to the markdown table +sorted_wishes = sorted(wishes.items(), key=lambda x: x[1], reverse=True) +for (url, _, _, _), count in sorted_wishes: + [summary, status] = issue_details.get(url, "No summary available") + new_leaderboard += f"| {url} | {summary} | {count} | {status} |\n" +new_leaderboard += f"\n> Last updated: {date.today().strftime('%Y-%m-%d')}\n" +print(new_leaderboard) + +new_content = re.sub( + r"(\| Feature Request \|)(.*?)(> Last updated:)(.*?\n)", + new_leaderboard, + wishlist_issue.body, + flags=re.DOTALL, +) + +wishlist_issue.edit(body=new_content) diff --git a/.github/workflows/check-licenses.yml b/.github/workflows/check-licenses.yml index 3bc95305f7467ebbede90526eadb156b89b1e7f9..b77135805409d1fb869b9a061e681b582924e4b7 100644 --- a/.github/workflows/check-licenses.yml +++ b/.github/workflows/check-licenses.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/setup-node@v4.0.1 + - uses: actions/setup-node@v4.0.3 with: node-version: "18.x" registry-url: "https://npm.pkg.github.com" diff --git a/.github/workflows/check-links.yml b/.github/workflows/check-links.yml index 58065f369c9cf160b0b94c233df9df1016426d07..090063e126b19f31b6121cf1a42bb5b7fb186a38 100644 --- a/.github/workflows/check-links.yml +++ b/.github/workflows/check-links.yml @@ -28,7 +28,7 @@ jobs: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.0 (22. Sep 2023) - name: Lychee link checker - uses: lycheeverse/lychee-action@c3089c702fbb949e3f7a8122be0c33c017904f9b # for v1.9.1 (10. Jan 2024) + uses: lycheeverse/lychee-action@2b973e86fc7b1f6b36a93795fe2c9c6ae1118621 # for v1.9.1 (10. Jan 2024) with: args: >- --config .config/lychee.toml diff --git a/.github/workflows/check-prdoc.yml b/.github/workflows/check-prdoc.yml index c31dee06ec54a0154efc3ad46ff24c79de4d0d7b..5df03f1044d88a7bcf9369c054235747f9f049b1 100644 --- a/.github/workflows/check-prdoc.yml +++ b/.github/workflows/check-prdoc.yml @@ -6,7 +6,7 @@ on: merge_group: env: - IMAGE: docker.io/paritytech/prdoc:v0.0.7 + IMAGE: docker.io/paritytech/prdoc:v0.0.8 API_BASE: https://api.github.com/repos REPO: ${{ github.repository }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/check-semver.yml b/.github/workflows/check-semver.yml index 04c63f4192b29ca1773d1018698b2abe6a666e1c..f65be00924dee913cd8b19c2a7039865b7b6db06 100644 --- a/.github/workflows/check-semver.yml +++ b/.github/workflows/check-semver.yml @@ -5,6 +5,8 @@ on: types: [opened, synchronize, reopened, ready_for_review] paths: - prdoc/*.prdoc +env: + TOOLCHAIN: nightly-2024-06-01 jobs: check-semver: @@ -19,14 +21,14 @@ jobs: with: cache-on-failure: true + - name: install parity-publish + run: cargo install parity-publish@0.7.0 + - name: Rust compilation prerequisites run: | - rustup default nightly-2024-03-01 - rustup target add wasm32-unknown-unknown --toolchain nightly-2024-03-01 - rustup component add rust-src --toolchain nightly-2024-03-01 - - - name: install parity-publish - run: cargo install parity-publish@0.5.1 + rustup default $TOOLCHAIN + rustup target add wasm32-unknown-unknown --toolchain $TOOLCHAIN + rustup component add rust-src --toolchain $TOOLCHAIN - name: extra git setup run: | @@ -39,7 +41,7 @@ jobs: export CARGO_TARGET_DIR=target export RUSTFLAGS='-A warnings -A missing_docs' export SKIP_WASM_BUILD=1 - if ! parity-publish --color always prdoc --since old --validate prdoc/pr_$PR.prdoc --toolchain nightly-2024-03-01 -v; then + if ! parity-publish --color always prdoc --since old --validate prdoc/pr_$PR.prdoc -v --toolchain $TOOLCHAIN; then cat <> $GITHUB_OUTPUT fmt: runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 20 needs: [set-image] container: image: ${{ needs.set-image.outputs.IMAGE }} @@ -40,7 +40,7 @@ jobs: run: cargo +nightly fmt --all -- --check check-dependency-rules: runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 20 steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: check dependency rules @@ -49,17 +49,23 @@ jobs: ../.gitlab/ensure-deps.sh check-rust-feature-propagation: runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 20 needs: [set-image] container: image: ${{ needs.set-image.outputs.IMAGE }} steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: fetch deps + run: | + # Pull all dependencies eagerly: + time cargo metadata --format-version=1 --locked > /dev/null - name: run zepter - run: zepter run check + run: | + zepter --version + time zepter run check test-rust-features: runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 20 needs: [set-image] container: image: ${{ needs.set-image.outputs.IMAGE }} @@ -69,7 +75,7 @@ jobs: run: bash .gitlab/rust-features.sh . check-toml-format: runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 20 needs: [set-image] container: image: ${{ needs.set-image.outputs.IMAGE }} @@ -81,7 +87,7 @@ jobs: echo "Please run `taplo format --config .config/taplo.toml` to fix any toml formatting issues" check-workspace: runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 20 steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.0 (22. Sep 2023) - name: install python deps @@ -98,12 +104,12 @@ jobs: run: python3 .github/scripts/deny-git-deps.py . check-markdown: runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 20 steps: - name: Checkout sources uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup Node.js - uses: actions/setup-node@v4.0.1 + uses: actions/setup-node@v4.0.3 with: node-version: "18.x" registry-url: "https://npm.pkg.github.com" @@ -121,7 +127,7 @@ jobs: markdownlint --config "$CONFIG" --ignore target . check-umbrella: runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 20 needs: [set-image] container: image: ${{ needs.set-image.outputs.IMAGE }} diff --git a/.github/workflows/command-bench-all.yml b/.github/workflows/command-bench-all.yml index b3fa0868c48797775c0ef8eff67e3acbd7f6facd..4128f86fb7c82f76e658fd39fad3365395a244e2 100644 --- a/.github/workflows/command-bench-all.yml +++ b/.github/workflows/command-bench-all.yml @@ -1,7 +1,7 @@ name: Command Bench All -on: - workflow_dispatch: +on: + workflow_dispatch: inputs: pr: description: Number of the Pull Request @@ -51,9 +51,8 @@ on: - people-rococo - people-westend - jobs: - set-image: + set-image: runs-on: ubuntu-latest outputs: IMAGE: ${{ steps.set_image.outputs.IMAGE }} @@ -64,9 +63,12 @@ jobs: run: cat .github/env >> $GITHUB_OUTPUT cmd-bench-all: needs: [set-image] - runs-on: arc-runners-polkadot-sdk-benchmark + runs-on: arc-runners-polkadot-sdk-weights container: image: ${{ needs.set-image.outputs.IMAGE }} + permissions: + contents: write + pull-requests: write steps: - name: Download repo uses: actions/checkout@v4 diff --git a/.github/workflows/command-bench-overhead.yml b/.github/workflows/command-bench-overhead.yml index 735b401021061c3dde3dd065a12d9f6f538b8c93..fec8d37bb9ef80505c9569da08071ccee7275067 100644 --- a/.github/workflows/command-bench-overhead.yml +++ b/.github/workflows/command-bench-overhead.yml @@ -1,7 +1,7 @@ name: Command Bench Overhead -on: - workflow_dispatch: +on: + workflow_dispatch: inputs: pr: description: Number of the Pull Request @@ -31,7 +31,7 @@ on: - cumulus jobs: - set-image: + set-image: runs-on: ubuntu-latest outputs: IMAGE: ${{ steps.set_image.outputs.IMAGE }} @@ -45,6 +45,9 @@ jobs: runs-on: arc-runners-polkadot-sdk-benchmark container: image: ${{ needs.set-image.outputs.IMAGE }} + permissions: + contents: write + pull-requests: write steps: - name: Download repo uses: actions/checkout@v4 diff --git a/.github/workflows/command-bench.yml b/.github/workflows/command-bench.yml index 0ff166be48c193aa00e858b3bf7138b856487e24..ac879f443755c65948c51f592dacc39ceb8f5c25 100644 --- a/.github/workflows/command-bench.yml +++ b/.github/workflows/command-bench.yml @@ -1,7 +1,7 @@ name: Command Bench -on: - workflow_dispatch: +on: + workflow_dispatch: inputs: pr: description: Number of the Pull Request @@ -76,9 +76,8 @@ on: - starters - testing - jobs: - set-image: + set-image: runs-on: ubuntu-latest outputs: IMAGE: ${{ steps.set_image.outputs.IMAGE }} @@ -92,6 +91,9 @@ jobs: runs-on: arc-runners-polkadot-sdk-benchmark container: image: ${{ needs.set-image.outputs.IMAGE }} + permissions: + contents: write + pull-requests: write steps: - name: Download repo uses: actions/checkout@v4 diff --git a/.github/workflows/command-fmt.yml b/.github/workflows/command-fmt.yml index d415007d938390ded98a95f5f5c8ecc61fb0dc84..fc37a17ac549b06e6850ea8a209ec4b27db8fb3f 100644 --- a/.github/workflows/command-fmt.yml +++ b/.github/workflows/command-fmt.yml @@ -1,14 +1,14 @@ name: Command FMT -on: - workflow_dispatch: +on: + workflow_dispatch: inputs: pr: description: Number of the Pull Request required: true jobs: - set-image: + set-image: runs-on: ubuntu-latest outputs: IMAGE: ${{ steps.set_image.outputs.IMAGE }} @@ -20,8 +20,12 @@ jobs: cmd-fmt: needs: [set-image] runs-on: ubuntu-latest + timeout-minutes: 20 container: image: ${{ needs.set-image.outputs.IMAGE }} + permissions: + contents: write + pull-requests: write steps: - name: Download repo uses: actions/checkout@v4 @@ -33,6 +37,13 @@ jobs: GH_TOKEN: ${{ github.token }} - name: Run FMT run: | + cargo --version + rustc --version + cargo +nightly --version + rustc +nightly --version + + cargo +nightly fmt + # format toml. # since paritytech/ci-unified:bullseye-1.73.0-2023-11-01-v20231204 includes taplo-cli taplo format --config .config/taplo.toml diff --git a/.github/workflows/command-inform.yml b/.github/workflows/command-inform.yml index 1c7323c998dfee3ba822f4bcb655c57a958fd80f..2825f4a604605fea8465ce0646d664c9ef5d38f5 100644 --- a/.github/workflows/command-inform.yml +++ b/.github/workflows/command-inform.yml @@ -7,9 +7,15 @@ on: jobs: comment: runs-on: ubuntu-latest + if: github.event.issue.pull_request && startsWith(github.event.comment.body, 'bot ') steps: - name: Inform that the new command exist - if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, 'bot ') }} - run: gh pr comment ${{ github.event.issue.number }} --body 'We are migrating this bot to be a GitHub Action

Please, see the documentation on how to use it' - env: - GH_TOKEN: ${{ github.token }} + uses: actions/github-script@v7 + with: + script: | + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: 'We are migrating the command bot to be a GitHub Action

Please, see the documentation on how to use it' + }) diff --git a/.github/workflows/command-sync.yml b/.github/workflows/command-sync.yml new file mode 100644 index 0000000000000000000000000000000000000000..c610f4066a873e3fe7304bebd2f4b866fe837a91 --- /dev/null +++ b/.github/workflows/command-sync.yml @@ -0,0 +1,71 @@ +name: Command Sync + +on: + workflow_dispatch: + inputs: + pr: + description: Number of the Pull Request + required: true + chain: + description: Chain + type: choice + required: true + options: + - westend + - rococo + sync-type: + description: Sync type + type: choice + required: true + options: + - warp + - full + - fast + - fast-unsafe + +jobs: + set-image: + runs-on: ubuntu-latest + outputs: + IMAGE: ${{ steps.set_image.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - id: set_image + run: cat .github/env >> $GITHUB_OUTPUT + cmd-sync: + needs: [set-image] + runs-on: arc-runners-polkadot-sdk-warpsync + container: + image: ${{ needs.set-image.outputs.IMAGE }} + permissions: + contents: write + pull-requests: write + steps: + - name: Download repo + uses: actions/checkout@v4 + - name: Install gh cli + id: gh + uses: ./.github/actions/set-up-gh + with: + pr-number: ${{ inputs.pr }} + GH_TOKEN: ${{ github.token }} + - name: Run sync + run: | + "./scripts/sync.sh" --chain "${{ inputs.chain }}" --type "${{ inputs.sync-type }}" + - name: Report failure + if: ${{ failure() }} + run: gh pr comment ${{ inputs.pr }} --body "

Command failed โŒ

Run by @${{ github.actor }} for ${{ github.workflow }} failed. See logs here." + env: + RUN: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GH_TOKEN: ${{ github.token }} + - run: git pull --rebase + - uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: cmd-action - ${{ github.workflow }} + branch: ${{ steps.gh.outputs.branch }} + - name: Report succeed + run: gh pr comment ${{ inputs.pr }} --body "

Action completed ๐ŸŽ‰๐ŸŽ‰

Run by @${{ github.actor }} for ${{ github.workflow }} completed ๐ŸŽ‰. See logs here." + env: + RUN: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GH_TOKEN: ${{ github.token }} diff --git a/.github/workflows/command-update-ui.yml b/.github/workflows/command-update-ui.yml index 9b9c45c5c0b9d78f0287b8d00314e0c58fff0c69..860177adc8790c28f7cd5873f4f8e0adf24a044f 100644 --- a/.github/workflows/command-update-ui.yml +++ b/.github/workflows/command-update-ui.yml @@ -1,7 +1,7 @@ name: Command Update UI -on: - workflow_dispatch: +on: + workflow_dispatch: inputs: pr: description: Number of the Pull Request @@ -11,7 +11,7 @@ on: required: false jobs: - set-image: + set-image: runs-on: ubuntu-latest outputs: IMAGE: ${{ steps.set_image.outputs.IMAGE }} @@ -23,8 +23,12 @@ jobs: cmd-update-ui: needs: [set-image] runs-on: arc-runners-polkadot-sdk-beefy + timeout-minutes: 90 container: image: ${{ needs.set-image.outputs.IMAGE }} + permissions: + contents: write + pull-requests: write steps: - name: Download repo uses: actions/checkout@v4 diff --git a/.github/workflows/misc-sync-templates.yml b/.github/workflows/misc-sync-templates.yml index d8027014863936ffd6c6a217f282dfa45bc2edd7..6fe907c76acaa08dcd0c85ae40b507bfaee70536 100644 --- a/.github/workflows/misc-sync-templates.yml +++ b/.github/workflows/misc-sync-templates.yml @@ -90,7 +90,12 @@ jobs: "runtime", ] resolver = "2" + + [workspace.dependencies] EOF + + echo "$(toml get -r ./runtime/Cargo.toml 'package.name') = { path = \"./runtime\", default-features = false }" >> Cargo.toml + echo "$(toml get -r ./pallets/template/Cargo.toml 'package.name') = { path = \"./pallets/template\", default-features = false }" >> Cargo.toml shell: bash working-directory: polkadot-sdk/templates/${{ matrix.template }}/ - name: Update workspace configuration @@ -116,9 +121,12 @@ jobs: - name: Copy over the new changes run: | cp -r polkadot-sdk/templates/${{ matrix.template }}/* "${{ env.template-path }}/" + + - name: Run psvm on monorepo workspace dependencies + run: psvm -o -v ${{ github.event.inputs.crate_release_version }} -p ./Cargo.toml + working-directory: polkadot-sdk/ - name: Copy over required workspace dependencies run: | - echo -e "\n[workspace.dependencies]" >> Cargo.toml set +e # If a workspace dependency is required.. while cargo tree --depth 1 --prefix none --no-dedupe 2>&1 | grep 'was not found in `workspace.dependencies`'; do @@ -150,7 +158,7 @@ jobs: timeout-minutes: 90 - name: Create PR on failure if: failure() && steps.check-compilation.outcome == 'failure' - uses: peter-evans/create-pull-request@5b4a9f6a9e2af26e5f02351490b90d01eb8ec1e5 # v5 + uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v5 with: path: "${{ env.template-path }}" token: ${{ steps.app_token.outputs.token }} diff --git a/.github/workflows/misc-update-wishlist-leaderboard.yml b/.github/workflows/misc-update-wishlist-leaderboard.yml new file mode 100644 index 0000000000000000000000000000000000000000..a825c4641124246032ac262989a0dc07af669150 --- /dev/null +++ b/.github/workflows/misc-update-wishlist-leaderboard.yml @@ -0,0 +1,36 @@ +name: Update wishlist leaderboard + +on: + schedule: + # Run every 3 hours + - cron: '0 */3 * * *' + +permissions: + contents: read + issues: write + +jobs: + update-wishlist-leaderboard: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install PyGithub + - name: Update developer wishlist + env: + GH_TOKEN: ${{ github.token }} + WISHLIST_REPOSITORY: "paritytech/polkadot-sdk" + WISHLIST_ISSUE_NUMBER: "3900" + run: python .github/scripts/update-wishlist-leaderboard.py + - name: Update user wishlist + env: + GH_TOKEN: ${{ github.token }} + WISHLIST_REPOSITORY: "paritytech/polkadot-sdk" + WISHLIST_ISSUE_NUMBER: "3901" + run: python .github/scripts/update-wishlist-leaderboard.py diff --git a/.github/workflows/publish-check-crates.yml b/.github/workflows/publish-check-crates.yml index 9b5b89e34475699ccbcaeca34cd290882ee45a9a..92b4d13e9deb289f7b00d7e6fcfad93d524749c7 100644 --- a/.github/workflows/publish-check-crates.yml +++ b/.github/workflows/publish-check-crates.yml @@ -20,7 +20,7 @@ jobs: cache-on-failure: true - name: install parity-publish - run: cargo install parity-publish@0.5.1 + run: cargo install parity-publish@0.7.0 - name: parity-publish check run: parity-publish --color always check --allow-unpublished diff --git a/.github/workflows/publish-claim-crates.yml b/.github/workflows/publish-claim-crates.yml index 9643361d9d318f84d64a212358a825a8e0b5aa20..b6a84090f729ab5b2333ac1496338e5f5d09d248 100644 --- a/.github/workflows/publish-claim-crates.yml +++ b/.github/workflows/publish-claim-crates.yml @@ -18,7 +18,7 @@ jobs: cache-on-failure: true - name: install parity-publish - run: cargo install parity-publish@0.5.1 + run: cargo install parity-publish@0.7.0 - name: parity-publish claim env: diff --git a/.github/workflows/release-10_rc-automation.yml b/.github/workflows/release-10_rc-automation.yml index 7231a8b75886d04ce18bb89fcef99029e3ab14c6..f5c5de8d0da97546d2adfbcdfabd4805d96e8a70 100644 --- a/.github/workflows/release-10_rc-automation.yml +++ b/.github/workflows/release-10_rc-automation.yml @@ -1,13 +1,18 @@ name: Release - RC automation on: - push: - branches: - # Catches release-polkadot-v1.2.3, release-v1.2.3-rc1, etc - - release-v[0-9]+.[0-9]+.[0-9]+* - - release-cumulus-v[0-9]+* - - release-polkadot-v[0-9]+* + # TODO: Activate it and delete old branches patterns, when the release process from stable is setteled + #push: + # branches: + # # Catches release-polkadot-v1.2.3, release-v1.2.3-rc1, etc + # - release-v[0-9]+.[0-9]+.[0-9]+* + # - release-cumulus-v[0-9]+* + # - release-polkadot-v[0-9]+* + # - stable workflow_dispatch: + inputs: + version: + description: Current release/rc version in format vX.X.X jobs: tag_rc: @@ -25,28 +30,19 @@ jobs: with: fetch-depth: 0 - - name: Get release product - id: get_rel_product - shell: bash - run: | - current_branch=$(git branch --show-current) - echo "Current branch: $current_branch" - if [[ "$current_branch" =~ "release-polkadot" ]]; then - echo "product=polkadot" >> $GITHUB_OUTPUT - elif [[ "$current_branch" =~ "release-cumulus" ]]; then - echo "product=polkadot-parachain" >> $GITHUB_OUTPUT - fi - - - - name: Compute next rc tag for polkadot - if: ${{ steps.get_rel_product.outputs.product == 'polkadot' }} - id: compute_tag_polkadot + - name: Compute next rc tag + # if: ${{ steps.get_rel_product.outputs.product == 'polkadot' }} + id: compute_tag shell: bash run: | . ./.github/scripts/common/lib.sh # Get last rc tag if exists, else set it to {version}-rc1 - version=$(get_version_from_ghref ${GITHUB_REF}) + if [[ -z "${{ inputs.version }}" ]]; then + version=v$(get_polkadot_node_version_from_code) + else + version=$(filter_version_from_input ${{ inputs.version }}) + fi echo "$version" echo "version=$version" >> $GITHUB_OUTPUT @@ -61,28 +57,6 @@ jobs: echo "first_rc=true" >> $GITHUB_OUTPUT fi - - name: Compute next rc tag for polkadot-parachain - if: ${{ steps.get_rel_product.outputs.product == 'polkadot-parachain' }} - id: compute_tag_cumulus - shell: bash - run: | - . ./.github/scripts/common/lib.sh - - # Get last rc tag if exists, else set it to polkadot-parachains-{version}-rc1 - version=$(get_version_from_ghref ${GITHUB_REF}) - echo "$version" - echo "version=$version" >> $GITHUB_OUTPUT - - last_rc=$(get_latest_rc_tag $version polkadot-parachain) - if [ -n "$last_rc" ]; then - suffix=$(increment_rc_tag $last_rc) - echo "new_tag=polkadot-parachains-$version-rc$suffix" >> $GITHUB_OUTPUT - echo "first_rc=false" >> $GITHUB_OUTPUT - else - echo "new_tag=polkadot-parachain-$version-rc1" >> $GITHUB_OUTPUT - echo "first_rc=true" >> $GITHUB_OUTPUT - fi - - name: Apply new tag uses: tvdias/github-tagger@ed7350546e3e503b5e942dffd65bc8751a95e49d # v0.0.2 with: @@ -90,17 +64,7 @@ jobs: # https://docs.github.com/en/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token # RELEASE_BRANCH_TOKEN requires public_repo OAuth scope repo-token: "${{ secrets.RELEASE_BRANCH_TOKEN }}" - tag: ${{ steps.compute_tag_polkadot.outputs.new_tag || steps.compute_tag_cumulus.outputs.new_tag }} - - # - id: create-issue - # uses: JasonEtco/create-an-issue@e27dddc79c92bc6e4562f268fffa5ed752639abd # v2.9.1 - # # Only create the issue if it's the first release candidate - # if: steps.compute_tag.outputs.first_rc == 'true' - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # VERSION: ${{ steps.compute_tag.outputs.version }} - # with: - # filename: .github/ISSUE_TEMPLATE/release.md + tag: ${{ steps.compute_tag.outputs.new_tag }} - name: Send Matrix message to ${{ matrix.channel.name }} uses: s3krit/matrix-message-action@70ad3fb812ee0e45ff8999d6af11cafad11a6ecf # v0.0.3 @@ -110,4 +74,4 @@ jobs: access_token: ${{ secrets.RELEASENOTES_MATRIX_V2_ACCESS_TOKEN }} server: m.parity.io message: | - Release process for polkadot ${{ steps.compute_tag_polkadot.outputs.new_tag || steps.compute_tag_cumulus.outputs.new_tag }} has been started.
+ Release process for polkadot ${{ steps.compute_tag.outputs.new_tag }} has been started.
diff --git a/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml index 4679f58578f7906b75e4a3d6d623ebc1d55df40d..63124a489e9db589b9928c88fa0c335235eea8be 100644 --- a/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -179,6 +179,7 @@ jobs: release=$( echo $VERSION | cut -f1 -d- ) echo "tag=latest" >> $GITHUB_OUTPUT echo "release=${release}" >> $GITHUB_OUTPUT + echo "stable=stable" >> $GITHUB_OUTPUT - name: Build Injected Container image for polkadot rc or chain-spec-builder if: ${{ env.BINARY == 'polkadot' || env.BINARY == 'chain-spec-builder' }} @@ -209,7 +210,7 @@ jobs: ./docker/scripts/build-injected.sh - name: Login to Dockerhub - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: username: ${{ secrets.CUMULUS_DOCKERHUB_USERNAME }} password: ${{ secrets.CUMULUS_DOCKERHUB_TOKEN }} @@ -274,7 +275,7 @@ jobs: ${{ runner.os }}-buildx- - name: Login to Docker Hub - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: username: ${{ secrets.POLKADOT_DOCKERHUB_USERNAME }} password: ${{ secrets.POLKADOT_DOCKERHUB_TOKEN }} @@ -287,13 +288,14 @@ jobs: - name: Build and push id: docker_build - uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0 + uses: docker/build-push-action@5176d81f87c23d6fc96624dfdbcd9f3830bbe445 # v6.5.0 with: push: true file: docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile # TODO: The owner should be used below but buildx does not resolve the VARs # TODO: It would be good to get rid of this GHA that we don't really need. tags: | + parity/polkadot:stable parity/polkadot:latest parity/polkadot:${{ needs.fetch-latest-debian-package-version.outputs.polkadot_container_tag }} build-args: | diff --git a/.github/workflows/release-srtool.yml b/.github/workflows/release-srtool.yml index 69a4bdbdda9ae87a188a23bceb9185d813424a98..e98269fecab0085f1fd6f32acb3aea9b98a5f235 100644 --- a/.github/workflows/release-srtool.yml +++ b/.github/workflows/release-srtool.yml @@ -5,11 +5,6 @@ env: TOML_CLI_VERSION: 0.2.4 on: - push: - branches: - - release-v[0-9]+.[0-9]+.[0-9]+* - - release-cumulus-v[0-9]+* - - release-polkadot-v[0-9]+* workflow_call: inputs: excluded_runtimes: diff --git a/.github/workflows/review-bot.yml b/.github/workflows/review-bot.yml index f1401406ae47afd3230cc163f35df0e3bcbac7b7..0d83b75b3bde5fa24c1daf86e0d8b8411b626bbc 100644 --- a/.github/workflows/review-bot.yml +++ b/.github/workflows/review-bot.yml @@ -30,7 +30,7 @@ jobs: with: artifact-name: pr_number - name: "Evaluates PR reviews and assigns reviewers" - uses: paritytech/review-bot@v2.4.0 + uses: paritytech/review-bot@v2.5.0 with: repo-token: ${{ steps.app_token.outputs.token }} team-token: ${{ steps.app_token.outputs.token }} diff --git a/.github/workflows/tests-linux-stable.yml b/.github/workflows/tests-linux-stable.yml index 6f2ac87c3efbea16efc9a5564fa770cd0f9ffbdf..55addf11de06db43b30b336d83b39f282d03c292 100644 --- a/.github/workflows/tests-linux-stable.yml +++ b/.github/workflows/tests-linux-stable.yml @@ -37,7 +37,7 @@ jobs: needs: [set-image, changes] if: ${{ needs.changes.outputs.rust }} runs-on: arc-runners-polkadot-sdk-beefy - timeout-minutes: 30 + timeout-minutes: 60 container: image: ${{ needs.set-image.outputs.IMAGE }} env: @@ -58,7 +58,7 @@ jobs: needs: [set-image, changes] if: ${{ needs.changes.outputs.rust }} runs-on: arc-runners-polkadot-sdk-beefy - timeout-minutes: 30 + timeout-minutes: 60 container: image: ${{ needs.set-image.outputs.IMAGE }} env: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0c1447cba33a372cbbf4cb057b9f63dd49565468..a413d330615931faab5326da6aee31469ac2903f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -34,7 +34,7 @@ jobs: needs: [set-image, changes] if: ${{ needs.changes.outputs.rust }} runs-on: arc-runners-polkadot-sdk-beefy - timeout-minutes: 30 + timeout-minutes: 60 container: image: ${{ needs.set-image.outputs.IMAGE }} env: @@ -53,7 +53,7 @@ jobs: needs: [set-image, changes] if: ${{ needs.changes.outputs.rust }} runs-on: arc-runners-polkadot-sdk-beefy - timeout-minutes: 30 + timeout-minutes: 60 container: image: ${{ needs.set-image.outputs.IMAGE }} continue-on-error: true # this rarely triggers in practice @@ -78,7 +78,7 @@ jobs: needs: [set-image, changes] if: ${{ needs.changes.outputs.rust }} runs-on: arc-runners-polkadot-sdk-beefy - timeout-minutes: 30 + timeout-minutes: 60 container: image: ${{ needs.set-image.outputs.IMAGE }} env: diff --git a/.gitignore b/.gitignore index 2f1631fb4b9d14496021907cca96b4cdf4902eb8..e3e382af6195ed4692672285a14e1cf5f1600a85 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ *.orig *.rej *.swp +*.wasm **/._* **/.criterion/ **/*.rs.bk diff --git a/.gitlab/pipeline/zombienet/cumulus.yml b/.gitlab/pipeline/zombienet/cumulus.yml index a7f321505bacf99df202c1469e7a75b4f0b30ba4..6e2b53fae6198501297960de84ecdb1606d3e128 100644 --- a/.gitlab/pipeline/zombienet/cumulus.yml +++ b/.gitlab/pipeline/zombienet/cumulus.yml @@ -149,3 +149,27 @@ zombienet-cumulus-0007-full_node_warp_sync: --local-dir="${LOCAL_DIR}" --concurrency=1 --test="0007-full_node_warp_sync.zndsl" + +zombienet-cumulus-0008-elastic_authoring: + extends: + - .zombienet-cumulus-common + - .zombienet-refs + - .zombienet-before-script + - .zombienet-after-script + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh + --local-dir="${LOCAL_DIR}" + --concurrency=1 + --test="0008-elastic_authoring.zndsl" + +zombienet-cumulus-0009-elastic_pov_recovery: + extends: + - .zombienet-cumulus-common + - .zombienet-refs + - .zombienet-before-script + - .zombienet-after-script + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh + --local-dir="${LOCAL_DIR}" + --concurrency=1 + --test="0009-elastic_pov_recovery.zndsl" diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml index 90251082077ce07f739a5b122deaf6023dcfeaa6..b4ef4bb7446c8a9bfe602322cd8ac07a30f14b40 100644 --- a/.gitlab/pipeline/zombienet/polkadot.yml +++ b/.gitlab/pipeline/zombienet/polkadot.yml @@ -276,6 +276,14 @@ zombienet-polkadot-smoke-0004-coretime-smoke-test: --local-dir="${LOCAL_DIR}/smoke" --test="0004-coretime-smoke-test.zndsl" +zombienet-polkadot-smoke-0005-precompile-pvf-smoke: + extends: + - .zombienet-polkadot-common + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh + --local-dir="${LOCAL_DIR}/smoke" + --test="0005-precompile-pvf-smoke.zndsl" + zombienet-polkadot-misc-0001-parachains-paritydb: extends: - .zombienet-polkadot-common diff --git a/Cargo.lock b/Cargo.lock index f86907030f84f79802db0172a7484126662fff8d..bce9bf3d03522fa36630f905d1f50a62b0c9f4ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -83,7 +83,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.10", + "getrandom", "once_cell", "version_check", ] @@ -95,7 +95,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom 0.2.10", + "getrandom", "once_cell", "version_check", "zerocopy", @@ -130,7 +130,7 @@ dependencies = [ "hex-literal", "itoa", "proptest", - "rand 0.8.5", + "rand", "ruint", "serde", "tiny-keccak", @@ -158,7 +158,7 @@ dependencies = [ "heck 0.4.1", "proc-macro-error", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", "syn-solidity", "tiny-keccak", @@ -262,9 +262,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "approx" @@ -285,7 +285,7 @@ dependencies = [ "itertools 0.10.5", "proc-macro-error", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -484,7 +484,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" dependencies = [ - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -494,7 +494,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" dependencies = [ - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -506,7 +506,7 @@ checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" dependencies = [ "num-bigint", "num-traits", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -519,7 +519,7 @@ dependencies = [ "num-bigint", "num-traits", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -580,7 +580,7 @@ dependencies = [ [[package]] name = "ark-secret-scalar" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" +source = "git+https://github.com/w3f/ring-vrf?rev=0fef826#0fef8266d851932ad25d6b41bc4b34d834d1e11d" dependencies = [ "ark-ec", "ark-ff 0.4.2", @@ -621,7 +621,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -632,7 +632,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" dependencies = [ "num-traits", - "rand 0.8.5", + "rand", ] [[package]] @@ -642,20 +642,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", - "rand 0.8.5", + "rand", "rayon", ] [[package]] name = "ark-transcript" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" +source = "git+https://github.com/w3f/ring-vrf?rev=0fef826#0fef8266d851932ad25d6b41bc4b34d834d1e11d" dependencies = [ "ark-ff 0.4.2", "ark-serialize 0.4.2", "ark-std 0.4.0", "digest 0.10.7", - "rand_core 0.6.4", + "rand_core", "sha3", ] @@ -692,8 +692,24 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" dependencies = [ - "asn1-rs-derive", - "asn1-rs-impl", + "asn1-rs-derive 0.4.0", + "asn1-rs-impl 0.1.0", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "asn1-rs" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ad1373757efa0f70ec53939aabc7152e1591cb485208052993070ac8d2429d" +dependencies = [ + "asn1-rs-derive 0.5.0", + "asn1-rs-impl 0.2.0", "displaydoc", "nom", "num-traits", @@ -709,9 +725,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", - "synstructure", + "synstructure 0.12.6", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.36", + "syn 2.0.61", + "synstructure 0.13.1", ] [[package]] @@ -721,15 +749,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.36", + "syn 2.0.61", +] + [[package]] name = "assert_cmd" -version = "2.0.12" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88903cb14723e4d4003335bb7f8a14f27691649105346a0f0957466c096adfe6" +checksum = "ed72493ac66d5804837f480ab3766c72bdfab91a65e565fc54fa9e42db0073a8" dependencies = [ "anstyle", "bstr", @@ -766,7 +805,6 @@ name = "asset-hub-rococo-integration-tests" version = "1.0.0" dependencies = [ "assert_matches", - "asset-hub-rococo-runtime", "asset-test-utils", "cumulus-pallet-parachain-system", "emulated-integration-tests-common", @@ -780,9 +818,7 @@ dependencies = [ "pallet-xcm", "parachains-common", "parity-scale-codec", - "penpal-runtime", "polkadot-runtime-common", - "rococo-runtime", "rococo-runtime-constants", "rococo-system-emulated-network", "sp-runtime", @@ -860,7 +896,6 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std 14.0.0", "sp-storage 19.0.0", "sp-transaction-pool", "sp-version", @@ -871,7 +906,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "testnet-parachains-constants", - "xcm-fee-payment-runtime-api", + "xcm-runtime-apis", ] [[package]] @@ -894,7 +929,6 @@ name = "asset-hub-westend-integration-tests" version = "1.0.0" dependencies = [ "assert_matches", - "asset-hub-westend-runtime", "asset-test-utils", "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", @@ -912,16 +946,14 @@ dependencies = [ "pallet-xcm", "parachains-common", "parity-scale-codec", - "penpal-runtime", "polkadot-runtime-common", "sp-core", "sp-keyring", "sp-runtime", "staging-xcm", "staging-xcm-executor", - "westend-runtime", "westend-system-emulated-network", - "xcm-fee-payment-runtime-api", + "xcm-runtime-apis", ] [[package]] @@ -993,7 +1025,6 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std 14.0.0", "sp-storage 19.0.0", "sp-transaction-pool", "sp-version", @@ -1004,7 +1035,7 @@ dependencies = [ "substrate-wasm-builder", "testnet-parachains-constants", "westend-runtime-constants", - "xcm-fee-payment-runtime-api", + "xcm-runtime-apis", ] [[package]] @@ -1029,7 +1060,6 @@ dependencies = [ "parity-scale-codec", "sp-io", "sp-runtime", - "sp-std 14.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -1052,7 +1082,6 @@ dependencies = [ "scale-info", "sp-api", "sp-runtime", - "sp-std 14.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -1065,7 +1094,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" dependencies = [ - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -1076,7 +1105,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", - "event-listener", + "event-listener 2.5.3", "futures-core", ] @@ -1086,11 +1115,11 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" dependencies = [ - "async-lock", + "async-lock 2.8.0", "async-task", "concurrent-queue", "fastrand 1.9.0", - "futures-lite", + "futures-lite 1.13.0", "slab", ] @@ -1100,10 +1129,10 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" dependencies = [ - "async-lock", + "async-lock 2.8.0", "autocfg", "blocking", - "futures-lite", + "futures-lite 1.13.0", ] [[package]] @@ -1114,10 +1143,10 @@ checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" dependencies = [ "async-channel", "async-executor", - "async-io", - "async-lock", + "async-io 1.13.0", + "async-lock 2.8.0", "blocking", - "futures-lite", + "futures-lite 1.13.0", "once_cell", ] @@ -1127,27 +1156,57 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ - "async-lock", + "async-lock 2.8.0", "autocfg", "cfg-if", "concurrent-queue", - "futures-lite", + "futures-lite 1.13.0", "log", "parking", - "polling", + "polling 2.8.0", "rustix 0.37.23", "slab", "socket2 0.4.9", "waker-fn", ] +[[package]] +name = "async-io" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +dependencies = [ + "async-lock 3.4.0", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.3.0", + "parking", + "polling 3.4.0", + "rustix 0.38.21", + "slab", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "async-lock" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ - "event-listener", + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.2.0", + "event-listener-strategy", + "pin-project-lite", ] [[package]] @@ -1156,10 +1215,10 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4051e67316bc7eff608fe723df5d32ed639946adcd69e07df41fd42a7b411f1f" dependencies = [ - "async-io", + "async-io 1.13.0", "autocfg", "blocking", - "futures-lite", + "futures-lite 1.13.0", ] [[package]] @@ -1168,13 +1227,13 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9" dependencies = [ - "async-io", - "async-lock", + "async-io 1.13.0", + "async-lock 2.8.0", "autocfg", "blocking", "cfg-if", - "event-listener", - "futures-lite", + "event-listener 2.5.3", + "futures-lite 1.13.0", "rustix 0.37.23", "signal-hook", "windows-sys 0.48.0", @@ -1189,19 +1248,19 @@ dependencies = [ "async-attributes", "async-channel", "async-global-executor", - "async-io", - "async-lock", + "async-io 1.13.0", + "async-lock 2.8.0", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-lite", + "futures-lite 1.13.0", "gloo-timers", "kv-log-macro", "log", "memchr", "once_cell", - "pin-project-lite 0.2.12", + "pin-project-lite", "pin-utils", "slab", "wasm-bindgen-futures", @@ -1215,7 +1274,7 @@ checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", - "pin-project-lite 0.2.12", + "pin-project-lite", ] [[package]] @@ -1225,7 +1284,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -1237,12 +1296,12 @@ checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" [[package]] name = "async-trait" -version = "0.1.79" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -1256,7 +1315,7 @@ dependencies = [ "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.12", + "pin-project-lite", ] [[package]] @@ -1271,6 +1330,17 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" +[[package]] +name = "attohttpc" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9a9bf8b79a749ee0b911b91b671cc2b6c670bdbc7e3dfd537576ddc94bb2a2" +dependencies = [ + "http 0.2.9", + "log", + "url", +] + [[package]] name = "atty" version = "0.2.14" @@ -1290,7 +1360,7 @@ checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" dependencies = [ "proc-macro-error", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -1306,16 +1376,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" dependencies = [ - "getrandom 0.2.10", + "getrandom", "instant", - "rand 0.8.5", + "rand", ] [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line 0.21.0", "cc", @@ -1329,7 +1399,7 @@ dependencies = [ [[package]] name = "bandersnatch_vrfs" version = "0.0.4" -source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" +source = "git+https://github.com/w3f/ring-vrf?rev=0fef826#0fef8266d851932ad25d6b41bc4b34d834d1e11d" dependencies = [ "ark-bls12-381", "ark-ec", @@ -1338,10 +1408,8 @@ dependencies = [ "ark-serialize 0.4.2", "ark-std 0.4.0", "dleq_vrf", - "fflonk", - "merlin", - "rand_chacha 0.3.1", - "rand_core 0.6.4", + "rand_chacha", + "rand_core", "ring 0.1.0", "sha2 0.10.8", "sp-ark-bls12-381", @@ -1373,6 +1441,12 @@ version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "base64ct" version = "1.6.0" @@ -1432,7 +1506,7 @@ dependencies = [ "peeking_take_while", "prettyplease 0.2.12", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "regex", "rustc-hash", "shlex", @@ -1495,9 +1569,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bitvec" @@ -1603,11 +1677,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" dependencies = [ "async-channel", - "async-lock", + "async-lock 2.8.0", "async-task", "atomic-waker", "fastrand 1.9.0", - "futures-lite", + "futures-lite 1.13.0", "log", ] @@ -1904,7 +1978,7 @@ dependencies = [ "bp-parachains", "bp-polkadot-core", "bp-runtime", - "ed25519-dalek 2.1.1", + "ed25519-dalek", "finality-grandpa", "parity-scale-codec", "sp-application-crypto", @@ -1956,7 +2030,6 @@ dependencies = [ "snowbridge-core", "sp-core", "sp-runtime", - "sp-std 14.0.0", "staging-xcm", ] @@ -1977,8 +2050,6 @@ dependencies = [ name = "bridge-hub-rococo-integration-tests" version = "1.0.0" dependencies = [ - "asset-hub-rococo-runtime", - "bridge-hub-rococo-runtime", "cumulus-pallet-xcmp-queue", "emulated-integration-tests-common", "frame-support", @@ -2100,10 +2171,9 @@ dependencies = [ "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", - "static_assertions", "substrate-wasm-builder", "testnet-parachains-constants", - "xcm-fee-payment-runtime-api", + "xcm-runtime-apis", ] [[package]] @@ -2138,7 +2208,6 @@ dependencies = [ "sp-io", "sp-keyring", "sp-runtime", - "sp-std 14.0.0", "sp-tracing 16.0.0", "staging-xcm", "staging-xcm-builder", @@ -2162,10 +2231,10 @@ dependencies = [ name = "bridge-hub-westend-integration-tests" version = "1.0.0" dependencies = [ - "bridge-hub-westend-runtime", "cumulus-pallet-xcmp-queue", "emulated-integration-tests-common", "frame-support", + "hex-literal", "pallet-asset-conversion", "pallet-assets", "pallet-balances", @@ -2259,11 +2328,10 @@ dependencies = [ "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", - "static_assertions", "substrate-wasm-builder", "testnet-parachains-constants", "westend-runtime-constants", - "xcm-fee-payment-runtime-api", + "xcm-runtime-apis", ] [[package]] @@ -2281,7 +2349,6 @@ dependencies = [ "bp-xcm-bridge-hub-router", "frame-support", "frame-system", - "hash-db", "log", "pallet-balances", "pallet-bridge-grandpa", @@ -2292,8 +2359,6 @@ dependencies = [ "pallet-utility", "parity-scale-codec", "scale-info", - "sp-api", - "sp-core", "sp-io", "sp-runtime", "sp-std 14.0.0", @@ -2442,14 +2507,20 @@ checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" [[package]] name = "cc" -version = "1.0.83" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" dependencies = [ "jobserver", "libc", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cexpr" version = "0.6.0" @@ -2535,7 +2606,6 @@ dependencies = [ "sp-genesis-builder", "sp-keyring", "sp-runtime", - "sp-std 14.0.0", "staging-chain-spec-builder", "substrate-wasm-builder", ] @@ -2591,7 +2661,7 @@ dependencies = [ "multibase", "multihash 0.17.0", "serde", - "unsigned-varint", + "unsigned-varint 0.7.2", ] [[package]] @@ -2604,7 +2674,7 @@ dependencies = [ "multibase", "multihash 0.18.1", "serde", - "unsigned-varint", + "unsigned-varint 0.7.2", ] [[package]] @@ -2681,12 +2751,12 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.3" +version = "4.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" +checksum = "8f6b81fb3c84f5563d509c59b5a48d935f689e993afa90fe39047f05adef9142" dependencies = [ "clap_builder", - "clap_derive 4.5.3", + "clap_derive 4.5.8", ] [[package]] @@ -2700,9 +2770,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "5ca6706fd5224857d9ac5eb9355f6683563cc0541c7cd9d014043b57cbec78ac" dependencies = [ "anstream", "anstyle", @@ -2717,7 +2787,7 @@ version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "586a385f7ef2f8b4d86bddaa0c094794e7ccbfe5ffef1f434fe928143fc783a5" dependencies = [ - "clap 4.5.3", + "clap 4.5.10", ] [[package]] @@ -2729,19 +2799,19 @@ dependencies = [ "heck 0.4.1", "proc-macro-error", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] [[package]] name = "clap_derive" -version = "4.5.3" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" +checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" dependencies = [ "heck 0.5.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -2768,7 +2838,7 @@ checksum = "a90d114103adbc625300f346d4d09dfb4ab1c4a8df6868435dd903392ecf4354" dependencies = [ "libc", "once_cell", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] @@ -2800,8 +2870,6 @@ name = "collectives-westend-integration-tests" version = "1.0.0" dependencies = [ "assert_matches", - "asset-hub-westend-runtime", - "collectives-westend-runtime", "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", "emulated-integration-tests-common", @@ -2820,7 +2888,6 @@ dependencies = [ "staging-xcm", "staging-xcm-executor", "testnet-parachains-constants", - "westend-runtime", "westend-runtime-constants", "westend-system-emulated-network", ] @@ -2888,7 +2955,6 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std 14.0.0", "sp-storage 19.0.0", "sp-transaction-pool", "sp-version", @@ -2899,7 +2965,7 @@ dependencies = [ "substrate-wasm-builder", "testnet-parachains-constants", "westend-runtime-constants", - "xcm-fee-payment-runtime-api", + "xcm-runtime-apis", ] [[package]] @@ -2932,7 +2998,7 @@ checksum = "d51beaa537d73d2d1ff34ee70bc095f170420ab2ec5d687ecd3ec2b0d092514b" dependencies = [ "nom", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -2977,7 +3043,7 @@ dependencies = [ [[package]] name = "common" version = "0.1.0" -source = "git+https://github.com/w3f/ring-proof#b273d33f9981e2bb3375ab45faeb537f7ee35224" +source = "git+https://github.com/w3f/ring-proof?rev=665f5f5#665f5f51af5734c7b6d90b985dd6861d4c5b4752" dependencies = [ "ark-ec", "ark-ff 0.4.2", @@ -2987,7 +3053,7 @@ dependencies = [ "fflonk", "getrandom_or_panic", "merlin", - "rand_chacha 0.3.1", + "rand_chacha", ] [[package]] @@ -3063,7 +3129,7 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb" dependencies = [ - "getrandom 0.2.10", + "getrandom", "once_cell", "proc-macro-hack", "tiny-keccak", @@ -3145,7 +3211,6 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std 14.0.0", "sp-storage 19.0.0", "sp-transaction-pool", "sp-version", @@ -3155,7 +3220,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "testnet-parachains-constants", - "xcm-fee-payment-runtime-api", + "xcm-runtime-apis", ] [[package]] @@ -3166,9 +3231,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -3176,9 +3241,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "core2" @@ -3189,6 +3254,36 @@ dependencies = [ "memchr", ] +[[package]] +name = "coretime-rococo-emulated-chain" +version = "0.0.0" +dependencies = [ + "coretime-rococo-runtime", + "cumulus-primitives-core", + "emulated-integration-tests-common", + "frame-support", + "parachains-common", + "sp-core", + "testnet-parachains-constants", +] + +[[package]] +name = "coretime-rococo-integration-tests" +version = "0.1.0" +dependencies = [ + "emulated-integration-tests-common", + "frame-support", + "pallet-balances", + "pallet-identity", + "pallet-message-queue", + "polkadot-runtime-common", + "rococo-runtime-constants", + "rococo-system-emulated-network", + "sp-runtime", + "staging-xcm", + "staging-xcm-executor", +] + [[package]] name = "coretime-rococo-runtime" version = "0.1.0" @@ -3204,6 +3299,7 @@ dependencies = [ "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", + "frame-metadata-hash-extension", "frame-support", "frame-system", "frame-system-benchmarking", @@ -3242,7 +3338,6 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std 14.0.0", "sp-storage 19.0.0", "sp-transaction-pool", "sp-version", @@ -3252,7 +3347,37 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "testnet-parachains-constants", - "xcm-fee-payment-runtime-api", + "xcm-runtime-apis", +] + +[[package]] +name = "coretime-westend-emulated-chain" +version = "0.0.0" +dependencies = [ + "coretime-westend-runtime", + "cumulus-primitives-core", + "emulated-integration-tests-common", + "frame-support", + "parachains-common", + "sp-core", + "testnet-parachains-constants", +] + +[[package]] +name = "coretime-westend-integration-tests" +version = "0.1.0" +dependencies = [ + "emulated-integration-tests-common", + "frame-support", + "pallet-balances", + "pallet-identity", + "pallet-message-queue", + "polkadot-runtime-common", + "sp-runtime", + "staging-xcm", + "staging-xcm-executor", + "westend-runtime-constants", + "westend-system-emulated-network", ] [[package]] @@ -3270,6 +3395,7 @@ dependencies = [ "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", + "frame-metadata-hash-extension", "frame-support", "frame-system", "frame-system-benchmarking", @@ -3306,7 +3432,6 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std 14.0.0", "sp-storage 19.0.0", "sp-transaction-pool", "sp-version", @@ -3317,7 +3442,7 @@ dependencies = [ "substrate-wasm-builder", "testnet-parachains-constants", "westend-runtime-constants", - "xcm-fee-payment-runtime-api", + "xcm-runtime-apis", ] [[package]] @@ -3488,7 +3613,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.3", + "clap 4.5.10", "criterion-plot", "futures", "is-terminal", @@ -3573,7 +3698,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" dependencies = [ "generic-array 0.14.7", - "rand_core 0.6.4", + "rand_core", "subtle 2.5.0", "zeroize", ] @@ -3585,7 +3710,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array 0.14.7", - "rand_core 0.6.4", + "rand_core", "typenum", ] @@ -3622,7 +3747,7 @@ dependencies = [ name = "cumulus-client-cli" version = "0.7.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.10", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -3647,7 +3772,7 @@ dependencies = [ "cumulus-test-runtime", "futures", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -3678,6 +3803,7 @@ dependencies = [ "cumulus-relay-chain-interface", "futures", "parity-scale-codec", + "parking_lot 0.12.3", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-overseer", @@ -3688,6 +3814,7 @@ dependencies = [ "sc-consensus-babe", "sc-consensus-slots", "sc-telemetry", + "sc-utils", "schnellru", "sp-api", "sp-application-crypto", @@ -3702,6 +3829,7 @@ dependencies = [ "sp-state-machine", "sp-timestamp", "substrate-prometheus-endpoint", + "tokio", "tracing", ] @@ -3761,7 +3889,7 @@ dependencies = [ "cumulus-primitives-core", "cumulus-relay-chain-interface", "futures", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "sc-consensus", "sp-api", "sp-block-builder", @@ -3786,7 +3914,7 @@ dependencies = [ "futures", "futures-timer", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-parachain-primitives", @@ -3822,13 +3950,11 @@ dependencies = [ "cumulus-test-relay-sproof-builder", "parity-scale-codec", "sc-client-api", - "scale-info", "sp-api", "sp-crypto-hashing", "sp-inherents", "sp-runtime", "sp-state-machine", - "sp-std 14.0.0", "sp-storage 19.0.0", "sp-trie", "tracing", @@ -3852,7 +3978,7 @@ dependencies = [ "polkadot-overseer", "polkadot-primitives", "portpicker", - "rand 0.8.5", + "rand", "rstest", "sc-cli", "sc-client-api", @@ -3920,7 +4046,6 @@ dependencies = [ "sp-application-crypto", "sp-consensus-aura", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -3937,7 +4062,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-tracing 16.0.0", "staging-xcm", ] @@ -3969,7 +4093,7 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-runtime-common", "polkadot-runtime-parachains", - "rand 0.8.5", + "rand", "sc-client-api", "scale-info", "sp-consensus-slots", @@ -3997,7 +4121,7 @@ version = "0.6.0" dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -4011,7 +4135,6 @@ dependencies = [ "pallet-session", "parity-scale-codec", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -4026,7 +4149,6 @@ dependencies = [ "polkadot-primitives", "scale-info", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -4040,7 +4162,6 @@ dependencies = [ "scale-info", "sp-io", "sp-runtime", - "sp-std 14.0.0", "staging-xcm", ] @@ -4065,7 +4186,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -4082,10 +4202,27 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime", - "sp-std 14.0.0", "staging-xcm", ] +[[package]] +name = "cumulus-pov-validator" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap 4.5.10", + "parity-scale-codec", + "polkadot-node-primitives", + "polkadot-parachain-primitives", + "polkadot-primitives", + "sc-executor", + "sp-core", + "sp-io", + "sp-maybe-compressed-blob", + "tracing", + "tracing-subscriber 0.3.18", +] + [[package]] name = "cumulus-primitives-aura" version = "0.7.0" @@ -4096,7 +4233,6 @@ dependencies = [ "sp-api", "sp-consensus-aura", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -4110,7 +4246,6 @@ dependencies = [ "scale-info", "sp-api", "sp-runtime", - "sp-std 14.0.0", "sp-trie", "staging-xcm", ] @@ -4127,7 +4262,6 @@ dependencies = [ "sp-inherents", "sp-runtime", "sp-state-machine", - "sp-std 14.0.0", "sp-trie", ] @@ -4158,7 +4292,6 @@ dependencies = [ "scale-info", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-trie", ] @@ -4170,7 +4303,6 @@ dependencies = [ "futures", "parity-scale-codec", "sp-inherents", - "sp-std 14.0.0", "sp-timestamp", ] @@ -4187,7 +4319,6 @@ dependencies = [ "polkadot-runtime-parachains", "sp-io", "sp-runtime", - "sp-std 14.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -4249,15 +4380,8 @@ dependencies = [ "cumulus-relay-chain-interface", "cumulus-relay-chain-rpc-interface", "futures", - "parking_lot 0.12.1", - "polkadot-availability-recovery", - "polkadot-collator-protocol", "polkadot-core-primitives", "polkadot-network-bridge", - "polkadot-node-collation-generation", - "polkadot-node-core-chain-api", - "polkadot-node-core-prospective-parachains", - "polkadot-node-core-runtime-api", "polkadot-node-network-protocol", "polkadot-node-subsystem-util", "polkadot-overseer", @@ -4294,7 +4418,7 @@ dependencies = [ "parity-scale-codec", "pin-project", "polkadot-overseer", - "rand 0.8.5", + "rand", "sc-client-api", "sc-rpc-api", "sc-service", @@ -4364,7 +4488,6 @@ dependencies = [ "polkadot-primitives", "sp-runtime", "sp-state-machine", - "sp-std 14.0.0", "sp-trie", ] @@ -4403,7 +4526,6 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std 14.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -4415,7 +4537,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.5.3", + "clap 4.5.10", "criterion", "cumulus-client-cli", "cumulus-client-collator", @@ -4450,8 +4572,7 @@ dependencies = [ "polkadot-service", "polkadot-test-service", "portpicker", - "rand 0.8.5", - "rococo-parachain-runtime", + "rand", "sc-basic-authorship", "sc-block-builder", "sc-chain-spec", @@ -4476,7 +4597,6 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-consensus-aura", - "sp-consensus-grandpa", "sp-core", "sp-io", "sp-keyring", @@ -4503,7 +4623,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "socket2 0.5.6", + "socket2 0.5.7", "windows-sys 0.52.0", ] @@ -4523,19 +4643,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "curve25519-dalek" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" -dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", - "subtle 2.5.0", - "zeroize", -] - [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -4559,7 +4666,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -4571,7 +4678,7 @@ checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" dependencies = [ "byteorder", "digest 0.9.0", - "rand_core 0.6.4", + "rand_core", "subtle-ng", "zeroize", ] @@ -4598,7 +4705,7 @@ dependencies = [ "codespan-reporting", "once_cell", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "scratch", "syn 2.0.61", ] @@ -4616,7 +4723,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -4684,7 +4791,7 @@ version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" dependencies = [ - "asn1-rs", + "asn1-rs 0.5.2", "displaydoc", "nom", "num-bigint", @@ -4693,33 +4800,33 @@ dependencies = [ ] [[package]] -name = "deranged" -version = "0.3.11" +name = "der-parser" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" dependencies = [ - "powerfmt", + "asn1-rs 0.6.1", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", ] [[package]] -name = "derivative" -version = "2.2.0" +name = "deranged" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 1.0.109", -] +checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" [[package]] -name = "derive-syn-parse" -version = "0.1.5" +name = "derivative" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79116f119dd1dba1abf1f3405f03b9b0e79a27a3883864bfebded8a3dc768cd" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -4730,7 +4837,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -4741,7 +4848,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -4753,7 +4860,7 @@ checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "rustc_version 0.4.0", "syn 1.0.109", ] @@ -4849,7 +4956,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -4862,7 +4969,7 @@ checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" [[package]] name = "dleq_vrf" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" +source = "git+https://github.com/w3f/ring-vrf?rev=0fef826#0fef8266d851932ad25d6b41bc4b34d834d1e11d" dependencies = [ "ark-ec", "ark-ff 0.4.2", @@ -4906,10 +5013,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a081e51fb188742f5a7a1164ad752121abcb22874b21e2c3b0dd040c515fdad" dependencies = [ "common-path", - "derive-syn-parse 0.2.0", + "derive-syn-parse", "once_cell", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "regex", "syn 2.0.61", "termcolor", @@ -4958,7 +5065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -4979,19 +5086,10 @@ dependencies = [ "elliptic-curve", "rfc6979", "serdect", - "signature 2.1.0", + "signature", "spki", ] -[[package]] -name = "ed25519" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" -dependencies = [ - "signature 1.6.4", -] - [[package]] name = "ed25519" version = "2.2.2" @@ -4999,21 +5097,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" dependencies = [ "pkcs8", - "signature 2.1.0", -] - -[[package]] -name = "ed25519-dalek" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" -dependencies = [ - "curve25519-dalek 3.2.0", - "ed25519 1.5.3", - "rand 0.7.3", - "serde", - "sha2 0.9.9", - "zeroize", + "signature", ] [[package]] @@ -5022,9 +5106,9 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ - "curve25519-dalek 4.1.3", - "ed25519 2.2.2", - "rand_core 0.6.4", + "curve25519-dalek", + "ed25519", + "rand_core", "serde", "sha2 0.10.8", "subtle 2.5.0", @@ -5037,11 +5121,11 @@ version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" dependencies = [ - "curve25519-dalek 4.1.3", - "ed25519 2.2.2", + "curve25519-dalek", + "ed25519", "hashbrown 0.14.3", "hex", - "rand_core 0.6.4", + "rand_core", "sha2 0.10.8", "zeroize", ] @@ -5065,7 +5149,7 @@ dependencies = [ "generic-array 0.14.7", "group", "pkcs8", - "rand_core 0.6.4", + "rand_core", "sec1", "serdect", "subtle 2.5.0", @@ -5127,7 +5211,7 @@ checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" dependencies = [ "heck 0.4.1", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -5139,7 +5223,7 @@ checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" dependencies = [ "heck 0.4.1", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -5159,18 +5243,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] [[package]] name = "enumn" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" +checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -5194,19 +5278,6 @@ dependencies = [ "regex", ] -[[package]] -name = "env_logger" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - [[package]] name = "env_logger" version = "0.10.1" @@ -5347,6 +5418,27 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "event-listener" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener 5.2.0", + "pin-project-lite", +] + [[package]] name = "exit-future" version = "0.2.0" @@ -5358,14 +5450,16 @@ dependencies = [ [[package]] name = "expander" -version = "2.0.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f86a749cf851891866c10515ef6c299b5c69661465e9c3bbe7e07a2b77fb0f7" +checksum = "e2c470c71d91ecbd179935b24170459e926382eaaa86b590b78814e180d8a8e2" dependencies = [ "blake2 0.10.6", + "file-guard", "fs-err", + "prettyplease 0.2.12", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -5437,7 +5531,7 @@ dependencies = [ "indexmap 2.2.3", "proc-macro-crate 3.1.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -5473,7 +5567,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core 0.6.4", + "rand_core", "subtle 2.5.0", ] @@ -5496,6 +5590,16 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" +[[package]] +name = "file-guard" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21ef72acf95ec3d7dbf61275be556299490a245f017cf084bd23b4f68cf9407c" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "file-per-thread-logger" version = "0.1.6" @@ -5530,8 +5634,8 @@ dependencies = [ "log", "num-traits", "parity-scale-codec", - "parking_lot 0.12.1", - "rand 0.8.5", + "parking_lot 0.12.3", + "rand", "scale-info", ] @@ -5546,7 +5650,7 @@ dependencies = [ "futures", "log", "num-traits", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "relay-utils", ] @@ -5569,7 +5673,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", - "rand 0.8.5", + "rand", "rustc-hex", "static_assertions", ] @@ -5587,7 +5691,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" dependencies = [ "crc32fast", - "libz-sys", "miniz_oxide", ] @@ -5630,9 +5733,9 @@ dependencies = [ [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -5685,7 +5788,6 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-runtime-interface 24.0.0", - "sp-std 14.0.0", "sp-storage 19.0.0", "static_assertions", ] @@ -5697,7 +5799,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.5.3", + "clap 4.5.10", "comfy-table", "frame-benchmarking", "frame-support", @@ -5709,7 +5811,7 @@ dependencies = [ "linked-hash-map", "log", "parity-scale-codec", - "rand 0.8.5", + "rand", "rand_pcg", "sc-block-builder", "sc-chain-spec", @@ -5750,7 +5852,6 @@ dependencies = [ "scale-info", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -5762,7 +5863,7 @@ dependencies = [ "parity-scale-codec", "proc-macro-crate 3.1.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "scale-info", "sp-arithmetic", "syn 2.0.61", @@ -5777,27 +5878,26 @@ dependencies = [ "frame-support", "frame-system", "parity-scale-codec", - "rand 0.8.5", + "rand", "scale-info", "sp-arithmetic", "sp-core", "sp-io", "sp-npos-elections", "sp-runtime", - "sp-std 14.0.0", ] [[package]] name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.5.3", + "clap 4.5.10", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", "honggfuzz", "parity-scale-codec", - "rand 0.8.5", + "rand", "scale-info", "sp-arithmetic", "sp-npos-elections", @@ -5822,7 +5922,6 @@ dependencies = [ "sp-inherents", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-tracing 16.0.0", "sp-version", ] @@ -5864,7 +5963,7 @@ dependencies = [ name = "frame-omni-bencher" version = "0.1.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.10", "cumulus-primitives-proof-size-hostfunction", "env_logger 0.11.3", "frame-benchmarking-cli", @@ -5947,16 +6046,27 @@ version = "23.0.0" dependencies = [ "Inflector", "cfg-expr", - "derive-syn-parse 0.2.0", + "derive-syn-parse", + "docify", "expander", + "frame-support", "frame-support-procedural-tools", + "frame-system", "itertools 0.11.0", "macro_magic", - "proc-macro-warning", + "parity-scale-codec", + "pretty_assertions", + "proc-macro-warning 1.0.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "regex", + "scale-info", + "sp-core", "sp-crypto-hashing", + "sp-io", + "sp-metadata-ir", + "sp-runtime", + "static_assertions", "syn 2.0.61", ] @@ -5967,7 +6077,7 @@ dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate 3.1.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -5976,7 +6086,7 @@ name = "frame-support-procedural-tools-derive" version = "11.0.0" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -6002,7 +6112,6 @@ dependencies = [ "sp-metadata-ir", "sp-runtime", "sp-state-machine", - "sp-std 14.0.0", "sp-version", "static_assertions", "trybuild", @@ -6077,7 +6186,6 @@ dependencies = [ "sp-externalities 0.25.0", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-version", ] @@ -6098,7 +6206,6 @@ dependencies = [ "parity-scale-codec", "sp-api", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -6154,6 +6261,16 @@ dependencies = [ "futures-util", ] +[[package]] +name = "futures-bounded" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b07bbbe7d7e78809544c6f718d875627addc73a7c3582447abc052cd3dc67e0" +dependencies = [ + "futures-timer", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.30" @@ -6199,10 +6316,20 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite 0.2.12", + "pin-project-lite", "waker-fn", ] +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.30" @@ -6210,19 +6337,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] [[package]] name = "futures-rustls" -version = "0.22.2" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2411eed028cdf8c8034eaf21f9915f956b6c3abec4d4c7949ee67f0721127bd" +checksum = "35bd3cf68c183738046838e300353e4716c674dc5e56890de4826801a6622a28" dependencies = [ "futures-io", - "rustls 0.20.8", - "webpki", + "rustls 0.21.7", ] [[package]] @@ -6256,7 +6382,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.12", + "pin-project-lite", "pin-utils", "slab", ] @@ -6313,17 +6439,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.10" @@ -6332,7 +6447,7 @@ checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -6341,8 +6456,8 @@ version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea1015b5a70616b688dc230cfe50c8af89d972cb132d5a622814d29773b10b9" dependencies = [ - "rand 0.8.5", - "rand_core 0.6.4", + "rand", + "rand_core", ] [[package]] @@ -6428,7 +6543,6 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std 14.0.0", "sp-storage 19.0.0", "sp-transaction-pool", "sp-version", @@ -6452,9 +6566,9 @@ dependencies = [ "futures-timer", "no-std-compat", "nonzero_ext", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "quanta", - "rand 0.8.5", + "rand", "smallvec", ] @@ -6465,7 +6579,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core 0.6.4", + "rand_core", "subtle 2.5.0", ] @@ -6480,7 +6594,26 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.9", + "indexmap 2.2.3", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.1.0", "indexmap 2.2.3", "slab", "tokio", @@ -6688,6 +6821,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.5" @@ -6695,15 +6839,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", - "http", - "pin-project-lite 0.2.12", + "http 0.2.9", + "pin-project-lite", ] [[package]] -name = "http-range-header" -version = "0.3.1" +name = "http-body" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "pin-project-lite", +] [[package]] name = "httparse" @@ -6725,44 +6886,103 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", - "h2", - "http", - "http-body", + "h2 0.3.26", + "http 0.2.9", + "http-body 0.4.5", "httparse", "httpdate", "itoa", - "pin-project-lite 0.2.12", - "socket2 0.4.9", + "pin-project-lite", + "socket2 0.5.7", "tokio", "tower-service", "tracing", "want", ] +[[package]] +name = "hyper" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.5", + "http 1.1.0", + "http-body 1.0.0", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + [[package]] name = "hyper-rustls" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http", - "hyper", + "http 0.2.9", + "hyper 0.14.29", "log", - "rustls 0.21.6", + "rustls 0.21.7", "rustls-native-certs 0.6.3", "tokio", "tokio-rustls 0.24.1", ] +[[package]] +name = "hyper-rustls" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.3.1", + "hyper-util", + "log", + "rustls 0.23.10", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.0", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "hyper 1.3.1", + "pin-project-lite", + "socket2 0.5.7", + "tokio", + "tower", + "tower-service", + "tracing", +] + [[package]] name = "iana-time-zone" version = "0.1.57" @@ -6807,23 +7027,33 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "if-addrs" -version = "0.7.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc0fa01ffc752e9dbc72818cdb072cd028b86be5e09dd04c5a643704fe101a9" +checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" dependencies = [ "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "if-watch" -version = "3.0.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9465340214b296cd17a0009acdb890d6160010b8adf8f78a00d0d7ab270f79f" +checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" dependencies = [ - "async-io", + "async-io 2.3.3", "core-foundation", "fnv", "futures", @@ -6833,7 +7063,26 @@ dependencies = [ "rtnetlink", "system-configuration", "tokio", - "windows 0.34.0", + "windows 0.51.1", +] + +[[package]] +name = "igd-next" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064d90fec10d541084e7b39ead8875a5a80d9114a2b18791565253bae25f49e4" +dependencies = [ + "async-trait", + "attohttpc", + "bytes", + "futures", + "http 0.2.9", + "hyper 0.14.29", + "log", + "rand", + "tokio", + "url", + "xmltree", ] [[package]] @@ -6881,7 +7130,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -6901,7 +7150,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", ] [[package]] @@ -7006,7 +7255,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2 0.5.6", + "socket2 0.5.7", "widestring", "windows-sys 0.48.0", "winreg", @@ -7050,13 +7299,13 @@ dependencies = [ "curl", "curl-sys", "encoding_rs", - "event-listener", - "futures-lite", - "http", + "event-listener 2.5.3", + "futures-lite 1.13.0", + "http 0.2.9", "log", "mime", "once_cell", - "polling", + "polling 2.8.0", "slab", "sluice", "tracing", @@ -7089,11 +7338,31 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ "libc", ] @@ -7126,9 +7395,9 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.22.5" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfdb12a2381ea5b2e68c3469ec604a007b367778cdb14d09612c8069ebd616ad" +checksum = "62b089779ad7f80768693755a031cc14a7766aba707cbe886674e3f79e9b7e47" dependencies = [ "jsonrpsee-core", "jsonrpsee-http-client", @@ -7142,20 +7411,22 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.22.5" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4978087a58c3ab02efc5b07c5e5e2803024536106fd5506f558db172c889b3aa" +checksum = "08163edd8bcc466c33d79e10f695cdc98c00d1e6ddfb95cec41b6b0279dd5432" dependencies = [ + "base64 0.22.1", "futures-util", - "http", + "http 1.1.0", "jsonrpsee-core", "pin-project", - "rustls-native-certs 0.7.0", + "rustls 0.23.10", "rustls-pki-types", - "soketto", + "rustls-platform-verifier", + "soketto 0.8.0", "thiserror", "tokio", - "tokio-rustls 0.25.0", + "tokio-rustls 0.26.0", "tokio-util", "tracing", "url", @@ -7163,20 +7434,23 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.22.5" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b257e1ec385e07b0255dde0b933f948b5c8b8c28d42afda9587c3a967b896d" +checksum = "79712302e737d23ca0daa178e752c9334846b08321d439fd89af9a384f8c830b" dependencies = [ "anyhow", "async-trait", "beef", + "bytes", "futures-timer", "futures-util", - "hyper", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", "jsonrpsee-types", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "pin-project", - "rand 0.8.5", + "rand", "rustc-hash", "serde", "serde_json", @@ -7188,15 +7462,20 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.22.5" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ccf93fc4a0bfe05d851d37d7c32b7f370fe94336b52a2f0efc5f1981895c2e5" +checksum = "2d90064e04fb9d7282b1c71044ea94d0bbc6eff5621c66f1a0bce9e9de7cf3ac" dependencies = [ "async-trait", - "hyper", - "hyper-rustls", + "base64 0.22.1", + "http-body 1.0.0", + "hyper 1.3.1", + "hyper-rustls 0.27.2", + "hyper-util", "jsonrpsee-core", "jsonrpsee-types", + "rustls 0.23.10", + "rustls-platform-verifier", "serde", "serde_json", "thiserror", @@ -7208,33 +7487,37 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.22.5" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d0bb047e79a143b32ea03974a6bf59b62c2a4c5f5d42a381c907a8bbb3f75c0" +checksum = "7895f186d5921065d96e16bd795e5ca89ac8356ec423fafc6e3d7cf8ec11aee4" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro-crate 3.1.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] [[package]] name = "jsonrpsee-server" -version = "0.22.5" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12d8b6a9674422a8572e0b0abb12feeb3f2aeda86528c80d0350c2bd0923ab41" +checksum = "654afab2e92e5d88ebd8a39d6074483f3f2bfdf91c5ac57fe285e7127cdd4f51" dependencies = [ + "anyhow", "futures-util", - "http", - "hyper", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.3.1", + "hyper-util", "jsonrpsee-core", "jsonrpsee-types", "pin-project", "route-recognizer", "serde", "serde_json", - "soketto", + "soketto 0.8.0", "thiserror", "tokio", "tokio-stream", @@ -7245,12 +7528,12 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.22.5" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "150d6168405890a7a3231a3c74843f58b8959471f6df76078db2619ddee1d07d" +checksum = "d9c465fbe385238e861fdc4d1c85e04ada6c1fd246161d26385c1b311724d2af" dependencies = [ - "anyhow", "beef", + "http 1.1.0", "serde", "serde_json", "thiserror", @@ -7258,11 +7541,11 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.22.5" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58b9db2dfd5bb1194b0ce921504df9ceae210a345bc2f6c5a61432089bbab070" +checksum = "1c28759775f5cb2f1ea9667672d3fe2b0e701d1f4b7b67954e60afe7fd058b5e" dependencies = [ - "http", + "http 1.1.0", "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-types", @@ -7351,7 +7634,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf7a85fe66f9ff9cd74e169fdd2c94c6e1e74c412c99a73b4df3200b5d3760b2" dependencies = [ "kvdb", - "parking_lot 0.12.1", + "parking_lot 0.12.3", ] [[package]] @@ -7362,7 +7645,7 @@ checksum = "b644c70b92285f66bfc2032922a79000ea30af7bc2ab31902992a5dcb9b434f6" dependencies = [ "kvdb", "num_cpus", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "regex", "rocksdb", "smallvec", @@ -7408,9 +7691,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libflate" @@ -7471,14 +7754,15 @@ dependencies = [ [[package]] name = "libp2p" -version = "0.51.4" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f35eae38201a993ece6bdc823292d6abd1bffed1c4d0f4a3517d2bd8e1d917fe" +checksum = "e94495eb319a85b70a68b85e2389a95bb3555c71c49025b78c691a854a7e6464" dependencies = [ "bytes", + "either", "futures", "futures-timer", - "getrandom 0.2.10", + "getrandom", "instant", "libp2p-allow-block-list", "libp2p-connection-limits", @@ -7495,18 +7779,21 @@ dependencies = [ "libp2p-request-response", "libp2p-swarm", "libp2p-tcp", + "libp2p-upnp", "libp2p-wasm-ext", "libp2p-websocket", "libp2p-yamux", - "multiaddr", + "multiaddr 0.18.1", "pin-project", + "rw-stream-sink", + "thiserror", ] [[package]] name = "libp2p-allow-block-list" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "510daa05efbc25184458db837f6f9a5143888f1caa742426d92e1833ddd38a50" +checksum = "55b46558c5c0bf99d3e2a1a38fd54ff5476ca66dd1737b12466a1824dd219311" dependencies = [ "libp2p-core", "libp2p-identity", @@ -7516,9 +7803,9 @@ dependencies = [ [[package]] name = "libp2p-connection-limits" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4caa33f1d26ed664c4fe2cca81a08c8e07d4c1c04f2f4ac7655c2dd85467fda0" +checksum = "2f5107ad45cb20b2f6c3628c7b6014b996fcb13a88053f4569c872c6e30abf58" dependencies = [ "libp2p-core", "libp2p-identity", @@ -7528,9 +7815,9 @@ dependencies = [ [[package]] name = "libp2p-core" -version = "0.39.2" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c1df63c0b582aa434fb09b2d86897fa2b419ffeccf934b36f87fcedc8e835c2" +checksum = "dd44289ab25e4c9230d9246c475a22241e301b23e8f4061d3bdef304a1a99713" dependencies = [ "either", "fnv", @@ -7539,50 +7826,53 @@ dependencies = [ "instant", "libp2p-identity", "log", - "multiaddr", - "multihash 0.17.0", + "multiaddr 0.18.1", + "multihash 0.19.1", "multistream-select", "once_cell", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "pin-project", "quick-protobuf", - "rand 0.8.5", + "rand", "rw-stream-sink", "smallvec", "thiserror", - "unsigned-varint", + "unsigned-varint 0.7.2", "void", ] [[package]] name = "libp2p-dns" -version = "0.39.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146ff7034daae62077c415c2376b8057368042df6ab95f5432ad5e88568b1554" +checksum = "e6a18db73084b4da2871438f6239fef35190b05023de7656e877c18a00541a3b" dependencies = [ + "async-trait", "futures", "libp2p-core", + "libp2p-identity", "log", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "smallvec", - "trust-dns-resolver 0.22.0", + "trust-dns-resolver", ] [[package]] name = "libp2p-identify" -version = "0.42.2" +version = "0.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5455f472243e63b9c497ff320ded0314254a9eb751799a39c283c6f20b793f3c" +checksum = "45a96638a0a176bec0a4bcaebc1afa8cf909b114477209d7456ade52c61cd9cd" dependencies = [ "asynchronous-codec", "either", "futures", + "futures-bounded", "futures-timer", "libp2p-core", "libp2p-identity", "libp2p-swarm", "log", - "lru 0.10.1", + "lru 0.12.3", "quick-protobuf", "quick-protobuf-codec", "smallvec", @@ -7592,27 +7882,27 @@ dependencies = [ [[package]] name = "libp2p-identity" -version = "0.1.3" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "276bb57e7af15d8f100d3c11cbdd32c6752b7eef4ba7a18ecf464972c07abcce" +checksum = "999ec70441b2fb35355076726a6bc466c932e9bdc66f6a11c6c0aa17c7ab9be0" dependencies = [ - "bs58 0.4.0", - "ed25519-dalek 2.1.1", - "log", - "multiaddr", - "multihash 0.17.0", + "bs58 0.5.0", + "ed25519-dalek", + "hkdf", + "multihash 0.19.1", "quick-protobuf", - "rand 0.8.5", + "rand", "sha2 0.10.8", "thiserror", + "tracing", "zeroize", ] [[package]] name = "libp2p-kad" -version = "0.43.3" +version = "0.44.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39d5ef876a2b2323d63c258e63c2f8e36f205fe5a11f0b3095d59635650790ff" +checksum = "16ea178dabba6dde6ffc260a8e0452ccdc8f79becf544946692fff9d412fc29d" dependencies = [ "arrayvec 0.7.4", "asynchronous-codec", @@ -7627,20 +7917,21 @@ dependencies = [ "libp2p-swarm", "log", "quick-protobuf", - "rand 0.8.5", + "quick-protobuf-codec", + "rand", "sha2 0.10.8", "smallvec", "thiserror", "uint", - "unsigned-varint", + "unsigned-varint 0.7.2", "void", ] [[package]] name = "libp2p-mdns" -version = "0.43.1" +version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19983e1f949f979a928f2c603de1cf180cc0dc23e4ac93a62651ccb18341460b" +checksum = "42a2567c305232f5ef54185e9604579a894fd0674819402bb0ac0246da82f52a" dependencies = [ "data-encoding", "futures", @@ -7649,9 +7940,9 @@ dependencies = [ "libp2p-identity", "libp2p-swarm", "log", - "rand 0.8.5", + "rand", "smallvec", - "socket2 0.4.9", + "socket2 0.5.7", "tokio", "trust-dns-proto 0.22.0", "void", @@ -7659,63 +7950,69 @@ dependencies = [ [[package]] name = "libp2p-metrics" -version = "0.12.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a42ec91e227d7d0dafa4ce88b333cdf5f277253873ab087555c92798db2ddd46" +checksum = "239ba7d28f8d0b5d77760dc6619c05c7e88e74ec8fbbe97f856f20a56745e620" dependencies = [ + "instant", "libp2p-core", "libp2p-identify", + "libp2p-identity", "libp2p-kad", "libp2p-ping", "libp2p-swarm", + "once_cell", "prometheus-client", ] [[package]] name = "libp2p-noise" -version = "0.42.2" +version = "0.43.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3673da89d29936bc6435bafc638e2f184180d554ce844db65915113f86ec5e" +checksum = "d2eeec39ad3ad0677551907dd304b2f13f17208ccebe333bef194076cd2e8921" dependencies = [ "bytes", - "curve25519-dalek 3.2.0", + "curve25519-dalek", "futures", "libp2p-core", "libp2p-identity", "log", + "multiaddr 0.18.1", + "multihash 0.19.1", "once_cell", "quick-protobuf", - "rand 0.8.5", + "rand", "sha2 0.10.8", "snow", "static_assertions", "thiserror", - "x25519-dalek 1.1.1", + "x25519-dalek", "zeroize", ] [[package]] name = "libp2p-ping" -version = "0.42.0" +version = "0.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e57759c19c28a73ef1eb3585ca410cefb72c1a709fcf6de1612a378e4219202" +checksum = "e702d75cd0827dfa15f8fd92d15b9932abe38d10d21f47c50438c71dd1b5dae3" dependencies = [ "either", "futures", "futures-timer", "instant", "libp2p-core", + "libp2p-identity", "libp2p-swarm", "log", - "rand 0.8.5", + "rand", "void", ] [[package]] name = "libp2p-quic" -version = "0.7.0-alpha.3" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6b26abd81cd2398382a1edfe739b539775be8a90fa6914f39b2ab49571ec735" +checksum = "130d451d83f21b81eb7b35b360bc7972aeafb15177784adc56528db082e6b927" dependencies = [ "bytes", "futures", @@ -7725,19 +8022,21 @@ dependencies = [ "libp2p-identity", "libp2p-tls", "log", - "parking_lot 0.12.1", - "quinn-proto", - "rand 0.8.5", - "rustls 0.20.8", + "parking_lot 0.12.3", + "quinn 0.10.2", + "rand", + "ring 0.16.20", + "rustls 0.21.7", + "socket2 0.5.7", "thiserror", "tokio", ] [[package]] name = "libp2p-request-response" -version = "0.24.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffdb374267d42dc5ed5bc53f6e601d4a64ac5964779c6e40bb9e4f14c1e30d5" +checksum = "d8e3b4d67870478db72bac87bfc260ee6641d0734e0e3e275798f089c3fecfd4" dependencies = [ "async-trait", "futures", @@ -7745,15 +8044,17 @@ dependencies = [ "libp2p-core", "libp2p-identity", "libp2p-swarm", - "rand 0.8.5", + "log", + "rand", "smallvec", + "void", ] [[package]] name = "libp2p-swarm" -version = "0.42.2" +version = "0.43.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "903b3d592d7694e56204d211f29d31bc004be99386644ba8731fc3e3ef27b296" +checksum = "580189e0074af847df90e75ef54f3f30059aedda37ea5a1659e8b9fca05c0141" dependencies = [ "either", "fnv", @@ -7764,7 +8065,9 @@ dependencies = [ "libp2p-identity", "libp2p-swarm-derive", "log", - "rand 0.8.5", + "multistream-select", + "once_cell", + "rand", "smallvec", "tokio", "void", @@ -7772,36 +8075,39 @@ dependencies = [ [[package]] name = "libp2p-swarm-derive" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fba456131824ab6acd4c7bf61e9c0f0a3014b5fc9868ccb8e10d344594cdc4f" +checksum = "c4d5ec2a3df00c7836d7696c136274c9c59705bac69133253696a6c932cd1d74" dependencies = [ "heck 0.4.1", - "quote 1.0.35", - "syn 1.0.109", + "proc-macro-warning 0.4.2", + "proc-macro2 1.0.82", + "quote 1.0.36", + "syn 2.0.61", ] [[package]] name = "libp2p-tcp" -version = "0.39.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d33698596d7722d85d3ab0c86c2c322254fce1241e91208e3679b4eb3026cf" +checksum = "b558dd40d1bcd1aaaed9de898e9ec6a436019ecc2420dd0016e712fbb61c5508" dependencies = [ "futures", "futures-timer", "if-watch", "libc", "libp2p-core", + "libp2p-identity", "log", - "socket2 0.4.9", + "socket2 0.5.7", "tokio", ] [[package]] name = "libp2p-tls" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff08d13d0dc66e5e9ba6279c1de417b84fa0d0adc3b03e5732928c180ec02781" +checksum = "8218d1d5482b122ccae396bbf38abdcb283ecc96fa54760e1dfd251f0546ac61" dependencies = [ "futures", "futures-rustls", @@ -7809,51 +8115,69 @@ dependencies = [ "libp2p-identity", "rcgen", "ring 0.16.20", - "rustls 0.20.8", + "rustls 0.21.7", + "rustls-webpki 0.101.4", "thiserror", - "webpki", - "x509-parser 0.14.0", + "x509-parser 0.15.1", "yasna", ] +[[package]] +name = "libp2p-upnp" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82775a47b34f10f787ad3e2a22e2c1541e6ebef4fe9f28f3ac553921554c94c1" +dependencies = [ + "futures", + "futures-timer", + "igd-next", + "libp2p-core", + "libp2p-swarm", + "log", + "tokio", + "void", +] + [[package]] name = "libp2p-wasm-ext" -version = "0.39.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77dff9d32353a5887adb86c8afc1de1a94d9e8c3bc6df8b2201d7cdf5c848f43" +checksum = "1e5d8e3a9e07da0ef5b55a9f26c009c8fb3c725d492d8bb4b431715786eea79c" dependencies = [ "futures", "js-sys", "libp2p-core", - "parity-send-wrapper", + "send_wrapper", "wasm-bindgen", "wasm-bindgen-futures", ] [[package]] name = "libp2p-websocket" -version = "0.41.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "111273f7b3d3510524c752e8b7a5314b7f7a1fee7e68161c01a7d72cbb06db9f" +checksum = "004ee9c4a4631435169aee6aad2f62e3984dc031c43b6d29731e8e82a016c538" dependencies = [ "either", "futures", "futures-rustls", "libp2p-core", + "libp2p-identity", "log", - "parking_lot 0.12.1", - "quicksink", + "parking_lot 0.12.3", + "pin-project-lite", "rw-stream-sink", - "soketto", + "soketto 0.8.0", + "thiserror", "url", - "webpki-roots 0.22.6", + "webpki-roots 0.25.2", ] [[package]] name = "libp2p-yamux" -version = "0.43.1" +version = "0.44.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd21d950662700a385d4c6d68e2f5f54d778e97068cdd718522222ef513bda" +checksum = "8eedcb62824c4300efb9cfd4e2a6edaf3ca097b9e68b36dabe45a44469fd6a85" dependencies = [ "futures", "libp2p-core", @@ -7890,7 +8214,7 @@ dependencies = [ "libsecp256k1-core", "libsecp256k1-gen-ecmult", "libsecp256k1-gen-genmult", - "rand 0.8.5", + "rand", "serde", "sha2 0.9.9", "typenum", @@ -8020,40 +8344,40 @@ dependencies = [ [[package]] name = "litep2p" -version = "0.5.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f02542ae3a94b4c4ffa37dc56388c923e286afa3bf65452e3984b50b2a2f316" +checksum = "0f46c51c205264b834ceed95c8b195026e700494bc3991aaba3b4ea9e20626d9" dependencies = [ "async-trait", "bs58 0.4.0", "bytes", "cid 0.10.1", - "ed25519-dalek 1.0.1", + "ed25519-dalek", "futures", "futures-timer", "hex-literal", "indexmap 2.2.3", "libc", "mockall 0.12.1", - "multiaddr", + "multiaddr 0.17.1", "multihash 0.17.0", "network-interface", "nohash-hasher", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "pin-project", - "prost 0.11.9", + "prost 0.12.6", "prost-build 0.11.9", - "quinn", - "rand 0.8.5", + "quinn 0.9.4", + "rand", "rcgen", "ring 0.16.20", - "rustls 0.20.8", + "rustls 0.20.9", "serde", "sha2 0.10.8", "simple-dns", "smallvec", "snow", - "socket2 0.5.6", + "socket2 0.5.7", "static_assertions", "str0m", "thiserror", @@ -8062,13 +8386,13 @@ dependencies = [ "tokio-tungstenite", "tokio-util", "tracing", - "trust-dns-resolver 0.23.2", + "trust-dns-resolver", "uint", - "unsigned-varint", + "unsigned-varint 0.8.0", "url", "webpki", - "x25519-dalek 2.0.0", - "x509-parser 0.15.1", + "x25519-dalek", + "x509-parser 0.16.0", "yasna", "zeroize", ] @@ -8085,9 +8409,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" dependencies = [ "serde", "value-bag", @@ -8104,18 +8428,18 @@ dependencies = [ [[package]] name = "lru" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718e8fae447df0c7e1ba7f5189829e63fd536945c8988d61444c19039f16b670" -dependencies = [ - "hashbrown 0.13.2", -] +checksum = "eedb2bdbad7e0634f83989bf596f497b070130daaa398ab22d84c39e266deec5" [[package]] name = "lru" -version = "0.11.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eedb2bdbad7e0634f83989bf596f497b070130daaa398ab22d84c39e266deec5" +checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +dependencies = [ + "hashbrown 0.14.3", +] [[package]] name = "lru-cache" @@ -8166,49 +8490,49 @@ dependencies = [ [[package]] name = "macro_magic" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e03844fc635e92f3a0067e25fa4bf3e3dbf3f2927bf3aa01bb7bc8f1c428949d" +checksum = "cc33f9f0351468d26fbc53d9ce00a096c8522ecb42f19b50f34f2c422f76d21d" dependencies = [ "macro_magic_core", "macro_magic_macros", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] [[package]] name = "macro_magic_core" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "468155613a44cfd825f1fb0ffa532b018253920d404e6fca1e8d43155198a46d" +checksum = "1687dc887e42f352865a393acae7cf79d98fab6351cde1f58e9e057da89bf150" dependencies = [ "const-random", - "derive-syn-parse 0.1.5", + "derive-syn-parse", "macro_magic_core_macros", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] [[package]] name = "macro_magic_core_macros" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea73aa640dc01d62a590d48c0c3521ed739d53b27f919b25c3551e233481654" +checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] [[package]] name = "macro_magic_macros" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef9d79ae96aaba821963320eb2b6e34d17df1e5a83d8a1985c29cc5be59577b3" +checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" dependencies = [ "macro_magic_core", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -8340,7 +8664,7 @@ checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" dependencies = [ "byteorder", "keccak", - "rand_core 0.6.4", + "rand_core", "zeroize", ] @@ -8351,13 +8675,12 @@ dependencies = [ "async-std", "async-trait", "bp-messages", - "env_logger 0.11.3", "finality-relay", "futures", "hex", "log", "num-traits", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "relay-utils", "sp-arithmetic", ] @@ -8369,7 +8692,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69672161530e8aeca1d1400fbf3f1a1747ff60ea604265a4e906c2442df20532" dependencies = [ "futures", - "rand 0.8.5", + "rand", "thrift", ] @@ -8402,7 +8725,7 @@ dependencies = [ name = "minimal-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.10", "docify", "futures", "futures-timer", @@ -8468,7 +8791,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.48.0", ] @@ -8483,14 +8806,14 @@ dependencies = [ "bitflags 1.3.2", "blake2 0.10.6", "c2-chacha", - "curve25519-dalek 4.1.3", + "curve25519-dalek", "either", "hashlink", "lioness", "log", - "parking_lot 0.12.1", - "rand 0.8.5", - "rand_chacha 0.3.1", + "parking_lot 0.12.3", + "rand", + "rand_chacha", "rand_distr", "subtle 2.5.0", "thiserror", @@ -8504,7 +8827,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "sc-block-builder", "sc-client-api", "sc-offchain", @@ -8573,7 +8896,7 @@ checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" dependencies = [ "cfg-if", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -8585,7 +8908,7 @@ checksum = "af7cbce79ec385a1d4f54baa90a76401eb15d9cab93685f62e7e9f942aa00ae2" dependencies = [ "cfg-if", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -8610,7 +8933,26 @@ dependencies = [ "percent-encoding", "serde", "static_assertions", - "unsigned-varint", + "unsigned-varint 0.7.2", + "url", +] + +[[package]] +name = "multiaddr" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b852bc02a2da5feed68cd14fa50d0774b92790a5bdbfa932a813926c8472070" +dependencies = [ + "arrayref", + "byteorder", + "data-encoding", + "libp2p-identity", + "multibase", + "multihash 0.19.1", + "percent-encoding", + "serde", + "static_assertions", + "unsigned-varint 0.7.2", "url", ] @@ -8636,10 +8978,10 @@ dependencies = [ "blake3", "core2", "digest 0.10.7", - "multihash-derive 0.8.0", + "multihash-derive", "sha2 0.10.8", "sha3", - "unsigned-varint", + "unsigned-varint 0.7.2", ] [[package]] @@ -8653,10 +8995,10 @@ dependencies = [ "blake3", "core2", "digest 0.10.7", - "multihash-derive 0.8.0", + "multihash-derive", "sha2 0.10.8", "sha3", - "unsigned-varint", + "unsigned-varint 0.7.2", ] [[package]] @@ -8666,27 +9008,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" dependencies = [ "core2", - "unsigned-varint", -] - -[[package]] -name = "multihash-codetable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6d815ecb3c8238d00647f8630ede7060a642c9f704761cd6082cb4028af6935" -dependencies = [ - "blake2b_simd", - "blake2s_simd", - "blake3", - "core2", - "digest 0.10.7", - "multihash-derive 0.9.0", - "ripemd", - "serde", - "sha1", - "sha2 0.10.8", - "sha3", - "strobe-rs", + "unsigned-varint 0.7.2", ] [[package]] @@ -8698,34 +9020,9 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro-error", "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 1.0.109", - "synstructure", -] - -[[package]] -name = "multihash-derive" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "890e72cb7396cb99ed98c1246a97b243cc16394470d94e0bc8b0c2c11d84290e" -dependencies = [ - "core2", - "multihash 0.19.1", - "multihash-derive-impl", -] - -[[package]] -name = "multihash-derive-impl" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38685e08adb338659871ecfc6ee47ba9b22dcc8abcf6975d379cc49145c3040" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro-error", - "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", - "synstructure", + "synstructure 0.12.6", ] [[package]] @@ -8736,16 +9033,16 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "multistream-select" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8552ab875c1313b97b8d20cb857b9fd63e2d1d6a0a1b53ce9821e575405f27a" +checksum = "ea0df8e5eec2298a62b326ee4f0d7fe1a6b90a09dfcf9df37b38f947a8c42f19" dependencies = [ "bytes", "futures", "log", "pin-project", "smallvec", - "unsigned-varint", + "unsigned-varint 0.7.2", ] [[package]] @@ -8771,7 +9068,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -8782,7 +9079,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bddcd3bf5144b6392de80e04c347cd7fab2508f6df16a85fc496ecd5cec39bc" dependencies = [ "clap 3.2.25", - "rand 0.8.5", + "rand", ] [[package]] @@ -8898,7 +9195,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "cfg-if", "cfg_aliases", "libc", @@ -8921,7 +9218,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", - "clap 4.5.3", + "clap 4.5.10", "derive_more", "fs_extra", "futures", @@ -8934,7 +9231,7 @@ dependencies = [ "node-primitives", "node-testing", "parity-db", - "rand 0.8.5", + "rand", "sc-basic-authorship", "sc-client-api", "sc-transaction-pool", @@ -9000,7 +9297,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.10", "generate-bags", "kitchensink-runtime", ] @@ -9009,7 +9306,7 @@ dependencies = [ name = "node-template-release" version = "3.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.10", "flate2", "fs_extra", "glob", @@ -9151,12 +9448,6 @@ 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-derive" version = "0.4.2" @@ -9164,7 +9455,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -9273,7 +9564,16 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" dependencies = [ - "asn1-rs", + "asn1-rs 0.5.2", +] + +[[package]] +name = "oid-registry" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c958dd45046245b9c3c2547369bb634eb461670b2e7e0de552905801a648d1d" +dependencies = [ + "asn1-rs 0.6.1", ] [[package]] @@ -9302,11 +9602,11 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.64" +version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "cfg-if", "foreign-types", "libc", @@ -9322,7 +9622,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -9343,9 +9643,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.102" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", @@ -9362,9 +9662,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "orchestra" -version = "0.3.6" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92829eef0328a3d1cd22a02c0e51deb92a5362df3e7d21a4e9bdc38934694e66" +checksum = "41f6bbacc8c189a3f2e45e0fd0436e5d97f194db888e721bdbc3973e7dbed4c2" dependencies = [ "async-trait", "dyn-clonable", @@ -9379,9 +9679,9 @@ dependencies = [ [[package]] name = "orchestra-proc-macro" -version = "0.3.6" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1344346d5af32c95bbddea91b18a88cc83eac394192d20ef2fc4c40a74332355" +checksum = "f7b1d40dd8f367db3c65bec8d3dd47d4a604ee8874480738f93191bddab4e0e0" dependencies = [ "expander", "indexmap 2.2.3", @@ -9389,7 +9689,7 @@ dependencies = [ "petgraph", "proc-macro-crate 3.1.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -9438,7 +9738,6 @@ dependencies = [ "sp-crypto-hashing", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -9459,7 +9758,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -9480,7 +9778,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -9498,7 +9795,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-storage 19.0.0", ] @@ -9515,7 +9811,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -9536,7 +9831,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-storage 19.0.0", ] @@ -9547,6 +9841,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "impl-trait-for-tuples", "log", "pallet-balances", "parity-scale-codec", @@ -9586,7 +9881,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -9604,7 +9898,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -9621,7 +9914,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -9636,7 +9928,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -9664,7 +9955,6 @@ dependencies = [ "sp-runtime", "sp-session", "sp-staking", - "sp-std 14.0.0", ] [[package]] @@ -9684,7 +9974,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-tracing 16.0.0", ] @@ -9695,7 +9984,7 @@ dependencies = [ "frame-election-provider-support", "honggfuzz", "pallet-bags-list", - "rand 0.8.5", + "rand", ] [[package]] @@ -9732,7 +10021,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -9760,7 +10048,6 @@ dependencies = [ "sp-session", "sp-staking", "sp-state-machine", - "sp-std 14.0.0", ] [[package]] @@ -9785,7 +10072,6 @@ dependencies = [ "sp-runtime", "sp-staking", "sp-state-machine", - "sp-std 14.0.0", ] [[package]] @@ -9803,7 +10089,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -9820,7 +10105,7 @@ dependencies = [ "pallet-beefy-mmr", "pallet-mmr", "parity-scale-codec", - "rand 0.8.5", + "rand", "scale-info", "serde", "sp-consensus-beefy", @@ -9837,7 +10122,6 @@ dependencies = [ "bp-header-chain", "bp-runtime", "bp-test-utils", - "finality-grandpa", "frame-benchmarking", "frame-support", "frame-system", @@ -9849,13 +10133,13 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std 14.0.0", - "sp-trie", ] [[package]] name = "pallet-bridge-messages" version = "0.7.0" dependencies = [ + "bp-header-chain", "bp-messages", "bp-runtime", "bp-test-utils", @@ -9863,13 +10147,15 @@ dependencies = [ "frame-support", "frame-system", "log", - "num-traits", "pallet-balances", + "pallet-bridge-grandpa", "parity-scale-codec", "scale-info", + "sp-core", "sp-io", "sp-runtime", "sp-std 14.0.0", + "sp-trie", ] [[package]] @@ -9892,7 +10178,6 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std 14.0.0", - "sp-trie", ] [[package]] @@ -9933,7 +10218,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-tracing 16.0.0", ] @@ -9953,7 +10237,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -9970,14 +10253,13 @@ dependencies = [ "pallet-session", "pallet-timestamp", "parity-scale-codec", - "rand 0.8.5", + "rand", "scale-info", "sp-consensus-aura", "sp-core", "sp-io", "sp-runtime", "sp-staking", - "sp-std 14.0.0", "sp-tracing 16.0.0", ] @@ -9994,7 +10276,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10009,7 +10290,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10039,7 +10319,7 @@ dependencies = [ "parity-scale-codec", "paste", "pretty_assertions", - "rand 0.8.5", + "rand", "rand_pcg", "scale-info", "serde", @@ -10102,7 +10382,6 @@ dependencies = [ "sp-io", "sp-keystore", "sp-runtime", - "sp-std 14.0.0", "sp-tracing 16.0.0", "staging-xcm", "staging-xcm-builder", @@ -10115,7 +10394,7 @@ name = "pallet-contracts-proc-macro" version = "18.0.0" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -10146,7 +10425,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10164,7 +10442,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10178,7 +10455,6 @@ dependencies = [ "scale-info", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10199,7 +10475,6 @@ dependencies = [ "sp-io", "sp-runtime", "sp-staking", - "sp-std 14.0.0", "sp-tracing 16.0.0", "substrate-test-utils", ] @@ -10221,7 +10496,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10237,7 +10511,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10256,7 +10529,7 @@ dependencies = [ "pallet-staking", "pallet-timestamp", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "scale-info", "sp-core", "sp-io", @@ -10279,15 +10552,14 @@ dependencies = [ "pallet-balances", "pallet-election-provider-support-benchmarking", "parity-scale-codec", - "parking_lot 0.12.1", - "rand 0.8.5", + "parking_lot 0.12.3", + "rand", "scale-info", "sp-arithmetic", "sp-core", "sp-io", "sp-npos-elections", "sp-runtime", - "sp-std 14.0.0", "sp-tracing 16.0.0", "strum 0.26.2", ] @@ -10302,7 +10574,6 @@ dependencies = [ "parity-scale-codec", "sp-npos-elections", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10321,7 +10592,6 @@ dependencies = [ "sp-npos-elections", "sp-runtime", "sp-staking", - "sp-std 14.0.0", "sp-tracing 16.0.0", "substrate-test-utils", ] @@ -10340,7 +10610,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10366,7 +10635,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10397,7 +10665,6 @@ dependencies = [ "sp-io", "sp-keystore", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10416,7 +10683,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-version", ] @@ -10432,7 +10698,6 @@ dependencies = [ "scale-info", "sp-core", "sp-io", - "sp-std 14.0.0", ] [[package]] @@ -10448,7 +10713,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10486,7 +10750,6 @@ dependencies = [ "sp-io", "sp-runtime", "sp-staking", - "sp-std 14.0.0", "sp-tracing 16.0.0", "substrate-test-utils", ] @@ -10507,7 +10770,6 @@ dependencies = [ "sp-inherents", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10537,7 +10799,6 @@ dependencies = [ "sp-runtime", "sp-session", "sp-staking", - "sp-std 14.0.0", ] [[package]] @@ -10556,7 +10817,6 @@ dependencies = [ "sp-io", "sp-keystore", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10576,7 +10836,6 @@ dependencies = [ "sp-io", "sp-runtime", "sp-staking", - "sp-std 14.0.0", ] [[package]] @@ -10593,7 +10852,6 @@ dependencies = [ "sp-io", "sp-keyring", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10608,7 +10866,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10625,7 +10882,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10641,7 +10897,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10654,7 +10909,7 @@ dependencies = [ "frame-system", "log", "parity-scale-codec", - "rand 0.8.5", + "rand", "rand_distr", "scale-info", "serde", @@ -10663,7 +10918,6 @@ dependencies = [ "sp-crypto-hashing", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-tracing 16.0.0", "sp-weights", ] @@ -10687,7 +10941,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-tracing 16.0.0", "sp-version", ] @@ -10717,7 +10970,6 @@ dependencies = [ "sp-io", "sp-mixnet", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10737,7 +10989,6 @@ dependencies = [ "sp-io", "sp-mmr-primitives", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10753,7 +11004,6 @@ dependencies = [ "scale-info", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10791,7 +11041,6 @@ dependencies = [ "sp-io", "sp-keystore", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10801,7 +11050,6 @@ dependencies = [ "pallet-nfts", "parity-scale-codec", "sp-api", - "sp-std 14.0.0", ] [[package]] @@ -10818,7 +11066,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10833,7 +11080,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -10850,7 +11096,6 @@ dependencies = [ "sp-io", "sp-runtime", "sp-staking", - "sp-std 14.0.0", "sp-tracing 16.0.0", ] @@ -10876,7 +11121,6 @@ dependencies = [ "sp-runtime", "sp-runtime-interface 24.0.0", "sp-staking", - "sp-std 14.0.0", ] [[package]] @@ -10888,7 +11132,7 @@ dependencies = [ "honggfuzz", "log", "pallet-nomination-pools", - "rand 0.8.5", + "rand", "sp-io", "sp-runtime", "sp-tracing 16.0.0", @@ -10901,7 +11145,6 @@ dependencies = [ "pallet-nomination-pools", "parity-scale-codec", "sp-api", - "sp-std 14.0.0", ] [[package]] @@ -10968,7 +11211,6 @@ dependencies = [ "sp-io", "sp-runtime", "sp-staking", - "sp-std 14.0.0", ] [[package]] @@ -10995,7 +11237,6 @@ dependencies = [ "sp-io", "sp-runtime", "sp-staking", - "sp-std 14.0.0", ] [[package]] @@ -11012,7 +11253,6 @@ dependencies = [ "sp-io", "sp-metadata-ir", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11057,7 +11297,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11074,7 +11313,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11091,7 +11329,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11109,7 +11346,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11125,7 +11361,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11147,7 +11382,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11163,7 +11397,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11198,7 +11431,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11218,7 +11450,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11236,7 +11467,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11255,7 +11485,6 @@ dependencies = [ "sp-crypto-hashing", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11273,7 +11502,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-weights", "substrate-test-utils", ] @@ -11290,7 +11518,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11310,7 +11537,6 @@ dependencies = [ "sp-session", "sp-staking", "sp-state-machine", - "sp-std 14.0.0", "sp-trie", ] @@ -11328,13 +11554,12 @@ dependencies = [ "pallet-staking-reward-curve", "pallet-timestamp", "parity-scale-codec", - "rand 0.8.5", + "rand", "scale-info", "sp-core", "sp-io", "sp-runtime", "sp-session", - "sp-std 14.0.0", ] [[package]] @@ -11346,7 +11571,6 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11360,14 +11584,13 @@ dependencies = [ "log", "pallet-balances", "parity-scale-codec", - "rand_chacha 0.3.1", + "rand_chacha", "scale-info", "sp-arithmetic", "sp-core", "sp-crypto-hashing", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11386,7 +11609,7 @@ dependencies = [ "pallet-staking-reward-curve", "pallet-timestamp", "parity-scale-codec", - "rand_chacha 0.3.1", + "rand_chacha", "scale-info", "serde", "sp-application-crypto", @@ -11395,7 +11618,6 @@ dependencies = [ "sp-npos-elections", "sp-runtime", "sp-staking", - "sp-std 14.0.0", "sp-tracing 16.0.0", "substrate-test-utils", ] @@ -11406,7 +11628,7 @@ version = "11.0.0" dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "sp-runtime", "syn 2.0.61", ] @@ -11439,13 +11661,12 @@ dependencies = [ "log", "pallet-balances", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "scale-info", "serde", "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-tracing 16.0.0", "substrate-state-trie-migration-rpc", "thousands", @@ -11468,7 +11689,6 @@ dependencies = [ "sp-io", "sp-runtime", "sp-statement-store", - "sp-std 14.0.0", ] [[package]] @@ -11484,7 +11704,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11516,7 +11735,6 @@ dependencies = [ "sp-inherents", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-storage 19.0.0", "sp-timestamp", ] @@ -11537,7 +11755,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-storage 19.0.0", ] @@ -11555,7 +11772,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11601,7 +11817,6 @@ dependencies = [ "sp-inherents", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-transaction-storage-proof", ] @@ -11622,7 +11837,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11641,7 +11855,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11677,7 +11890,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11694,7 +11906,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11712,7 +11923,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -11734,11 +11944,10 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", - "xcm-fee-payment-runtime-api", + "xcm-runtime-apis", ] [[package]] @@ -11758,7 +11967,6 @@ dependencies = [ "scale-info", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-tracing 16.0.0", "staging-xcm", "staging-xcm-builder", @@ -11779,6 +11987,7 @@ dependencies = [ "log", "pallet-balances", "pallet-bridge-messages", + "pallet-xcm-bridge-hub-router", "parity-scale-codec", "scale-info", "sp-core", @@ -11813,7 +12022,7 @@ dependencies = [ name = "parachain-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.10", "color-print", "cumulus-client-cli", "cumulus-client-collator", @@ -11919,7 +12128,6 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std 14.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -11952,7 +12160,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-executor", @@ -11997,7 +12204,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-tracing 16.0.0", "staging-parachain-info", "staging-xcm", @@ -12012,8 +12218,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e69bf016dc406eff7d53a7d3f7cf1c2e72c82b9088aac1118591e36dd2cd3e9" dependencies = [ "bitcoin_hashes 0.13.0", - "rand 0.8.5", - "rand_core 0.6.4", + "rand", + "rand_core", "serde", "unicode-normalization", ] @@ -12038,8 +12244,8 @@ dependencies = [ "log", "lz4", "memmap2 0.5.10", - "parking_lot 0.12.1", - "rand 0.8.5", + "parking_lot 0.12.3", + "rand", "siphasher", "snap", ] @@ -12067,16 +12273,10 @@ checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] -[[package]] -name = "parity-send-wrapper" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" - [[package]] name = "parity-util-mem" version = "0.12.0" @@ -12089,7 +12289,7 @@ dependencies = [ "impl-trait-for-tuples", "lru 0.8.1", "parity-util-mem-derive", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "primitive-types", "smallvec", "winapi", @@ -12103,7 +12303,7 @@ checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" dependencies = [ "proc-macro2 1.0.82", "syn 1.0.109", - "synstructure", + "synstructure 0.12.6", ] [[package]] @@ -12131,9 +12331,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core 0.9.8", @@ -12179,15 +12379,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", - "rand_core 0.6.4", + "rand_core", "subtle 2.5.0", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pbkdf2" @@ -12277,7 +12477,6 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std 14.0.0", "sp-storage 19.0.0", "sp-transaction-pool", "sp-version", @@ -12286,7 +12485,7 @@ dependencies = [ "staging-xcm-builder", "staging-xcm-executor", "substrate-wasm-builder", - "xcm-fee-payment-runtime-api", + "xcm-runtime-apis", ] [[package]] @@ -12314,9 +12513,7 @@ dependencies = [ "pallet-message-queue", "parachains-common", "parity-scale-codec", - "people-rococo-runtime", "polkadot-runtime-common", - "rococo-runtime", "rococo-runtime-constants", "rococo-system-emulated-network", "sp-runtime", @@ -12377,7 +12574,6 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std 14.0.0", "sp-storage 19.0.0", "sp-transaction-pool", "sp-version", @@ -12387,7 +12583,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "testnet-parachains-constants", - "xcm-fee-payment-runtime-api", + "xcm-runtime-apis", ] [[package]] @@ -12415,12 +12611,10 @@ dependencies = [ "pallet-message-queue", "parachains-common", "parity-scale-codec", - "people-westend-runtime", "polkadot-runtime-common", "sp-runtime", "staging-xcm", "staging-xcm-executor", - "westend-runtime", "westend-runtime-constants", "westend-system-emulated-network", ] @@ -12477,7 +12671,6 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std 14.0.0", "sp-storage 19.0.0", "sp-transaction-pool", "sp-version", @@ -12488,14 +12681,14 @@ dependencies = [ "substrate-wasm-builder", "testnet-parachains-constants", "westend-runtime-constants", - "xcm-fee-payment-runtime-api", + "xcm-runtime-apis", ] [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" @@ -12526,7 +12719,7 @@ dependencies = [ "pest", "pest_meta", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -12567,21 +12760,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] [[package]] name = "pin-project-lite" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" - -[[package]] -name = "pin-project-lite" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -12680,9 +12867,9 @@ dependencies = [ "polkadot-node-subsystem-util", "polkadot-primitives", "polkadot-primitives-test-helpers", - "rand 0.8.5", - "rand_chacha 0.3.1", - "rand_core 0.6.4", + "rand", + "rand_chacha", + "rand_core", "schnorrkel 0.11.4", "sp-authority-discovery", "sp-core", @@ -12706,8 +12893,8 @@ dependencies = [ "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", "polkadot-primitives", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand", + "rand_chacha", "sp-application-crypto", "sp-authority-discovery", "sp-core", @@ -12735,7 +12922,7 @@ dependencies = [ "polkadot-primitives", "polkadot-primitives-test-helpers", "polkadot-subsystem-bench", - "rand 0.8.5", + "rand", "rstest", "sc-network", "schnellru", @@ -12767,7 +12954,7 @@ dependencies = [ "polkadot-primitives", "polkadot-primitives-test-helpers", "polkadot-subsystem-bench", - "rand 0.8.5", + "rand", "rstest", "sc-network", "schnellru", @@ -12795,7 +12982,7 @@ name = "polkadot-cli" version = "7.0.0" dependencies = [ "cfg-if", - "clap 4.5.3", + "clap 4.5.10", "frame-benchmarking-cli", "futures", "log", @@ -12858,7 +13045,6 @@ dependencies = [ "scale-info", "sp-core", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -12918,15 +13104,15 @@ dependencies = [ "futures", "futures-timer", "lazy_static", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "polkadot-node-network-protocol", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", "polkadot-primitives", "quickcheck", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand", + "rand_chacha", "sc-network", "sc-network-common", "sp-application-crypto", @@ -12952,7 +13138,7 @@ dependencies = [ "futures", "futures-timer", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-subsystem", @@ -13008,7 +13194,7 @@ dependencies = [ "log", "merlin", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "polkadot-node-jaeger", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -13018,9 +13204,9 @@ dependencies = [ "polkadot-primitives", "polkadot-primitives-test-helpers", "polkadot-subsystem-bench", - "rand 0.8.5", - "rand_chacha 0.3.1", - "rand_core 0.6.4", + "rand", + "rand_chacha", + "rand_core", "sc-keystore", "schnellru", "schnorrkel 0.11.4", @@ -13049,7 +13235,7 @@ dependencies = [ "kvdb-memorydb", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "polkadot-erasure-coding", "polkadot-node-jaeger", "polkadot-node-primitives", @@ -13129,8 +13315,10 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-primitives-test-helpers", + "sp-application-crypto", "sp-core", "sp-keyring", + "sp-keystore", "sp-maybe-compressed-blob", "tracing-gum", ] @@ -13165,7 +13353,7 @@ dependencies = [ "kvdb", "kvdb-memorydb", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -13296,7 +13484,7 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-primitives", "procfs", - "rand 0.8.5", + "rand", "rococo-runtime", "rusty-fork", "sc-sysinfo", @@ -13428,7 +13616,7 @@ dependencies = [ "log", "mick-jaeger", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "polkadot-node-primitives", "polkadot-primitives", "sc-network", @@ -13446,7 +13634,9 @@ dependencies = [ "bs58 0.5.0", "futures", "futures-timer", - "hyper", + "http-body-util", + "hyper 1.3.1", + "hyper-util", "log", "parity-scale-codec", "polkadot-primitives", @@ -13479,8 +13669,8 @@ dependencies = [ "polkadot-node-jaeger", "polkadot-node-primitives", "polkadot-primitives", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand", + "rand_chacha", "sc-authority-discovery", "sc-network", "sc-network-types", @@ -13528,7 +13718,7 @@ version = "1.0.0" dependencies = [ "async-trait", "futures", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "polkadot-erasure-coding", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -13591,7 +13781,7 @@ dependencies = [ "log", "parity-db", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "pin-project", "polkadot-erasure-coding", "polkadot-node-jaeger", @@ -13605,7 +13795,7 @@ dependencies = [ "polkadot-primitives", "polkadot-primitives-test-helpers", "prioritized-metered-channel", - "rand 0.8.5", + "rand", "sc-client-api", "schnellru", "sp-application-crypto", @@ -13626,7 +13816,7 @@ dependencies = [ "futures", "futures-timer", "orchestra", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -13652,7 +13842,7 @@ dependencies = [ "async-trait", "bridge-hub-rococo-runtime", "bridge-hub-westend-runtime", - "clap 4.5.3", + "clap 4.5.10", "collectives-westend-runtime", "color-print", "contracts-rococo-runtime", @@ -13669,6 +13859,7 @@ dependencies = [ "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-relay-chain-interface", + "docify", "frame-benchmarking", "frame-benchmarking-cli", "frame-support", @@ -13751,7 +13942,6 @@ dependencies = [ "serde", "sp-core", "sp-runtime", - "sp-std 14.0.0", "sp-weights", ] @@ -13778,7 +13968,6 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-staking", - "sp-std 14.0.0", ] [[package]] @@ -13786,7 +13975,7 @@ name = "polkadot-primitives-test-helpers" version = "1.0.0" dependencies = [ "polkadot-primitives", - "rand 0.8.5", + "rand", "sp-application-crypto", "sp-core", "sp-keyring", @@ -13876,7 +14065,6 @@ dependencies = [ "sp-runtime", "sp-session", "sp-staking", - "sp-std 14.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -13891,7 +14079,6 @@ dependencies = [ "frame-benchmarking", "parity-scale-codec", "polkadot-primitives", - "sp-std 14.0.0", "sp-tracing 16.0.0", ] @@ -13917,6 +14104,7 @@ dependencies = [ "pallet-balances", "pallet-broker", "pallet-message-queue", + "pallet-mmr", "pallet-session", "pallet-staking", "pallet-timestamp", @@ -13927,10 +14115,9 @@ dependencies = [ "polkadot-primitives", "polkadot-primitives-test-helpers", "polkadot-runtime-metrics", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand", + "rand_chacha", "rstest", - "rustc-hex", "sc-keystore", "scale-info", "serde", @@ -14337,8 +14524,8 @@ dependencies = [ "tracing-gum-proc-macro", "westend-runtime-constants", "xcm-emulator", - "xcm-fee-payment-runtime-api", "xcm-procedural", + "xcm-runtime-apis", "xcm-simulator", ] @@ -14359,6 +14546,8 @@ dependencies = [ "frame-system", "kitchensink-runtime", "minimal-template-runtime", + "pallet-asset-conversion-tx-payment", + "pallet-asset-tx-payment", "pallet-assets", "pallet-aura", "pallet-authorship", @@ -14377,6 +14566,7 @@ dependencies = [ "pallet-proxy", "pallet-referenda", "pallet-scheduler", + "pallet-skip-feeless-payment", "pallet-timestamp", "pallet-transaction-payment", "pallet-uniques", @@ -14450,7 +14640,6 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std 14.0.0", "sp-storage 19.0.0", "sp-transaction-pool", "sp-version", @@ -14483,7 +14672,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "parity-db", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", @@ -14581,7 +14770,7 @@ dependencies = [ "tracing-gum", "westend-runtime", "westend-runtime-constants", - "xcm-fee-payment-runtime-api", + "xcm-runtime-apis", ] [[package]] @@ -14605,7 +14794,7 @@ dependencies = [ "polkadot-primitives", "polkadot-primitives-test-helpers", "polkadot-subsystem-bench", - "rand_chacha 0.3.1", + "rand_chacha", "sc-keystore", "sc-network", "sp-application-crypto", @@ -14637,7 +14826,7 @@ dependencies = [ "async-trait", "bincode", "bitvec", - "clap 4.5.3", + "clap 4.5.10", "clap-num", "color-eyre", "colored", @@ -14673,9 +14862,9 @@ dependencies = [ "prometheus", "pyroscope", "pyroscope_pprofrs", - "rand 0.8.5", - "rand_chacha 0.3.1", - "rand_core 0.6.4", + "rand", + "rand_chacha", + "rand_core", "rand_distr", "sc-keystore", "sc-network", @@ -14694,7 +14883,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-timestamp", - "strum 0.24.1", + "strum 0.26.2", "substrate-prometheus-endpoint", "tokio", "tracing-gum", @@ -14735,7 +14924,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "async-trait", - "clap 4.5.3", + "clap 4.5.10", "color-eyre", "futures", "futures-timer", @@ -14754,7 +14943,7 @@ dependencies = [ "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-primitives", - "rand 0.8.5", + "rand", "sp-core", "sp-keystore", "substrate-build-script-utils", @@ -14810,7 +14999,6 @@ dependencies = [ "sp-runtime", "sp-session", "sp-staking", - "sp-std 14.0.0", "sp-transaction-pool", "sp-trie", "sp-version", @@ -14842,7 +15030,7 @@ dependencies = [ "polkadot-runtime-parachains", "polkadot-service", "polkadot-test-runtime", - "rand 0.8.5", + "rand", "sc-authority-discovery", "sc-chain-spec", "sc-cli", @@ -14878,7 +15066,7 @@ dependencies = [ name = "polkadot-voter-bags" version = "7.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.10", "generate-bags", "sp-io", "westend-runtime", @@ -14932,7 +15120,7 @@ checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c" dependencies = [ "polkavm-common", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -14979,10 +15167,24 @@ dependencies = [ "concurrent-queue", "libc", "log", - "pin-project-lite 0.2.12", + "pin-project-lite", "windows-sys 0.48.0", ] +[[package]] +name = "polling" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14" +dependencies = [ + "cfg-if", + "concurrent-queue", + "pin-project-lite", + "rustix 0.38.21", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "poly1305" version = "0.8.0" @@ -15018,15 +15220,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be97d76faf1bfab666e1375477b23fde79eccf0276e9b63b92a39d676a889ba9" dependencies = [ - "rand 0.8.5", + "rand", ] -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - [[package]] name = "pprof" version = "0.12.1" @@ -15040,7 +15236,7 @@ dependencies = [ "log", "nix 0.26.2", "once_cell", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "smallvec", "symbolic-demangle", "tempfile", @@ -15183,7 +15379,7 @@ checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", "version_check", ] @@ -15195,7 +15391,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "version_check", ] @@ -15205,6 +15401,17 @@ version = "0.5.20+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" +[[package]] +name = "proc-macro-warning" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.36", + "syn 2.0.61", +] + [[package]] name = "proc-macro-warning" version = "1.0.0" @@ -15212,7 +15419,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -15240,7 +15447,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "chrono", "flate2", "hex", @@ -15255,7 +15462,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "chrono", "hex", ] @@ -15270,19 +15477,19 @@ dependencies = [ "fnv", "lazy_static", "memchr", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "thiserror", ] [[package]] name = "prometheus-client" -version = "0.19.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6fa99d535dd930d1249e6c79cb3c2915f9172a540fe2b02a4c8f9ca954721e" +checksum = "3c99afa9a01501019ac3a14d71d9f94050346f55ca471ce90c799a15c58f61e2" dependencies = [ "dtoa", "itoa", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "prometheus-client-derive-encode", ] @@ -15293,7 +15500,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -15317,11 +15524,11 @@ checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.4.0", + "bitflags 2.6.0", "lazy_static", "num-traits", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand", + "rand_chacha", "rand_xorshift", "regex-syntax 0.8.2", "rusty-fork", @@ -15341,12 +15548,12 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes", - "prost-derive 0.12.4", + "prost-derive 0.12.6", ] [[package]] @@ -15385,7 +15592,7 @@ dependencies = [ "once_cell", "petgraph", "prettyplease 0.2.12", - "prost 0.12.4", + "prost 0.12.6", "prost-types 0.12.4", "regex", "syn 2.0.61", @@ -15401,20 +15608,20 @@ dependencies = [ "anyhow", "itertools 0.10.5", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] [[package]] name = "prost-derive" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19de2de2a00075bf566bee3bd4db014b11587e84184d3f7a791bc17f1a8e9e48" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", "itertools 0.11.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -15433,7 +15640,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3235c33eb02c1f1e212abdbe34c78b264b038fb58ca612664343271e36e55ffe" dependencies = [ - "prost 0.12.4", + "prost 0.12.6", ] [[package]] @@ -15486,7 +15693,7 @@ dependencies = [ "mach2", "once_cell", "raw-cpuid", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "web-sys", "winapi", ] @@ -15508,15 +15715,15 @@ dependencies = [ [[package]] name = "quick-protobuf-codec" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1693116345026436eb2f10b677806169c1a1260c1c60eaaffe3fb5a29ae23d8b" +checksum = "f8ededb1cd78531627244d51dd0c7139fbe736c7d57af0092a76f0ffb2f56e98" dependencies = [ "asynchronous-codec", "bytes", "quick-protobuf", "thiserror", - "unsigned-varint", + "unsigned-varint 0.7.2", ] [[package]] @@ -15527,7 +15734,7 @@ checksum = "5253a3a0d56548d5b0be25414171dc780cc6870727746d05bd2bde352eee96c5" dependencies = [ "ahash 0.8.11", "hashbrown 0.13.2", - "parking_lot 0.12.1", + "parking_lot 0.12.3", ] [[package]] @@ -15538,49 +15745,56 @@ checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" dependencies = [ "env_logger 0.8.4", "log", - "rand 0.8.5", + "rand", ] [[package]] -name = "quicksink" -version = "0.1.2" +name = "quinn" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77de3c815e5a160b1539c6592796801df2043ae35e123b46d73380cfa57af858" +checksum = "2e8b432585672228923edbbf64b8b12c14e1112f62e88737655b4a083dbcd78e" dependencies = [ - "futures-core", - "futures-sink", - "pin-project-lite 0.1.12", + "bytes", + "pin-project-lite", + "quinn-proto 0.9.6", + "quinn-udp 0.3.2", + "rustc-hash", + "rustls 0.20.9", + "thiserror", + "tokio", + "tracing", + "webpki", ] [[package]] name = "quinn" -version = "0.9.4" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e8b432585672228923edbbf64b8b12c14e1112f62e88737655b4a083dbcd78e" +checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" dependencies = [ "bytes", - "pin-project-lite 0.2.12", - "quinn-proto", - "quinn-udp", + "futures-io", + "pin-project-lite", + "quinn-proto 0.10.6", + "quinn-udp 0.4.1", "rustc-hash", - "rustls 0.20.8", + "rustls 0.21.7", "thiserror", "tokio", "tracing", - "webpki", ] [[package]] name = "quinn-proto" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c956be1b23f4261676aed05a0046e204e8a6836e50203902683a718af0797989" +checksum = "94b0b33c13a79f669c85defaf4c275dc86a0c0372807d0ca3d78e0bb87274863" dependencies = [ "bytes", - "rand 0.8.5", + "rand", "ring 0.16.20", "rustc-hash", - "rustls 0.20.8", + "rustls 0.20.9", "slab", "thiserror", "tinyvec", @@ -15588,6 +15802,23 @@ dependencies = [ "webpki", ] +[[package]] +name = "quinn-proto" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" +dependencies = [ + "bytes", + "rand", + "ring 0.16.20", + "rustc-hash", + "rustls 0.21.7", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + [[package]] name = "quinn-udp" version = "0.3.2" @@ -15595,12 +15826,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "641538578b21f5e5c8ea733b736895576d0fe329bb883b937db6f4d163dbaaf4" dependencies = [ "libc", - "quinn-proto", + "quinn-proto 0.9.6", "socket2 0.4.9", "tracing", "windows-sys 0.42.0", ] +[[package]] +name = "quinn-udp" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" +dependencies = [ + "bytes", + "libc", + "socket2 0.5.7", + "tracing", + "windows-sys 0.48.0", +] + [[package]] name = "quote" version = "0.6.13" @@ -15612,9 +15856,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2 1.0.82", ] @@ -15625,19 +15869,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", -] - [[package]] name = "rand" version = "0.8.5" @@ -15645,18 +15876,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "rand_chacha", + "rand_core", ] [[package]] @@ -15666,16 +15887,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", + "rand_core", ] [[package]] @@ -15684,7 +15896,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.10", + "getrandom", ] [[package]] @@ -15694,16 +15906,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" dependencies = [ "num-traits", - "rand 0.8.5", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", + "rand", ] [[package]] @@ -15712,7 +15915,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" dependencies = [ - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -15721,7 +15924,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -15824,7 +16027,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.10", + "getrandom", "redox_syscall 0.2.16", "thiserror", ] @@ -15857,7 +16060,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -15954,24 +16157,22 @@ dependencies = [ "bp-runtime", "finality-relay", "frame-support", - "frame-system", "futures", "jsonrpsee", "log", "num-traits", - "pallet-balances", - "pallet-bridge-messages", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-utility", "parity-scale-codec", "quick_cache", - "rand 0.8.5", + "rand", "relay-utils", "sc-chain-spec", "sc-rpc-api", "sc-transaction-pool-api", "scale-info", + "serde_json", "sp-consensus-grandpa", "sp-core", "sp-rpc", @@ -15988,19 +16189,19 @@ dependencies = [ name = "relay-utils" version = "0.1.0" dependencies = [ - "ansi_term", "anyhow", "async-std", "async-trait", "backoff", "bp-runtime", + "console", "env_logger 0.11.3", "futures", "isahc", "jsonpath_lib", "log", "num-traits", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "serde_json", "sp-runtime", "substrate-prometheus-endpoint", @@ -16014,7 +16215,7 @@ dependencies = [ name = "remote-ext-tests-bags-list" version = "1.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.10", "frame-system", "log", "pallet-bags-list-remote-tests", @@ -16036,19 +16237,19 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-rustls", + "h2 0.3.26", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.29", + "hyper-rustls 0.24.2", "ipnet", "js-sys", "log", "mime", "once_cell", "percent-encoding", - "pin-project-lite 0.2.12", - "rustls 0.21.6", + "pin-project-lite", + "rustls 0.21.7", "rustls-pemfile 1.0.3", "serde", "serde_json", @@ -16087,13 +16288,14 @@ dependencies = [ [[package]] name = "ring" version = "0.1.0" -source = "git+https://github.com/w3f/ring-proof#b273d33f9981e2bb3375ab45faeb537f7ee35224" +source = "git+https://github.com/w3f/ring-proof?rev=665f5f5#665f5f51af5734c7b6d90b985dd6861d4c5b4752" dependencies = [ "ark-ec", "ark-ff 0.4.2", "ark-poly", "ark-serialize 0.4.2", "ark-std 0.4.0", + "arrayvec 0.7.4", "blake2 0.10.6", "common", "fflonk", @@ -16122,22 +16324,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", - "getrandom 0.2.10", + "getrandom", "libc", "spin 0.9.8", "untrusted 0.9.0", "windows-sys 0.48.0", ] -[[package]] -name = "ripemd" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" -dependencies = [ - "digest 0.10.7", -] - [[package]] name = "rle-decode-fast" version = "1.0.3" @@ -16221,7 +16414,6 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std 14.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -16323,7 +16515,6 @@ dependencies = [ "sp-runtime", "sp-session", "sp-staking", - "sp-std 14.0.0", "sp-storage 19.0.0", "sp-tracing 16.0.0", "sp-transaction-pool", @@ -16336,7 +16527,7 @@ dependencies = [ "substrate-wasm-builder", "tiny-keccak", "tokio", - "xcm-fee-payment-runtime-api", + "xcm-runtime-apis", ] [[package]] @@ -16360,6 +16551,7 @@ version = "0.0.0" dependencies = [ "asset-hub-rococo-emulated-chain", "bridge-hub-rococo-emulated-chain", + "coretime-rococo-emulated-chain", "emulated-integration-tests-common", "penpal-emulated-chain", "people-rococo-emulated-chain", @@ -16418,7 +16610,7 @@ dependencies = [ "cfg-if", "glob", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "regex", "relative-path", "rustc_version 0.4.0", @@ -16467,7 +16659,7 @@ dependencies = [ "parity-scale-codec", "primitive-types", "proptest", - "rand 0.8.5", + "rand", "rlp", "ruint-macro", "serde", @@ -16569,7 +16761,7 @@ version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys 0.4.10", @@ -16578,11 +16770,10 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" dependencies = [ - "log", "ring 0.16.20", "sct", "webpki", @@ -16590,9 +16781,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.6" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb" +checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" dependencies = [ "log", "ring 0.16.20", @@ -16602,14 +16793,15 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.2" +version = "0.23.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" +checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" dependencies = [ "log", + "once_cell", "ring 0.17.7", "rustls-pki-types", - "rustls-webpki 0.102.2", + "rustls-webpki 0.102.4", "subtle 2.5.0", "zeroize", ] @@ -16659,10 +16851,37 @@ dependencies = [ ] [[package]] -name = "rustls-pki-types" -version = "1.2.0" +name = "rustls-pki-types" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" + +[[package]] +name = "rustls-platform-verifier" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5f0d26fa1ce3c790f9590868f0109289a044acb954525f933e2aa3b871c157d" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls 0.23.10", + "rustls-native-certs 0.7.0", + "rustls-platform-verifier-android", + "rustls-webpki 0.102.4", + "security-framework", + "security-framework-sys", + "webpki-roots 0.26.3", + "winapi", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a716eb65e3158e90e17cd93d855216e27bde02745ab842f2cab4a39dba1bacf" +checksum = "84e217e7fdc8466b5b35d30f8c0a30febd29173df4a3a0c2115d306b9c4117ad" [[package]] name = "rustls-webpki" @@ -16676,9 +16895,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.2" +version = "0.102.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" +checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" dependencies = [ "ring 0.17.7", "rustls-pki-types", @@ -16716,9 +16935,9 @@ dependencies = [ [[package]] name = "rw-stream-sink" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26338f5e09bb721b85b135ea05af7767c90b52f6de4f087d4f4a3a9d64e7dc04" +checksum = "d8c9026ff5d2f23da5e45bbc283f156383001bfb09c4e44256d02c1a685fe9a1" dependencies = [ "futures", "pin-project", @@ -16779,13 +16998,12 @@ dependencies = [ "libp2p", "linked_hash_set", "log", - "multihash 0.17.0", - "multihash-codetable", + "multihash 0.19.1", "parity-scale-codec", - "prost 0.12.4", + "prost 0.12.6", "prost-build 0.12.4", "quickcheck", - "rand 0.8.5", + "rand", "sc-client-api", "sc-network", "sc-network-types", @@ -16809,7 +17027,7 @@ dependencies = [ "futures-timer", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "sc-block-builder", "sc-client-api", "sc-proposer-metrics", @@ -16847,7 +17065,7 @@ name = "sc-chain-spec" version = "28.0.0" dependencies = [ "array-bytes", - "clap 4.5.3", + "clap 4.5.10", "docify", "log", "memmap2 0.9.3", @@ -16880,7 +17098,7 @@ version = "11.0.0" dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -16890,7 +17108,7 @@ version = "0.36.0" dependencies = [ "array-bytes", "chrono", - "clap 4.5.3", + "clap 4.5.10", "fdlimit", "futures", "futures-timer", @@ -16900,7 +17118,7 @@ dependencies = [ "names", "parity-bip39", "parity-scale-codec", - "rand 0.8.5", + "rand", "regex", "rpassword", "sc-client-api", @@ -16935,7 +17153,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "sc-executor", "sc-transaction-pool-api", "sc-utils", @@ -16971,9 +17189,9 @@ dependencies = [ "log", "parity-db", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "quickcheck", - "rand 0.8.5", + "rand", "sc-client-api", "sc-state-db", "schnellru", @@ -16995,10 +17213,9 @@ version = "0.33.0" dependencies = [ "async-trait", "futures", - "futures-timer", "log", "mockall 0.11.4", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "sc-client-api", "sc-network-types", "sc-utils", @@ -17022,7 +17239,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -17064,7 +17281,7 @@ dependencies = [ "num-rational", "num-traits", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -17133,7 +17350,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -17174,7 +17391,7 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "sc-consensus-beefy", "sc-rpc", "serde", @@ -17215,8 +17432,8 @@ dependencies = [ "futures-timer", "log", "parity-scale-codec", - "parking_lot 0.12.1", - "rand 0.8.5", + "parking_lot 0.12.3", + "rand", "sc-block-builder", "sc-chain-spec", "sc-client-api", @@ -17321,7 +17538,7 @@ dependencies = [ "futures-timer", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "sc-client-api", "sc-consensus", "sp-api", @@ -17369,7 +17586,7 @@ dependencies = [ "env_logger 0.11.3", "num_cpus", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "paste", "regex", "sc-executor-common", @@ -17431,7 +17648,7 @@ dependencies = [ "libc", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "paste", "rustix 0.36.15", "sc-allocator", @@ -17449,7 +17666,7 @@ dependencies = [ name = "sc-informant" version = "0.33.0" dependencies = [ - "ansi_term", + "console", "futures", "futures-timer", "log", @@ -17466,7 +17683,7 @@ name = "sc-keystore" version = "25.0.0" dependencies = [ "array-bytes", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "serde_json", "sp-application-crypto", "sp-core", @@ -17487,9 +17704,9 @@ dependencies = [ "futures-timer", "log", "mixnet", - "multiaddr", + "multiaddr 0.18.1", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "sc-client-api", "sc-network", "sc-network-types", @@ -17527,12 +17744,12 @@ dependencies = [ "multistream-select", "once_cell", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "partial_sort", "pin-project", - "prost 0.12.4", + "prost 0.12.6", "prost-build 0.12.4", - "rand 0.8.5", + "rand", "sc-block-builder", "sc-client-api", "sc-network-common", @@ -17561,7 +17778,7 @@ dependencies = [ "tokio-stream", "tokio-test", "tokio-util", - "unsigned-varint", + "unsigned-varint 0.7.2", "void", "wasm-timer", "zeroize", @@ -17593,7 +17810,6 @@ dependencies = [ "async-trait", "futures", "futures-timer", - "libp2p", "log", "parity-scale-codec", "quickcheck", @@ -17618,7 +17834,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "prost 0.12.4", + "prost 0.12.6", "prost-build 0.12.4", "sc-client-api", "sc-network", @@ -17636,7 +17852,6 @@ dependencies = [ "array-bytes", "async-channel", "futures", - "libp2p", "log", "parity-scale-codec", "sc-network", @@ -17663,7 +17878,7 @@ dependencies = [ "log", "mockall 0.11.4", "parity-scale-codec", - "prost 0.12.4", + "prost 0.12.6", "prost-build 0.12.4", "quickcheck", "sc-block-builder", @@ -17699,8 +17914,8 @@ dependencies = [ "futures-timer", "libp2p", "log", - "parking_lot 0.12.1", - "rand 0.8.5", + "parking_lot 0.12.3", + "rand", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -17727,7 +17942,6 @@ version = "0.33.0" dependencies = [ "array-bytes", "futures", - "libp2p", "log", "parity-scale-codec", "sc-network", @@ -17745,13 +17959,14 @@ name = "sc-network-types" version = "0.10.0" dependencies = [ "bs58 0.5.0", - "ed25519-dalek 2.1.1", + "ed25519-dalek", "libp2p-identity", "litep2p", - "multiaddr", - "multihash 0.17.0", + "log", + "multiaddr 0.18.1", + "multihash 0.19.1", "quickcheck", - "rand 0.8.5", + "rand", "thiserror", "zeroize", ] @@ -17766,16 +17981,15 @@ dependencies = [ "fnv", "futures", "futures-timer", - "hyper", - "hyper-rustls", + "hyper 0.14.29", + "hyper-rustls 0.24.2", "lazy_static", - "libp2p", "log", "num_cpus", "once_cell", "parity-scale-codec", - "parking_lot 0.12.1", - "rand 0.8.5", + "parking_lot 0.12.3", + "rand", "sc-block-builder", "sc-client-api", "sc-client-db", @@ -17817,7 +18031,7 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "pretty_assertions", "sc-block-builder", "sc-chain-spec", @@ -17875,8 +18089,9 @@ dependencies = [ "forwarded-header-value", "futures", "governor", - "http", - "hyper", + "http 1.1.0", + "http-body-util", + "hyper 1.3.1", "ip_network", "jsonrpsee", "log", @@ -17900,9 +18115,9 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "pretty_assertions", - "rand 0.8.5", + "rand", "sc-block-builder", "sc-chain-spec", "sc-client-api", @@ -17939,7 +18154,6 @@ dependencies = [ "sp-io", "sp-runtime", "sp-runtime-interface 24.0.0", - "sp-std 14.0.0", "substrate-wasm-builder", ] @@ -17955,9 +18169,9 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "pin-project", - "rand 0.8.5", + "rand", "sc-chain-spec", "sc-client-api", "sc-client-db", @@ -18018,7 +18232,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "sc-block-builder", "sc-client-api", "sc-client-db", @@ -18050,7 +18264,7 @@ version = "0.30.0" dependencies = [ "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "sp-core", ] @@ -18061,7 +18275,7 @@ dependencies = [ "env_logger 0.11.3", "log", "parity-db", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "sc-client-api", "sc-keystore", "sp-api", @@ -18078,7 +18292,7 @@ dependencies = [ name = "sc-storage-monitor" version = "0.16.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.10", "fs4", "log", "sp-core", @@ -18112,7 +18326,7 @@ dependencies = [ "futures", "libc", "log", - "rand 0.8.5", + "rand", "rand_pcg", "regex", "sc-telemetry", @@ -18133,9 +18347,9 @@ dependencies = [ "futures", "libp2p", "log", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "pin-project", - "rand 0.8.5", + "rand", "sc-network", "sc-utils", "serde", @@ -18148,15 +18362,15 @@ dependencies = [ name = "sc-tracing" version = "28.0.0" dependencies = [ - "ansi_term", "chrono", + "console", "criterion", "is-terminal", "lazy_static", "libc", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "regex", "rustc-hash", "sc-client-api", @@ -18180,7 +18394,7 @@ version = "11.0.0" dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -18197,7 +18411,7 @@ dependencies = [ "linked-hash-map", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "sc-block-builder", "sc-client-api", "sc-transaction-pool-api", @@ -18243,7 +18457,7 @@ dependencies = [ "futures-timer", "lazy_static", "log", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "prometheus", "sp-arithmetic", "tokio-test", @@ -18261,9 +18475,9 @@ dependencies = [ [[package]] name = "scale-decode" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b12ebca36cec2a3f983c46295b282b35e5f8496346fb859a8776dad5389e5389" +checksum = "e98f3262c250d90e700bb802eb704e1f841e03331c2eb815e46516c4edbf5b27" dependencies = [ "derive_more", "parity-scale-codec", @@ -18294,7 +18508,7 @@ checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -18332,7 +18546,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0f696e21e10fa546b7ffb1c9672c6de8fbc7a81acf59524386d8639bf12737" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "serde_derive_internals", "syn 1.0.109", ] @@ -18358,7 +18572,7 @@ dependencies = [ "arrayvec 0.7.4", "curve25519-dalek-ng", "merlin", - "rand_core 0.6.4", + "rand_core", "sha2 0.9.9", "subtle-ng", "zeroize", @@ -18373,10 +18587,10 @@ dependencies = [ "aead", "arrayref", "arrayvec 0.7.4", - "curve25519-dalek 4.1.3", + "curve25519-dalek", "getrandom_or_panic", "merlin", - "rand_core 0.6.4", + "rand_core", "serde_bytes", "sha2 0.10.8", "subtle 2.5.0", @@ -18421,7 +18635,7 @@ dependencies = [ "crc", "fxhash", "log", - "rand 0.8.5", + "rand", "slab", "thiserror", ] @@ -18452,18 +18666,18 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.28.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" +checksum = "2acea373acb8c21ecb5a23741452acd2593ed44ee3d343e72baaa143bc89d0d5" dependencies = [ "secp256k1-sys", ] [[package]] name = "secp256k1-sys" -version = "0.9.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" +checksum = "09e67c467c38fd24bd5499dc9a18183b31575c12ee549197e3e20d57aa4fe3b7" dependencies = [ "cc", ] @@ -18479,22 +18693,23 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.9.2" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", + "num-bigint", "security-framework-sys", ] [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" dependencies = [ "core-foundation-sys", "libc", @@ -18528,7 +18743,6 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std 14.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -18586,6 +18800,12 @@ dependencies = [ "pest", ] +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + [[package]] name = "separator" version = "0.4.1" @@ -18594,9 +18814,9 @@ checksum = "f97841a747eef040fcd2e7b3b9a220a7205926e60488e673d9e4926d27772ce5" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] @@ -18621,12 +18841,12 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -18637,7 +18857,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -18652,9 +18872,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "indexmap 2.2.3", "itoa", @@ -18685,9 +18905,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.33" +version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0623d197252096520c6f2a5e1171ee436e5af99a5d7caa2891e55e61950e6d9" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ "indexmap 2.2.3", "itoa", @@ -18716,7 +18936,7 @@ dependencies = [ "futures", "lazy_static", "log", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "serial_test_derive", ] @@ -18727,7 +18947,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -18846,7 +19066,6 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std 14.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -18881,12 +19100,6 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" - [[package]] name = "signature" version = "2.1.0" @@ -18894,7 +19107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ "digest 0.10.7", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -18916,7 +19129,7 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cae9a3fcdadafb6d97f4c0e007e4247b114ee0f119f650c3cbf3a8b3a1479694" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", ] [[package]] @@ -18959,14 +19172,13 @@ dependencies = [ "parity-scale-codec", "paste", "sp-runtime", - "sp-std 14.0.0", ] [[package]] name = "slotmap" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" dependencies = [ "version_check", ] @@ -18997,12 +19209,12 @@ dependencies = [ "async-channel", "async-executor", "async-fs", - "async-io", - "async-lock", + "async-io 1.13.0", + "async-lock 2.8.0", "async-net", "async-process", "blocking", - "futures-lite", + "futures-lite 1.13.0", ] [[package]] @@ -19021,7 +19233,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0bb30cf57b7b5f6109ce17c3164445e2d6f270af2cb48f6e4d31c2967c9a9f5" dependencies = [ "arrayvec 0.7.4", - "async-lock", + "async-lock 2.8.0", "atomic-take", "base64 0.21.2", "bip39", @@ -19032,9 +19244,9 @@ dependencies = [ "derive_more", "ed25519-zebra", "either", - "event-listener", + "event-listener 2.5.3", "fnv", - "futures-lite", + "futures-lite 1.13.0", "futures-util", "hashbrown 0.14.3", "hex", @@ -19050,8 +19262,8 @@ dependencies = [ "pbkdf2", "pin-project", "poly1305", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand", + "rand_chacha", "ruzstd", "schnorrkel 0.10.2", "serde", @@ -19061,10 +19273,10 @@ dependencies = [ "siphasher", "slab", "smallvec", - "soketto", + "soketto 0.7.1", "twox-hash", "wasmi 0.31.2", - "x25519-dalek 2.0.0", + "x25519-dalek", "zeroize", ] @@ -19075,15 +19287,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "256b5bad1d6b49045e95fe87492ce73d5af81545d8b4d8318a872d2007024c33" dependencies = [ "async-channel", - "async-lock", + "async-lock 2.8.0", "base64 0.21.2", "blake2-rfc", "derive_more", "either", - "event-listener", + "event-listener 2.5.3", "fnv", "futures-channel", - "futures-lite", + "futures-lite 1.13.0", "futures-util", "hashbrown 0.14.3", "hex", @@ -19091,10 +19303,10 @@ dependencies = [ "log", "lru 0.11.0", "no-std-net", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "pin-project", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand", + "rand_chacha", "serde", "serde_json", "siphasher", @@ -19119,8 +19331,8 @@ dependencies = [ "aes-gcm", "blake2 0.10.6", "chacha20poly1305", - "curve25519-dalek 4.1.3", - "rand_core 0.6.4", + "curve25519-dalek", + "rand_core", "ring 0.17.7", "rustc_version 0.4.0", "sha2 0.10.8", @@ -19192,7 +19404,7 @@ dependencies = [ "hex-literal", "parity-bytes", "parity-scale-codec", - "rand 0.8.5", + "rand", "rlp", "scale-info", "serde", @@ -19213,7 +19425,7 @@ dependencies = [ "hex", "lazy_static", "parity-scale-codec", - "rand 0.8.5", + "rand", "scale-info", "snowbridge-amcl", "zeroize", @@ -19257,7 +19469,7 @@ dependencies = [ "log", "pallet-timestamp", "parity-scale-codec", - "rand 0.8.5", + "rand", "scale-info", "serde", "serde_json", @@ -19381,7 +19593,6 @@ dependencies = [ "hex-literal", "log", "parity-scale-codec", - "rustc-hex", "scale-info", "snowbridge-core", "sp-core", @@ -19460,9 +19671,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", @@ -19476,21 +19687,36 @@ checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" dependencies = [ "base64 0.13.1", "bytes", - "flate2", "futures", - "http", "httparse", "log", - "rand 0.8.5", + "rand", "sha-1 0.9.8", ] +[[package]] +name = "soketto" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37468c595637c10857701c990f93a40ce0e357cedb0953d1c26c8d8027f9bb53" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures", + "http 1.1.0", + "httparse", + "log", + "rand", + "sha1", +] + [[package]] name = "solochain-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.10", "frame-benchmarking-cli", + "frame-metadata-hash-extension", "frame-system", "futures", "jsonrpsee", @@ -19533,6 +19759,7 @@ version = "0.0.0" dependencies = [ "frame-benchmarking", "frame-executive", + "frame-metadata-hash-extension", "frame-support", "frame-system", "frame-system-benchmarking", @@ -19558,7 +19785,6 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std 14.0.0", "sp-storage 19.0.0", "sp-transaction-pool", "sp-version", @@ -19581,7 +19807,6 @@ dependencies = [ "sp-runtime", "sp-runtime-interface 24.0.0", "sp-state-machine", - "sp-std 14.0.0", "sp-test-primitives", "sp-trie", "sp-version", @@ -19598,7 +19823,7 @@ dependencies = [ "expander", "proc-macro-crate 3.1.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -19634,7 +19859,6 @@ dependencies = [ "serde", "sp-core", "sp-io", - "sp-std 14.0.0", ] [[package]] @@ -19658,11 +19882,10 @@ dependencies = [ "num-traits", "parity-scale-codec", "primitive-types", - "rand 0.8.5", + "rand", "scale-info", "serde", "sp-crypto-hashing", - "sp-std 14.0.0", "static_assertions", ] @@ -19720,16 +19943,17 @@ name = "sp-blockchain" version = "28.0.0" dependencies = [ "futures", - "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "schnellru", "sp-api", "sp-consensus", + "sp-core", "sp-database", "sp-runtime", "sp-state-machine", "thiserror", + "tracing", ] [[package]] @@ -19875,10 +20099,10 @@ dependencies = [ "merlin", "parity-bip39", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "paste", "primitive-types", - "rand 0.8.5", + "rand", "regex", "scale-info", "schnorrkel 0.11.4", @@ -19982,7 +20206,7 @@ dependencies = [ name = "sp-crypto-hashing-proc-macro" version = "0.1.0" dependencies = [ - "quote 1.0.35", + "quote 1.0.36", "sp-crypto-hashing", "syn 2.0.61", ] @@ -19992,7 +20216,7 @@ name = "sp-database" version = "10.0.0" dependencies = [ "kvdb", - "parking_lot 0.12.1", + "parking_lot 0.12.3", ] [[package]] @@ -20001,7 +20225,7 @@ version = "8.0.0" source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -20010,7 +20234,7 @@ name = "sp-debug-derive" version = "14.0.0" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -20064,7 +20288,7 @@ version = "30.0.0" dependencies = [ "bytes", "docify", - "ed25519-dalek 2.1.1", + "ed25519-dalek", "libsecp256k1", "log", "parity-scale-codec", @@ -20077,7 +20301,6 @@ dependencies = [ "sp-keystore", "sp-runtime-interface 24.0.0", "sp-state-machine", - "sp-std 14.0.0", "sp-tracing 16.0.0", "sp-trie", "tracing", @@ -20098,9 +20321,9 @@ name = "sp-keystore" version = "0.34.0" dependencies = [ "parity-scale-codec", - "parking_lot 0.12.1", - "rand 0.8.5", - "rand_chacha 0.3.1", + "parking_lot 0.12.3", + "rand", + "rand_chacha", "sp-core", "sp-externalities 0.25.0", ] @@ -20154,7 +20377,7 @@ name = "sp-npos-elections" version = "26.0.0" dependencies = [ "parity-scale-codec", - "rand 0.8.5", + "rand", "scale-info", "serde", "sp-arithmetic", @@ -20167,9 +20390,9 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.5.3", + "clap 4.5.10", "honggfuzz", - "rand 0.8.5", + "rand", "sp-npos-elections", "sp-runtime", ] @@ -20214,7 +20437,7 @@ dependencies = [ "num-traits", "parity-scale-codec", "paste", - "rand 0.8.5", + "rand", "scale-info", "serde", "serde_json", @@ -20229,6 +20452,7 @@ dependencies = [ "sp-tracing 16.0.0", "sp-weights", "substrate-test-runtime-client", + "tracing", "zstd 0.12.4", ] @@ -20282,7 +20506,7 @@ dependencies = [ "Inflector", "proc-macro-crate 1.3.1", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -20294,7 +20518,7 @@ dependencies = [ "expander", "proc-macro-crate 3.1.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -20322,7 +20546,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime-interface 24.0.0", - "sp-std 14.0.0", "substrate-wasm-builder", ] @@ -20371,9 +20594,9 @@ dependencies = [ "hash-db", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "pretty_assertions", - "rand 0.8.5", + "rand", "smallvec", "sp-core", "sp-externalities 0.25.0", @@ -20390,11 +20613,11 @@ name = "sp-statement-store" version = "10.0.0" dependencies = [ "aes-gcm", - "curve25519-dalek 4.1.3", - "ed25519-dalek 2.1.1", + "curve25519-dalek", + "ed25519-dalek", "hkdf", "parity-scale-codec", - "rand 0.8.5", + "rand", "scale-info", "sha2 0.10.8", "sp-api", @@ -20405,7 +20628,7 @@ dependencies = [ "sp-runtime", "sp-runtime-interface 24.0.0", "thiserror", - "x25519-dalek 2.0.0", + "x25519-dalek", ] [[package]] @@ -20519,8 +20742,8 @@ dependencies = [ "memory-db", "nohash-hasher", "parity-scale-codec", - "parking_lot 0.12.1", - "rand 0.8.5", + "parking_lot 0.12.3", + "rand", "scale-info", "schnellru", "sp-core", @@ -20556,7 +20779,7 @@ version = "13.0.0" dependencies = [ "parity-scale-codec", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "sp-version", "syn 2.0.61", ] @@ -20641,7 +20864,7 @@ dependencies = [ "Inflector", "num-format", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "serde", "serde_json", "unicode-xid 0.2.4", @@ -20666,7 +20889,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f07d54c4d01a1713eb363b55ba51595da15f6f1211435b71466460da022aa140" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -20680,7 +20903,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" name = "staging-chain-spec-builder" version = "1.6.1" dependencies = [ - "clap 4.5.3", + "clap 4.5.10", "log", "sc-chain-spec", "serde_json", @@ -20693,7 +20916,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "clap 4.5.3", + "clap 4.5.10", "clap_complete", "criterion", "futures", @@ -20707,13 +20930,14 @@ dependencies = [ "parity-scale-codec", "platforms", "polkadot-sdk", - "rand 0.8.5", + "pretty_assertions", + "rand", "regex", "sc-service-test", "scale-info", "serde", "serde_json", - "soketto", + "soketto 0.7.1", "staging-node-inspect", "substrate-cli-test-utils", "tempfile", @@ -20727,7 +20951,7 @@ dependencies = [ name = "staging-node-inspect" version = "0.12.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.10", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -20750,7 +20974,6 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -20774,6 +20997,7 @@ dependencies = [ "schemars", "serde", "sp-io", + "sp-runtime", "sp-weights", "xcm-procedural", ] @@ -20802,7 +21026,6 @@ dependencies = [ "sp-arithmetic", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-weights", "staging-xcm", "staging-xcm-executor", @@ -20816,16 +21039,15 @@ dependencies = [ "frame-benchmarking", "frame-support", "impl-trait-for-tuples", - "log", "parity-scale-codec", "scale-info", "sp-arithmetic", "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", "sp-weights", "staging-xcm", + "tracing", ] [[package]] @@ -20858,7 +21080,7 @@ dependencies = [ "cfg_aliases", "memchr", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -20893,19 +21115,6 @@ dependencies = [ "serde", ] -[[package]] -name = "strobe-rs" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabb238a1cccccfa4c4fb703670c0d157e1256c1ba695abf1b93bd2bb14bab2d" -dependencies = [ - "bitflags 1.3.2", - "byteorder", - "keccak", - "subtle 2.5.0", - "zeroize", -] - [[package]] name = "strsim" version = "0.8.0" @@ -20944,7 +21153,7 @@ dependencies = [ "heck 0.3.3", "proc-macro-error", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -20980,7 +21189,7 @@ checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.1", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "rustversion", "syn 1.0.109", ] @@ -20993,7 +21202,7 @@ checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" dependencies = [ "heck 0.4.1", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "rustversion", "syn 2.0.61", ] @@ -21006,7 +21215,7 @@ checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" dependencies = [ "heck 0.4.1", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "rustversion", "syn 2.0.61", ] @@ -21015,7 +21224,7 @@ dependencies = [ name = "subkey" version = "9.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.10", "sc-cli", ] @@ -21098,7 +21307,9 @@ dependencies = [ name = "substrate-prometheus-endpoint" version = "0.17.0" dependencies = [ - "hyper", + "http-body-util", + "hyper 1.3.1", + "hyper-util", "log", "prometheus", "thiserror", @@ -21118,9 +21329,7 @@ dependencies = [ "bp-polkadot-core", "bp-relayers", "bp-runtime", - "bridge-runtime-common", "equivocation-detector", - "finality-grandpa", "finality-relay", "frame-support", "frame-system", @@ -21140,9 +21349,11 @@ dependencies = [ "rbtag", "relay-substrate-client", "relay-utils", + "scale-info", "sp-consensus-grandpa", "sp-core", "sp-runtime", + "sp-trie", "structopt", "strum 0.26.2", "thiserror", @@ -21216,7 +21427,6 @@ dependencies = [ "frame-system", "frame-system-rpc-runtime-api", "futures", - "hex-literal", "log", "pallet-babe", "pallet-balances", @@ -21254,6 +21464,7 @@ dependencies = [ "sp-version", "substrate-test-runtime-client", "substrate-wasm-builder", + "tracing", "trie-db", ] @@ -21280,7 +21491,7 @@ version = "2.0.0" dependencies = [ "futures", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "sc-transaction-pool", "sc-transaction-pool-api", "sp-blockchain", @@ -21309,6 +21520,7 @@ dependencies = [ "console", "filetime", "frame-metadata", + "jobserver", "merkleized-metadata", "parity-scale-codec", "parity-wasm", @@ -21453,7 +21665,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "unicode-ident", ] @@ -21464,7 +21676,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "unicode-ident", ] @@ -21476,7 +21688,7 @@ checksum = "86b837ef12ab88835251726eb12237655e61ec8dc8a280085d1961cdc3dfd047" dependencies = [ "paste", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -21487,11 +21699,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", "unicode-xid 0.2.4", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.36", + "syn 2.0.61", +] + [[package]] name = "sysinfo" version = "0.30.5" @@ -21607,7 +21830,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -21619,7 +21842,6 @@ dependencies = [ "parity-scale-codec", "polkadot-parachain-primitives", "sp-io", - "sp-std 14.0.0", "substrate-wasm-builder", "tiny-keccak", ] @@ -21628,7 +21850,7 @@ dependencies = [ name = "test-parachain-adder-collator" version = "1.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.10", "futures", "futures-timer", "log", @@ -21667,7 +21889,6 @@ dependencies = [ "parity-scale-codec", "polkadot-parachain-primitives", "sp-io", - "sp-std 14.0.0", "substrate-wasm-builder", "tiny-keccak", ] @@ -21676,7 +21897,7 @@ dependencies = [ name = "test-parachain-undying-collator" version = "1.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.10", "futures", "futures-timer", "log", @@ -21773,7 +21994,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -21784,7 +22005,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -21859,16 +22080,14 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "0bb39ee79a6d8de55f48f2293a830e040392f1c5f16e336bdd1788cd0aadce07" dependencies = [ "deranged", "itoa", "libc", - "num-conv", "num_threads", - "powerfmt", "serde", "time-core", "time-macros", @@ -21876,17 +22095,16 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "733d258752e9303d392b94b75230d07b0b9c489350c69b851fc6c065fde3e8f9" dependencies = [ - "num-conv", "time-core", ] @@ -21935,10 +22153,10 @@ dependencies = [ "libc", "mio", "num_cpus", - "parking_lot 0.12.1", - "pin-project-lite 0.2.12", + "parking_lot 0.12.3", + "pin-project-lite", "signal-hook-registry", - "socket2 0.5.6", + "socket2 0.5.7", "tokio-macros", "windows-sys 0.48.0", ] @@ -21950,7 +22168,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -21961,7 +22179,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f57eb36ecbe0fc510036adff84824dd3c24bb781e21bfa67b69d556aa85214f" dependencies = [ "pin-project", - "rand 0.8.5", + "rand", "tokio", ] @@ -21971,17 +22189,17 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.6", + "rustls 0.21.7", "tokio", ] [[package]] name = "tokio-rustls" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.22.2", + "rustls 0.23.10", "rustls-pki-types", "tokio", ] @@ -21993,7 +22211,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", - "pin-project-lite 0.2.12", + "pin-project-lite", "tokio", "tokio-util", ] @@ -22019,7 +22237,7 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls 0.21.6", + "rustls 0.21.7", "rustls-native-certs 0.6.3", "tokio", "tokio-rustls 0.24.1", @@ -22036,7 +22254,7 @@ dependencies = [ "futures-core", "futures-io", "futures-sink", - "pin-project-lite 0.2.12", + "pin-project-lite", "tokio", ] @@ -22103,7 +22321,8 @@ dependencies = [ "futures-core", "futures-util", "pin-project", - "pin-project-lite 0.2.12", + "pin-project-lite", + "tokio", "tower-layer", "tower-service", "tracing", @@ -22111,18 +22330,16 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.4.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ae70283aba8d2a8b411c695c437fe25b8b5e44e23e780662002fc72fb47a82" +checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "bytes", - "futures-core", - "futures-util", - "http", - "http-body", - "http-range-header", - "pin-project-lite 0.2.12", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "pin-project-lite", "tower-layer", "tower-service", ] @@ -22146,7 +22363,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "log", - "pin-project-lite 0.2.12", + "pin-project-lite", "tracing-attributes", "tracing-core", ] @@ -22158,7 +22375,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -22200,7 +22417,7 @@ dependencies = [ "expander", "proc-macro-crate 3.1.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -22268,7 +22485,7 @@ dependencies = [ "matchers 0.1.0", "nu-ansi-term", "once_cell", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "regex", "sharded-slab", "smallvec", @@ -22341,7 +22558,7 @@ dependencies = [ "idna 0.2.3", "ipnet", "lazy_static", - "rand 0.8.5", + "rand", "smallvec", "socket2 0.4.9", "thiserror", @@ -22367,7 +22584,7 @@ dependencies = [ "idna 0.4.0", "ipnet", "once_cell", - "rand 0.8.5", + "rand", "smallvec", "thiserror", "tinyvec", @@ -22376,26 +22593,6 @@ dependencies = [ "url", ] -[[package]] -name = "trust-dns-resolver" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aff21aa4dcefb0a1afbfac26deb0adc93888c7d295fb63ab273ef276ba2b7cfe" -dependencies = [ - "cfg-if", - "futures-util", - "ipconfig", - "lazy_static", - "lru-cache", - "parking_lot 0.12.1", - "resolv-conf", - "smallvec", - "thiserror", - "tokio", - "tracing", - "trust-dns-proto 0.22.0", -] - [[package]] name = "trust-dns-resolver" version = "0.23.2" @@ -22407,8 +22604,8 @@ dependencies = [ "ipconfig", "lru-cache", "once_cell", - "parking_lot 0.12.1", - "rand 0.8.5", + "parking_lot 0.12.3", + "rand", "resolv-conf", "smallvec", "thiserror", @@ -22454,11 +22651,11 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 0.2.9", "httparse", "log", - "rand 0.8.5", - "rustls 0.21.6", + "rand", + "rustls 0.21.7", "sha1", "thiserror", "url", @@ -22479,7 +22676,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.7", - "rand 0.8.5", + "rand", "static_assertions", ] @@ -22584,6 +22781,15 @@ dependencies = [ "bytes", "futures-io", "futures-util", +] + +[[package]] +name = "unsigned-varint" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" +dependencies = [ + "bytes", "tokio-util", ] @@ -22601,12 +22807,12 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.4.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", - "idna 0.4.0", + "idna 0.5.0", "percent-encoding", ] @@ -22709,9 +22915,9 @@ dependencies = [ "arrayref", "constcat", "digest 0.10.7", - "rand 0.8.5", - "rand_chacha 0.3.1", - "rand_core 0.6.4", + "rand", + "rand_chacha", + "rand_core", "sha2 0.10.8", "sha3", "thiserror", @@ -22752,12 +22958,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -22766,9 +22966,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "serde", @@ -22778,15 +22978,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", "wasm-bindgen-shared", ] @@ -22805,22 +23005,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ - "quote 1.0.35", + "quote 1.0.36", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", "wasm-bindgen-backend", "wasm-bindgen-shared", @@ -22828,9 +23028,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-bindgen-test" @@ -22853,7 +23053,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", ] [[package]] @@ -23194,7 +23394,7 @@ dependencies = [ "memfd", "memoffset 0.8.0", "paste", - "rand 0.8.5", + "rand", "rustix 0.36.15", "wasmtime-asm-macros", "wasmtime-environ", @@ -23257,18 +23457,18 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.22.6" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" -dependencies = [ - "webpki", -] +checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" [[package]] name = "webpki-roots" -version = "0.25.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +dependencies = [ + "rustls-pki-types", +] [[package]] name = "westend-emulated-chain" @@ -23287,7 +23487,7 @@ dependencies = [ "staging-xcm", "westend-runtime", "westend-runtime-constants", - "xcm-fee-payment-runtime-api", + "xcm-runtime-apis", ] [[package]] @@ -23336,6 +23536,7 @@ dependencies = [ "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-offences-benchmarking", + "pallet-parameters", "pallet-preimage", "pallet-proxy", "pallet-recovery", @@ -23346,7 +23547,6 @@ dependencies = [ "pallet-session-benchmarking", "pallet-society", "pallet-staking", - "pallet-staking-reward-curve", "pallet-staking-runtime-api", "pallet-state-trie-migration", "pallet-sudo", @@ -23364,7 +23564,6 @@ dependencies = [ "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-parachains", - "rustc-hex", "scale-info", "serde", "serde_derive", @@ -23388,7 +23587,6 @@ dependencies = [ "sp-runtime", "sp-session", "sp-staking", - "sp-std 14.0.0", "sp-storage 19.0.0", "sp-tracing 16.0.0", "sp-transaction-pool", @@ -23400,7 +23598,7 @@ dependencies = [ "tiny-keccak", "tokio", "westend-runtime-constants", - "xcm-fee-payment-runtime-api", + "xcm-runtime-apis", ] [[package]] @@ -23425,6 +23623,7 @@ dependencies = [ "asset-hub-westend-emulated-chain", "bridge-hub-westend-emulated-chain", "collectives-westend-emulated-chain", + "coretime-westend-emulated-chain", "emulated-integration-tests-common", "penpal-emulated-chain", "people-westend-emulated-chain", @@ -23491,23 +23690,20 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.34.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45296b64204227616fdbf2614cefa4c236b98ee64dfaaaa435207ed99fe7829f" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows_aarch64_msvc 0.34.0", - "windows_i686_gnu 0.34.0", - "windows_i686_msvc 0.34.0", - "windows_x86_64_gnu 0.34.0", - "windows_x86_64_msvc 0.34.0", + "windows-targets 0.48.5", ] [[package]] name = "windows" -version = "0.48.0" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" dependencies = [ + "windows-core 0.51.1", "windows-targets 0.48.5", ] @@ -23517,10 +23713,19 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "windows-core", + "windows-core 0.52.0", "windows-targets 0.52.0", ] +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -23635,12 +23840,6 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" -[[package]] -name = "windows_aarch64_msvc" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" - [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -23659,12 +23858,6 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" -[[package]] -name = "windows_i686_gnu" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" - [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -23683,12 +23876,6 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" -[[package]] -name = "windows_i686_msvc" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" - [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -23707,12 +23894,6 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" -[[package]] -name = "windows_x86_64_gnu" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" - [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -23749,12 +23930,6 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" -[[package]] -name = "windows_x86_64_msvc" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" - [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -23801,42 +23976,30 @@ dependencies = [ "tap", ] -[[package]] -name = "x25519-dalek" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f" -dependencies = [ - "curve25519-dalek 3.2.0", - "rand_core 0.5.1", - "zeroize", -] - [[package]] name = "x25519-dalek" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" dependencies = [ - "curve25519-dalek 4.1.3", - "rand_core 0.6.4", + "curve25519-dalek", + "rand_core", "serde", "zeroize", ] [[package]] name = "x509-parser" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" +checksum = "7069fba5b66b9193bd2c5d3d4ff12b839118f6bcbef5328efafafb5395cf63da" dependencies = [ - "asn1-rs", - "base64 0.13.1", + "asn1-rs 0.5.2", "data-encoding", - "der-parser", + "der-parser 8.2.0", "lazy_static", "nom", - "oid-registry", + "oid-registry 0.6.1", "rusticata-macros", "thiserror", "time", @@ -23844,16 +24007,16 @@ dependencies = [ [[package]] name = "x509-parser" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7069fba5b66b9193bd2c5d3d4ff12b839118f6bcbef5328efafafb5395cf63da" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" dependencies = [ - "asn1-rs", + "asn1-rs 0.6.1", "data-encoding", - "der-parser", + "der-parser 9.0.0", "lazy_static", "nom", - "oid-registry", + "oid-registry 0.7.0", "rusticata-macros", "thiserror", "time", @@ -23951,13 +24114,26 @@ dependencies = [ ] [[package]] -name = "xcm-fee-payment-runtime-api" +name = "xcm-procedural" +version = "7.0.0" +dependencies = [ + "Inflector", + "proc-macro2 1.0.82", + "quote 1.0.36", + "staging-xcm", + "syn 2.0.61", + "trybuild", +] + +[[package]] +name = "xcm-runtime-apis" version = "0.1.0" dependencies = [ - "env_logger 0.9.3", + "env_logger 0.11.3", "frame-executive", "frame-support", "frame-system", + "hex-literal", "log", "pallet-assets", "pallet-balances", @@ -23966,26 +24142,12 @@ dependencies = [ "scale-info", "sp-api", "sp-io", - "sp-runtime", - "sp-std 14.0.0", "sp-weights", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", ] -[[package]] -name = "xcm-procedural" -version = "7.0.0" -dependencies = [ - "Inflector", - "proc-macro2 1.0.82", - "quote 1.0.35", - "staging-xcm", - "syn 2.0.61", - "trybuild", -] - [[package]] name = "xcm-simulator" version = "7.0.0" @@ -24062,17 +24224,33 @@ dependencies = [ "xcm-simulator", ] +[[package]] +name = "xml-rs" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" + +[[package]] +name = "xmltree" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb" +dependencies = [ + "xml-rs", +] + [[package]] name = "yamux" -version = "0.10.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d9ba232399af1783a58d8eb26f6b5006fbefe2dc9ef36bd283324792d03ea5" +checksum = "9ed0164ae619f2dc144909a9f082187ebb5893693d8c0196e8085283ccd4b776" dependencies = [ "futures", "log", "nohash-hasher", - "parking_lot 0.12.1", - "rand 0.8.5", + "parking_lot 0.12.3", + "pin-project", + "rand", "static_assertions", ] @@ -24107,15 +24285,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] @@ -24127,7 +24305,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] diff --git a/Cargo.toml b/Cargo.toml index ba52b0179ff81000e6fc77498f2d993bdc12fb72..ba0526b21c369132a9f6072c4da3f866142c8f57 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,6 +61,7 @@ members = [ "bridges/snowbridge/primitives/router", "bridges/snowbridge/runtime/runtime-common", "bridges/snowbridge/runtime/test-common", + "cumulus/bin/pov-validator", "cumulus/client/cli", "cumulus/client/collator", "cumulus/client/consensus/aura", @@ -90,6 +91,8 @@ members = [ "cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo", "cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend", "cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend", + "cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo", + "cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend", "cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo", "cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend", "cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal", @@ -104,6 +107,8 @@ members = [ "cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo", "cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend", "cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend", + "cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo", + "cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend", "cumulus/parachains/integration-tests/emulated/tests/people/people-rococo", "cumulus/parachains/integration-tests/emulated/tests/people/people-westend", "cumulus/parachains/pallets/collective-content", @@ -226,7 +231,7 @@ members = [ "polkadot/xcm/xcm-builder", "polkadot/xcm/xcm-executor", "polkadot/xcm/xcm-executor/integration-tests", - "polkadot/xcm/xcm-fee-payment-runtime-api", + "polkadot/xcm/xcm-runtime-apis", "polkadot/xcm/xcm-simulator", "polkadot/xcm/xcm-simulator/example", "polkadot/xcm/xcm-simulator/fuzzer", @@ -565,19 +570,789 @@ extra-unused-type-parameters = { level = "allow", priority = 2 } # stylistic default_constructed_unit_structs = { level = "allow", priority = 2 } # stylistic [workspace.dependencies] +Inflector = { version = "0.11.4" } +aes-gcm = { version = "0.10" } +ahash = { version = "0.8.2" } +alloy-primitives = { version = "0.4.2", default-features = false } +alloy-sol-types = { version = "0.4.2", default-features = false } +always-assert = { version = "0.1" } +anyhow = { version = "1.0.81" } +aquamarine = { version = "0.5.0" } +arbitrary = { version = "1.3.2" } +ark-bls12-377 = { version = "0.4.0", default-features = false } +ark-bls12-377-ext = { version = "0.4.1", default-features = false } +ark-bls12-381 = { version = "0.4.0", default-features = false } +ark-bls12-381-ext = { version = "0.4.1", default-features = false } +ark-bw6-761 = { version = "0.4.0", default-features = false } +ark-bw6-761-ext = { version = "0.4.1", default-features = false } +ark-ec = { version = "0.4.2", default-features = false } +ark-ed-on-bls12-377 = { version = "0.4.0", default-features = false } +ark-ed-on-bls12-377-ext = { version = "0.4.1", default-features = false } +ark-ed-on-bls12-381-bandersnatch = { version = "0.4.0", default-features = false } +ark-ed-on-bls12-381-bandersnatch-ext = { version = "0.4.1", default-features = false } +ark-scale = { version = "0.0.12", default-features = false } +array-bytes = { version = "6.2.2", default-features = false } +arrayvec = { version = "0.7.4" } +assert_cmd = { version = "2.0.14" } +assert_matches = { version = "1.5.0" } +asset-hub-rococo-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo" } +asset-hub-rococo-runtime = { path = "cumulus/parachains/runtimes/assets/asset-hub-rococo", default-features = false } +asset-hub-westend-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend" } +asset-hub-westend-runtime = { path = "cumulus/parachains/runtimes/assets/asset-hub-westend" } +asset-test-utils = { path = "cumulus/parachains/runtimes/assets/test-utils", default-features = false } +assets-common = { path = "cumulus/parachains/runtimes/assets/common", default-features = false } +async-channel = { version = "1.8.0" } +async-std = { version = "1.9.0" } +async-trait = { version = "0.1.79" } +asynchronous-codec = { version = "0.6" } +backoff = { version = "0.4" } +backtrace = { version = "0.3.71" } +binary-merkle-tree = { path = "substrate/utils/binary-merkle-tree", default-features = false } +bincode = { version = "1.3.3" } +bip39 = { version = "2.0.0" } +bitflags = { version = "1.3.2" } +bitvec = { version = "1.0.1", default-features = false } +blake2 = { version = "0.10.4", default-features = false } +blake2b_simd = { version = "1.0.1", default-features = false } +blake3 = { version = "1.5" } +bounded-collections = { version = "0.2.0", default-features = false } +bounded-vec = { version = "0.7" } +bp-asset-hub-rococo = { path = "bridges/chains/chain-asset-hub-rococo", default-features = false } +bp-asset-hub-westend = { path = "bridges/chains/chain-asset-hub-westend", default-features = false } +bp-beefy = { path = "bridges/primitives/beefy", default-features = false } +bp-bridge-hub-cumulus = { path = "bridges/chains/chain-bridge-hub-cumulus", default-features = false } +bp-bridge-hub-kusama = { default-features = false, path = "bridges/chains/chain-bridge-hub-kusama" } +bp-bridge-hub-polkadot = { path = "bridges/chains/chain-bridge-hub-polkadot", default-features = false } +bp-bridge-hub-rococo = { path = "bridges/chains/chain-bridge-hub-rococo", default-features = false } +bp-bridge-hub-westend = { path = "bridges/chains/chain-bridge-hub-westend", default-features = false } +bp-header-chain = { path = "bridges/primitives/header-chain", default-features = false } +bp-kusama = { default-features = false, path = "bridges/chains/chain-kusama" } +bp-messages = { path = "bridges/primitives/messages", default-features = false } +bp-parachains = { path = "bridges/primitives/parachains", default-features = false } +bp-polkadot = { default-features = false, path = "bridges/chains/chain-polkadot" } +bp-polkadot-bulletin = { path = "bridges/chains/chain-polkadot-bulletin", default-features = false } +bp-polkadot-core = { path = "bridges/primitives/polkadot-core", default-features = false } +bp-relayers = { path = "bridges/primitives/relayers", default-features = false } +bp-rococo = { path = "bridges/chains/chain-rococo", default-features = false } +bp-runtime = { path = "bridges/primitives/runtime", default-features = false } +bp-test-utils = { path = "bridges/primitives/test-utils", default-features = false } +bp-westend = { path = "bridges/chains/chain-westend", default-features = false } +bp-xcm-bridge-hub = { path = "bridges/primitives/xcm-bridge-hub", default-features = false } +bp-xcm-bridge-hub-router = { path = "bridges/primitives/xcm-bridge-hub-router", default-features = false } +bridge-hub-common = { path = "cumulus/parachains/runtimes/bridge-hubs/common", default-features = false } +bridge-hub-rococo-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo" } +bridge-hub-rococo-runtime = { path = "cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo", default-features = false } +bridge-hub-test-utils = { path = "cumulus/parachains/runtimes/bridge-hubs/test-utils", default-features = false } +bridge-hub-westend-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend" } +bridge-hub-westend-runtime = { path = "cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend", default-features = false } +bridge-runtime-common = { path = "bridges/bin/runtime-common", default-features = false } +bs58 = { version = "0.5.0", default-features = false } +build-helper = { version = "0.1.1" } +byte-slice-cast = { version = "1.2.1", default-features = false } +byteorder = { version = "1.3.2", default-features = false } +bytes = { version = "1.4.0", default-features = false } +cargo_metadata = { version = "0.15.4" } +cfg-expr = { version = "0.15.5" } +cfg-if = { version = "1.0" } +chain-spec-builder = { path = "substrate/bin/utils/chain-spec-builder", default-features = false, package = "staging-chain-spec-builder" } +chain-spec-guide-runtime = { path = "docs/sdk/src/reference_docs/chain_spec_runtime" } +chrono = { version = "0.4.31" } +cid = { version = "0.9.0" } +clap = { version = "4.5.10" } +clap-num = { version = "1.0.2" } +clap_complete = { version = "4.0.2" } +coarsetime = { version = "0.1.22" } +codec = { version = "3.6.12", default-features = false, package = "parity-scale-codec" } +collectives-westend-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend" } +collectives-westend-runtime = { path = "cumulus/parachains/runtimes/collectives/collectives-westend" } +color-eyre = { version = "0.6.1", default-features = false } +color-print = { version = "0.3.4" } +colored = { version = "2.0.4" } +comfy-table = { version = "7.1.0", default-features = false } +console = { version = "0.15.8" } +contracts-rococo-runtime = { path = "cumulus/parachains/runtimes/contracts/contracts-rococo" } +coretime-rococo-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo" } +coretime-rococo-runtime = { path = "cumulus/parachains/runtimes/coretime/coretime-rococo" } +coretime-westend-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend" } +coretime-westend-runtime = { path = "cumulus/parachains/runtimes/coretime/coretime-westend" } +cpu-time = { version = "1.0.0" } +criterion = { version = "0.5.1", default-features = false } +cumulus-client-cli = { path = "cumulus/client/cli", default-features = false } +cumulus-client-collator = { path = "cumulus/client/collator", default-features = false } +cumulus-client-consensus-aura = { path = "cumulus/client/consensus/aura", default-features = false } +cumulus-client-consensus-common = { path = "cumulus/client/consensus/common", default-features = false } +cumulus-client-consensus-proposer = { path = "cumulus/client/consensus/proposer", default-features = false } +cumulus-client-consensus-relay-chain = { path = "cumulus/client/consensus/relay-chain", default-features = false } +cumulus-client-network = { path = "cumulus/client/network", default-features = false } +cumulus-client-parachain-inherent = { path = "cumulus/client/parachain-inherent", default-features = false } +cumulus-client-pov-recovery = { path = "cumulus/client/pov-recovery", default-features = false } +cumulus-client-service = { path = "cumulus/client/service", default-features = false } +cumulus-pallet-aura-ext = { path = "cumulus/pallets/aura-ext", default-features = false } +cumulus-pallet-dmp-queue = { default-features = false, path = "cumulus/pallets/dmp-queue" } +cumulus-pallet-parachain-system = { path = "cumulus/pallets/parachain-system", default-features = false } +cumulus-pallet-parachain-system-proc-macro = { path = "cumulus/pallets/parachain-system/proc-macro", default-features = false } +cumulus-pallet-session-benchmarking = { path = "cumulus/pallets/session-benchmarking", default-features = false } +cumulus-pallet-solo-to-para = { path = "cumulus/pallets/solo-to-para", default-features = false } +cumulus-pallet-xcm = { path = "cumulus/pallets/xcm", default-features = false } +cumulus-pallet-xcmp-queue = { path = "cumulus/pallets/xcmp-queue", default-features = false } +cumulus-ping = { path = "cumulus/parachains/pallets/ping", default-features = false } +cumulus-primitives-aura = { path = "cumulus/primitives/aura", default-features = false } +cumulus-primitives-core = { path = "cumulus/primitives/core", default-features = false } +cumulus-primitives-parachain-inherent = { path = "cumulus/primitives/parachain-inherent", default-features = false } +cumulus-primitives-proof-size-hostfunction = { path = "cumulus/primitives/proof-size-hostfunction", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "cumulus/primitives/storage-weight-reclaim", default-features = false } +cumulus-primitives-timestamp = { path = "cumulus/primitives/timestamp", default-features = false } +cumulus-primitives-utility = { path = "cumulus/primitives/utility", default-features = false } +cumulus-relay-chain-inprocess-interface = { path = "cumulus/client/relay-chain-inprocess-interface", default-features = false } +cumulus-relay-chain-interface = { path = "cumulus/client/relay-chain-interface", default-features = false } +cumulus-relay-chain-minimal-node = { path = "cumulus/client/relay-chain-minimal-node", default-features = false } +cumulus-relay-chain-rpc-interface = { path = "cumulus/client/relay-chain-rpc-interface", default-features = false } +cumulus-test-client = { path = "cumulus/test/client" } +cumulus-test-relay-sproof-builder = { path = "cumulus/test/relay-sproof-builder", default-features = false } +cumulus-test-runtime = { path = "cumulus/test/runtime" } +cumulus-test-service = { path = "cumulus/test/service" } +curve25519-dalek = { version = "4.1.3" } +derivative = { version = "2.2.0", default-features = false } +derive-syn-parse = { version = "0.2.0" } +derive_more = { version = "0.99.17", default-features = false } +digest = { version = "0.10.3", default-features = false } +directories = { version = "5.0.1" } +dlmalloc = { version = "0.2.4" } +docify = { version = "0.2.8" } +dyn-clonable = { version = "0.9.0" } +dyn-clone = { version = "1.0.16" } +ed25519-dalek = { version = "2.1", default-features = false } +ed25519-zebra = { version = "4.0.3", default-features = false } +either = { version = "1.8.1", default-features = false } +emulated-integration-tests-common = { path = "cumulus/parachains/integration-tests/emulated/common", default-features = false } +enumflags2 = { version = "0.7.7" } +enumn = { version = "0.1.13" } +env_logger = { version = "0.11.3" } +environmental = { version = "1.1.4", default-features = false } +equivocation-detector = { path = "bridges/relays/equivocation" } +ethabi = { version = "1.0.0", default-features = false, package = "ethabi-decode" } +ethbloom = { version = "0.13.0", default-features = false } +ethereum-types = { version = "0.14.1", default-features = false } +exit-future = { version = "0.2.0" } +expander = { version = "2.0.0" } +fatality = { version = "0.1.1" } +fdlimit = { version = "0.3.0" } +femme = { version = "2.2.1" } +filetime = { version = "0.2.16" } +finality-grandpa = { version = "0.16.2", default-features = false } +finality-relay = { path = "bridges/relays/finality" } +flate2 = { version = "1.0" } +fnv = { version = "1.0.6" } +fork-tree = { path = "substrate/utils/fork-tree", default-features = false } +forwarded-header-value = { version = "0.1.1" } +fraction = { version = "0.13.1" } +frame = { path = "substrate/frame", default-features = false, package = "polkadot-sdk-frame" } +frame-benchmarking = { path = "substrate/frame/benchmarking", default-features = false } +frame-benchmarking-cli = { path = "substrate/utils/frame/benchmarking-cli", default-features = false } +frame-benchmarking-pallet-pov = { default-features = false, path = "substrate/frame/benchmarking/pov" } +frame-election-provider-solution-type = { path = "substrate/frame/election-provider-support/solution-type", default-features = false } +frame-election-provider-support = { path = "substrate/frame/election-provider-support", default-features = false } +frame-executive = { path = "substrate/frame/executive", default-features = false } +frame-metadata = { version = "16.0.0", default-features = false } +frame-metadata-hash-extension = { path = "substrate/frame/metadata-hash-extension", default-features = false } +frame-support = { path = "substrate/frame/support", default-features = false } +frame-support-procedural = { path = "substrate/frame/support/procedural", default-features = false } +frame-support-procedural-tools = { path = "substrate/frame/support/procedural/tools", default-features = false } +frame-support-procedural-tools-derive = { path = "substrate/frame/support/procedural/tools/derive", default-features = false } +frame-support-test = { path = "substrate/frame/support/test" } +frame-system = { path = "substrate/frame/system", default-features = false } +frame-system-benchmarking = { path = "substrate/frame/system/benchmarking", default-features = false } +frame-system-rpc-runtime-api = { path = "substrate/frame/system/rpc/runtime-api", default-features = false } +frame-try-runtime = { path = "substrate/frame/try-runtime", default-features = false } +fs4 = { version = "0.7.0" } +fs_extra = { version = "1.3.0" } +futures = { version = "0.3.30" } +futures-channel = { version = "0.3.23" } +futures-timer = { version = "3.0.2" } +futures-util = { version = "0.3.30", default-features = false } +generate-bags = { path = "substrate/utils/frame/generate-bags", default-features = false } +gethostname = { version = "0.2.3" } +glob = { version = "0.3" } +glutton-westend-runtime = { path = "cumulus/parachains/runtimes/glutton/glutton-westend" } +governor = { version = "0.6.0" } +gum = { path = "polkadot/node/gum", default-features = false, package = "tracing-gum" } +gum-proc-macro = { path = "polkadot/node/gum/proc-macro", default-features = false, package = "tracing-gum-proc-macro" } +handlebars = { version = "5.1.0" } +hash-db = { version = "0.16.0", default-features = false } +hash256-std-hasher = { version = "0.15.2", default-features = false } +hex = { version = "0.4.3", default-features = false } +hex-literal = { version = "0.4.1", default-features = false } +hkdf = { version = "0.12.0" } +hmac = { version = "0.12.1" } +honggfuzz = { version = "0.5.55" } +http = { version = "1.1" } +http-body = { version = "1", default-features = false } +http-body-util = { version = "0.1.2", default-features = false } +hyper = { version = "1.3.1", default-features = false } +hyper-rustls = { version = "0.24.2" } +hyper-util = { version = "0.1.5", default-features = false } +# TODO: remove hyper v0.14 https://github.com/paritytech/polkadot-sdk/issues/4896 +hyperv14 = { package = "hyper", version = "0.14.29", default-features = false } +impl-serde = { version = "0.4.0", default-features = false } +impl-trait-for-tuples = { version = "0.2.2" } +indexmap = { version = "2.0.0" } +indicatif = { version = "0.17.7" } +integer-sqrt = { version = "0.1.2" } +ip_network = { version = "0.4.1" } +is-terminal = { version = "0.4.9" } +is_executable = { version = "1.0.1" } +isahc = { version = "1.2" } +itertools = { version = "0.11" } +jobserver = { version = "0.1.26" } +jsonpath_lib = { version = "0.3" } +jsonrpsee = { version = "0.23.2" } +jsonrpsee-core = { version = "0.23.2" } +k256 = { version = "0.13.3", default-features = false } +kitchensink-runtime = { path = "substrate/bin/node/runtime" } +kvdb = { version = "0.13.0" } +kvdb-memorydb = { version = "0.13.0" } +kvdb-rocksdb = { version = "0.19.0" } +kvdb-shared-tests = { version = "0.11.0" } +landlock = { version = "0.3.0" } +lazy_static = { version = "1.4.0" } +libc = { version = "0.2.155" } +libfuzzer-sys = { version = "0.4" } +libp2p = { version = "0.52.4" } +libp2p-identity = { version = "0.2.3" } +libsecp256k1 = { version = "0.7.0", default-features = false } +linked-hash-map = { version = "0.5.4" } +linked_hash_set = { version = "0.1.4" } +linregress = { version = "0.5.1" } +lite-json = { version = "0.2.0", default-features = false } +litep2p = { version = "0.6.2" } +log = { version = "0.4.22", default-features = false } +macro_magic = { version = "0.5.1" } +maplit = { version = "1.0.2" } +memmap2 = { version = "0.9.3" } +memory-db = { version = "0.32.0", default-features = false } +merkleized-metadata = { version = "0.1.0" } +merlin = { version = "3.0", default-features = false } +messages-relay = { path = "bridges/relays/messages" } +metered = { version = "0.6.1", default-features = false, package = "prioritized-metered-channel" } +mick-jaeger = { version = "0.1.8" } +milagro-bls = { version = "1.5.4", default-features = false, package = "snowbridge-milagro-bls" } +minimal-template-node = { path = "templates/minimal/node" } +minimal-template-runtime = { path = "templates/minimal/runtime" } +mixnet = { version = "0.7.0" } +mmr-gadget = { path = "substrate/client/merkle-mountain-range", default-features = false } +mmr-lib = { version = "0.5.2", package = "ckb-merkle-mountain-range" } +mmr-rpc = { path = "substrate/client/merkle-mountain-range/rpc", default-features = false } +mockall = { version = "0.11.3" } +multiaddr = { version = "0.18.1" } +multihash = { version = "0.19.1", default-features = false } +multihash-codetable = { version = "0.1.1" } +multistream-select = { version = "0.13.0" } +names = { version = "0.14.0", default-features = false } +nix = { version = "0.28.0" } +node-cli = { path = "substrate/bin/node/cli", package = "staging-node-cli" } +node-inspect = { path = "substrate/bin/node/inspect", default-features = false, package = "staging-node-inspect" } +node-primitives = { path = "substrate/bin/node/primitives", default-features = false } +node-rpc = { path = "substrate/bin/node/rpc" } +node-testing = { path = "substrate/bin/node/testing" } +nohash-hasher = { version = "0.2.0" } +novelpoly = { version = "2.0.0", package = "reed-solomon-novelpoly" } +num-bigint = { version = "0.4.3" } +num-format = { version = "0.4.3" } +num-rational = { version = "0.4.1" } +num-traits = { version = "0.2.17", default-features = false } +num_cpus = { version = "1.13.1" } +once_cell = { version = "1.19.0" } +orchestra = { version = "0.4.0", default-features = false } +pallet-alliance = { path = "substrate/frame/alliance", default-features = false } +pallet-asset-conversion = { path = "substrate/frame/asset-conversion", default-features = false } +pallet-asset-conversion-ops = { path = "substrate/frame/asset-conversion/ops", default-features = false } +pallet-asset-conversion-tx-payment = { path = "substrate/frame/transaction-payment/asset-conversion-tx-payment", default-features = false } +pallet-asset-rate = { path = "substrate/frame/asset-rate", default-features = false } +pallet-asset-tx-payment = { path = "substrate/frame/transaction-payment/asset-tx-payment", default-features = false } +pallet-assets = { path = "substrate/frame/assets", default-features = false } +pallet-assets-freezer = { path = "substrate/frame/assets-freezer", default-features = false } +pallet-atomic-swap = { default-features = false, path = "substrate/frame/atomic-swap" } +pallet-aura = { path = "substrate/frame/aura", default-features = false } +pallet-authority-discovery = { path = "substrate/frame/authority-discovery", default-features = false } +pallet-authorship = { path = "substrate/frame/authorship", default-features = false } +pallet-babe = { path = "substrate/frame/babe", default-features = false } +pallet-bags-list = { path = "substrate/frame/bags-list", default-features = false } +pallet-bags-list-remote-tests = { path = "substrate/frame/bags-list/remote-tests" } +pallet-balances = { path = "substrate/frame/balances", default-features = false } +pallet-beefy = { path = "substrate/frame/beefy", default-features = false } +pallet-beefy-mmr = { path = "substrate/frame/beefy-mmr", default-features = false } +pallet-bounties = { path = "substrate/frame/bounties", default-features = false } +pallet-bridge-grandpa = { path = "bridges/modules/grandpa", default-features = false } +pallet-bridge-messages = { path = "bridges/modules/messages", default-features = false } +pallet-bridge-parachains = { path = "bridges/modules/parachains", default-features = false } +pallet-bridge-relayers = { path = "bridges/modules/relayers", default-features = false } +pallet-broker = { path = "substrate/frame/broker", default-features = false } +pallet-child-bounties = { path = "substrate/frame/child-bounties", default-features = false } +pallet-collator-selection = { path = "cumulus/pallets/collator-selection", default-features = false } +pallet-collective = { path = "substrate/frame/collective", default-features = false } +pallet-collective-content = { path = "cumulus/parachains/pallets/collective-content", default-features = false } +pallet-contracts = { path = "substrate/frame/contracts", default-features = false } +pallet-contracts-fixtures = { path = "substrate/frame/contracts/fixtures" } +pallet-contracts-mock-network = { default-features = false, path = "substrate/frame/contracts/mock-network" } +pallet-contracts-proc-macro = { path = "substrate/frame/contracts/proc-macro", default-features = false } +pallet-contracts-uapi = { path = "substrate/frame/contracts/uapi", default-features = false } +pallet-conviction-voting = { path = "substrate/frame/conviction-voting", default-features = false } +pallet-core-fellowship = { path = "substrate/frame/core-fellowship", default-features = false } +pallet-default-config-example = { path = "substrate/frame/examples/default-config", default-features = false } +pallet-delegated-staking = { path = "substrate/frame/delegated-staking", default-features = false } +pallet-democracy = { path = "substrate/frame/democracy", default-features = false } +pallet-dev-mode = { path = "substrate/frame/examples/dev-mode", default-features = false } +pallet-election-provider-multi-phase = { path = "substrate/frame/election-provider-multi-phase", default-features = false } +pallet-election-provider-support-benchmarking = { path = "substrate/frame/election-provider-support/benchmarking", default-features = false } +pallet-elections-phragmen = { path = "substrate/frame/elections-phragmen", default-features = false } +pallet-example-basic = { path = "substrate/frame/examples/basic", default-features = false } +pallet-example-frame-crate = { path = "substrate/frame/examples/frame-crate", default-features = false } +pallet-example-kitchensink = { path = "substrate/frame/examples/kitchensink", default-features = false } +pallet-example-mbm = { path = "substrate/frame/examples/multi-block-migrations", default-features = false } +pallet-example-offchain-worker = { path = "substrate/frame/examples/offchain-worker", default-features = false } +pallet-example-single-block-migrations = { path = "substrate/frame/examples/single-block-migrations", default-features = false } +pallet-example-split = { path = "substrate/frame/examples/split", default-features = false } +pallet-example-tasks = { path = "substrate/frame/examples/tasks", default-features = false } +pallet-examples = { path = "substrate/frame/examples" } +pallet-fast-unstake = { path = "substrate/frame/fast-unstake", default-features = false } +pallet-glutton = { path = "substrate/frame/glutton", default-features = false } +pallet-grandpa = { path = "substrate/frame/grandpa", default-features = false } +pallet-identity = { path = "substrate/frame/identity", default-features = false } +pallet-im-online = { path = "substrate/frame/im-online", default-features = false } +pallet-indices = { path = "substrate/frame/indices", default-features = false } +pallet-insecure-randomness-collective-flip = { path = "substrate/frame/insecure-randomness-collective-flip", default-features = false } +pallet-lottery = { default-features = false, path = "substrate/frame/lottery" } +pallet-membership = { path = "substrate/frame/membership", default-features = false } +pallet-message-queue = { path = "substrate/frame/message-queue", default-features = false } +pallet-migrations = { path = "substrate/frame/migrations", default-features = false } +pallet-minimal-template = { path = "templates/minimal/pallets/template", default-features = false } +pallet-mixnet = { default-features = false, path = "substrate/frame/mixnet" } +pallet-mmr = { path = "substrate/frame/merkle-mountain-range", default-features = false } +pallet-multisig = { path = "substrate/frame/multisig", default-features = false } +pallet-nft-fractionalization = { path = "substrate/frame/nft-fractionalization", default-features = false } +pallet-nfts = { path = "substrate/frame/nfts", default-features = false } +pallet-nfts-runtime-api = { path = "substrate/frame/nfts/runtime-api", default-features = false } +pallet-nis = { path = "substrate/frame/nis", default-features = false } +pallet-node-authorization = { default-features = false, path = "substrate/frame/node-authorization" } +pallet-nomination-pools = { path = "substrate/frame/nomination-pools", default-features = false } +pallet-nomination-pools-benchmarking = { path = "substrate/frame/nomination-pools/benchmarking", default-features = false } +pallet-nomination-pools-runtime-api = { path = "substrate/frame/nomination-pools/runtime-api", default-features = false } +pallet-offences = { path = "substrate/frame/offences", default-features = false } +pallet-offences-benchmarking = { path = "substrate/frame/offences/benchmarking", default-features = false } +pallet-paged-list = { path = "substrate/frame/paged-list", default-features = false } +pallet-parachain-template = { path = "templates/parachain/pallets/template", default-features = false } +pallet-parameters = { path = "substrate/frame/parameters", default-features = false } +pallet-preimage = { path = "substrate/frame/preimage", default-features = false } +pallet-proxy = { path = "substrate/frame/proxy", default-features = false } +pallet-ranked-collective = { path = "substrate/frame/ranked-collective", default-features = false } +pallet-recovery = { path = "substrate/frame/recovery", default-features = false } +pallet-referenda = { path = "substrate/frame/referenda", default-features = false } +pallet-remark = { default-features = false, path = "substrate/frame/remark" } +pallet-root-offences = { default-features = false, path = "substrate/frame/root-offences" } +pallet-root-testing = { path = "substrate/frame/root-testing", default-features = false } +pallet-safe-mode = { default-features = false, path = "substrate/frame/safe-mode" } +pallet-salary = { path = "substrate/frame/salary", default-features = false } +pallet-scheduler = { path = "substrate/frame/scheduler", default-features = false } +pallet-scored-pool = { default-features = false, path = "substrate/frame/scored-pool" } +pallet-session = { path = "substrate/frame/session", default-features = false } +pallet-session-benchmarking = { path = "substrate/frame/session/benchmarking", default-features = false } +pallet-skip-feeless-payment = { path = "substrate/frame/transaction-payment/skip-feeless-payment", default-features = false } +pallet-society = { path = "substrate/frame/society", default-features = false } +pallet-staking = { path = "substrate/frame/staking", default-features = false } +pallet-staking-reward-curve = { path = "substrate/frame/staking/reward-curve", default-features = false } +pallet-staking-reward-fn = { path = "substrate/frame/staking/reward-fn", default-features = false } +pallet-staking-runtime-api = { path = "substrate/frame/staking/runtime-api", default-features = false } +pallet-state-trie-migration = { path = "substrate/frame/state-trie-migration", default-features = false } +pallet-statement = { default-features = false, path = "substrate/frame/statement" } +pallet-sudo = { path = "substrate/frame/sudo", default-features = false } +pallet-template = { path = "templates/solochain/pallets/template", default-features = false } +pallet-timestamp = { path = "substrate/frame/timestamp", default-features = false } +pallet-tips = { path = "substrate/frame/tips", default-features = false } +pallet-transaction-payment = { path = "substrate/frame/transaction-payment", default-features = false } +pallet-transaction-payment-rpc = { path = "substrate/frame/transaction-payment/rpc", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { path = "substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } +pallet-transaction-storage = { default-features = false, path = "substrate/frame/transaction-storage" } +pallet-treasury = { path = "substrate/frame/treasury", default-features = false } +pallet-tx-pause = { default-features = false, path = "substrate/frame/tx-pause" } +pallet-uniques = { path = "substrate/frame/uniques", default-features = false } +pallet-utility = { path = "substrate/frame/utility", default-features = false } +pallet-vesting = { path = "substrate/frame/vesting", default-features = false } +pallet-whitelist = { path = "substrate/frame/whitelist", default-features = false } +pallet-xcm = { path = "polkadot/xcm/pallet-xcm", default-features = false } +pallet-xcm-benchmarks = { path = "polkadot/xcm/pallet-xcm-benchmarks", default-features = false } +pallet-xcm-bridge-hub = { path = "bridges/modules/xcm-bridge-hub", default-features = false } +pallet-xcm-bridge-hub-router = { path = "bridges/modules/xcm-bridge-hub-router", default-features = false } +parachain-info = { path = "cumulus/parachains/pallets/parachain-info", default-features = false, package = "staging-parachain-info" } +parachain-template-runtime = { path = "templates/parachain/runtime" } +parachains-common = { path = "cumulus/parachains/common", default-features = false } +parachains-relay = { path = "bridges/relays/parachains" } +parachains-runtimes-test-utils = { path = "cumulus/parachains/runtimes/test-utils", default-features = false } +parity-bytes = { version = "0.1.2", default-features = false } +parity-db = { version = "0.4.12" } +parity-util-mem = { version = "0.12.0" } +parity-wasm = { version = "0.45.0" } +parking_lot = { version = "0.12.1", default-features = false } +partial_sort = { version = "0.2.0" } +paste = { version = "1.0.15", default-features = false } +pbkdf2 = { version = "0.12.2", default-features = false } +penpal-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal" } +penpal-runtime = { path = "cumulus/parachains/runtimes/testing/penpal" } +people-rococo-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo" } +people-rococo-runtime = { path = "cumulus/parachains/runtimes/people/people-rococo" } +people-westend-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend" } +people-westend-runtime = { path = "cumulus/parachains/runtimes/people/people-westend" } +pin-project = { version = "1.1.3" } +platforms = { version = "3.0" } +polkadot-approval-distribution = { path = "polkadot/node/network/approval-distribution", default-features = false } +polkadot-availability-bitfield-distribution = { path = "polkadot/node/network/bitfield-distribution", default-features = false } +polkadot-availability-distribution = { path = "polkadot/node/network/availability-distribution", default-features = false } +polkadot-availability-recovery = { path = "polkadot/node/network/availability-recovery", default-features = false } +polkadot-cli = { path = "polkadot/cli", default-features = false } +polkadot-collator-protocol = { path = "polkadot/node/network/collator-protocol", default-features = false } +polkadot-core-primitives = { path = "polkadot/core-primitives", default-features = false } +polkadot-dispute-distribution = { path = "polkadot/node/network/dispute-distribution", default-features = false } +polkadot-erasure-coding = { path = "polkadot/erasure-coding", default-features = false } +polkadot-gossip-support = { path = "polkadot/node/network/gossip-support", default-features = false } +polkadot-network-bridge = { path = "polkadot/node/network/bridge", default-features = false } +polkadot-node-collation-generation = { path = "polkadot/node/collation-generation", default-features = false } +polkadot-node-core-approval-voting = { path = "polkadot/node/core/approval-voting", default-features = false } +polkadot-node-core-av-store = { path = "polkadot/node/core/av-store", default-features = false } +polkadot-node-core-backing = { path = "polkadot/node/core/backing", default-features = false } +polkadot-node-core-bitfield-signing = { path = "polkadot/node/core/bitfield-signing", default-features = false } +polkadot-node-core-candidate-validation = { path = "polkadot/node/core/candidate-validation", default-features = false } +polkadot-node-core-chain-api = { path = "polkadot/node/core/chain-api", default-features = false } +polkadot-node-core-chain-selection = { path = "polkadot/node/core/chain-selection", default-features = false } +polkadot-node-core-dispute-coordinator = { path = "polkadot/node/core/dispute-coordinator", default-features = false } +polkadot-node-core-parachains-inherent = { path = "polkadot/node/core/parachains-inherent", default-features = false } +polkadot-node-core-prospective-parachains = { path = "polkadot/node/core/prospective-parachains", default-features = false } +polkadot-node-core-provisioner = { path = "polkadot/node/core/provisioner", default-features = false } +polkadot-node-core-pvf = { path = "polkadot/node/core/pvf", default-features = false } +polkadot-node-core-pvf-checker = { path = "polkadot/node/core/pvf-checker", default-features = false } +polkadot-node-core-pvf-common = { path = "polkadot/node/core/pvf/common", default-features = false } +polkadot-node-core-pvf-execute-worker = { path = "polkadot/node/core/pvf/execute-worker", default-features = false } +polkadot-node-core-pvf-prepare-worker = { path = "polkadot/node/core/pvf/prepare-worker", default-features = false } +polkadot-node-core-runtime-api = { path = "polkadot/node/core/runtime-api", default-features = false } +polkadot-node-jaeger = { path = "polkadot/node/jaeger", default-features = false } +polkadot-node-metrics = { path = "polkadot/node/metrics", default-features = false } +polkadot-node-network-protocol = { path = "polkadot/node/network/protocol", default-features = false } +polkadot-node-primitives = { path = "polkadot/node/primitives", default-features = false } +polkadot-node-subsystem = { path = "polkadot/node/subsystem", default-features = false } +polkadot-node-subsystem-test-helpers = { path = "polkadot/node/subsystem-test-helpers" } +polkadot-node-subsystem-types = { path = "polkadot/node/subsystem-types", default-features = false } +polkadot-node-subsystem-util = { path = "polkadot/node/subsystem-util", default-features = false } +polkadot-overseer = { path = "polkadot/node/overseer", default-features = false } +polkadot-parachain-primitives = { path = "polkadot/parachain", default-features = false } +polkadot-primitives = { path = "polkadot/primitives", default-features = false } +polkadot-primitives-test-helpers = { path = "polkadot/primitives/test-helpers" } +polkadot-rpc = { path = "polkadot/rpc", default-features = false } +polkadot-runtime-common = { path = "polkadot/runtime/common", default-features = false } +polkadot-runtime-metrics = { path = "polkadot/runtime/metrics", default-features = false } +polkadot-runtime-parachains = { path = "polkadot/runtime/parachains", default-features = false } +polkadot-sdk = { path = "umbrella", default-features = false } +polkadot-sdk-docs = { path = "docs/sdk" } +polkadot-service = { path = "polkadot/node/service", default-features = false } +polkadot-statement-distribution = { path = "polkadot/node/network/statement-distribution", default-features = false } +polkadot-statement-table = { path = "polkadot/statement-table", default-features = false } +polkadot-subsystem-bench = { path = "polkadot/node/subsystem-bench" } +polkadot-test-client = { path = "polkadot/node/test/client" } +polkadot-test-runtime = { path = "polkadot/runtime/test-runtime" } +polkadot-test-service = { path = "polkadot/node/test/service" } polkavm = "0.9.3" -polkavm-linker = "0.9.2" polkavm-derive = "0.9.1" -log = { version = "0.4.21", default-features = false } -quote = { version = "1.0.33" } -serde = { version = "1.0.197", default-features = false } +polkavm-linker = "0.9.2" +portpicker = { version = "0.1.1" } +pretty_assertions = { version = "1.3.0" } +primitive-types = { version = "0.12.1", default-features = false } +proc-macro-crate = { version = "3.0.0" } +proc-macro-warning = { version = "1.0.0", default-features = false } +proc-macro2 = { version = "1.0.64" } +procfs = { version = "0.16.0" } +prometheus = { version = "0.13.0", default-features = false } +prometheus-endpoint = { path = "substrate/utils/prometheus", default-features = false, package = "substrate-prometheus-endpoint" } +prometheus-parse = { version = "0.2.2" } +prost = { version = "0.12.4" } +prost-build = { version = "0.12.4" } +pyroscope = { version = "0.5.7" } +pyroscope_pprofrs = { version = "0.2.7" } +quick_cache = { version = "0.3" } +quickcheck = { version = "1.0.3", default-features = false } +quote = { version = "1.0.36" } +rand = { version = "0.8.5", default-features = false } +rand_chacha = { version = "0.3.1", default-features = false } +rand_core = { version = "0.6.2" } +rand_distr = { version = "0.4.3" } +rand_pcg = { version = "0.3.1" } +rayon = { version = "1.5.1" } +rbtag = { version = "0.3" } +ref-cast = { version = "1.0.0" } +regex = { version = "1.10.2" } +relay-substrate-client = { path = "bridges/relays/client-substrate" } +relay-utils = { path = "bridges/relays/utils" } +remote-externalities = { path = "substrate/utils/frame/remote-externalities", default-features = false, package = "frame-remote-externalities" } +reqwest = { version = "0.11", default-features = false } +rlp = { version = "0.5.2", default-features = false } +rococo-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/relays/rococo" } +rococo-parachain-runtime = { path = "cumulus/parachains/runtimes/testing/rococo-parachain" } +rococo-runtime = { path = "polkadot/runtime/rococo" } +rococo-runtime-constants = { path = "polkadot/runtime/rococo/constants", default-features = false } +rococo-system-emulated-network = { path = "cumulus/parachains/integration-tests/emulated/networks/rococo-system" } +rococo-westend-system-emulated-network = { path = "cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system" } +rpassword = { version = "7.0.0" } +rstest = { version = "0.18.2" } +rustc-hash = { version = "1.1.0" } +rustc-hex = { version = "2.1.0", default-features = false } +rustix = { version = "0.36.7", default-features = false } +rustversion = { version = "1.0.6" } +rusty-fork = { version = "0.3.0", default-features = false } +safe-mix = { version = "1.0", default-features = false } +sc-allocator = { path = "substrate/client/allocator", default-features = false } +sc-authority-discovery = { path = "substrate/client/authority-discovery", default-features = false } +sc-basic-authorship = { path = "substrate/client/basic-authorship", default-features = false } +sc-block-builder = { path = "substrate/client/block-builder", default-features = false } +sc-chain-spec = { path = "substrate/client/chain-spec", default-features = false } +sc-chain-spec-derive = { path = "substrate/client/chain-spec/derive", default-features = false } +sc-cli = { path = "substrate/client/cli", default-features = false } +sc-client-api = { path = "substrate/client/api", default-features = false } +sc-client-db = { path = "substrate/client/db", default-features = false } +sc-consensus = { path = "substrate/client/consensus/common", default-features = false } +sc-consensus-aura = { path = "substrate/client/consensus/aura", default-features = false } +sc-consensus-babe = { path = "substrate/client/consensus/babe", default-features = false } +sc-consensus-babe-rpc = { path = "substrate/client/consensus/babe/rpc", default-features = false } +sc-consensus-beefy = { path = "substrate/client/consensus/beefy", default-features = false } +sc-consensus-beefy-rpc = { path = "substrate/client/consensus/beefy/rpc", default-features = false } +sc-consensus-epochs = { path = "substrate/client/consensus/epochs", default-features = false } +sc-consensus-grandpa = { path = "substrate/client/consensus/grandpa", default-features = false } +sc-consensus-grandpa-rpc = { path = "substrate/client/consensus/grandpa/rpc", default-features = false } +sc-consensus-manual-seal = { path = "substrate/client/consensus/manual-seal", default-features = false } +sc-consensus-pow = { path = "substrate/client/consensus/pow", default-features = false } +sc-consensus-slots = { path = "substrate/client/consensus/slots", default-features = false } +sc-executor = { path = "substrate/client/executor", default-features = false } +sc-executor-common = { path = "substrate/client/executor/common", default-features = false } +sc-executor-polkavm = { path = "substrate/client/executor/polkavm", default-features = false } +sc-executor-wasmtime = { path = "substrate/client/executor/wasmtime", default-features = false } +sc-informant = { path = "substrate/client/informant", default-features = false } +sc-keystore = { path = "substrate/client/keystore", default-features = false } +sc-mixnet = { path = "substrate/client/mixnet", default-features = false } +sc-network = { path = "substrate/client/network", default-features = false } +sc-network-common = { path = "substrate/client/network/common", default-features = false } +sc-network-gossip = { path = "substrate/client/network-gossip", default-features = false } +sc-network-light = { path = "substrate/client/network/light", default-features = false } +sc-network-statement = { default-features = false, path = "substrate/client/network/statement" } +sc-network-sync = { path = "substrate/client/network/sync", default-features = false } +sc-network-test = { path = "substrate/client/network/test" } +sc-network-transactions = { path = "substrate/client/network/transactions", default-features = false } +sc-network-types = { path = "substrate/client/network/types", default-features = false } +sc-offchain = { path = "substrate/client/offchain", default-features = false } +sc-proposer-metrics = { path = "substrate/client/proposer-metrics", default-features = false } +sc-rpc = { path = "substrate/client/rpc", default-features = false } +sc-rpc-api = { path = "substrate/client/rpc-api", default-features = false } +sc-rpc-server = { path = "substrate/client/rpc-servers", default-features = false } +sc-rpc-spec-v2 = { path = "substrate/client/rpc-spec-v2", default-features = false } +sc-runtime-test = { path = "substrate/client/executor/runtime-test" } +sc-service = { path = "substrate/client/service", default-features = false } +sc-service-test = { path = "substrate/client/service/test" } +sc-state-db = { path = "substrate/client/state-db", default-features = false } +sc-statement-store = { default-features = false, path = "substrate/client/statement-store" } +sc-storage-monitor = { path = "substrate/client/storage-monitor", default-features = false } +sc-sync-state-rpc = { path = "substrate/client/sync-state-rpc", default-features = false } +sc-sysinfo = { path = "substrate/client/sysinfo", default-features = false } +sc-telemetry = { path = "substrate/client/telemetry", default-features = false } +sc-tracing = { path = "substrate/client/tracing", default-features = false } +sc-tracing-proc-macro = { path = "substrate/client/tracing/proc-macro", default-features = false } +sc-transaction-pool = { path = "substrate/client/transaction-pool", default-features = false } +sc-transaction-pool-api = { path = "substrate/client/transaction-pool/api", default-features = false } +sc-utils = { path = "substrate/client/utils", default-features = false } +scale-info = { version = "2.11.1", default-features = false } +schemars = { version = "0.8.13", default-features = false } +schnellru = { version = "0.2.1" } +schnorrkel = { version = "0.11.4", default-features = false } +seccompiler = { version = "0.4.0" } +secp256k1 = { version = "0.28.0", default-features = false } +secrecy = { version = "0.8.0", default-features = false } +seedling-runtime = { path = "cumulus/parachains/runtimes/starters/seedling" } +separator = { version = "0.4.1" } +serde = { version = "1.0.204", default-features = false } serde-big-array = { version = "0.3.2" } serde_derive = { version = "1.0.117" } -serde_json = { version = "1.0.114", default-features = false } +serde_json = { version = "1.0.120", default-features = false } serde_yaml = { version = "0.9" } +serial_test = { version = "2.0.0" } +sha1 = { version = "0.10.6" } +sha2 = { version = "0.10.7", default-features = false } +sha3 = { version = "0.10.0", default-features = false } +shell-runtime = { path = "cumulus/parachains/runtimes/starters/shell" } +slot-range-helper = { path = "polkadot/runtime/common/slot_range_helper", default-features = false } +slotmap = { version = "1.0" } +smallvec = { version = "1.11.0", default-features = false } +smoldot = { version = "0.11.0", default-features = false } +smoldot-light = { version = "0.9.0", default-features = false } +snowbridge-beacon-primitives = { path = "bridges/snowbridge/primitives/beacon", default-features = false } +snowbridge-core = { path = "bridges/snowbridge/primitives/core", default-features = false } +snowbridge-ethereum = { path = "bridges/snowbridge/primitives/ethereum", default-features = false } +snowbridge-outbound-queue-merkle-tree = { path = "bridges/snowbridge/pallets/outbound-queue/merkle-tree", default-features = false } +snowbridge-outbound-queue-runtime-api = { path = "bridges/snowbridge/pallets/outbound-queue/runtime-api", default-features = false } +snowbridge-pallet-ethereum-client = { path = "bridges/snowbridge/pallets/ethereum-client", default-features = false } +snowbridge-pallet-ethereum-client-fixtures = { path = "bridges/snowbridge/pallets/ethereum-client/fixtures", default-features = false } +snowbridge-pallet-inbound-queue = { path = "bridges/snowbridge/pallets/inbound-queue", default-features = false } +snowbridge-pallet-inbound-queue-fixtures = { path = "bridges/snowbridge/pallets/inbound-queue/fixtures", default-features = false } +snowbridge-pallet-outbound-queue = { path = "bridges/snowbridge/pallets/outbound-queue", default-features = false } +snowbridge-pallet-system = { path = "bridges/snowbridge/pallets/system", default-features = false } +snowbridge-router-primitives = { path = "bridges/snowbridge/primitives/router", default-features = false } +snowbridge-runtime-common = { path = "bridges/snowbridge/runtime/runtime-common", default-features = false } +snowbridge-runtime-test-common = { path = "bridges/snowbridge/runtime/test-common", default-features = false } +snowbridge-system-runtime-api = { path = "bridges/snowbridge/pallets/system/runtime-api", default-features = false } +soketto = { version = "0.7.1" } +solochain-template-runtime = { path = "templates/solochain/runtime" } +sp-api = { path = "substrate/primitives/api", default-features = false } +sp-api-proc-macro = { path = "substrate/primitives/api/proc-macro", default-features = false } +sp-application-crypto = { path = "substrate/primitives/application-crypto", default-features = false } +sp-arithmetic = { path = "substrate/primitives/arithmetic", default-features = false } +sp-authority-discovery = { path = "substrate/primitives/authority-discovery", default-features = false } +sp-block-builder = { path = "substrate/primitives/block-builder", default-features = false } +sp-blockchain = { path = "substrate/primitives/blockchain", default-features = false } +sp-consensus = { path = "substrate/primitives/consensus/common", default-features = false } +sp-consensus-aura = { path = "substrate/primitives/consensus/aura", default-features = false } +sp-consensus-babe = { path = "substrate/primitives/consensus/babe", default-features = false } +sp-consensus-beefy = { path = "substrate/primitives/consensus/beefy", default-features = false } +sp-consensus-grandpa = { path = "substrate/primitives/consensus/grandpa", default-features = false } +sp-consensus-pow = { path = "substrate/primitives/consensus/pow", default-features = false } +sp-consensus-sassafras = { path = "substrate/primitives/consensus/sassafras", default-features = false } +sp-consensus-slots = { path = "substrate/primitives/consensus/slots", default-features = false } +sp-core = { path = "substrate/primitives/core", default-features = false } +sp-core-hashing = { default-features = false, path = "substrate/deprecated/hashing" } +sp-core-hashing-proc-macro = { default-features = false, path = "substrate/deprecated/hashing/proc-macro" } +sp-crypto-ec-utils = { default-features = false, path = "substrate/primitives/crypto/ec-utils" } +sp-crypto-hashing = { path = "substrate/primitives/crypto/hashing", default-features = false } +sp-crypto-hashing-proc-macro = { path = "substrate/primitives/crypto/hashing/proc-macro", default-features = false } +sp-database = { path = "substrate/primitives/database", default-features = false } +sp-debug-derive = { path = "substrate/primitives/debug-derive", default-features = false } +sp-externalities = { path = "substrate/primitives/externalities", default-features = false } +sp-genesis-builder = { path = "substrate/primitives/genesis-builder", default-features = false } +sp-inherents = { path = "substrate/primitives/inherents", default-features = false } +sp-io = { path = "substrate/primitives/io", default-features = false } +sp-keyring = { path = "substrate/primitives/keyring", default-features = false } +sp-keystore = { path = "substrate/primitives/keystore", default-features = false } +sp-maybe-compressed-blob = { path = "substrate/primitives/maybe-compressed-blob", default-features = false } +sp-metadata-ir = { path = "substrate/primitives/metadata-ir", default-features = false } +sp-mixnet = { path = "substrate/primitives/mixnet", default-features = false } +sp-mmr-primitives = { path = "substrate/primitives/merkle-mountain-range", default-features = false } +sp-npos-elections = { path = "substrate/primitives/npos-elections", default-features = false } +sp-offchain = { path = "substrate/primitives/offchain", default-features = false } +sp-panic-handler = { path = "substrate/primitives/panic-handler", default-features = false } +sp-rpc = { path = "substrate/primitives/rpc", default-features = false } +sp-runtime = { path = "substrate/primitives/runtime", default-features = false } +sp-runtime-interface = { path = "substrate/primitives/runtime-interface", default-features = false } +sp-runtime-interface-proc-macro = { path = "substrate/primitives/runtime-interface/proc-macro", default-features = false } +sp-runtime-interface-test-wasm = { path = "substrate/primitives/runtime-interface/test-wasm" } +sp-runtime-interface-test-wasm-deprecated = { path = "substrate/primitives/runtime-interface/test-wasm-deprecated" } +sp-session = { path = "substrate/primitives/session", default-features = false } +sp-staking = { path = "substrate/primitives/staking", default-features = false } +sp-state-machine = { path = "substrate/primitives/state-machine", default-features = false } +sp-statement-store = { path = "substrate/primitives/statement-store", default-features = false } +sp-std = { path = "substrate/primitives/std", default-features = false } +sp-storage = { path = "substrate/primitives/storage", default-features = false } +sp-test-primitives = { path = "substrate/primitives/test-primitives" } +sp-timestamp = { path = "substrate/primitives/timestamp", default-features = false } +sp-tracing = { path = "substrate/primitives/tracing", default-features = false } +sp-transaction-pool = { path = "substrate/primitives/transaction-pool", default-features = false } +sp-transaction-storage-proof = { path = "substrate/primitives/transaction-storage-proof", default-features = false } +sp-trie = { path = "substrate/primitives/trie", default-features = false } +sp-version = { path = "substrate/primitives/version", default-features = false } +sp-version-proc-macro = { path = "substrate/primitives/version/proc-macro", default-features = false } +sp-wasm-interface = { path = "substrate/primitives/wasm-interface", default-features = false } +sp-weights = { path = "substrate/primitives/weights", default-features = false } +spinners = { version = "4.1.0" } +ss58-registry = { version = "1.34.0", default-features = false } +ssz_rs = { version = "0.9.0", default-features = false } +ssz_rs_derive = { version = "0.9.0", default-features = false } +static_assertions = { version = "1.1.0", default-features = false } +static_init = { version = "1.0.3" } +structopt = { version = "0.3" } +strum = { version = "0.26.2", default-features = false } +subkey = { path = "substrate/bin/utils/subkey", default-features = false } +substrate-bip39 = { path = "substrate/utils/substrate-bip39", default-features = false } +substrate-build-script-utils = { path = "substrate/utils/build-script-utils", default-features = false } +substrate-cli-test-utils = { path = "substrate/test-utils/cli" } +substrate-frame-rpc-support = { default-features = false, path = "substrate/utils/frame/rpc/support" } +substrate-frame-rpc-system = { path = "substrate/utils/frame/rpc/system", default-features = false } +substrate-rpc-client = { path = "substrate/utils/frame/rpc/client", default-features = false } +substrate-state-trie-migration-rpc = { path = "substrate/utils/frame/rpc/state-trie-migration-rpc", default-features = false } +substrate-test-client = { path = "substrate/test-utils/client" } +substrate-test-runtime = { path = "substrate/test-utils/runtime" } +substrate-test-runtime-client = { path = "substrate/test-utils/runtime/client" } +substrate-test-runtime-transaction-pool = { path = "substrate/test-utils/runtime/transaction-pool" } +substrate-test-utils = { path = "substrate/test-utils" } +substrate-wasm-builder = { path = "substrate/utils/wasm-builder", default-features = false } syn = { version = "2.0.53" } +sysinfo = { version = "0.30" } +tar = { version = "0.4" } +tempfile = { version = "3.8.1" } +test-log = { version = "0.2.14" } +test-pallet = { path = "substrate/frame/support/test/pallet", default-features = false, package = "frame-support-test-pallet" } +test-parachain-adder = { path = "polkadot/parachain/test-parachains/adder" } +test-parachain-halt = { path = "polkadot/parachain/test-parachains/halt" } +test-parachain-undying = { path = "polkadot/parachain/test-parachains/undying" } +test-runtime-constants = { path = "polkadot/runtime/test-runtime/constants", default-features = false } +testnet-parachains-constants = { path = "cumulus/parachains/runtimes/constants", default-features = false } thiserror = { version = "1.0.48" } +thousands = { version = "0.2.0" } +threadpool = { version = "1.7" } +tikv-jemalloc-ctl = { version = "0.5.0" } +tikv-jemallocator = { version = "0.5.0" } +time = { version = "0.3" } +tiny-keccak = { version = "2.0.2" } +tokio = { version = "1.37.0", default-features = false } +tokio-retry = { version = "0.3.0" } +tokio-stream = { version = "0.1.14" } +tokio-test = { version = "0.4.2" } +tokio-tungstenite = { version = "0.20.1" } +tokio-util = { version = "0.7.8" } +toml = { version = "0.8.8" } +toml_edit = { version = "0.19" } +tower = { version = "0.4.13" } +tower-http = { version = "0.5.2" } +tracing = { version = "0.1.37", default-features = false } +tracing-core = { version = "0.1.32", default-features = false } +tracing-futures = { version = "0.2.4" } +tracing-log = { version = "0.2.0" } tracing-subscriber = { version = "0.3.18" } +tracking-allocator = { path = "polkadot/node/tracking-allocator", default-features = false, package = "staging-tracking-allocator" } +trie-bench = { version = "0.39.0" } +trie-db = { version = "0.29.0", default-features = false } +trie-root = { version = "0.18.0", default-features = false } +trie-standardmap = { version = "0.16.0" } +trybuild = { version = "1.0.88" } +tt-call = { version = "1.0.8" } +tuplex = { version = "0.1", default-features = false } +twox-hash = { version = "1.6.3", default-features = false } +unsigned-varint = { version = "0.7.2" } +url = { version = "2.4.0" } +void = { version = "1.0.2" } +w3f-bls = { version = "0.1.3", default-features = false } +wait-timeout = { version = "0.2" } +walkdir = { version = "2.4.0" } +wasm-bindgen-test = { version = "0.3.19" } +wasm-instrument = { version = "0.4", default-features = false } +wasm-opt = { version = "0.116" } +wasm-timer = { version = "0.2.5" } +wasmi = { version = "0.32.3", default-features = false } +wasmtime = { version = "8.0.1", default-features = false } +wat = { version = "1.0.0" } +westend-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/relays/westend", default-features = false } +westend-runtime = { path = "polkadot/runtime/westend" } +westend-runtime-constants = { path = "polkadot/runtime/westend/constants", default-features = false } +westend-system-emulated-network = { path = "cumulus/parachains/integration-tests/emulated/networks/westend-system" } +x25519-dalek = { version = "2.0" } +xcm = { path = "polkadot/xcm", default-features = false, package = "staging-xcm" } +xcm-builder = { path = "polkadot/xcm/xcm-builder", default-features = false, package = "staging-xcm-builder" } +xcm-docs = { path = "polkadot/xcm/docs" } +xcm-emulator = { path = "cumulus/xcm/xcm-emulator", default-features = false } +xcm-executor = { path = "polkadot/xcm/xcm-executor", default-features = false, package = "staging-xcm-executor" } +xcm-procedural = { path = "polkadot/xcm/procedural", default-features = false } +xcm-runtime-apis = { path = "polkadot/xcm/xcm-runtime-apis", default-features = false } +xcm-simulator = { path = "polkadot/xcm/xcm-simulator", default-features = false } +zeroize = { version = "1.7.0", default-features = false } +zstd = { version = "0.12.4", default-features = false } [profile.release] # Polkadot runtime requires unwinding. diff --git a/README.md b/README.md index 92901d070db0854dd4b1daef8c3ed7a3fd3893f2..a070d61170f687d4217f1d391b0a5cf54eddd0dc 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,12 @@ forks](https://img.shields.io/github/forks/paritytech/polkadot-sdk) +## โšก Quickstart +If you want to get an example node running quickly you can execute the following getting started script: +``` +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/scripts/getting-started.sh +``` + ## ๐Ÿ“š Documentation * [๐Ÿฆ€ rust-docs](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/index.html) diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index 783009a8c890768bcc85dafec14dc3da9e8da573..36f27b6aa0358fcb8027bbfe6e571bc1a50962e6 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -11,48 +11,44 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -hash-db = { version = "0.16.0", default-features = false } +codec = { features = ["derive"], workspace = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } -static_assertions = { version = "1.1", optional = true } -tuplex = { version = "0.1", default-features = false } +scale-info = { features = ["derive"], workspace = true } +static_assertions = { optional = true, workspace = true, default-features = true } +tuplex = { workspace = true } # Bridge dependencies - -bp-header-chain = { path = "../../primitives/header-chain", default-features = false } -bp-messages = { path = "../../primitives/messages", default-features = false } -bp-parachains = { path = "../../primitives/parachains", default-features = false } -bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } -bp-relayers = { path = "../../primitives/relayers", default-features = false } -bp-runtime = { path = "../../primitives/runtime", default-features = false } -bp-xcm-bridge-hub = { path = "../../primitives/xcm-bridge-hub", default-features = false } -bp-xcm-bridge-hub-router = { path = "../../primitives/xcm-bridge-hub-router", default-features = false } -pallet-bridge-grandpa = { path = "../../modules/grandpa", default-features = false } -pallet-bridge-messages = { path = "../../modules/messages", default-features = false } -pallet-bridge-parachains = { path = "../../modules/parachains", default-features = false } -pallet-bridge-relayers = { path = "../../modules/relayers", default-features = false } +bp-header-chain = { workspace = true } +bp-messages = { workspace = true } +bp-parachains = { workspace = true } +bp-polkadot-core = { workspace = true } +bp-relayers = { workspace = true } +bp-runtime = { workspace = true } +bp-xcm-bridge-hub = { workspace = true } +bp-xcm-bridge-hub-router = { workspace = true } +pallet-bridge-grandpa = { workspace = true } +pallet-bridge-messages = { workspace = true } +pallet-bridge-parachains = { workspace = true } +pallet-bridge-relayers = { workspace = true } # Substrate dependencies - -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false } -pallet-utility = { path = "../../../substrate/frame/utility", default-features = false } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-utility = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } +sp-trie = { optional = true, workspace = true } # Polkadot dependencies -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false } +xcm = { workspace = true } +xcm-builder = { workspace = true } [dev-dependencies] -bp-test-utils = { path = "../../primitives/test-utils" } -pallet-balances = { path = "../../../substrate/frame/balances" } +bp-test-utils = { workspace = true } +pallet-balances = { workspace = true } +pallet-bridge-messages = { features = ["std", "test-helpers"], workspace = true } [features] default = ["std"] @@ -63,13 +59,14 @@ std = [ "bp-polkadot-core/std", "bp-relayers/std", "bp-runtime/std", + "bp-test-utils/std", "bp-xcm-bridge-hub-router/std", "bp-xcm-bridge-hub/std", "codec/std", "frame-support/std", "frame-system/std", - "hash-db/std", "log/std", + "pallet-balances/std", "pallet-bridge-grandpa/std", "pallet-bridge-messages/std", "pallet-bridge-parachains/std", @@ -77,8 +74,6 @@ std = [ "pallet-transaction-payment/std", "pallet-utility/std", "scale-info/std", - "sp-api/std", - "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", @@ -88,15 +83,22 @@ std = [ "xcm/std", ] runtime-benchmarks = [ + "bp-runtime/test-helpers", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-bridge-grandpa/runtime-benchmarks", "pallet-bridge-messages/runtime-benchmarks", + "pallet-bridge-messages/test-helpers", "pallet-bridge-parachains/runtime-benchmarks", "pallet-bridge-relayers/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "sp-trie", "xcm-builder/runtime-benchmarks", ] integrity-test = ["static_assertions"] +test-helpers = [ + "bp-runtime/test-helpers", + "sp-trie", +] diff --git a/bridges/bin/runtime-common/src/extensions/priority_calculator.rs b/bridges/bin/runtime-common/src/extensions/priority_calculator.rs index 92810290f95e77a7fdc04cafaa1e6ab290e1661a..9f559dc13b64d3912f0d1679c21fa682034bdb8e 100644 --- a/bridges/bin/runtime-common/src/extensions/priority_calculator.rs +++ b/bridges/bin/runtime-common/src/extensions/priority_calculator.rs @@ -319,6 +319,7 @@ mod integrity_tests { pub mod per_message { use super::*; + use bp_messages::ChainWithMessages; use pallet_bridge_messages::WeightInfoExt; /// Ensures that the value of `PriorityBoostPerMessage` matches the value of @@ -339,7 +340,7 @@ mod integrity_tests { BalanceOf: Send + Sync + FixedPointOperand, { let maximal_messages_in_delivery_transaction = - Runtime::MaxUnconfirmedMessagesAtInboundLane::get(); + Runtime::BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; super::ensure_priority_boost_is_sane::>( "PriorityBoostPerMessage", maximal_messages_in_delivery_transaction, diff --git a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs b/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs index 5aa7f1c095d540a4ee5050aeb7d694c98b744683..6ba3506377d0e602bf9ee706b13c248efd6afaca 100644 --- a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs +++ b/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs @@ -22,9 +22,9 @@ use crate::messages_call_ext::{ CallHelper as MessagesCallHelper, CallInfo as MessagesCallInfo, MessagesCallSubType, }; -use bp_messages::{LaneId, MessageNonce}; +use bp_messages::{ChainWithMessages, LaneId, MessageNonce}; use bp_relayers::{ExplicitOrAccountParams, RewardsAccountOwner, RewardsAccountParams}; -use bp_runtime::{Parachain, RangeInclusiveExt, StaticStrProvider}; +use bp_runtime::{Chain, Parachain, RangeInclusiveExt, StaticStrProvider}; use codec::{Codec, Decode, Encode}; use frame_support::{ dispatch::{CallableCallFor, DispatchInfo, PostDispatchInfo}, @@ -293,7 +293,7 @@ pub trait RefundSignedExtension: ::Id::get(), ::Instance, - >>::BridgedChainId::get(), + >>::BridgedChain::ID, if call_info.is_receive_messages_proof_call() { RewardsAccountOwner::ThisChain } else { @@ -406,8 +406,7 @@ pub trait RefundSignedExtension: // a quick check to avoid invalid high-priority transactions let max_unconfirmed_messages_in_confirmation_tx = ::Instance, - >>::MaxUnconfirmedMessagesAtInboundLane::get( - ); + >>::BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; if bundled_messages > max_unconfirmed_messages_in_confirmation_tx { return None } @@ -935,9 +934,6 @@ where pub(crate) mod tests { use super::*; use crate::{ - messages::{ - source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, - }, messages_call_ext::{ BaseMessagesProofInfo, ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, UnrewardedRelayerOccupation, @@ -946,8 +942,10 @@ pub(crate) mod tests { }; use bp_header_chain::StoredHeaderDataBuilder; use bp_messages::{ - DeliveredMessages, InboundLaneData, MessageNonce, MessagesOperatingMode, OutboundLaneData, - UnrewardedRelayer, UnrewardedRelayersState, + source_chain::FromBridgedChainMessagesDeliveryProof, + target_chain::FromBridgedChainMessagesProof, DeliveredMessages, InboundLaneData, + MessageNonce, MessagesOperatingMode, OutboundLaneData, UnrewardedRelayer, + UnrewardedRelayersState, }; use bp_parachains::{BestParaHeadHash, ParaInfo}; use bp_polkadot_core::parachains::{ParaHeadsProof, ParaId}; @@ -1123,7 +1121,7 @@ pub(crate) mod tests { ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), [parachain_head_at_relay_header_number as u8; 32].into(), )], - parachain_heads_proof: ParaHeadsProof { storage_proof: vec![] }, + parachain_heads_proof: ParaHeadsProof { storage_proof: Default::default() }, }) } @@ -1136,7 +1134,7 @@ pub(crate) mod tests { ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), [parachain_head_at_relay_header_number as u8; 32].into(), )], - parachain_heads_proof: ParaHeadsProof { storage_proof: vec![] }, + parachain_heads_proof: ParaHeadsProof { storage_proof: Default::default() }, is_free_execution_expected: false, }) } @@ -1144,9 +1142,9 @@ pub(crate) mod tests { fn message_delivery_call(best_message: MessageNonce) -> RuntimeCall { RuntimeCall::BridgeMessages(MessagesCall::receive_messages_proof { relayer_id_at_bridged_chain: relayer_account_at_bridged_chain(), - proof: FromBridgedChainMessagesProof { + proof: Box::new(FromBridgedChainMessagesProof { bridged_header_hash: Default::default(), - storage_proof: vec![], + storage_proof: Default::default(), lane: TestLaneId::get(), nonces_start: pallet_bridge_messages::InboundLanes::::get( TEST_LANE_ID, @@ -1154,7 +1152,7 @@ pub(crate) mod tests { .last_delivered_nonce() + 1, nonces_end: best_message, - }, + }), messages_count: 1, dispatch_weight: Weight::zero(), }) @@ -1164,7 +1162,7 @@ pub(crate) mod tests { RuntimeCall::BridgeMessages(MessagesCall::receive_messages_delivery_proof { proof: FromBridgedChainMessagesDeliveryProof { bridged_header_hash: Default::default(), - storage_proof: vec![], + storage_proof: Default::default(), lane: TestLaneId::get(), }, relayers_state: UnrewardedRelayersState { @@ -1327,8 +1325,10 @@ pub(crate) mod tests { best_stored_nonce: 100, }, unrewarded_relayers: UnrewardedRelayerOccupation { - free_relayer_slots: MaxUnrewardedRelayerEntriesAtInboundLane::get(), - free_message_slots: MaxUnconfirmedMessagesAtInboundLane::get(), + free_relayer_slots: + BridgedUnderlyingChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + free_message_slots: + BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, }, }), ), @@ -1397,8 +1397,10 @@ pub(crate) mod tests { best_stored_nonce: 100, }, unrewarded_relayers: UnrewardedRelayerOccupation { - free_relayer_slots: MaxUnrewardedRelayerEntriesAtInboundLane::get(), - free_message_slots: MaxUnconfirmedMessagesAtInboundLane::get(), + free_relayer_slots: + BridgedUnderlyingChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + free_message_slots: + BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, }, }), ), @@ -1459,8 +1461,10 @@ pub(crate) mod tests { best_stored_nonce: 100, }, unrewarded_relayers: UnrewardedRelayerOccupation { - free_relayer_slots: MaxUnrewardedRelayerEntriesAtInboundLane::get(), - free_message_slots: MaxUnconfirmedMessagesAtInboundLane::get(), + free_relayer_slots: + BridgedUnderlyingChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + free_message_slots: + BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, }, }), ), @@ -1499,8 +1503,10 @@ pub(crate) mod tests { best_stored_nonce: 100, }, unrewarded_relayers: UnrewardedRelayerOccupation { - free_relayer_slots: MaxUnrewardedRelayerEntriesAtInboundLane::get(), - free_message_slots: MaxUnconfirmedMessagesAtInboundLane::get(), + free_relayer_slots: + BridgedUnderlyingChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + free_message_slots: + BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, }, }, )), @@ -1735,14 +1741,16 @@ pub(crate) mod tests { let fns = [run_validate, run_grandpa_validate, run_messages_validate]; for f in fns { - let priority_of_max_messages_delivery = - f(message_delivery_call(100 + MaxUnconfirmedMessagesAtInboundLane::get())) - .unwrap() - .priority; - let priority_of_more_than_max_messages_delivery = - f(message_delivery_call(100 + MaxUnconfirmedMessagesAtInboundLane::get() + 1)) - .unwrap() - .priority; + let priority_of_max_messages_delivery = f(message_delivery_call( + 100 + BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + )) + .unwrap() + .priority; + let priority_of_more_than_max_messages_delivery = f(message_delivery_call( + 100 + BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX + 1, + )) + .unwrap() + .priority; assert!( priority_of_max_messages_delivery > priority_of_more_than_max_messages_delivery, @@ -2103,7 +2111,7 @@ pub(crate) mod tests { [1u8; 32].into(), ), ], - parachain_heads_proof: ParaHeadsProof { storage_proof: vec![] }, + parachain_heads_proof: ParaHeadsProof { storage_proof: Default::default() }, }), message_delivery_call(200), ], @@ -2865,7 +2873,8 @@ pub(crate) mod tests { #[test] fn does_not_panic_on_boosting_priority_of_empty_message_delivery_transaction() { run_test(|| { - let best_delivered_message = MaxUnconfirmedMessagesAtInboundLane::get(); + let best_delivered_message = + BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; initialize_environment(100, 100, best_delivered_message); // register relayer so it gets priority boost diff --git a/bridges/bin/runtime-common/src/integrity.rs b/bridges/bin/runtime-common/src/integrity.rs index d3827a14dd6cc24e088a8d05d26aba9d769eb213..a0a9367dd1400309d0f0be967665a4543ad982cb 100644 --- a/bridges/bin/runtime-common/src/integrity.rs +++ b/bridges/bin/runtime-common/src/integrity.rs @@ -19,26 +19,33 @@ //! Most of the tests in this module assume that the bridge is using standard (see `crate::messages` //! module for details) configuration. -use crate::{messages, messages::MessageBridge}; - -use bp_messages::{InboundLaneData, MessageNonce}; -use bp_runtime::{Chain, ChainId}; +use bp_header_chain::ChainWithGrandpa; +use bp_messages::{ChainWithMessages, InboundLaneData, MessageNonce}; +use bp_runtime::Chain; use codec::Encode; use frame_support::{storage::generator::StorageValue, traits::Get, weights::Weight}; use frame_system::limits; use pallet_bridge_messages::WeightInfoExt as _; +// Re-export to avoid include all dependencies everywhere. +#[doc(hidden)] +pub mod __private { + pub use bp_xcm_bridge_hub; + pub use static_assertions; +} + /// Macro that ensures that the runtime configuration and chain primitives crate are sharing /// the same types (nonce, block number, hash, hasher, account id and header). #[macro_export] macro_rules! assert_chain_types( ( runtime: $r:path, this_chain: $this:path ) => { { + use frame_system::{Config as SystemConfig, pallet_prelude::{BlockNumberFor, HeaderFor}}; + use $crate::integrity::__private::static_assertions::assert_type_eq_all; + // if one of asserts fail, then either bridge isn't configured properly (or alternatively - non-standard // configuration is used), or something has broke existing configuration (meaning that all bridged chains // and relays will stop functioning) - use frame_system::{Config as SystemConfig, pallet_prelude::{BlockNumberFor, HeaderFor}}; - use static_assertions::assert_type_eq_all; assert_type_eq_all!(<$r as SystemConfig>::Nonce, bp_runtime::NonceOf<$this>); assert_type_eq_all!(BlockNumberFor<$r>, bp_runtime::BlockNumberOf<$this>); @@ -50,23 +57,6 @@ macro_rules! assert_chain_types( } ); -/// Macro that ensures that the bridge GRANDPA pallet is configured properly to bridge with given -/// chain. -#[macro_export] -macro_rules! assert_bridge_grandpa_pallet_types( - ( runtime: $r:path, with_bridged_chain_grandpa_instance: $i:path, bridged_chain: $bridged:path ) => { - { - // if one of asserts fail, then either bridge isn't configured properly (or alternatively - non-standard - // configuration is used), or something has broke existing configuration (meaning that all bridged chains - // and relays will stop functioning) - use pallet_bridge_grandpa::Config as GrandpaConfig; - use static_assertions::assert_type_eq_all; - - assert_type_eq_all!(<$r as GrandpaConfig<$i>>::BridgedChain, $bridged); - } - } -); - /// Macro that ensures that the bridge messages pallet is configured properly to bridge using given /// configuration. #[macro_export] @@ -74,32 +64,31 @@ macro_rules! assert_bridge_messages_pallet_types( ( runtime: $r:path, with_bridged_chain_messages_instance: $i:path, - bridge: $bridge:path + this_chain: $this:path, + bridged_chain: $bridged:path, ) => { { + use $crate::messages_xcm_extension::XcmAsPlainPayload; + use $crate::integrity::__private::static_assertions::assert_type_eq_all; + use bp_messages::ChainWithMessages; + use bp_runtime::Chain; + use pallet_bridge_messages::Config as MessagesConfig; + // if one of asserts fail, then either bridge isn't configured properly (or alternatively - non-standard // configuration is used), or something has broke existing configuration (meaning that all bridged chains // and relays will stop functioning) - use $crate::messages::{ - source::{FromThisChainMessagePayload, TargetHeaderChainAdapter}, - target::{FromBridgedChainMessagePayload, SourceHeaderChainAdapter}, - AccountIdOf, BalanceOf, BridgedChain, ThisChain, - }; - use pallet_bridge_messages::Config as MessagesConfig; - use static_assertions::assert_type_eq_all; - assert_type_eq_all!(<$r as MessagesConfig<$i>>::OutboundPayload, FromThisChainMessagePayload); + assert_type_eq_all!(<$r as MessagesConfig<$i>>::ThisChain, $this); + assert_type_eq_all!(<$r as MessagesConfig<$i>>::BridgedChain, $bridged); - assert_type_eq_all!(<$r as MessagesConfig<$i>>::InboundRelayer, AccountIdOf>); - - assert_type_eq_all!(<$r as MessagesConfig<$i>>::TargetHeaderChain, TargetHeaderChainAdapter<$bridge>); - assert_type_eq_all!(<$r as MessagesConfig<$i>>::SourceHeaderChain, SourceHeaderChainAdapter<$bridge>); + assert_type_eq_all!(<$r as MessagesConfig<$i>>::OutboundPayload, XcmAsPlainPayload); + assert_type_eq_all!(<$r as MessagesConfig<$i>>::InboundPayload, XcmAsPlainPayload); } } ); /// Macro that combines four other macro calls - `assert_chain_types`, `assert_bridge_types`, -/// `assert_bridge_grandpa_pallet_types` and `assert_bridge_messages_pallet_types`. It may be used +/// and `assert_bridge_messages_pallet_types`. It may be used /// at the chain that is implementing complete standard messages bridge (i.e. with bridge GRANDPA /// and messages pallets deployed). #[macro_export] @@ -108,20 +97,15 @@ macro_rules! assert_complete_bridge_types( runtime: $r:path, with_bridged_chain_grandpa_instance: $gi:path, with_bridged_chain_messages_instance: $mi:path, - bridge: $bridge:path, this_chain: $this:path, bridged_chain: $bridged:path, ) => { $crate::assert_chain_types!(runtime: $r, this_chain: $this); - $crate::assert_bridge_grandpa_pallet_types!( - runtime: $r, - with_bridged_chain_grandpa_instance: $gi, - bridged_chain: $bridged - ); $crate::assert_bridge_messages_pallet_types!( runtime: $r, with_bridged_chain_messages_instance: $mi, - bridge: $bridge + this_chain: $this, + bridged_chain: $bridged, ); } ); @@ -184,20 +168,8 @@ where ); } -/// Parameters for asserting messages pallet constants. -#[derive(Debug)] -pub struct AssertBridgeMessagesPalletConstants { - /// Maximal number of unrewarded relayer entries in a confirmation transaction at the bridged - /// chain. - pub max_unrewarded_relayers_in_bridged_confirmation_tx: MessageNonce, - /// Maximal number of unconfirmed messages in a confirmation transaction at the bridged chain. - pub max_unconfirmed_messages_in_bridged_confirmation_tx: MessageNonce, - /// Identifier of the bridged chain. - pub bridged_chain_id: ChainId, -} - /// Test that the constants, used in messages pallet configuration are valid. -pub fn assert_bridge_messages_pallet_constants(params: AssertBridgeMessagesPalletConstants) +pub fn assert_bridge_messages_pallet_constants() where R: pallet_bridge_messages::Config, MI: 'static, @@ -207,27 +179,22 @@ where "ActiveOutboundLanes ({:?}) must not be empty", R::ActiveOutboundLanes::get(), ); + assert!( - R::MaxUnrewardedRelayerEntriesAtInboundLane::get() <= params.max_unrewarded_relayers_in_bridged_confirmation_tx, - "MaxUnrewardedRelayerEntriesAtInboundLane ({}) must be <= than the hardcoded value for bridged chain: {}", - R::MaxUnrewardedRelayerEntriesAtInboundLane::get(), - params.max_unrewarded_relayers_in_bridged_confirmation_tx, - ); - assert!( - R::MaxUnconfirmedMessagesAtInboundLane::get() <= params.max_unconfirmed_messages_in_bridged_confirmation_tx, - "MaxUnrewardedRelayerEntriesAtInboundLane ({}) must be <= than the hardcoded value for bridged chain: {}", - R::MaxUnconfirmedMessagesAtInboundLane::get(), - params.max_unconfirmed_messages_in_bridged_confirmation_tx, + pallet_bridge_messages::BridgedChainOf::::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX + <= pallet_bridge_messages::BridgedChainOf::::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + "MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX ({}) of {:?} is larger than \ + its MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX ({}). This makes \ + no sense", + pallet_bridge_messages::BridgedChainOf::::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + pallet_bridge_messages::BridgedChainOf::::ID, + pallet_bridge_messages::BridgedChainOf::::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, ); - assert_eq!(R::BridgedChainId::get(), params.bridged_chain_id); } /// Parameters for asserting bridge pallet names. #[derive(Debug)] pub struct AssertBridgePalletNames<'a> { - /// Name of the messages pallet, deployed at the bridged chain and used to bridge with this - /// chain. - pub with_this_chain_messages_pallet_name: &'a str, /// Name of the GRANDPA pallet, deployed at this chain and used to bridge with the bridged /// chain. pub with_bridged_chain_grandpa_pallet_name: &'a str, @@ -238,18 +205,22 @@ pub struct AssertBridgePalletNames<'a> { /// Tests that bridge pallet names used in `construct_runtime!()` macro call are matching constants /// from chain primitives crates. -pub fn assert_bridge_pallet_names(params: AssertBridgePalletNames) +fn assert_bridge_pallet_names(params: AssertBridgePalletNames) where - B: MessageBridge, R: pallet_bridge_grandpa::Config + pallet_bridge_messages::Config, GI: 'static, MI: 'static, { - assert_eq!(B::BRIDGED_MESSAGES_PALLET_NAME, params.with_this_chain_messages_pallet_name); + // check that the bridge GRANDPA pallet has required name assert_eq!( pallet_bridge_grandpa::PalletOwner::::storage_value_final_key().to_vec(), - bp_runtime::storage_value_key(params.with_bridged_chain_grandpa_pallet_name, "PalletOwner",).0, + bp_runtime::storage_value_key( + params.with_bridged_chain_grandpa_pallet_name, + "PalletOwner", + ).0, ); + + // check that the bridge messages pallet has required name assert_eq!( pallet_bridge_messages::PalletOwner::::storage_value_final_key().to_vec(), bp_runtime::storage_value_key( @@ -262,35 +233,58 @@ where /// Parameters for asserting complete standard messages bridge. #[derive(Debug)] -pub struct AssertCompleteBridgeConstants<'a> { +pub struct AssertCompleteBridgeConstants { /// Parameters to assert this chain constants. pub this_chain_constants: AssertChainConstants, - /// Parameters to assert messages pallet constants. - pub messages_pallet_constants: AssertBridgeMessagesPalletConstants, - /// Parameters to assert pallet names constants. - pub pallet_names: AssertBridgePalletNames<'a>, } -/// All bridge-related constants tests for the complete standard messages bridge (i.e. with bridge -/// GRANDPA and messages pallets deployed). -pub fn assert_complete_bridge_constants(params: AssertCompleteBridgeConstants) -where +/// All bridge-related constants tests for the complete standard relay-chain messages bridge +/// (i.e. with bridge GRANDPA and messages pallets deployed). +pub fn assert_complete_with_relay_chain_bridge_constants( + params: AssertCompleteBridgeConstants, +) where R: frame_system::Config + pallet_bridge_grandpa::Config + pallet_bridge_messages::Config, GI: 'static, MI: 'static, - B: MessageBridge, { assert_chain_constants::(params.this_chain_constants); assert_bridge_grandpa_pallet_constants::(); - assert_bridge_messages_pallet_constants::(params.messages_pallet_constants); - assert_bridge_pallet_names::(params.pallet_names); + assert_bridge_messages_pallet_constants::(); + assert_bridge_pallet_names::(AssertBridgePalletNames { + with_bridged_chain_grandpa_pallet_name: + >::BridgedChain::WITH_CHAIN_GRANDPA_PALLET_NAME, + with_bridged_chain_messages_pallet_name: + >::BridgedChain::WITH_CHAIN_MESSAGES_PALLET_NAME, + }); +} + +/// All bridge-related constants tests for the complete standard parachain messages bridge +/// (i.e. with bridge GRANDPA, parachains and messages pallets deployed). +pub fn assert_complete_with_parachain_bridge_constants( + params: AssertCompleteBridgeConstants, +) where + R: frame_system::Config + + pallet_bridge_grandpa::Config + + pallet_bridge_messages::Config, + GI: 'static, + MI: 'static, + RelayChain: ChainWithGrandpa, +{ + assert_chain_constants::(params.this_chain_constants); + assert_bridge_grandpa_pallet_constants::(); + assert_bridge_messages_pallet_constants::(); + assert_bridge_pallet_names::(AssertBridgePalletNames { + with_bridged_chain_grandpa_pallet_name: RelayChain::WITH_CHAIN_GRANDPA_PALLET_NAME, + with_bridged_chain_messages_pallet_name: + >::BridgedChain::WITH_CHAIN_MESSAGES_PALLET_NAME, + }); } /// Check that the message lane weights are correct. pub fn check_message_lane_weights< - C: Chain, + C: ChainWithMessages, T: frame_system::Config + pallet_bridge_messages::Config, MessagesPalletInstance: 'static, >( @@ -308,14 +302,20 @@ pub fn check_message_lane_weights< // check basic weight assumptions pallet_bridge_messages::ensure_weights_are_correct::>(); + // check that the maximal message dispatch weight is below hardcoded limit + pallet_bridge_messages::ensure_maximal_message_dispatch::>( + C::maximal_incoming_message_size(), + C::maximal_incoming_message_dispatch_weight(), + ); + // check that weights allow us to receive messages - let max_incoming_message_proof_size = bridged_chain_extra_storage_proof_size - .saturating_add(messages::target::maximal_incoming_message_size(C::max_extrinsic_size())); + let max_incoming_message_proof_size = + bridged_chain_extra_storage_proof_size.saturating_add(C::maximal_incoming_message_size()); pallet_bridge_messages::ensure_able_to_receive_message::>( C::max_extrinsic_size(), C::max_extrinsic_weight(), max_incoming_message_proof_size, - messages::target::maximal_incoming_message_dispatch_weight(C::max_extrinsic_weight()), + C::maximal_incoming_message_dispatch_weight(), ); // check that weights allow us to receive delivery confirmations diff --git a/bridges/bin/runtime-common/src/lib.rs b/bridges/bin/runtime-common/src/lib.rs index 5679acd6006ccb8540f940f0f90363f902d643f7..b65bb6041d5610ce2bdfb63f923f3f24b21dcd7f 100644 --- a/bridges/bin/runtime-common/src/lib.rs +++ b/bridges/bin/runtime-common/src/lib.rs @@ -20,11 +20,10 @@ #![cfg_attr(not(feature = "std"), no_std)] pub mod extensions; -pub mod messages; + pub mod messages_api; pub mod messages_benchmarking; pub mod messages_call_ext; -pub mod messages_generation; pub mod messages_xcm_extension; pub mod parachains_benchmarking; diff --git a/bridges/bin/runtime-common/src/messages.rs b/bridges/bin/runtime-common/src/messages.rs deleted file mode 100644 index 0fe9935dbdb6dfc776977ff8cfbad87d3eee9f6e..0000000000000000000000000000000000000000 --- a/bridges/bin/runtime-common/src/messages.rs +++ /dev/null @@ -1,701 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity Bridges Common is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity Bridges Common. If not, see . - -//! Types that allow runtime to act as a source/target endpoint of message lanes. -//! -//! Messages are assumed to be encoded `Call`s of the target chain. Call-dispatch -//! pallet is used to dispatch incoming messages. Message identified by a tuple -//! of to elements - message lane id and message nonce. - -pub use bp_runtime::{RangeInclusiveExt, UnderlyingChainOf, UnderlyingChainProvider}; - -use bp_header_chain::HeaderChain; -use bp_messages::{ - source_chain::TargetHeaderChain, - target_chain::{ProvedLaneMessages, ProvedMessages, SourceHeaderChain}, - InboundLaneData, LaneId, Message, MessageKey, MessageNonce, MessagePayload, OutboundLaneData, - VerificationError, -}; -use bp_runtime::{Chain, RawStorageProof, Size, StorageProofChecker}; -use codec::{Decode, Encode}; -use frame_support::{traits::Get, weights::Weight}; -use hash_db::Hasher; -use scale_info::TypeInfo; -use sp_runtime::RuntimeDebug; -use sp_std::{marker::PhantomData, vec::Vec}; - -/// Bidirectional message bridge. -pub trait MessageBridge { - /// Name of the paired messages pallet instance at the Bridged chain. - /// - /// Should be the name that is used in the `construct_runtime!()` macro. - const BRIDGED_MESSAGES_PALLET_NAME: &'static str; - - /// This chain in context of message bridge. - type ThisChain: ThisChainWithMessages; - /// Bridged chain in context of message bridge. - type BridgedChain: BridgedChainWithMessages; - /// Bridged header chain. - type BridgedHeaderChain: HeaderChain>; -} - -/// This chain that has `pallet-bridge-messages` module. -pub trait ThisChainWithMessages: UnderlyingChainProvider { - /// Call origin on the chain. - type RuntimeOrigin; -} - -/// Bridged chain that has `pallet-bridge-messages` module. -pub trait BridgedChainWithMessages: UnderlyingChainProvider {} - -/// This chain in context of message bridge. -pub type ThisChain = ::ThisChain; -/// Bridged chain in context of message bridge. -pub type BridgedChain = ::BridgedChain; -/// Hash used on the chain. -pub type HashOf = bp_runtime::HashOf<::Chain>; -/// Hasher used on the chain. -pub type HasherOf = bp_runtime::HasherOf>; -/// Account id used on the chain. -pub type AccountIdOf = bp_runtime::AccountIdOf>; -/// Type of balances that is used on the chain. -pub type BalanceOf = bp_runtime::BalanceOf>; - -/// Sub-module that is declaring types required for processing This -> Bridged chain messages. -pub mod source { - use super::*; - - /// Message payload for This -> Bridged chain messages. - pub type FromThisChainMessagePayload = crate::messages_xcm_extension::XcmAsPlainPayload; - - /// Maximal size of outbound message payload. - pub struct FromThisChainMaximalOutboundPayloadSize(PhantomData); - - impl Get for FromThisChainMaximalOutboundPayloadSize { - fn get() -> u32 { - maximal_message_size::() - } - } - - /// Messages delivery proof from bridged chain: - /// - /// - hash of finalized header; - /// - storage proof of inbound lane state; - /// - lane id. - #[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)] - pub struct FromBridgedChainMessagesDeliveryProof { - /// Hash of the bridge header the proof is for. - pub bridged_header_hash: BridgedHeaderHash, - /// Storage trie proof generated for [`Self::bridged_header_hash`]. - pub storage_proof: RawStorageProof, - /// Lane id of which messages were delivered and the proof is for. - pub lane: LaneId, - } - - impl Size for FromBridgedChainMessagesDeliveryProof { - fn size(&self) -> u32 { - u32::try_from( - self.storage_proof - .iter() - .fold(0usize, |sum, node| sum.saturating_add(node.len())), - ) - .unwrap_or(u32::MAX) - } - } - - /// 'Parsed' message delivery proof - inbound lane id and its state. - pub type ParsedMessagesDeliveryProofFromBridgedChain = - (LaneId, InboundLaneData>>); - - /// Return maximal message size of This -> Bridged chain message. - pub fn maximal_message_size() -> u32 { - super::target::maximal_incoming_message_size( - UnderlyingChainOf::>::max_extrinsic_size(), - ) - } - - /// `TargetHeaderChain` implementation that is using default types and perform default checks. - pub struct TargetHeaderChainAdapter(PhantomData); - - impl TargetHeaderChain>> - for TargetHeaderChainAdapter - { - type MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof>>; - - fn verify_message(payload: &FromThisChainMessagePayload) -> Result<(), VerificationError> { - verify_chain_message::(payload) - } - - fn verify_messages_delivery_proof( - proof: Self::MessagesDeliveryProof, - ) -> Result<(LaneId, InboundLaneData>>), VerificationError> { - verify_messages_delivery_proof::(proof) - } - } - - /// Do basic Bridged-chain specific verification of This -> Bridged chain message. - /// - /// Ok result from this function means that the delivery transaction with this message - /// may be 'mined' by the target chain. - pub fn verify_chain_message( - payload: &FromThisChainMessagePayload, - ) -> Result<(), VerificationError> { - // IMPORTANT: any error that is returned here is fatal for the bridge, because - // this code is executed at the bridge hub and message sender actually lives - // at some sibling parachain. So we are failing **after** the message has been - // sent and we can't report it back to sender (unless error report mechanism is - // embedded into message and its dispatcher). - - // apart from maximal message size check (see below), we should also check the message - // dispatch weight here. But we assume that the bridged chain will just push the message - // to some queue (XCMP, UMP, DMP), so the weight is constant and fits the block. - - // The maximal size of extrinsic at Substrate-based chain depends on the - // `frame_system::Config::MaximumBlockLength` and - // `frame_system::Config::AvailableBlockRatio` constants. This check is here to be sure that - // the lane won't stuck because message is too large to fit into delivery transaction. - // - // **IMPORTANT NOTE**: the delivery transaction contains storage proof of the message, not - // the message itself. The proof is always larger than the message. But unless chain state - // is enormously large, it should be several dozens/hundreds of bytes. The delivery - // transaction also contains signatures and signed extensions. Because of this, we reserve - // 1/3 of the the maximal extrinsic size for this data. - if payload.len() > maximal_message_size::() as usize { - return Err(VerificationError::MessageTooLarge) - } - - Ok(()) - } - - /// Verify proof of This -> Bridged chain messages delivery. - /// - /// This function is used when Bridged chain is directly using GRANDPA finality. For Bridged - /// parachains, please use the `verify_messages_delivery_proof_from_parachain`. - pub fn verify_messages_delivery_proof( - proof: FromBridgedChainMessagesDeliveryProof>>, - ) -> Result, VerificationError> { - let FromBridgedChainMessagesDeliveryProof { bridged_header_hash, storage_proof, lane } = - proof; - let mut storage = - B::BridgedHeaderChain::storage_proof_checker(bridged_header_hash, storage_proof) - .map_err(VerificationError::HeaderChain)?; - // Messages delivery proof is just proof of single storage key read => any error - // is fatal. - let storage_inbound_lane_data_key = bp_messages::storage_keys::inbound_lane_data_key( - B::BRIDGED_MESSAGES_PALLET_NAME, - &lane, - ); - let inbound_lane_data = storage - .read_and_decode_mandatory_value(storage_inbound_lane_data_key.0.as_ref()) - .map_err(VerificationError::InboundLaneStorage)?; - - // check that the storage proof doesn't have any untouched trie nodes - storage.ensure_no_unused_nodes().map_err(VerificationError::StorageProof)?; - - Ok((lane, inbound_lane_data)) - } -} - -/// Sub-module that is declaring types required for processing Bridged -> This chain messages. -pub mod target { - use super::*; - - /// Decoded Bridged -> This message payload. - pub type FromBridgedChainMessagePayload = crate::messages_xcm_extension::XcmAsPlainPayload; - - /// Messages proof from bridged chain: - /// - /// - hash of finalized header; - /// - storage proof of messages and (optionally) outbound lane state; - /// - lane id; - /// - nonces (inclusive range) of messages which are included in this proof. - #[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)] - pub struct FromBridgedChainMessagesProof { - /// Hash of the finalized bridged header the proof is for. - pub bridged_header_hash: BridgedHeaderHash, - /// A storage trie proof of messages being delivered. - pub storage_proof: RawStorageProof, - /// Messages in this proof are sent over this lane. - pub lane: LaneId, - /// Nonce of the first message being delivered. - pub nonces_start: MessageNonce, - /// Nonce of the last message being delivered. - pub nonces_end: MessageNonce, - } - - impl Size for FromBridgedChainMessagesProof { - fn size(&self) -> u32 { - u32::try_from( - self.storage_proof - .iter() - .fold(0usize, |sum, node| sum.saturating_add(node.len())), - ) - .unwrap_or(u32::MAX) - } - } - - /// Return maximal dispatch weight of the message we're able to receive. - pub fn maximal_incoming_message_dispatch_weight(maximal_extrinsic_weight: Weight) -> Weight { - maximal_extrinsic_weight / 2 - } - - /// Return maximal message size given maximal extrinsic size. - pub fn maximal_incoming_message_size(maximal_extrinsic_size: u32) -> u32 { - maximal_extrinsic_size / 3 * 2 - } - - /// `SourceHeaderChain` implementation that is using default types and perform default checks. - pub struct SourceHeaderChainAdapter(PhantomData); - - impl SourceHeaderChain for SourceHeaderChainAdapter { - type MessagesProof = FromBridgedChainMessagesProof>>; - - fn verify_messages_proof( - proof: Self::MessagesProof, - messages_count: u32, - ) -> Result, VerificationError> { - verify_messages_proof::(proof, messages_count) - } - } - - /// Verify proof of Bridged -> This chain messages. - /// - /// This function is used when Bridged chain is directly using GRANDPA finality. For Bridged - /// parachains, please use the `verify_messages_proof_from_parachain`. - /// - /// The `messages_count` argument verification (sane limits) is supposed to be made - /// outside of this function. This function only verifies that the proof declares exactly - /// `messages_count` messages. - pub fn verify_messages_proof( - proof: FromBridgedChainMessagesProof>>, - messages_count: u32, - ) -> Result, VerificationError> { - let FromBridgedChainMessagesProof { - bridged_header_hash, - storage_proof, - lane, - nonces_start, - nonces_end, - } = proof; - let storage = - B::BridgedHeaderChain::storage_proof_checker(bridged_header_hash, storage_proof) - .map_err(VerificationError::HeaderChain)?; - let mut parser = StorageProofCheckerAdapter::<_, B> { storage, _dummy: Default::default() }; - let nonces_range = nonces_start..=nonces_end; - - // receiving proofs where end < begin is ok (if proof includes outbound lane state) - let messages_in_the_proof = nonces_range.checked_len().unwrap_or(0); - if messages_in_the_proof != MessageNonce::from(messages_count) { - return Err(VerificationError::MessagesCountMismatch) - } - - // Read messages first. All messages that are claimed to be in the proof must - // be in the proof. So any error in `read_value`, or even missing value is fatal. - // - // Mind that we allow proofs with no messages if outbound lane state is proved. - let mut messages = Vec::with_capacity(messages_in_the_proof as _); - for nonce in nonces_range { - let message_key = MessageKey { lane_id: lane, nonce }; - let message_payload = parser.read_and_decode_message_payload(&message_key)?; - messages.push(Message { key: message_key, payload: message_payload }); - } - - // Now let's check if proof contains outbound lane state proof. It is optional, so - // we simply ignore `read_value` errors and missing value. - let proved_lane_messages = ProvedLaneMessages { - lane_state: parser.read_and_decode_outbound_lane_data(&lane)?, - messages, - }; - - // Now we may actually check if the proof is empty or not. - if proved_lane_messages.lane_state.is_none() && proved_lane_messages.messages.is_empty() { - return Err(VerificationError::EmptyMessageProof) - } - - // check that the storage proof doesn't have any untouched trie nodes - parser - .storage - .ensure_no_unused_nodes() - .map_err(VerificationError::StorageProof)?; - - // We only support single lane messages in this generated_schema - let mut proved_messages = ProvedMessages::new(); - proved_messages.insert(lane, proved_lane_messages); - - Ok(proved_messages) - } - - struct StorageProofCheckerAdapter { - storage: StorageProofChecker, - _dummy: sp_std::marker::PhantomData, - } - - impl StorageProofCheckerAdapter { - fn read_and_decode_outbound_lane_data( - &mut self, - lane_id: &LaneId, - ) -> Result, VerificationError> { - let storage_outbound_lane_data_key = bp_messages::storage_keys::outbound_lane_data_key( - B::BRIDGED_MESSAGES_PALLET_NAME, - lane_id, - ); - - self.storage - .read_and_decode_opt_value(storage_outbound_lane_data_key.0.as_ref()) - .map_err(VerificationError::OutboundLaneStorage) - } - - fn read_and_decode_message_payload( - &mut self, - message_key: &MessageKey, - ) -> Result { - let storage_message_key = bp_messages::storage_keys::message_key( - B::BRIDGED_MESSAGES_PALLET_NAME, - &message_key.lane_id, - message_key.nonce, - ); - self.storage - .read_and_decode_mandatory_value(storage_message_key.0.as_ref()) - .map_err(VerificationError::MessageStorage) - } - } -} - -/// The `BridgeMessagesCall` used by a chain. -pub type BridgeMessagesCallOf = bp_messages::BridgeMessagesCall< - bp_runtime::AccountIdOf, - target::FromBridgedChainMessagesProof>, - source::FromBridgedChainMessagesDeliveryProof>, ->; - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - messages_generation::{ - encode_all_messages, encode_lane_data, prepare_messages_storage_proof, - }, - mock::*, - }; - use bp_header_chain::{HeaderChainError, StoredHeaderDataBuilder}; - use bp_runtime::{HeaderId, StorageProofError}; - use codec::Encode; - use sp_core::H256; - use sp_runtime::traits::Header as _; - - #[test] - fn verify_chain_message_rejects_message_with_too_large_declared_weight() { - assert!(source::verify_chain_message::(&vec![ - 42; - BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT - - 1 - ]) - .is_err()); - } - - #[test] - fn verify_chain_message_rejects_message_too_large_message() { - assert!(source::verify_chain_message::(&vec![ - 0; - source::maximal_message_size::() - as usize + 1 - ],) - .is_err()); - } - - #[test] - fn verify_chain_message_accepts_maximal_message() { - assert_eq!( - source::verify_chain_message::(&vec![ - 0; - source::maximal_message_size::() - as _ - ],), - Ok(()), - ); - } - - fn using_messages_proof( - nonces_end: MessageNonce, - outbound_lane_data: Option, - encode_message: impl Fn(MessageNonce, &MessagePayload) -> Option>, - encode_outbound_lane_data: impl Fn(&OutboundLaneData) -> Vec, - test: impl Fn(target::FromBridgedChainMessagesProof) -> R, - ) -> R { - let (state_root, storage_proof) = prepare_messages_storage_proof::( - TEST_LANE_ID, - 1..=nonces_end, - outbound_lane_data, - bp_runtime::StorageProofSize::Minimal(0), - vec![42], - encode_message, - encode_outbound_lane_data, - ); - - sp_io::TestExternalities::new(Default::default()).execute_with(move || { - let bridged_header = BridgedChainHeader::new( - 0, - Default::default(), - state_root, - Default::default(), - Default::default(), - ); - let bridged_header_hash = bridged_header.hash(); - - pallet_bridge_grandpa::BestFinalized::::put(HeaderId( - 0, - bridged_header_hash, - )); - pallet_bridge_grandpa::ImportedHeaders::::insert( - bridged_header_hash, - bridged_header.build(), - ); - test(target::FromBridgedChainMessagesProof { - bridged_header_hash, - storage_proof, - lane: TEST_LANE_ID, - nonces_start: 1, - nonces_end, - }) - }) - } - - #[test] - fn messages_proof_is_rejected_if_declared_less_than_actual_number_of_messages() { - assert_eq!( - using_messages_proof(10, None, encode_all_messages, encode_lane_data, |proof| { - target::verify_messages_proof::(proof, 5) - }), - Err(VerificationError::MessagesCountMismatch), - ); - } - - #[test] - fn messages_proof_is_rejected_if_declared_more_than_actual_number_of_messages() { - assert_eq!( - using_messages_proof(10, None, encode_all_messages, encode_lane_data, |proof| { - target::verify_messages_proof::(proof, 15) - }), - Err(VerificationError::MessagesCountMismatch), - ); - } - - #[test] - fn message_proof_is_rejected_if_header_is_missing_from_the_chain() { - assert_eq!( - using_messages_proof(10, None, encode_all_messages, encode_lane_data, |proof| { - let bridged_header_hash = - pallet_bridge_grandpa::BestFinalized::::get().unwrap().1; - pallet_bridge_grandpa::ImportedHeaders::::remove(bridged_header_hash); - target::verify_messages_proof::(proof, 10) - }), - Err(VerificationError::HeaderChain(HeaderChainError::UnknownHeader)), - ); - } - - #[test] - fn message_proof_is_rejected_if_header_state_root_mismatches() { - assert_eq!( - using_messages_proof(10, None, encode_all_messages, encode_lane_data, |proof| { - let bridged_header_hash = - pallet_bridge_grandpa::BestFinalized::::get().unwrap().1; - pallet_bridge_grandpa::ImportedHeaders::::insert( - bridged_header_hash, - BridgedChainHeader::new( - 0, - Default::default(), - Default::default(), - Default::default(), - Default::default(), - ) - .build(), - ); - target::verify_messages_proof::(proof, 10) - }), - Err(VerificationError::HeaderChain(HeaderChainError::StorageProof( - StorageProofError::StorageRootMismatch - ))), - ); - } - - #[test] - fn message_proof_is_rejected_if_it_has_duplicate_trie_nodes() { - assert_eq!( - using_messages_proof(10, None, encode_all_messages, encode_lane_data, |mut proof| { - let node = proof.storage_proof.pop().unwrap(); - proof.storage_proof.push(node.clone()); - proof.storage_proof.push(node); - target::verify_messages_proof::(proof, 10) - },), - Err(VerificationError::HeaderChain(HeaderChainError::StorageProof( - StorageProofError::DuplicateNodesInProof - ))), - ); - } - - #[test] - fn message_proof_is_rejected_if_it_has_unused_trie_nodes() { - assert_eq!( - using_messages_proof(10, None, encode_all_messages, encode_lane_data, |mut proof| { - proof.storage_proof.push(vec![42]); - target::verify_messages_proof::(proof, 10) - },), - Err(VerificationError::StorageProof(StorageProofError::UnusedNodesInTheProof)), - ); - } - - #[test] - fn message_proof_is_rejected_if_required_message_is_missing() { - matches!( - using_messages_proof( - 10, - None, - |n, m| if n != 5 { Some(m.encode()) } else { None }, - encode_lane_data, - |proof| target::verify_messages_proof::(proof, 10) - ), - Err(VerificationError::MessageStorage(StorageProofError::StorageValueEmpty)), - ); - } - - #[test] - fn message_proof_is_rejected_if_message_decode_fails() { - matches!( - using_messages_proof( - 10, - None, - |n, m| { - let mut m = m.encode(); - if n == 5 { - m = vec![42] - } - Some(m) - }, - encode_lane_data, - |proof| target::verify_messages_proof::(proof, 10), - ), - Err(VerificationError::MessageStorage(StorageProofError::StorageValueDecodeFailed(_))), - ); - } - - #[test] - fn message_proof_is_rejected_if_outbound_lane_state_decode_fails() { - matches!( - using_messages_proof( - 10, - Some(OutboundLaneData { - oldest_unpruned_nonce: 1, - latest_received_nonce: 1, - latest_generated_nonce: 1, - }), - encode_all_messages, - |d| { - let mut d = d.encode(); - d.truncate(1); - d - }, - |proof| target::verify_messages_proof::(proof, 10), - ), - Err(VerificationError::OutboundLaneStorage( - StorageProofError::StorageValueDecodeFailed(_) - )), - ); - } - - #[test] - fn message_proof_is_rejected_if_it_is_empty() { - assert_eq!( - using_messages_proof(0, None, encode_all_messages, encode_lane_data, |proof| { - target::verify_messages_proof::(proof, 0) - },), - Err(VerificationError::EmptyMessageProof), - ); - } - - #[test] - fn non_empty_message_proof_without_messages_is_accepted() { - assert_eq!( - using_messages_proof( - 0, - Some(OutboundLaneData { - oldest_unpruned_nonce: 1, - latest_received_nonce: 1, - latest_generated_nonce: 1, - }), - encode_all_messages, - encode_lane_data, - |proof| target::verify_messages_proof::(proof, 0), - ), - Ok(vec![( - TEST_LANE_ID, - ProvedLaneMessages { - lane_state: Some(OutboundLaneData { - oldest_unpruned_nonce: 1, - latest_received_nonce: 1, - latest_generated_nonce: 1, - }), - messages: Vec::new(), - }, - )] - .into_iter() - .collect()), - ); - } - - #[test] - fn non_empty_message_proof_is_accepted() { - assert_eq!( - using_messages_proof( - 1, - Some(OutboundLaneData { - oldest_unpruned_nonce: 1, - latest_received_nonce: 1, - latest_generated_nonce: 1, - }), - encode_all_messages, - encode_lane_data, - |proof| target::verify_messages_proof::(proof, 1), - ), - Ok(vec![( - TEST_LANE_ID, - ProvedLaneMessages { - lane_state: Some(OutboundLaneData { - oldest_unpruned_nonce: 1, - latest_received_nonce: 1, - latest_generated_nonce: 1, - }), - messages: vec![Message { - key: MessageKey { lane_id: TEST_LANE_ID, nonce: 1 }, - payload: vec![42], - }], - }, - )] - .into_iter() - .collect()), - ); - } - - #[test] - fn verify_messages_proof_does_not_panic_if_messages_count_mismatches() { - assert_eq!( - using_messages_proof(1, None, encode_all_messages, encode_lane_data, |mut proof| { - proof.nonces_end = u64::MAX; - target::verify_messages_proof::(proof, u32::MAX) - },), - Err(VerificationError::MessagesCountMismatch), - ); - } -} diff --git a/bridges/bin/runtime-common/src/messages_benchmarking.rs b/bridges/bin/runtime-common/src/messages_benchmarking.rs index 74494f7908045fac601b4c3f64a456ad12dacd6f..1880e65547fe6d5e0af71e6ec7c6e0e214f20866 100644 --- a/bridges/bin/runtime-common/src/messages_benchmarking.rs +++ b/bridges/bin/runtime-common/src/messages_benchmarking.rs @@ -19,23 +19,22 @@ #![cfg(feature = "runtime-benchmarks")] -use crate::{ - messages::{ - source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, - AccountIdOf, BridgedChain, HashOf, MessageBridge, ThisChain, - }, +use bp_messages::{ + source_chain::FromBridgedChainMessagesDeliveryProof, + target_chain::FromBridgedChainMessagesProof, MessagePayload, +}; +use bp_polkadot_core::parachains::ParaHash; +use bp_runtime::{AccountIdOf, Chain, HashOf, Parachain}; +use codec::Encode; +use frame_support::weights::Weight; +use pallet_bridge_messages::{ + benchmarking::{MessageDeliveryProofParams, MessageProofParams}, messages_generation::{ encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof, prepare_messages_storage_proof, }, + BridgedChainOf, ThisChainOf, }; - -use bp_messages::MessagePayload; -use bp_polkadot_core::parachains::ParaHash; -use bp_runtime::{Chain, Parachain, StorageProofSize, UnderlyingChainOf}; -use codec::Encode; -use frame_support::weights::Weight; -use pallet_bridge_messages::benchmarking::{MessageDeliveryProofParams, MessageProofParams}; use sp_runtime::traits::{Header, Zero}; use sp_std::prelude::*; use xcm::latest::prelude::*; @@ -45,11 +44,7 @@ fn prepare_inbound_message( params: &MessageProofParams, successful_dispatch_message_generator: impl Fn(usize) -> MessagePayload, ) -> MessagePayload { - // we only care about **this** message size when message proof needs to be `Minimal` - let expected_size = match params.size { - StorageProofSize::Minimal(size) => size as usize, - _ => 0, - }; + let expected_size = params.proof_params.db_size.unwrap_or(0) as usize; // if we don't need a correct message, then we may just return some random blob if !params.is_successful_dispatch_expected { @@ -75,25 +70,32 @@ fn prepare_inbound_message( /// This method is intended to be used when benchmarking pallet, linked to the chain that /// uses GRANDPA finality. For parachains, please use the `prepare_message_proof_from_parachain` /// function. -pub fn prepare_message_proof_from_grandpa_chain( +pub fn prepare_message_proof_from_grandpa_chain( params: MessageProofParams, message_generator: impl Fn(usize) -> MessagePayload, -) -> (FromBridgedChainMessagesProof>>, Weight) +) -> (FromBridgedChainMessagesProof>>, Weight) where - R: pallet_bridge_grandpa::Config>>, + R: pallet_bridge_grandpa::Config> + + pallet_bridge_messages::Config< + MI, + BridgedHeaderChain = pallet_bridge_grandpa::Pallet, + >, FI: 'static, - B: MessageBridge, + MI: 'static, { // prepare storage proof - let (state_root, storage_proof) = prepare_messages_storage_proof::( - params.lane, - params.message_nonces.clone(), - params.outbound_lane_data.clone(), - params.size, - prepare_inbound_message(¶ms, message_generator), - encode_all_messages, - encode_lane_data, - ); + let (state_root, storage_proof) = + prepare_messages_storage_proof::, ThisChainOf>( + params.lane, + params.message_nonces.clone(), + params.outbound_lane_data.clone(), + params.proof_params, + |_| prepare_inbound_message(¶ms, &message_generator), + encode_all_messages, + encode_lane_data, + false, + false, + ); // update runtime storage let (_, bridged_header_hash) = insert_header_to_grandpa_pallet::(state_root); @@ -118,30 +120,33 @@ where /// This method is intended to be used when benchmarking pallet, linked to the chain that /// uses parachain finality. For GRANDPA chains, please use the /// `prepare_message_proof_from_grandpa_chain` function. -pub fn prepare_message_proof_from_parachain( +pub fn prepare_message_proof_from_parachain( params: MessageProofParams, message_generator: impl Fn(usize) -> MessagePayload, -) -> (FromBridgedChainMessagesProof>>, Weight) +) -> (FromBridgedChainMessagesProof>>, Weight) where - R: pallet_bridge_parachains::Config, + R: pallet_bridge_parachains::Config + pallet_bridge_messages::Config, PI: 'static, - B: MessageBridge, - UnderlyingChainOf>: Chain + Parachain, + MI: 'static, + BridgedChainOf: Chain + Parachain, { // prepare storage proof - let (state_root, storage_proof) = prepare_messages_storage_proof::( - params.lane, - params.message_nonces.clone(), - params.outbound_lane_data.clone(), - params.size, - prepare_inbound_message(¶ms, message_generator), - encode_all_messages, - encode_lane_data, - ); + let (state_root, storage_proof) = + prepare_messages_storage_proof::, ThisChainOf>( + params.lane, + params.message_nonces.clone(), + params.outbound_lane_data.clone(), + params.proof_params, + |_| prepare_inbound_message(¶ms, &message_generator), + encode_all_messages, + encode_lane_data, + false, + false, + ); // update runtime storage let (_, bridged_header_hash) = - insert_header_to_parachains_pallet::>>(state_root); + insert_header_to_parachains_pallet::>(state_root); ( FromBridgedChainMessagesProof { @@ -160,21 +165,24 @@ where /// This method is intended to be used when benchmarking pallet, linked to the chain that /// uses GRANDPA finality. For parachains, please use the /// `prepare_message_delivery_proof_from_parachain` function. -pub fn prepare_message_delivery_proof_from_grandpa_chain( - params: MessageDeliveryProofParams>>, -) -> FromBridgedChainMessagesDeliveryProof>> +pub fn prepare_message_delivery_proof_from_grandpa_chain( + params: MessageDeliveryProofParams>>, +) -> FromBridgedChainMessagesDeliveryProof>> where - R: pallet_bridge_grandpa::Config>>, + R: pallet_bridge_grandpa::Config> + + pallet_bridge_messages::Config< + MI, + BridgedHeaderChain = pallet_bridge_grandpa::Pallet, + >, FI: 'static, - B: MessageBridge, + MI: 'static, { // prepare storage proof let lane = params.lane; - let (state_root, storage_proof) = prepare_message_delivery_storage_proof::( - params.lane, - params.inbound_lane_data, - params.size, - ); + let (state_root, storage_proof) = prepare_message_delivery_storage_proof::< + BridgedChainOf, + ThisChainOf, + >(params.lane, params.inbound_lane_data, params.proof_params); // update runtime storage let (_, bridged_header_hash) = insert_header_to_grandpa_pallet::(state_root); @@ -191,26 +199,25 @@ where /// This method is intended to be used when benchmarking pallet, linked to the chain that /// uses parachain finality. For GRANDPA chains, please use the /// `prepare_message_delivery_proof_from_grandpa_chain` function. -pub fn prepare_message_delivery_proof_from_parachain( - params: MessageDeliveryProofParams>>, -) -> FromBridgedChainMessagesDeliveryProof>> +pub fn prepare_message_delivery_proof_from_parachain( + params: MessageDeliveryProofParams>>, +) -> FromBridgedChainMessagesDeliveryProof>> where - R: pallet_bridge_parachains::Config, + R: pallet_bridge_parachains::Config + pallet_bridge_messages::Config, PI: 'static, - B: MessageBridge, - UnderlyingChainOf>: Chain + Parachain, + MI: 'static, + BridgedChainOf: Chain + Parachain, { // prepare storage proof let lane = params.lane; - let (state_root, storage_proof) = prepare_message_delivery_storage_proof::( - params.lane, - params.inbound_lane_data, - params.size, - ); + let (state_root, storage_proof) = prepare_message_delivery_storage_proof::< + BridgedChainOf, + ThisChainOf, + >(params.lane, params.inbound_lane_data, params.proof_params); // update runtime storage let (_, bridged_header_hash) = - insert_header_to_parachains_pallet::>>(state_root); + insert_header_to_parachains_pallet::>(state_root); FromBridgedChainMessagesDeliveryProof { bridged_header_hash: bridged_header_hash.into(), diff --git a/bridges/bin/runtime-common/src/messages_call_ext.rs b/bridges/bin/runtime-common/src/messages_call_ext.rs index fb07f7b6dd69110918af23b227708e226bede625..a9ee1969ae0ca462f36098f03b4454e1399af129 100644 --- a/bridges/bin/runtime-common/src/messages_call_ext.rs +++ b/bridges/bin/runtime-common/src/messages_call_ext.rs @@ -14,19 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -//! Signed extension for the `pallet-bridge-messages` that is able to reject obsolete -//! (and some other invalid) transactions. +//! Helpers for easier manipulation of call processing with signed extensions. -use crate::messages::{ - source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, +use bp_messages::{ + target_chain::MessageDispatch, ChainWithMessages, InboundLaneData, LaneId, MessageNonce, }; -use bp_messages::{target_chain::MessageDispatch, InboundLaneData, LaneId, MessageNonce}; -use bp_runtime::OwnedBridgeModule; -use frame_support::{ - dispatch::CallableCallFor, - traits::{Get, IsSubType}, -}; -use pallet_bridge_messages::{Config, Pallet}; +use bp_runtime::{AccountIdOf, OwnedBridgeModule}; +use frame_support::{dispatch::CallableCallFor, traits::IsSubType}; +use pallet_bridge_messages::{BridgedChainOf, Config, Pallet}; use sp_runtime::{transaction_validity::TransactionValidity, RuntimeDebug}; use sp_std::ops::RangeInclusive; @@ -213,18 +208,8 @@ pub trait MessagesCallSubType, I: 'static>: } impl< - BridgedHeaderHash, - SourceHeaderChain: bp_messages::target_chain::SourceHeaderChain< - MessagesProof = FromBridgedChainMessagesProof, - >, - TargetHeaderChain: bp_messages::source_chain::TargetHeaderChain< - >::OutboundPayload, - ::AccountId, - MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof, - >, Call: IsSubType, T>>, - T: frame_system::Config - + Config, + T: frame_system::Config + Config, I: 'static, > MessagesCallSubType for T::RuntimeCall { @@ -340,16 +325,17 @@ impl< /// Returns occupation state of unrewarded relayers vector. fn unrewarded_relayers_occupation, I: 'static>( - inbound_lane_data: &InboundLaneData, + inbound_lane_data: &InboundLaneData>>, ) -> UnrewardedRelayerOccupation { UnrewardedRelayerOccupation { - free_relayer_slots: T::MaxUnrewardedRelayerEntriesAtInboundLane::get() + free_relayer_slots: T::BridgedChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX .saturating_sub(inbound_lane_data.relayers.len() as MessageNonce), free_message_slots: { let unconfirmed_messages = inbound_lane_data .last_delivered_nonce() .saturating_sub(inbound_lane_data.last_confirmed_nonce); - T::MaxUnconfirmedMessagesAtInboundLane::get().saturating_sub(unconfirmed_messages) + T::BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX + .saturating_sub(unconfirmed_messages) }, } } @@ -358,22 +344,20 @@ fn unrewarded_relayers_occupation, I: 'static>( mod tests { use super::*; use crate::{ - messages::{ - source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, - }, messages_call_ext::MessagesCallSubType, - mock::{ - DummyMessageDispatch, MaxUnconfirmedMessagesAtInboundLane, - MaxUnrewardedRelayerEntriesAtInboundLane, TestRuntime, ThisChainRuntimeCall, - }, + mock::{BridgedUnderlyingChain, DummyMessageDispatch, TestRuntime, ThisChainRuntimeCall}, + }; + use bp_messages::{ + source_chain::FromBridgedChainMessagesDeliveryProof, + target_chain::FromBridgedChainMessagesProof, DeliveredMessages, UnrewardedRelayer, + UnrewardedRelayersState, }; - use bp_messages::{DeliveredMessages, UnrewardedRelayer, UnrewardedRelayersState}; use sp_std::ops::RangeInclusive; fn fill_unrewarded_relayers() { let mut inbound_lane_state = pallet_bridge_messages::InboundLanes::::get(LaneId([0, 0, 0, 0])); - for n in 0..MaxUnrewardedRelayerEntriesAtInboundLane::get() { + for n in 0..BridgedUnderlyingChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX { inbound_lane_state.relayers.push_back(UnrewardedRelayer { relayer: Default::default(), messages: DeliveredMessages { begin: n + 1, end: n + 1 }, @@ -392,7 +376,7 @@ mod tests { relayer: Default::default(), messages: DeliveredMessages { begin: 1, - end: MaxUnconfirmedMessagesAtInboundLane::get(), + end: BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, }, }); pallet_bridge_messages::InboundLanes::::insert( @@ -418,13 +402,13 @@ mod tests { messages_count: nonces_end.checked_sub(nonces_start).map(|x| x + 1).unwrap_or(0) as u32, dispatch_weight: frame_support::weights::Weight::zero(), - proof: FromBridgedChainMessagesProof { + proof: Box::new(FromBridgedChainMessagesProof { bridged_header_hash: Default::default(), - storage_proof: vec![], + storage_proof: Default::default(), lane: LaneId([0, 0, 0, 0]), nonces_start, nonces_end, - }, + }), }, ) .check_obsolete_call() @@ -508,8 +492,8 @@ mod tests { sp_io::TestExternalities::new(Default::default()).execute_with(|| { fill_unrewarded_messages(); assert!(validate_message_delivery( - MaxUnconfirmedMessagesAtInboundLane::get(), - MaxUnconfirmedMessagesAtInboundLane::get() - 1 + BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX - 1 )); }); } @@ -540,7 +524,7 @@ mod tests { pallet_bridge_messages::Call::::receive_messages_delivery_proof { proof: FromBridgedChainMessagesDeliveryProof { bridged_header_hash: Default::default(), - storage_proof: Vec::new(), + storage_proof: Default::default(), lane: LaneId([0, 0, 0, 0]), }, relayers_state: UnrewardedRelayersState { @@ -608,7 +592,7 @@ mod tests { free_message_slots: if is_empty { 0 } else { - MaxUnconfirmedMessagesAtInboundLane::get() + BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX }, }, }, diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index f49474667896049cfd6aff4bf4a4b0d9d6e73c95..2f248a7162a6cbdcc09d2980a922b1a065127e40 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -18,26 +18,16 @@ #![cfg(test)] -use crate::messages::{ - source::{ - FromThisChainMaximalOutboundPayloadSize, FromThisChainMessagePayload, - TargetHeaderChainAdapter, - }, - target::{FromBridgedChainMessagePayload, SourceHeaderChainAdapter}, - BridgedChainWithMessages, HashOf, MessageBridge, ThisChainWithMessages, -}; +use crate::messages_xcm_extension::XcmAsPlainPayload; -use bp_header_chain::{ChainWithGrandpa, HeaderChain}; +use bp_header_chain::ChainWithGrandpa; use bp_messages::{ target_chain::{DispatchMessage, MessageDispatch}, - LaneId, MessageNonce, + ChainWithMessages, LaneId, MessageNonce, }; use bp_parachains::SingleParaStoredHeaderDataBuilder; use bp_relayers::PayRewardFromAccount; -use bp_runtime::{ - messages::MessageDispatchResult, Chain, ChainId, Parachain, UnderlyingChainProvider, -}; -use codec::{Decode, Encode}; +use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId, Parachain}; use frame_support::{ derive_impl, parameter_types, weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight}, @@ -46,7 +36,7 @@ use pallet_transaction_payment::Multiplier; use sp_runtime::{ testing::H256, traits::{BlakeTwo256, ConstU32, ConstU64, ConstU8}, - FixedPointNumber, Perquintill, + FixedPointNumber, Perquintill, StateVersion, }; /// Account identifier at `ThisChain`. @@ -61,8 +51,6 @@ pub type ThisChainHash = H256; pub type ThisChainHasher = BlakeTwo256; /// Runtime call at `ThisChain`. pub type ThisChainRuntimeCall = RuntimeCall; -/// Runtime call origin at `ThisChain`. -pub type ThisChainCallOrigin = RuntimeOrigin; /// Header of `ThisChain`. pub type ThisChainHeader = sp_runtime::generic::Header; /// Block of `ThisChain`. @@ -100,8 +88,6 @@ pub type TestStakeAndSlash = pallet_bridge_relayers::StakeAndSlashNamed< pub const TEST_LANE_ID: LaneId = LaneId([0, 0, 0, 0]); /// Bridged chain id used in tests. pub const TEST_BRIDGED_CHAIN_ID: ChainId = *b"brdg"; -/// Maximal extrinsic weight at the `BridgedChain`. -pub const BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT: usize = 2048; /// Maximal extrinsic size at the `BridgedChain`. pub const BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE: u32 = 1024; @@ -126,7 +112,6 @@ crate::generate_bridge_reject_obsolete_headers_and_messages! { parameter_types! { pub const ActiveOutboundLanes: &'static [LaneId] = &[TEST_LANE_ID]; - pub const BridgedChainId: ChainId = TEST_BRIDGED_CHAIN_ID; pub const BridgedParasPalletName: &'static str = "Paras"; pub const ExistentialDeposit: ThisChainBalance = 500; pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 1, write: 2 }; @@ -136,8 +121,6 @@ parameter_types! { pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(3, 100_000); pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000u128); pub MaximumMultiplier: Multiplier = sp_runtime::traits::Bounded::max_value(); - pub const MaxUnrewardedRelayerEntriesAtInboundLane: MessageNonce = 16; - pub const MaxUnconfirmedMessagesAtInboundLane: MessageNonce = 1_000; pub const ReserveId: [u8; 8] = *b"brdgrlrs"; } @@ -203,17 +186,12 @@ impl pallet_bridge_messages::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type WeightInfo = pallet_bridge_messages::weights::BridgeWeight; type ActiveOutboundLanes = ActiveOutboundLanes; - type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; - type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; - type MaximalOutboundPayloadSize = FromThisChainMaximalOutboundPayloadSize; - type OutboundPayload = FromThisChainMessagePayload; + type OutboundPayload = XcmAsPlainPayload; - type InboundPayload = FromBridgedChainMessagePayload; - type InboundRelayer = BridgedChainAccountId; + type InboundPayload = Vec; type DeliveryPayments = (); - type TargetHeaderChain = TargetHeaderChainAdapter; type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< TestRuntime, (), @@ -221,9 +199,11 @@ impl pallet_bridge_messages::Config for TestRuntime { >; type OnMessagesDelivered = (); - type SourceHeaderChain = SourceHeaderChainAdapter; type MessageDispatch = DummyMessageDispatch; - type BridgedChainId = BridgedChainId; + + type ThisChain = ThisUnderlyingChain; + type BridgedChain = BridgedUnderlyingChain; + type BridgedHeaderChain = BridgeGrandpa; } impl pallet_bridge_relayers::Config for TestRuntime { @@ -262,55 +242,6 @@ impl MessageDispatch for DummyMessageDispatch { } } -/// Bridge that is deployed on `ThisChain` and allows sending/receiving messages to/from -/// `BridgedChain`. -#[derive(Debug, PartialEq, Eq)] -pub struct OnThisChainBridge; - -impl MessageBridge for OnThisChainBridge { - const BRIDGED_MESSAGES_PALLET_NAME: &'static str = ""; - - type ThisChain = ThisChain; - type BridgedChain = BridgedChain; - type BridgedHeaderChain = pallet_bridge_grandpa::GrandpaChainHeaders; -} - -/// Bridge that is deployed on `BridgedChain` and allows sending/receiving messages to/from -/// `ThisChain`. -#[derive(Debug, PartialEq, Eq)] -pub struct OnBridgedChainBridge; - -impl MessageBridge for OnBridgedChainBridge { - const BRIDGED_MESSAGES_PALLET_NAME: &'static str = ""; - - type ThisChain = BridgedChain; - type BridgedChain = ThisChain; - type BridgedHeaderChain = ThisHeaderChain; -} - -/// Dummy implementation of `HeaderChain` for `ThisChain` at the `BridgedChain`. -pub struct ThisHeaderChain; - -impl HeaderChain for ThisHeaderChain { - fn finalized_header_state_root(_hash: HashOf) -> Option> { - unreachable!() - } -} - -/// Call origin at `BridgedChain`. -#[derive(Clone, Debug)] -pub struct BridgedChainOrigin; - -impl From - for Result, BridgedChainOrigin> -{ - fn from( - _origin: BridgedChainOrigin, - ) -> Result, BridgedChainOrigin> { - unreachable!() - } -} - /// Underlying chain of `ThisChain`. pub struct ThisUnderlyingChain; @@ -326,6 +257,8 @@ impl Chain for ThisUnderlyingChain { type Nonce = u32; type Signature = sp_runtime::MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE } @@ -335,29 +268,20 @@ impl Chain for ThisUnderlyingChain { } } -/// The chain where we are in tests. -pub struct ThisChain; - -impl UnderlyingChainProvider for ThisChain { - type Chain = ThisUnderlyingChain; -} +impl ChainWithMessages for ThisUnderlyingChain { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = ""; -impl ThisChainWithMessages for ThisChain { - type RuntimeOrigin = ThisChainCallOrigin; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1000; } -impl BridgedChainWithMessages for ThisChain {} - /// Underlying chain of `BridgedChain`. pub struct BridgedUnderlyingChain; /// Some parachain under `BridgedChain` consensus. pub struct BridgedUnderlyingParachain; -/// Runtime call of the `BridgedChain`. -#[derive(Decode, Encode)] -pub struct BridgedChainCall; impl Chain for BridgedUnderlyingChain { - const ID: ChainId = *b"buch"; + const ID: ChainId = TEST_BRIDGED_CHAIN_ID; type BlockNumber = BridgedChainBlockNumber; type Hash = BridgedChainHash; @@ -368,6 +292,8 @@ impl Chain for BridgedUnderlyingChain { type Nonce = u32; type Signature = sp_runtime::MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE } @@ -384,6 +310,12 @@ impl ChainWithGrandpa for BridgedUnderlyingChain { const AVERAGE_HEADER_SIZE: u32 = 64; } +impl ChainWithMessages for BridgedUnderlyingChain { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = ""; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1000; +} + impl Chain for BridgedUnderlyingParachain { const ID: ChainId = *b"bupc"; @@ -396,6 +328,8 @@ impl Chain for BridgedUnderlyingParachain { type Nonce = u32; type Signature = sp_runtime::MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE } @@ -409,19 +343,6 @@ impl Parachain for BridgedUnderlyingParachain { const MAX_HEADER_SIZE: u32 = 1_024; } -/// The other, bridged chain, used in tests. -pub struct BridgedChain; - -impl UnderlyingChainProvider for BridgedChain { - type Chain = BridgedUnderlyingChain; -} - -impl ThisChainWithMessages for BridgedChain { - type RuntimeOrigin = BridgedChainOrigin; -} - -impl BridgedChainWithMessages for BridgedChain {} - /// Run test within test externalities. pub fn run_test(test: impl FnOnce()) { sp_io::TestExternalities::new(Default::default()).execute_with(test) diff --git a/bridges/bin/runtime-common/src/parachains_benchmarking.rs b/bridges/bin/runtime-common/src/parachains_benchmarking.rs index b3050b9ac0f3ccec617399d3eb91647dcab7eb3d..bcbd779b44dea5fbef7781335cfa1d359ab8c1f1 100644 --- a/bridges/bin/runtime-common/src/parachains_benchmarking.rs +++ b/bridges/bin/runtime-common/src/parachains_benchmarking.rs @@ -18,14 +18,11 @@ #![cfg(feature = "runtime-benchmarks")] -use crate::{ - messages_benchmarking::insert_header_to_grandpa_pallet, - messages_generation::grow_trie_leaf_value, -}; +use crate::messages_benchmarking::insert_header_to_grandpa_pallet; use bp_parachains::parachain_head_storage_key_at_source; use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}; -use bp_runtime::{record_all_trie_keys, StorageProofSize}; +use bp_runtime::{grow_storage_value, record_all_trie_keys, Chain, UnverifiedStorageProofParams}; use codec::Encode; use frame_support::traits::Get; use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; @@ -39,14 +36,14 @@ use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, TrieMut}; pub fn prepare_parachain_heads_proof( parachains: &[ParaId], parachain_head_size: u32, - size: StorageProofSize, + proof_params: UnverifiedStorageProofParams, ) -> (RelayBlockNumber, RelayBlockHash, ParaHeadsProof, Vec<(ParaId, ParaHash)>) where R: pallet_bridge_parachains::Config + pallet_bridge_grandpa::Config, PI: 'static, >::BridgedChain: - bp_runtime::Chain, + Chain, { let parachain_head = ParaHead(vec![0u8; parachain_head_size as usize]); @@ -64,7 +61,7 @@ where let storage_key = parachain_head_storage_key_at_source(R::ParasPalletName::get(), *parachain); let leaf_data = if i == 0 { - grow_trie_leaf_value(parachain_head.encode(), size) + grow_storage_value(parachain_head.encode(), &proof_params) } else { parachain_head.encode() }; diff --git a/bridges/chains/chain-asset-hub-rococo/Cargo.toml b/bridges/chains/chain-asset-hub-rococo/Cargo.toml index d9afe2c8bf76713104beead1ad4c36dc08dae1ed..b765fbc57bb0aec2eb4544a01dd84c057ced16ef 100644 --- a/bridges/chains/chain-asset-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-asset-hub-rococo/Cargo.toml @@ -11,14 +11,14 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { workspace = true } +scale-info = { features = ["derive"], workspace = true } # Substrate Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-support = { workspace = true } # Bridge Dependencies -bp-xcm-bridge-hub-router = { path = "../../primitives/xcm-bridge-hub-router", default-features = false } +bp-xcm-bridge-hub-router = { workspace = true } [features] default = ["std"] diff --git a/bridges/chains/chain-asset-hub-westend/Cargo.toml b/bridges/chains/chain-asset-hub-westend/Cargo.toml index 4b3ed052f1382d0c7f076ad5152c861f60d8bef1..ff89864fb2db4667d7929ef540ad4ec46cf2a36c 100644 --- a/bridges/chains/chain-asset-hub-westend/Cargo.toml +++ b/bridges/chains/chain-asset-hub-westend/Cargo.toml @@ -11,14 +11,14 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { workspace = true } +scale-info = { features = ["derive"], workspace = true } # Substrate Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-support = { workspace = true } # Bridge Dependencies -bp-xcm-bridge-hub-router = { path = "../../primitives/xcm-bridge-hub-router", default-features = false } +bp-xcm-bridge-hub-router = { workspace = true } [features] default = ["std"] diff --git a/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml b/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml index 4b900002a4d81abb9d7364f555a150a2af6c839c..5609398385f98b9d3731b196a057e939b1c099de 100644 --- a/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml @@ -13,19 +13,19 @@ workspace = true [dependencies] # Bridge Dependencies -bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } -bp-messages = { path = "../../primitives/messages", default-features = false } -bp-runtime = { path = "../../primitives/runtime", default-features = false } +bp-polkadot-core = { workspace = true } +bp-messages = { workspace = true } +bp-runtime = { workspace = true } # Substrate Based Dependencies -frame-system = { path = "../../../substrate/frame/system", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-system = { workspace = true } +frame-support = { workspace = true } +sp-api = { workspace = true } +sp-std = { workspace = true } # Polkadot Dependencies -polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false } +polkadot-primitives = { workspace = true } [features] default = ["std"] diff --git a/bridges/chains/chain-bridge-hub-kusama/Cargo.toml b/bridges/chains/chain-bridge-hub-kusama/Cargo.toml index ff6dd8849abe3897f1c3eb3cb1de8b7d89af5ca7..605643b0a4eb7e5d514edb1d4f1ad9db65a2c8ec 100644 --- a/bridges/chains/chain-bridge-hub-kusama/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-kusama/Cargo.toml @@ -13,16 +13,16 @@ workspace = true [dependencies] # Bridge Dependencies -bp-bridge-hub-cumulus = { path = "../chain-bridge-hub-cumulus", default-features = false } -bp-runtime = { path = "../../primitives/runtime", default-features = false } -bp-messages = { path = "../../primitives/messages", default-features = false } +bp-bridge-hub-cumulus = { workspace = true } +bp-runtime = { workspace = true } +bp-messages = { workspace = true } # Substrate Based Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +sp-api = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } [features] default = ["std"] diff --git a/bridges/chains/chain-bridge-hub-kusama/src/lib.rs b/bridges/chains/chain-bridge-hub-kusama/src/lib.rs index ef3ef4ab7b7a9bc111218e3c53091ac232f34721..c990e8a12f367cafbd35b0693b323a6ec5fb5e96 100644 --- a/bridges/chains/chain-bridge-hub-kusama/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-kusama/src/lib.rs @@ -29,7 +29,7 @@ use frame_support::{ dispatch::DispatchClass, sp_runtime::{MultiAddress, MultiSigner}, }; -use sp_runtime::RuntimeDebug; +use sp_runtime::{RuntimeDebug, StateVersion}; /// BridgeHubKusama parachain. #[derive(RuntimeDebug)] @@ -48,6 +48,8 @@ impl Chain for BridgeHubKusama { type Nonce = Nonce; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { *BlockLength::get().max.get(DispatchClass::Normal) } diff --git a/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml b/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml index da8b8a82fa702eeab719335fa9968b78ee965163..97e36a19c748c0e5da990eda75bdbed9aa444e6f 100644 --- a/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml @@ -14,16 +14,16 @@ workspace = true # Bridge Dependencies -bp-bridge-hub-cumulus = { path = "../chain-bridge-hub-cumulus", default-features = false } -bp-runtime = { path = "../../primitives/runtime", default-features = false } -bp-messages = { path = "../../primitives/messages", default-features = false } +bp-bridge-hub-cumulus = { workspace = true } +bp-runtime = { workspace = true } +bp-messages = { workspace = true } # Substrate Based Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +sp-api = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } [features] default = ["std"] diff --git a/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs b/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs index 9db71af928e5df01170cf4ab8bf5f20cd72f7610..7379b8863b1de5c1a1482db90077e958f0a33366 100644 --- a/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs @@ -26,7 +26,7 @@ use bp_runtime::{ decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, Chain, ChainId, Parachain, }; use frame_support::dispatch::DispatchClass; -use sp_runtime::RuntimeDebug; +use sp_runtime::{RuntimeDebug, StateVersion}; /// BridgeHubPolkadot parachain. #[derive(RuntimeDebug)] @@ -45,6 +45,8 @@ impl Chain for BridgeHubPolkadot { type Nonce = Nonce; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { *BlockLength::get().max.get(DispatchClass::Normal) } diff --git a/bridges/chains/chain-bridge-hub-rococo/Cargo.toml b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml index f7672df012f2fc2a21cfc987468427a3222317ea..5c918470322353c32556c3e5d381fb2ea713b2ab 100644 --- a/bridges/chains/chain-bridge-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml @@ -13,16 +13,16 @@ workspace = true [dependencies] # Bridge Dependencies -bp-bridge-hub-cumulus = { path = "../chain-bridge-hub-cumulus", default-features = false } -bp-runtime = { path = "../../primitives/runtime", default-features = false } -bp-messages = { path = "../../primitives/messages", default-features = false } +bp-bridge-hub-cumulus = { workspace = true } +bp-runtime = { workspace = true } +bp-messages = { workspace = true } # Substrate Based Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +sp-api = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } [features] default = ["std"] diff --git a/bridges/chains/chain-bridge-hub-rococo/src/lib.rs b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs index d7097f01c5316a58851f400a86b98eda3d7e8bcc..73af997b9950ef640040e44cbba0b93b6a7a56a3 100644 --- a/bridges/chains/chain-bridge-hub-rococo/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs @@ -25,8 +25,10 @@ use bp_messages::*; use bp_runtime::{ decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, Chain, ChainId, Parachain, }; -use frame_support::dispatch::DispatchClass; -use sp_runtime::{MultiAddress, MultiSigner, RuntimeDebug}; +use frame_support::{ + dispatch::DispatchClass, + sp_runtime::{MultiAddress, MultiSigner, RuntimeDebug, StateVersion}, +}; /// BridgeHubRococo parachain. #[derive(RuntimeDebug)] @@ -45,6 +47,8 @@ impl Chain for BridgeHubRococo { type Nonce = Nonce; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { *BlockLength::get().max.get(DispatchClass::Normal) } @@ -103,10 +107,10 @@ frame_support::parameter_types! { pub const BridgeHubRococoBaseXcmFeeInRocs: u128 = 59_034_266; /// Transaction fee that is paid at the Rococo BridgeHub for delivering single inbound message. - /// (initially was calculated by test `BridgeHubRococo::can_calculate_fee_for_complex_message_delivery_transaction` + `33%`) + /// (initially was calculated by test `BridgeHubRococo::can_calculate_fee_for_standalone_message_delivery_transaction` + `33%`) pub const BridgeHubRococoBaseDeliveryFeeInRocs: u128 = 314_037_860; /// Transaction fee that is paid at the Rococo BridgeHub for delivering single outbound message confirmation. - /// (initially was calculated by test `BridgeHubRococo::can_calculate_fee_for_complex_message_confirmation_transaction` + `33%`) + /// (initially was calculated by test `BridgeHubRococo::can_calculate_fee_for_standalone_message_confirmation_transaction` + `33%`) pub const BridgeHubRococoBaseConfirmationFeeInRocs: u128 = 57_414_813; } diff --git a/bridges/chains/chain-bridge-hub-westend/Cargo.toml b/bridges/chains/chain-bridge-hub-westend/Cargo.toml index ec74c4b947d693dba92d4da5051526e49349e0a5..0b429ab9a0bd9793a9129ed8483a608f71bfb44c 100644 --- a/bridges/chains/chain-bridge-hub-westend/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-westend/Cargo.toml @@ -14,16 +14,16 @@ workspace = true # Bridge Dependencies -bp-bridge-hub-cumulus = { path = "../chain-bridge-hub-cumulus", default-features = false } -bp-runtime = { path = "../../primitives/runtime", default-features = false } -bp-messages = { path = "../../primitives/messages", default-features = false } +bp-bridge-hub-cumulus = { workspace = true } +bp-runtime = { workspace = true } +bp-messages = { workspace = true } # Substrate Based Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +sp-api = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } [features] default = ["std"] diff --git a/bridges/chains/chain-bridge-hub-westend/src/lib.rs b/bridges/chains/chain-bridge-hub-westend/src/lib.rs index 800f290d7bfa41cec4139e80a7dc9ea8962a6da5..17ff2c858a1d3eeae329cb972d95adc32952ede4 100644 --- a/bridges/chains/chain-bridge-hub-westend/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-westend/src/lib.rs @@ -25,7 +25,7 @@ use bp_runtime::{ decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, Chain, ChainId, Parachain, }; use frame_support::dispatch::DispatchClass; -use sp_runtime::RuntimeDebug; +use sp_runtime::{RuntimeDebug, StateVersion}; /// BridgeHubWestend parachain. #[derive(RuntimeDebug)] @@ -44,6 +44,8 @@ impl Chain for BridgeHubWestend { type Nonce = Nonce; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { *BlockLength::get().max.get(DispatchClass::Normal) } diff --git a/bridges/chains/chain-kusama/Cargo.toml b/bridges/chains/chain-kusama/Cargo.toml index 66061ff2793cbdd3419fa8894ab78e37486102ea..ec45c1eddce5d3b7be1f3a8ae9b83ca6332e7c28 100644 --- a/bridges/chains/chain-kusama/Cargo.toml +++ b/bridges/chains/chain-kusama/Cargo.toml @@ -14,15 +14,15 @@ workspace = true # Bridge Dependencies -bp-header-chain = { path = "../../primitives/header-chain", default-features = false } -bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } -bp-runtime = { path = "../../primitives/runtime", default-features = false } +bp-header-chain = { workspace = true } +bp-polkadot-core = { workspace = true } +bp-runtime = { workspace = true } # Substrate Based Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +sp-api = { workspace = true } +sp-std = { workspace = true } [features] default = ["std"] diff --git a/bridges/chains/chain-kusama/src/lib.rs b/bridges/chains/chain-kusama/src/lib.rs index fd7172c5869d468ff534e54f9ef6278cf86a88ed..dcd0b23abbbefa2dfba741d6934b5d5510c93017 100644 --- a/bridges/chains/chain-kusama/src/lib.rs +++ b/bridges/chains/chain-kusama/src/lib.rs @@ -23,7 +23,7 @@ pub use bp_polkadot_core::*; use bp_header_chain::ChainWithGrandpa; use bp_runtime::{decl_bridge_finality_runtime_apis, Chain, ChainId}; -use frame_support::weights::Weight; +use frame_support::{sp_runtime::StateVersion, weights::Weight}; /// Kusama Chain pub struct Kusama; @@ -41,6 +41,8 @@ impl Chain for Kusama { type Nonce = Nonce; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V0; + fn max_extrinsic_size() -> u32 { max_extrinsic_size() } diff --git a/bridges/chains/chain-polkadot-bulletin/Cargo.toml b/bridges/chains/chain-polkadot-bulletin/Cargo.toml index 700247b7055a891bec2d4a40bfd126720a0d952c..ea5f4d2e77591bd8840e869f9b3567df5d56fd56 100644 --- a/bridges/chains/chain-polkadot-bulletin/Cargo.toml +++ b/bridges/chains/chain-polkadot-bulletin/Cargo.toml @@ -11,23 +11,23 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } # Bridge Dependencies -bp-header-chain = { path = "../../primitives/header-chain", default-features = false } -bp-messages = { path = "../../primitives/messages", default-features = false } -bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } -bp-runtime = { path = "../../primitives/runtime", default-features = false } +bp-header-chain = { workspace = true } +bp-messages = { workspace = true } +bp-polkadot-core = { workspace = true } +bp-runtime = { workspace = true } # Substrate Based Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-api = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } [features] default = ["std"] diff --git a/bridges/chains/chain-polkadot-bulletin/src/lib.rs b/bridges/chains/chain-polkadot-bulletin/src/lib.rs index f3d300567f2b4f92cec272e0929a3c53d718c823..88980a9575016bd5c5e1428329454e8131a2075d 100644 --- a/bridges/chains/chain-polkadot-bulletin/src/lib.rs +++ b/bridges/chains/chain-polkadot-bulletin/src/lib.rs @@ -37,7 +37,9 @@ use frame_support::{ }; use frame_system::limits; use scale_info::TypeInfo; -use sp_runtime::{traits::DispatchInfoOf, transaction_validity::TransactionValidityError, Perbill}; +use sp_runtime::{ + traits::DispatchInfoOf, transaction_validity::TransactionValidityError, Perbill, StateVersion, +}; // This chain reuses most of Polkadot primitives. pub use bp_polkadot_core::{ @@ -192,6 +194,8 @@ impl Chain for PolkadotBulletin { type Nonce = Nonce; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { *BlockLength::get().max.get(DispatchClass::Normal) } diff --git a/bridges/chains/chain-polkadot/Cargo.toml b/bridges/chains/chain-polkadot/Cargo.toml index c700935f3083b5f287277c7d9975be53352b2506..50f637af4251c8a7ed822861281a217ec12bdb28 100644 --- a/bridges/chains/chain-polkadot/Cargo.toml +++ b/bridges/chains/chain-polkadot/Cargo.toml @@ -14,15 +14,15 @@ workspace = true # Bridge Dependencies -bp-header-chain = { path = "../../primitives/header-chain", default-features = false } -bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } -bp-runtime = { path = "../../primitives/runtime", default-features = false } +bp-header-chain = { workspace = true } +bp-polkadot-core = { workspace = true } +bp-runtime = { workspace = true } # Substrate Based Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +sp-api = { workspace = true } +sp-std = { workspace = true } [features] default = ["std"] diff --git a/bridges/chains/chain-polkadot/src/lib.rs b/bridges/chains/chain-polkadot/src/lib.rs index a8cac0467d574e9355a8fe9ba2e7c2378019349d..f4b262d40735d7470a4d7e289f24bc1d4556d039 100644 --- a/bridges/chains/chain-polkadot/src/lib.rs +++ b/bridges/chains/chain-polkadot/src/lib.rs @@ -25,7 +25,7 @@ use bp_header_chain::ChainWithGrandpa; use bp_runtime::{ decl_bridge_finality_runtime_apis, extensions::PrevalidateAttests, Chain, ChainId, }; -use frame_support::weights::Weight; +use frame_support::{sp_runtime::StateVersion, weights::Weight}; /// Polkadot Chain pub struct Polkadot; @@ -43,6 +43,8 @@ impl Chain for Polkadot { type Nonce = Nonce; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V0; + fn max_extrinsic_size() -> u32 { max_extrinsic_size() } diff --git a/bridges/chains/chain-rococo/Cargo.toml b/bridges/chains/chain-rococo/Cargo.toml index 5a5613bb376a5a4f75c773b3350993262149f973..49a1a397ee096532cfc0b5d3a42cf14469f8ed46 100644 --- a/bridges/chains/chain-rococo/Cargo.toml +++ b/bridges/chains/chain-rococo/Cargo.toml @@ -14,15 +14,15 @@ workspace = true # Bridge Dependencies -bp-header-chain = { path = "../../primitives/header-chain", default-features = false } -bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } -bp-runtime = { path = "../../primitives/runtime", default-features = false } +bp-header-chain = { workspace = true } +bp-polkadot-core = { workspace = true } +bp-runtime = { workspace = true } # Substrate Based Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +sp-api = { workspace = true } +sp-std = { workspace = true } [features] default = ["std"] diff --git a/bridges/chains/chain-rococo/src/lib.rs b/bridges/chains/chain-rococo/src/lib.rs index b290fe71c829d08130556a2b061c0d63f0787d4c..bfcafdf41ea2e629c9a58f2545016b2e776375b8 100644 --- a/bridges/chains/chain-rococo/src/lib.rs +++ b/bridges/chains/chain-rococo/src/lib.rs @@ -23,7 +23,7 @@ pub use bp_polkadot_core::*; use bp_header_chain::ChainWithGrandpa; use bp_runtime::{decl_bridge_finality_runtime_apis, Chain, ChainId}; -use frame_support::weights::Weight; +use frame_support::{sp_runtime::StateVersion, weights::Weight}; /// Rococo Chain pub struct Rococo; @@ -41,6 +41,8 @@ impl Chain for Rococo { type Nonce = Nonce; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { max_extrinsic_size() } diff --git a/bridges/chains/chain-westend/Cargo.toml b/bridges/chains/chain-westend/Cargo.toml index 10b06d76507ef95bbff00f5560b705ecee1ec4ce..5e27bc647bfc5f07d5ab029307ef6dcf67121fb3 100644 --- a/bridges/chains/chain-westend/Cargo.toml +++ b/bridges/chains/chain-westend/Cargo.toml @@ -14,15 +14,15 @@ workspace = true # Bridge Dependencies -bp-header-chain = { path = "../../primitives/header-chain", default-features = false } -bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } -bp-runtime = { path = "../../primitives/runtime", default-features = false } +bp-header-chain = { workspace = true } +bp-polkadot-core = { workspace = true } +bp-runtime = { workspace = true } # Substrate Based Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +sp-api = { workspace = true } +sp-std = { workspace = true } [features] default = ["std"] diff --git a/bridges/chains/chain-westend/src/lib.rs b/bridges/chains/chain-westend/src/lib.rs index ef451f7de0a9640bc1a278e1c712bbb099193ceb..2a247e03e59d666d3c5dd54d74e3a4f852a60bd3 100644 --- a/bridges/chains/chain-westend/src/lib.rs +++ b/bridges/chains/chain-westend/src/lib.rs @@ -23,7 +23,7 @@ pub use bp_polkadot_core::*; use bp_header_chain::ChainWithGrandpa; use bp_runtime::{decl_bridge_finality_runtime_apis, Chain, ChainId}; -use frame_support::weights::Weight; +use frame_support::{sp_runtime::StateVersion, weights::Weight}; /// Westend Chain pub struct Westend; @@ -41,6 +41,8 @@ impl Chain for Westend { type Nonce = Nonce; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { max_extrinsic_size() } diff --git a/bridges/modules/beefy/Cargo.toml b/bridges/modules/beefy/Cargo.toml index e36bbb615f23a20d4ef4a4f4ea8418e752d5b01f..cffc62d290828f032c5c57f27982e7f60f9b94ef 100644 --- a/bridges/modules/beefy/Cargo.toml +++ b/bridges/modules/beefy/Cargo.toml @@ -12,32 +12,32 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } +codec = { workspace = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } serde = { optional = true, workspace = true } # Bridge Dependencies -bp-beefy = { path = "../../primitives/beefy", default-features = false } -bp-runtime = { path = "../../primitives/runtime", default-features = false } +bp-beefy = { workspace = true } +bp-runtime = { workspace = true } # Substrate Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } [dev-dependencies] -sp-consensus-beefy = { path = "../../../substrate/primitives/consensus/beefy" } -mmr-lib = { package = "ckb-merkle-mountain-range", version = "0.5.2" } -pallet-beefy-mmr = { path = "../../../substrate/frame/beefy-mmr" } -pallet-mmr = { path = "../../../substrate/frame/merkle-mountain-range" } -rand = "0.8.5" -sp-io = { path = "../../../substrate/primitives/io" } -bp-test-utils = { path = "../../primitives/test-utils" } +sp-consensus-beefy = { workspace = true, default-features = true } +mmr-lib = { workspace = true } +pallet-beefy-mmr = { workspace = true, default-features = true } +pallet-mmr = { workspace = true, default-features = true } +rand = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +bp-test-utils = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/bridges/modules/beefy/src/mock.rs b/bridges/modules/beefy/src/mock.rs index 53efd57c29a0dfc870e43be4fec7bcdf817a3282..3b751ddf066c9562cd8fc0f054b1b103306479dd 100644 --- a/bridges/modules/beefy/src/mock.rs +++ b/bridges/modules/beefy/src/mock.rs @@ -29,6 +29,7 @@ use sp_core::{sr25519::Signature, Pair}; use sp_runtime::{ testing::{Header, H256}, traits::{BlakeTwo256, Hash}, + StateVersion, }; pub use sp_consensus_beefy::ecdsa_crypto::{AuthorityId as BeefyId, Pair as BeefyPair}; @@ -93,6 +94,8 @@ impl Chain for TestBridgedChain { type Nonce = u64; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { unreachable!() } diff --git a/bridges/modules/grandpa/Cargo.toml b/bridges/modules/grandpa/Cargo.toml index 0ca6b67503511976ea9122f64e3c2e515e971177..6d1419ae5b030733ad9fb38a6a459ab7ce34f99f 100644 --- a/bridges/modules/grandpa/Cargo.toml +++ b/bridges/modules/grandpa/Cargo.toml @@ -13,32 +13,31 @@ workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -finality-grandpa = { version = "0.16.2", default-features = false } +codec = { workspace = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } # Bridge Dependencies -bp-runtime = { path = "../../primitives/runtime", default-features = false } -bp-header-chain = { path = "../../primitives/header-chain", default-features = false } +bp-runtime = { workspace = true } +bp-header-chain = { workspace = true } # Substrate Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -sp-consensus-grandpa = { path = "../../../substrate/primitives/consensus/grandpa", default-features = false, features = ["serde"] } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false, features = ["serde"] } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-consensus-grandpa = { features = ["serde"], workspace = true } +sp-runtime = { features = ["serde"], workspace = true } +sp-std = { workspace = true } # Optional Benchmarking Dependencies -bp-test-utils = { path = "../../primitives/test-utils", default-features = false, optional = true } -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } +bp-test-utils = { optional = true, workspace = true } +frame-benchmarking = { optional = true, workspace = true } [dev-dependencies] -sp-core = { path = "../../../substrate/primitives/core" } -sp-io = { path = "../../../substrate/primitives/io" } +bp-runtime = { features = ["test-helpers"], workspace = true } +sp-core = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } [features] default = ["std"] @@ -47,7 +46,6 @@ std = [ "bp-runtime/std", "bp-test-utils/std", "codec/std", - "finality-grandpa/std", "frame-benchmarking/std", "frame-support/std", "frame-system/std", @@ -56,7 +54,6 @@ std = [ "sp-consensus-grandpa/std", "sp-runtime/std", "sp-std/std", - "sp-trie/std", ] runtime-benchmarks = [ "bp-test-utils", diff --git a/bridges/modules/grandpa/src/lib.rs b/bridges/modules/grandpa/src/lib.rs index 3b77f676870e1a28b8367f1b14d24c9ca83ece4a..c62951b74656b052d4858dec2af1393e41553029 100644 --- a/bridges/modules/grandpa/src/lib.rs +++ b/bridges/modules/grandpa/src/lib.rs @@ -1443,11 +1443,14 @@ mod tests { } #[test] - fn parse_finalized_storage_proof_rejects_proof_on_unknown_header() { + fn verify_storage_proof_rejects_unknown_header() { run_test(|| { assert_noop!( - Pallet::::storage_proof_checker(Default::default(), vec![],) - .map(|_| ()), + Pallet::::verify_storage_proof( + Default::default(), + Default::default(), + ) + .map(|_| ()), bp_header_chain::HeaderChainError::UnknownHeader, ); }); @@ -1465,9 +1468,7 @@ mod tests { >::put(HeaderId(2, hash)); >::insert(hash, header.build()); - assert_ok!( - Pallet::::storage_proof_checker(hash, storage_proof).map(|_| ()) - ); + assert_ok!(Pallet::::verify_storage_proof(hash, storage_proof).map(|_| ())); }); } diff --git a/bridges/modules/grandpa/src/mock.rs b/bridges/modules/grandpa/src/mock.rs index 27df9d9c78f540d0d73f74c6a86ba19af30d4b6b..71af6182e057cca3d06b98ee6fe94283b93ab77d 100644 --- a/bridges/modules/grandpa/src/mock.rs +++ b/bridges/modules/grandpa/src/mock.rs @@ -20,7 +20,8 @@ use bp_header_chain::ChainWithGrandpa; use bp_runtime::{Chain, ChainId}; use frame_support::{ - construct_runtime, derive_impl, parameter_types, traits::Hooks, weights::Weight, + construct_runtime, derive_impl, parameter_types, sp_runtime::StateVersion, traits::Hooks, + weights::Weight, }; use sp_core::sr25519::Signature; @@ -78,6 +79,8 @@ impl Chain for TestBridgedChain { type Nonce = u64; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { unreachable!() } diff --git a/bridges/modules/messages/Cargo.toml b/bridges/modules/messages/Cargo.toml index 71c86ccc0361708684d0a93166f858118dbf0d92..33f524030d264e4ed292f8f67273e838e15fc3a9 100644 --- a/bridges/modules/messages/Cargo.toml +++ b/bridges/modules/messages/Cargo.toml @@ -11,54 +11,69 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } +codec = { workspace = true } log = { workspace = true } -num-traits = { version = "0.2", default-features = false } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } # Bridge dependencies - -bp-messages = { path = "../../primitives/messages", default-features = false } -bp-runtime = { path = "../../primitives/runtime", default-features = false } +bp-header-chain = { workspace = true } +bp-messages = { workspace = true } +bp-runtime = { workspace = true } # Substrate Dependencies - -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } +sp-trie = { optional = true, workspace = true } [dev-dependencies] -bp-test-utils = { path = "../../primitives/test-utils" } -pallet-balances = { path = "../../../substrate/frame/balances" } -sp-io = { path = "../../../substrate/primitives/io" } +bp-runtime = { features = ["test-helpers"], workspace = true } +bp-test-utils = { workspace = true } +pallet-balances = { workspace = true } +pallet-bridge-grandpa = { workspace = true } +sp-io = { workspace = true } +sp-core = { workspace = true } [features] default = ["std"] std = [ + "bp-header-chain/std", "bp-messages/std", "bp-runtime/std", + "bp-test-utils/std", "codec/std", "frame-benchmarking/std", "frame-support/std", "frame-system/std", "log/std", - "num-traits/std", + "pallet-balances/std", + "pallet-bridge-grandpa/std", "scale-info/std", + "sp-core/std", + "sp-io/std", "sp-runtime/std", "sp-std/std", + "sp-trie/std", ] runtime-benchmarks = [ + "bp-runtime/test-helpers", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-bridge-grandpa/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "pallet-balances/try-runtime", + "pallet-bridge-grandpa/try-runtime", "sp-runtime/try-runtime", ] +test-helpers = [ + "bp-runtime/test-helpers", + "sp-trie", +] diff --git a/bridges/modules/messages/README.md b/bridges/modules/messages/README.md index c06b96b857dea1cdf7fdaed81e70d66aff116064..80fd92eb0e5a7d975ba45619838007a12f5f5553 100644 --- a/bridges/modules/messages/README.md +++ b/bridges/modules/messages/README.md @@ -104,17 +104,22 @@ the message. When a message is delivered to the target chain, the `MessagesDeliv `receive_messages_delivery_proof()` transaction. The `MessagesDelivered` contains the message lane identifier and inclusive range of delivered message nonces. -The pallet provides no means to get the result of message dispatch at the target chain. If that is required, it must be -done outside of the pallet. For example, XCM messages, when dispatched, have special instructions to send some data back -to the sender. Other dispatchers may use similar mechanism for that. -### How to plug-in Messages Module to Send Messages to the Bridged Chain? - -The `pallet_bridge_messages::Config` trait has 3 main associated types that are used to work with outbound messages. The -`pallet_bridge_messages::Config::TargetHeaderChain` defines how we see the bridged chain as the target for our outbound -messages. It must be able to check that the bridged chain may accept our message - like that the message has size below -maximal possible transaction size of the chain and so on. And when the relayer sends us a confirmation transaction, this -implementation must be able to parse and verify the proof of messages delivery. Normally, you would reuse the same -(configurable) type on all chains that are sending messages to the same bridged chain. +The pallet provides no means to get the result of message dispatch at the target chain. If that is +required, it must be done outside of the pallet. For example, XCM messages, when dispatched, have +special instructions to send some data back to the sender. Other dispatchers may use similar +mechanism for that. + +### How to plug-in Messages Module to Send and Receive Messages from the Bridged Chain? + +The `pallet_bridge_messages::Config` trait has 2 main associated types that are used to work with +inbound messages. The `pallet_bridge_messages::BridgedChain` defines basic primitives of the bridged +chain. The `pallet_bridge_messages::BridgedHeaderChain` defines the way we access the bridged chain +headers in our runtime. You may use `pallet_bridge_grandpa` if you're bridging with chain that uses +GRANDPA finality or `pallet_bridge_parachains::ParachainHeaders` if you're bridging with parachain. + +The `pallet_bridge_messages::Config::MessageDispatch` defines a way on how to dispatch delivered +messages. Apart from actually dispatching the message, the implementation must return the correct +dispatch weight of the message before dispatch is called. The last type is the `pallet_bridge_messages::Config::DeliveryConfirmationPayments`. When confirmation transaction is received, we call the `pay_reward()` method, passing the range of delivered messages. @@ -129,18 +134,6 @@ You should be looking at the `bp_messages::source_chain::ForbidOutboundMessages` [`bp_messages::source_chain`](../../primitives/messages/src/source_chain.rs). It implements all required traits and will simply reject all transactions, related to outbound messages. -### How to plug-in Messages Module to Receive Messages from the Bridged Chain? - -The `pallet_bridge_messages::Config` trait has 2 main associated types that are used to work with inbound messages. The -`pallet_bridge_messages::Config::SourceHeaderChain` defines how we see the bridged chain as the source of our inbound -messages. When relayer sends us a delivery transaction, this implementation must be able to parse and verify the proof -of messages wrapped in this transaction. Normally, you would reuse the same (configurable) type on all chains that are -sending messages to the same bridged chain. - -The `pallet_bridge_messages::Config::MessageDispatch` defines a way on how to dispatch delivered messages. Apart from -actually dispatching the message, the implementation must return the correct dispatch weight of the message before -dispatch is called. - ### I have a Messages Module in my Runtime, but I Want to Reject all Inbound Messages. What shall I do? You should be looking at the `bp_messages::target_chain::ForbidInboundMessages` structure from the @@ -150,36 +143,42 @@ and will simply reject all transactions, related to inbound messages. ### What about other Constants in the Messages Module Configuration Trait? Two settings that are used to check messages in the `send_message()` function. The -`pallet_bridge_messages::Config::ActiveOutboundLanes` is an array of all message lanes, that may be used to send -messages. All messages sent using other lanes are rejected. All messages that have size above -`pallet_bridge_messages::Config::MaximalOutboundPayloadSize` will also be rejected. - -To be able to reward the relayer for delivering messages, we store a map of message nonces range => identifier of the -relayer that has delivered this range at the target chain runtime storage. If a relayer delivers multiple consequent -ranges, they're merged into single entry. So there may be more than one entry for the same relayer. Eventually, this -whole map must be delivered back to the source chain to confirm delivery and pay rewards. So to make sure we are able to -craft this confirmation transaction, we need to: (1) keep the size of this map below a certain limit and (2) make sure -that the weight of processing this map is below a certain limit. Both size and processing weight mostly depend on the -number of entries. The number of entries is limited with the -`pallet_bridge_messages::ConfigMaxUnrewardedRelayerEntriesAtInboundLane` parameter. Processing weight also depends on -the total number of messages that are being confirmed, because every confirmed message needs to be read. So there's -another `pallet_bridge_messages::Config::MaxUnconfirmedMessagesAtInboundLane` parameter for that. - -When choosing values for these parameters, you must also keep in mind that if proof in your scheme is based on finality -of headers (and it is the most obvious option for Substrate-based chains with finality notion), then choosing too small -values for these parameters may cause significant delays in message delivery. That's because there are too many actors -involved in this scheme: 1) authorities that are finalizing headers of the target chain need to finalize header with -non-empty map; 2) the headers relayer then needs to submit this header and its finality proof to the source chain; 3) -the messages relayer must then send confirmation transaction (storage proof of this map) to the source chain; 4) when -the confirmation transaction will be mined at some header, source chain authorities must finalize this header; 5) the -headers relay then needs to submit this header and its finality proof to the target chain; 6) only now the messages -relayer may submit new messages from the source to target chain and prune the entry from the map. - -Delivery transaction requires the relayer to provide both number of entries and total number of messages in the map. -This means that the module never charges an extra cost for delivering a map - the relayer would need to pay exactly for -the number of entries+messages it has delivered. So the best guess for values of these parameters would be the pair that -would occupy `N` percent of the maximal transaction size and weight of the source chain. The `N` should be large enough -to process large maps, at the same time keeping reserve for future source chain upgrades. +`pallet_bridge_messages::Config::ActiveOutboundLanes` is an array of all message lanes, that +may be used to send messages. All messages sent using other lanes are rejected. All messages that have +size above `pallet_bridge_messages::Config::MaximalOutboundPayloadSize` will also be rejected. + +To be able to reward the relayer for delivering messages, we store a map of message nonces range => +identifier of the relayer that has delivered this range at the target chain runtime storage. If a +relayer delivers multiple consequent ranges, they're merged into single entry. So there may be more +than one entry for the same relayer. Eventually, this whole map must be delivered back to the source +chain to confirm delivery and pay rewards. So to make sure we are able to craft this confirmation +transaction, we need to: (1) keep the size of this map below a certain limit and (2) make sure that +the weight of processing this map is below a certain limit. Both size and processing weight mostly +depend on the number of entries. The number of entries is limited with the +`pallet_bridge_messages::Config::BridgedChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX` parameter. +Processing weight also depends on the total number of messages that are being confirmed, because every +confirmed message needs to be read. So there's another +`pallet_bridge_messages::Config::BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX` parameter +for that. + +When choosing values for these parameters, you must also keep in mind that if proof in your scheme +is based on finality of headers (and it is the most obvious option for Substrate-based chains with +finality notion), then choosing too small values for these parameters may cause significant delays +in message delivery. That's because there are too many actors involved in this scheme: 1) authorities +that are finalizing headers of the target chain need to finalize header with non-empty map; 2) the +headers relayer then needs to submit this header and its finality proof to the source chain; 3) the +messages relayer must then send confirmation transaction (storage proof of this map) to the source +chain; 4) when the confirmation transaction will be mined at some header, source chain authorities +must finalize this header; 5) the headers relay then needs to submit this header and its finality +proof to the target chain; 6) only now the messages relayer may submit new messages from the source +to target chain and prune the entry from the map. + +Delivery transaction requires the relayer to provide both number of entries and total number of +messages in the map. This means that the module never charges an extra cost for delivering a map - +the relayer would need to pay exactly for the number of entries+messages it has delivered. So the +best guess for values of these parameters would be the pair that would occupy `N` percent of the +maximal transaction size and weight of the source chain. The `N` should be large enough to process +large maps, at the same time keeping reserve for future source chain upgrades. ## Non-Essential Functionality diff --git a/bridges/modules/messages/src/benchmarking.rs b/bridges/modules/messages/src/benchmarking.rs index 4f13c4409672b3e76d36fd7d3dd2fab5c7e2ec1b..d38aaf32dc94bd157de0d3e910b729a7970c1684 100644 --- a/bridges/modules/messages/src/benchmarking.rs +++ b/bridges/modules/messages/src/benchmarking.rs @@ -16,19 +16,22 @@ //! Messages pallet benchmarking. +#![cfg(feature = "runtime-benchmarks")] + use crate::{ inbound_lane::InboundLaneStorage, outbound_lane, weights_ext::EXPECTED_DEFAULT_MESSAGE_LENGTH, - Call, OutboundLanes, RuntimeInboundLaneStorage, + BridgedChainOf, Call, OutboundLanes, RuntimeInboundLaneStorage, }; use bp_messages::{ - source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, DeliveredMessages, + source_chain::FromBridgedChainMessagesDeliveryProof, + target_chain::FromBridgedChainMessagesProof, ChainWithMessages, DeliveredMessages, InboundLaneData, LaneId, MessageNonce, OutboundLaneData, UnrewardedRelayer, UnrewardedRelayersState, }; -use bp_runtime::StorageProofSize; +use bp_runtime::{AccountIdOf, HashOf, UnverifiedStorageProofParams}; use codec::Decode; -use frame_benchmarking::{account, benchmarks_instance_pallet}; +use frame_benchmarking::{account, v2::*}; use frame_support::weights::Weight; use frame_system::RawOrigin; use sp_runtime::{traits::TrailingZeroInput, BoundedVec}; @@ -54,7 +57,7 @@ pub struct MessageProofParams { /// return `true` from the `is_message_successfully_dispatched`. pub is_successful_dispatch_expected: bool, /// Proof size requirements. - pub size: StorageProofSize, + pub proof_params: UnverifiedStorageProofParams, } /// Benchmark-specific message delivery proof parameters. @@ -65,7 +68,7 @@ pub struct MessageDeliveryProofParams { /// The proof needs to include this inbound lane data. pub inbound_lane_data: InboundLaneData, /// Proof size requirements. - pub size: StorageProofSize, + pub proof_params: UnverifiedStorageProofParams, } /// Trait that must be implemented by runtime. @@ -80,8 +83,8 @@ pub trait Config: crate::Config { /// Return id of relayer account at the bridged chain. /// /// By default, zero account is returned. - fn bridged_relayer_id() -> Self::InboundRelayer { - Self::InboundRelayer::decode(&mut TrailingZeroInput::zeroes()).unwrap() + fn bridged_relayer_id() -> AccountIdOf> { + Decode::decode(&mut TrailingZeroInput::zeroes()).unwrap() } /// Create given account and give it enough balance for test purposes. Used to create @@ -94,11 +97,11 @@ pub trait Config: crate::Config { /// Prepare messages proof to receive by the module. fn prepare_message_proof( params: MessageProofParams, - ) -> (::MessagesProof, Weight); + ) -> (FromBridgedChainMessagesProof>>, Weight); /// Prepare messages delivery proof to receive by the module. fn prepare_message_delivery_proof( params: MessageDeliveryProofParams, - ) -> >::MessagesDeliveryProof; + ) -> FromBridgedChainMessagesDeliveryProof>>; /// Returns true if message has been successfully dispatched or not. fn is_message_successfully_dispatched(_nonce: MessageNonce) -> bool { @@ -109,174 +112,227 @@ pub trait Config: crate::Config { fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool; } -benchmarks_instance_pallet! { +fn send_regular_message, I: 'static>() { + let mut outbound_lane = outbound_lane::(T::bench_lane_id()); + outbound_lane.send_message(BoundedVec::try_from(vec![]).expect("We craft valid messages")); +} + +fn receive_messages, I: 'static>(nonce: MessageNonce) { + let mut inbound_lane_storage = + RuntimeInboundLaneStorage::::from_lane_id(T::bench_lane_id()); + inbound_lane_storage.set_data(InboundLaneData { + relayers: vec![UnrewardedRelayer { + relayer: T::bridged_relayer_id(), + messages: DeliveredMessages::new(nonce), + }] + .into_iter() + .collect(), + last_confirmed_nonce: 0, + }); +} + +struct ReceiveMessagesProofSetup, I: 'static> { + relayer_id_on_src: AccountIdOf>, + relayer_id_on_tgt: T::AccountId, + msgs_count: u32, + _phantom_data: sp_std::marker::PhantomData, +} + +impl, I: 'static> ReceiveMessagesProofSetup { + const LATEST_RECEIVED_NONCE: MessageNonce = 20; + + fn new(msgs_count: u32) -> Self { + let setup = Self { + relayer_id_on_src: T::bridged_relayer_id(), + relayer_id_on_tgt: account("relayer", 0, SEED), + msgs_count, + _phantom_data: Default::default(), + }; + T::endow_account(&setup.relayer_id_on_tgt); + // mark messages 1..=latest_recvd_nonce as delivered + receive_messages::(Self::LATEST_RECEIVED_NONCE); + + setup + } + + fn relayer_id_on_src(&self) -> AccountIdOf> { + self.relayer_id_on_src.clone() + } + + fn relayer_id_on_tgt(&self) -> T::AccountId { + self.relayer_id_on_tgt.clone() + } + + fn last_nonce(&self) -> MessageNonce { + Self::LATEST_RECEIVED_NONCE + self.msgs_count as u64 + } + + fn nonces(&self) -> RangeInclusive { + (Self::LATEST_RECEIVED_NONCE + 1)..=self.last_nonce() + } + + fn check_last_nonce(&self) { + assert_eq!( + crate::InboundLanes::::get(&T::bench_lane_id()).last_delivered_nonce(), + self.last_nonce(), + ); + } +} + +#[instance_benchmarks] +mod benchmarks { + use super::*; + // // Benchmarks that are used directly by the runtime calls weight formulae. // - // Benchmark `receive_messages_proof` extrinsic with single minimal-weight message and following conditions: + fn max_msgs, I: 'static>() -> u32 { + T::BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX as u32 - + ReceiveMessagesProofSetup::::LATEST_RECEIVED_NONCE as u32 + } + + // Benchmark `receive_messages_proof` extrinsic with single minimal-weight message and following + // conditions: // * proof does not include outbound lane state proof; // * inbound lane already has state, so it needs to be read and decoded; // * message is dispatched (reminder: dispatch weight should be minimal); // * message requires all heavy checks done by dispatcher. - // - // This is base benchmark for all other message delivery benchmarks. - receive_single_message_proof { - let relayer_id_on_source = T::bridged_relayer_id(); - let relayer_id_on_target = account("relayer", 0, SEED); - T::endow_account(&relayer_id_on_target); - - // mark messages 1..=20 as delivered - receive_messages::(20); - + #[benchmark] + fn receive_single_message_proof() { + // setup code + let setup = ReceiveMessagesProofSetup::::new(1); let (proof, dispatch_weight) = T::prepare_message_proof(MessageProofParams { lane: T::bench_lane_id(), - message_nonces: 21..=21, + message_nonces: setup.nonces(), outbound_lane_data: None, is_successful_dispatch_expected: false, - size: StorageProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH), + proof_params: UnverifiedStorageProofParams::from_db_size( + EXPECTED_DEFAULT_MESSAGE_LENGTH, + ), }); - }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight) - verify { - assert_eq!( - crate::InboundLanes::::get(&T::bench_lane_id()).last_delivered_nonce(), - 21, + + #[extrinsic_call] + receive_messages_proof( + RawOrigin::Signed(setup.relayer_id_on_tgt()), + setup.relayer_id_on_src(), + Box::new(proof), + setup.msgs_count, + dispatch_weight, ); + + // verification code + setup.check_last_nonce(); } - // Benchmark `receive_messages_proof` extrinsic with two minimal-weight messages and following conditions: + // Benchmark `receive_messages_proof` extrinsic with `n` minimal-weight messages and following + // conditions: // * proof does not include outbound lane state proof; // * inbound lane already has state, so it needs to be read and decoded; // * message is dispatched (reminder: dispatch weight should be minimal); // * message requires all heavy checks done by dispatcher. - // - // The weight of single message delivery could be approximated as - // `weight(receive_two_messages_proof) - weight(receive_single_message_proof)`. - // This won't be super-accurate if message has non-zero dispatch weight, but estimation should - // be close enough to real weight. - receive_two_messages_proof { - let relayer_id_on_source = T::bridged_relayer_id(); - let relayer_id_on_target = account("relayer", 0, SEED); - T::endow_account(&relayer_id_on_target); - - // mark messages 1..=20 as delivered - receive_messages::(20); - + #[benchmark] + fn receive_n_messages_proof(n: Linear<1, { max_msgs::() }>) { + // setup code + let setup = ReceiveMessagesProofSetup::::new(n); let (proof, dispatch_weight) = T::prepare_message_proof(MessageProofParams { lane: T::bench_lane_id(), - message_nonces: 21..=22, + message_nonces: setup.nonces(), outbound_lane_data: None, is_successful_dispatch_expected: false, - size: StorageProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH), + proof_params: UnverifiedStorageProofParams::from_db_size( + EXPECTED_DEFAULT_MESSAGE_LENGTH, + ), }); - }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 2, dispatch_weight) - verify { - assert_eq!( - crate::InboundLanes::::get(&T::bench_lane_id()).last_delivered_nonce(), - 22, + + #[extrinsic_call] + receive_messages_proof( + RawOrigin::Signed(setup.relayer_id_on_tgt()), + setup.relayer_id_on_src(), + Box::new(proof), + setup.msgs_count, + dispatch_weight, ); + + // verification code + setup.check_last_nonce(); } - // Benchmark `receive_messages_proof` extrinsic with single minimal-weight message and following conditions: + // Benchmark `receive_messages_proof` extrinsic with single minimal-weight message and following + // conditions: // * proof includes outbound lane state proof; // * inbound lane already has state, so it needs to be read and decoded; // * message is successfully dispatched (reminder: dispatch weight should be minimal); // * message requires all heavy checks done by dispatcher. // // The weight of outbound lane state delivery would be - // `weight(receive_single_message_proof_with_outbound_lane_state) - weight(receive_single_message_proof)`. - // This won't be super-accurate if message has non-zero dispatch weight, but estimation should - // be close enough to real weight. - receive_single_message_proof_with_outbound_lane_state { - let relayer_id_on_source = T::bridged_relayer_id(); - let relayer_id_on_target = account("relayer", 0, SEED); - T::endow_account(&relayer_id_on_target); - - // mark messages 1..=20 as delivered - receive_messages::(20); - + // `weight(receive_single_message_proof_with_outbound_lane_state) - + // weight(receive_single_message_proof)`. This won't be super-accurate if message has non-zero + // dispatch weight, but estimation should be close enough to real weight. + #[benchmark] + fn receive_single_message_proof_with_outbound_lane_state() { + // setup code + let setup = ReceiveMessagesProofSetup::::new(1); let (proof, dispatch_weight) = T::prepare_message_proof(MessageProofParams { lane: T::bench_lane_id(), - message_nonces: 21..=21, + message_nonces: setup.nonces(), outbound_lane_data: Some(OutboundLaneData { - oldest_unpruned_nonce: 21, - latest_received_nonce: 20, - latest_generated_nonce: 21, + oldest_unpruned_nonce: setup.last_nonce(), + latest_received_nonce: ReceiveMessagesProofSetup::::LATEST_RECEIVED_NONCE, + latest_generated_nonce: setup.last_nonce(), }), is_successful_dispatch_expected: false, - size: StorageProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH), + proof_params: UnverifiedStorageProofParams::from_db_size( + EXPECTED_DEFAULT_MESSAGE_LENGTH, + ), }); - }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight) - verify { - let lane_state = crate::InboundLanes::::get(&T::bench_lane_id()); - assert_eq!(lane_state.last_delivered_nonce(), 21); - assert_eq!(lane_state.last_confirmed_nonce, 20); - } - - // Benchmark `receive_messages_proof` extrinsic with single minimal-weight message and following conditions: - // * the proof has large leaf with total size of approximately 1KB; - // * proof does not include outbound lane state proof; - // * inbound lane already has state, so it needs to be read and decoded; - // * message is dispatched (reminder: dispatch weight should be minimal); - // * message requires all heavy checks done by dispatcher. - // - // With single KB of messages proof, the weight of the call is increased (roughly) by - // `(receive_single_message_proof_16KB - receive_single_message_proof_1_kb) / 15`. - receive_single_message_proof_1_kb { - let relayer_id_on_source = T::bridged_relayer_id(); - let relayer_id_on_target = account("relayer", 0, SEED); - T::endow_account(&relayer_id_on_target); - - // mark messages 1..=20 as delivered - receive_messages::(20); - let (proof, dispatch_weight) = T::prepare_message_proof(MessageProofParams { - lane: T::bench_lane_id(), - message_nonces: 21..=21, - outbound_lane_data: None, - is_successful_dispatch_expected: false, - size: StorageProofSize::HasLargeLeaf(1024), - }); - }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight) - verify { - assert_eq!( - crate::InboundLanes::::get(&T::bench_lane_id()).last_delivered_nonce(), - 21, + #[extrinsic_call] + receive_messages_proof( + RawOrigin::Signed(setup.relayer_id_on_tgt()), + setup.relayer_id_on_src(), + Box::new(proof), + setup.msgs_count, + dispatch_weight, ); + + // verification code + setup.check_last_nonce(); } - // Benchmark `receive_messages_proof` extrinsic with single minimal-weight message and following conditions: - // * the proof has large leaf with total size of approximately 16KB; + // Benchmark `receive_messages_proof` extrinsic with single minimal-weight message and following + // conditions: + // * the proof has large leaf with total size ranging between 1KB and 16KB; // * proof does not include outbound lane state proof; // * inbound lane already has state, so it needs to be read and decoded; // * message is dispatched (reminder: dispatch weight should be minimal); // * message requires all heavy checks done by dispatcher. - // - // Size of proof grows because it contains extra trie nodes in it. - // - // With single KB of messages proof, the weight of the call is increased (roughly) by - // `(receive_single_message_proof_16KB - receive_single_message_proof) / 15`. - receive_single_message_proof_16_kb { - let relayer_id_on_source = T::bridged_relayer_id(); - let relayer_id_on_target = account("relayer", 0, SEED); - T::endow_account(&relayer_id_on_target); - - // mark messages 1..=20 as delivered - receive_messages::(20); - + #[benchmark] + fn receive_single_n_bytes_message_proof( + /// Proof size in KB + n: Linear<1, { 16 * 1024 }>, + ) { + // setup code + let setup = ReceiveMessagesProofSetup::::new(1); let (proof, dispatch_weight) = T::prepare_message_proof(MessageProofParams { lane: T::bench_lane_id(), - message_nonces: 21..=21, + message_nonces: setup.nonces(), outbound_lane_data: None, is_successful_dispatch_expected: false, - size: StorageProofSize::HasLargeLeaf(16 * 1024), + proof_params: UnverifiedStorageProofParams::from_db_size(n), }); - }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight) - verify { - assert_eq!( - crate::InboundLanes::::get(&T::bench_lane_id()).last_delivered_nonce(), - 21, + + #[extrinsic_call] + receive_messages_proof( + RawOrigin::Signed(setup.relayer_id_on_tgt()), + setup.relayer_id_on_src(), + Box::new(proof), + setup.msgs_count, + dispatch_weight, ); + + // verification code + setup.check_last_nonce(); } // Benchmark `receive_messages_delivery_proof` extrinsic with following conditions: @@ -284,7 +340,8 @@ benchmarks_instance_pallet! { // * relayer account does not exist (in practice it needs to exist in production environment). // // This is base benchmark for all other confirmations delivery benchmarks. - receive_delivery_proof_for_single_message { + #[benchmark] + fn receive_delivery_proof_for_single_message() { let relayer_id: T::AccountId = account("relayer", 0, SEED); // send message that we're going to confirm @@ -302,13 +359,21 @@ benchmarks_instance_pallet! { relayers: vec![UnrewardedRelayer { relayer: relayer_id.clone(), messages: DeliveredMessages::new(1), - }].into_iter().collect(), + }] + .into_iter() + .collect(), last_confirmed_nonce: 0, }, - size: StorageProofSize::Minimal(0), + proof_params: UnverifiedStorageProofParams::default(), }); - }: receive_messages_delivery_proof(RawOrigin::Signed(relayer_id.clone()), proof, relayers_state) - verify { + + #[extrinsic_call] + receive_messages_delivery_proof( + RawOrigin::Signed(relayer_id.clone()), + proof, + relayers_state, + ); + assert_eq!(OutboundLanes::::get(T::bench_lane_id()).latest_received_nonce, 1); assert!(T::is_relayer_rewarded(&relayer_id)); } @@ -320,7 +385,8 @@ benchmarks_instance_pallet! { // Additional weight for paying single-message reward to the same relayer could be computed // as `weight(receive_delivery_proof_for_two_messages_by_single_relayer) // - weight(receive_delivery_proof_for_single_message)`. - receive_delivery_proof_for_two_messages_by_single_relayer { + #[benchmark] + fn receive_delivery_proof_for_two_messages_by_single_relayer() { let relayer_id: T::AccountId = account("relayer", 0, SEED); // send message that we're going to confirm @@ -341,13 +407,21 @@ benchmarks_instance_pallet! { relayers: vec![UnrewardedRelayer { relayer: relayer_id.clone(), messages: delivered_messages, - }].into_iter().collect(), + }] + .into_iter() + .collect(), last_confirmed_nonce: 0, }, - size: StorageProofSize::Minimal(0), + proof_params: UnverifiedStorageProofParams::default(), }); - }: receive_messages_delivery_proof(RawOrigin::Signed(relayer_id.clone()), proof, relayers_state) - verify { + + #[extrinsic_call] + receive_messages_delivery_proof( + RawOrigin::Signed(relayer_id.clone()), + proof, + relayers_state, + ); + assert_eq!(OutboundLanes::::get(T::bench_lane_id()).latest_received_nonce, 2); assert!(T::is_relayer_rewarded(&relayer_id)); } @@ -359,7 +433,8 @@ benchmarks_instance_pallet! { // Additional weight for paying reward to the next relayer could be computed // as `weight(receive_delivery_proof_for_two_messages_by_two_relayers) // - weight(receive_delivery_proof_for_two_messages_by_single_relayer)`. - receive_delivery_proof_for_two_messages_by_two_relayers { + #[benchmark] + fn receive_delivery_proof_for_two_messages_by_two_relayers() { let relayer1_id: T::AccountId = account("relayer1", 1, SEED); let relayer2_id: T::AccountId = account("relayer2", 2, SEED); @@ -385,13 +460,21 @@ benchmarks_instance_pallet! { relayer: relayer2_id.clone(), messages: DeliveredMessages::new(2), }, - ].into_iter().collect(), + ] + .into_iter() + .collect(), last_confirmed_nonce: 0, }, - size: StorageProofSize::Minimal(0), + proof_params: UnverifiedStorageProofParams::default(), }); - }: receive_messages_delivery_proof(RawOrigin::Signed(relayer1_id.clone()), proof, relayers_state) - verify { + + #[extrinsic_call] + receive_messages_delivery_proof( + RawOrigin::Signed(relayer1_id.clone()), + proof, + relayers_state, + ); + assert_eq!(OutboundLanes::::get(T::bench_lane_id()).latest_received_nonce, 2); assert!(T::is_relayer_rewarded(&relayer1_id)); assert!(T::is_relayer_rewarded(&relayer2_id)); @@ -411,51 +494,38 @@ benchmarks_instance_pallet! { // * inbound lane already has state, so it needs to be read and decoded; // * message is **SUCCESSFULLY** dispatched; // * message requires all heavy checks done by dispatcher. - receive_single_message_proof_with_dispatch { - // maybe dispatch weight relies on the message size too? - let i in EXPECTED_DEFAULT_MESSAGE_LENGTH .. EXPECTED_DEFAULT_MESSAGE_LENGTH * 16; - - let relayer_id_on_source = T::bridged_relayer_id(); - let relayer_id_on_target = account("relayer", 0, SEED); - T::endow_account(&relayer_id_on_target); - - // mark messages 1..=20 as delivered - receive_messages::(20); - + #[benchmark] + fn receive_single_n_bytes_message_proof_with_dispatch( + /// Proof size in KB + n: Linear<1, { 16 * 1024 }>, + ) { + // setup code + let setup = ReceiveMessagesProofSetup::::new(1); let (proof, dispatch_weight) = T::prepare_message_proof(MessageProofParams { lane: T::bench_lane_id(), - message_nonces: 21..=21, + message_nonces: setup.nonces(), outbound_lane_data: None, is_successful_dispatch_expected: true, - size: StorageProofSize::Minimal(i), + proof_params: UnverifiedStorageProofParams::from_db_size(n), }); - }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight) - verify { - assert_eq!( - crate::InboundLanes::::get(&T::bench_lane_id()).last_delivered_nonce(), - 21, - ); - assert!(T::is_message_successfully_dispatched(21)); - } - impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::TestRuntime) -} + #[extrinsic_call] + receive_messages_proof( + RawOrigin::Signed(setup.relayer_id_on_tgt()), + setup.relayer_id_on_src(), + Box::new(proof), + setup.msgs_count, + dispatch_weight, + ); -fn send_regular_message, I: 'static>() { - let mut outbound_lane = outbound_lane::(T::bench_lane_id()); - outbound_lane.send_message(BoundedVec::try_from(vec![]).expect("We craft valid messages")); -} + // verification code + setup.check_last_nonce(); + assert!(T::is_message_successfully_dispatched(setup.last_nonce())); + } -fn receive_messages, I: 'static>(nonce: MessageNonce) { - let mut inbound_lane_storage = - RuntimeInboundLaneStorage::::from_lane_id(T::bench_lane_id()); - inbound_lane_storage.set_data(InboundLaneData { - relayers: vec![UnrewardedRelayer { - relayer: T::bridged_relayer_id(), - messages: DeliveredMessages::new(nonce), - }] - .into_iter() - .collect(), - last_confirmed_nonce: 0, - }); + impl_benchmark_test_suite!( + Pallet, + crate::tests::mock::new_test_ext(), + crate::tests::mock::TestRuntime + ); } diff --git a/bridges/modules/messages/src/inbound_lane.rs b/bridges/modules/messages/src/inbound_lane.rs index da1698e6e0370f9f84ca8dd53bc1ebc99f696017..7ef4599a93c4823a9be7fa918b35c309cea6611a 100644 --- a/bridges/modules/messages/src/inbound_lane.rs +++ b/bridges/modules/messages/src/inbound_lane.rs @@ -16,15 +16,15 @@ //! Everything about incoming messages receival. -use crate::Config; +use crate::{BridgedChainOf, Config}; use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, - DeliveredMessages, InboundLaneData, LaneId, MessageKey, MessageNonce, OutboundLaneData, - ReceptionResult, UnrewardedRelayer, + ChainWithMessages, DeliveredMessages, InboundLaneData, LaneId, MessageKey, MessageNonce, + OutboundLaneData, ReceptionResult, UnrewardedRelayer, }; +use bp_runtime::AccountIdOf; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; -use frame_support::traits::Get; use scale_info::{Type, TypeInfo}; use sp_runtime::RuntimeDebug; use sp_std::prelude::PartialEq; @@ -55,10 +55,12 @@ pub trait InboundLaneStorage { /// /// The encoding of this type matches encoding of the corresponding `MessageData`. #[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq)] -pub struct StoredInboundLaneData, I: 'static>(pub InboundLaneData); +pub struct StoredInboundLaneData, I: 'static>( + pub InboundLaneData>>, +); impl, I: 'static> sp_std::ops::Deref for StoredInboundLaneData { - type Target = InboundLaneData; + type Target = InboundLaneData>>; fn deref(&self) -> &Self::Target { &self.0 @@ -78,7 +80,7 @@ impl, I: 'static> Default for StoredInboundLaneData { } impl, I: 'static> From> - for InboundLaneData + for InboundLaneData>> { fn from(data: StoredInboundLaneData) -> Self { data.0 @@ -86,7 +88,7 @@ impl, I: 'static> From> } impl, I: 'static> EncodeLike> - for InboundLaneData + for InboundLaneData>> { } @@ -94,14 +96,14 @@ impl, I: 'static> TypeInfo for StoredInboundLaneData { type Identity = Self; fn type_info() -> Type { - InboundLaneData::::type_info() + InboundLaneData::>>::type_info() } } impl, I: 'static> MaxEncodedLen for StoredInboundLaneData { fn max_encoded_len() -> usize { - InboundLaneData::::encoded_size_hint( - T::MaxUnrewardedRelayerEntriesAtInboundLane::get() as usize, + InboundLaneData::>>::encoded_size_hint( + BridgedChainOf::::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX as usize, ) .unwrap_or(usize::MAX) } @@ -216,10 +218,10 @@ mod tests { use super::*; use crate::{ inbound_lane, - mock::{ + tests::mock::{ dispatch_result, inbound_message_data, inbound_unrewarded_relayers_state, run_test, - unrewarded_relayer, TestMessageDispatch, TestRuntime, REGULAR_PAYLOAD, TEST_LANE_ID, - TEST_RELAYER_A, TEST_RELAYER_B, TEST_RELAYER_C, + unrewarded_relayer, BridgedChain, TestMessageDispatch, TestRuntime, REGULAR_PAYLOAD, + TEST_LANE_ID, TEST_RELAYER_A, TEST_RELAYER_B, TEST_RELAYER_C, }, RuntimeInboundLaneStorage, }; @@ -372,8 +374,7 @@ mod tests { fn fails_to_receive_messages_above_unrewarded_relayer_entries_limit_per_lane() { run_test(|| { let mut lane = inbound_lane::(TEST_LANE_ID); - let max_nonce = - ::MaxUnrewardedRelayerEntriesAtInboundLane::get(); + let max_nonce = BridgedChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; for current_nonce in 1..max_nonce + 1 { assert_eq!( lane.receive_message::( @@ -409,7 +410,7 @@ mod tests { fn fails_to_receive_messages_above_unconfirmed_messages_limit_per_lane() { run_test(|| { let mut lane = inbound_lane::(TEST_LANE_ID); - let max_nonce = ::MaxUnconfirmedMessagesAtInboundLane::get(); + let max_nonce = BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; for current_nonce in 1..=max_nonce { assert_eq!( lane.receive_message::( diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index e31a4542056cb30466f236d0dc9957c053a03f66..bf105b14040185f61e627a35f4f53b3a66b48c19 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -41,8 +41,8 @@ pub use outbound_lane::StoredMessagePayload; pub use weights::WeightInfo; pub use weights_ext::{ ensure_able_to_receive_confirmation, ensure_able_to_receive_message, - ensure_weights_are_correct, WeightInfoExt, EXPECTED_DEFAULT_MESSAGE_LENGTH, - EXTRA_STORAGE_PROOF_SIZE, + ensure_maximal_message_dispatch, ensure_weights_are_correct, WeightInfoExt, + EXPECTED_DEFAULT_MESSAGE_LENGTH, EXTRA_STORAGE_PROOF_SIZE, }; use crate::{ @@ -50,20 +50,23 @@ use crate::{ outbound_lane::{OutboundLane, OutboundLaneStorage, ReceptionConfirmationError}, }; +use bp_header_chain::HeaderChain; use bp_messages::{ source_chain::{ - DeliveryConfirmationPayments, OnMessagesDelivered, SendMessageArtifacts, TargetHeaderChain, + DeliveryConfirmationPayments, FromBridgedChainMessagesDeliveryProof, OnMessagesDelivered, + SendMessageArtifacts, }, target_chain::{ - DeliveryPayments, DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, - SourceHeaderChain, + DeliveryPayments, DispatchMessage, FromBridgedChainMessagesProof, MessageDispatch, + ProvedLaneMessages, ProvedMessages, }, - DeliveredMessages, InboundLaneData, InboundMessageDetails, LaneId, MessageKey, MessageNonce, - MessagePayload, MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, - UnrewardedRelayersState, VerificationError, + ChainWithMessages, DeliveredMessages, InboundLaneData, InboundMessageDetails, LaneId, + MessageKey, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData, + OutboundMessageDetails, UnrewardedRelayersState, VerificationError, }; use bp_runtime::{ - BasicOperatingMode, ChainId, OwnedBridgeModule, PreComputedSize, RangeInclusiveExt, Size, + AccountIdOf, BasicOperatingMode, HashOf, OwnedBridgeModule, PreComputedSize, RangeInclusiveExt, + Size, }; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{dispatch::PostDispatchInfo, ensure, fail, traits::Get, DefaultNoBound}; @@ -72,6 +75,8 @@ use sp_std::{marker::PhantomData, prelude::*}; mod inbound_lane; mod outbound_lane; +mod proofs; +mod tests; mod weights_ext; pub mod weights; @@ -79,10 +84,9 @@ pub mod weights; #[cfg(feature = "runtime-benchmarks")] pub mod benchmarking; -#[cfg(test)] -mod mock; - pub use pallet::*; +#[cfg(feature = "test-helpers")] +pub use tests::*; /// The target that will be used when publishing logs related to this pallet. pub const LOG_TARGET: &str = "runtime::bridge-messages"; @@ -105,76 +109,39 @@ pub mod pallet { /// Benchmarks results from runtime we're plugged into. type WeightInfo: WeightInfoExt; - /// Gets the chain id value from the instance. - #[pallet::constant] - type BridgedChainId: Get; + /// This chain type. + type ThisChain: ChainWithMessages; + /// Bridged chain type. + type BridgedChain: ChainWithMessages; + /// Bridged chain headers provider. + type BridgedHeaderChain: HeaderChain; /// Get all active outbound lanes that the message pallet is serving. type ActiveOutboundLanes: Get<&'static [LaneId]>; - /// Maximal number of unrewarded relayer entries at inbound lane. Unrewarded means that the - /// relayer has delivered messages, but either confirmations haven't been delivered back to - /// the source chain, or we haven't received reward confirmations yet. - /// - /// This constant limits maximal number of entries in the `InboundLaneData::relayers`. Keep - /// in mind that the same relayer account may take several (non-consecutive) entries in this - /// set. - type MaxUnrewardedRelayerEntriesAtInboundLane: Get; - /// Maximal number of unconfirmed messages at inbound lane. Unconfirmed means that the - /// message has been delivered, but either confirmations haven't been delivered back to the - /// source chain, or we haven't received reward confirmations for these messages yet. - /// - /// This constant limits difference between last message from last entry of the - /// `InboundLaneData::relayers` and first message at the first entry. - /// - /// There is no point of making this parameter lesser than - /// MaxUnrewardedRelayerEntriesAtInboundLane, because then maximal number of relayer entries - /// will be limited by maximal number of messages. - /// - /// This value also represents maximal number of messages in single delivery transaction. - /// Transaction that is declaring more messages than this value, will be rejected. Even if - /// these messages are from different lanes. - type MaxUnconfirmedMessagesAtInboundLane: Get; - - /// Maximal encoded size of the outbound payload. - #[pallet::constant] - type MaximalOutboundPayloadSize: Get; + /// Payload type of outbound messages. This payload is dispatched on the bridged chain. type OutboundPayload: Parameter + Size; - /// Payload type of inbound messages. This payload is dispatched on this chain. type InboundPayload: Decode; - /// Identifier of relayer that deliver messages to this chain. Relayer reward is paid on the - /// bridged chain. - type InboundRelayer: Parameter + MaxEncodedLen; - /// Delivery payments. - type DeliveryPayments: DeliveryPayments; - - // Types that are used by outbound_lane (on source chain). - /// Target header chain. - type TargetHeaderChain: TargetHeaderChain; - /// Delivery confirmation payments. + /// Handler for relayer payments that happen during message delivery transaction. + type DeliveryPayments: DeliveryPayments; + /// Handler for relayer payments that happen during message delivery confirmation + /// transaction. type DeliveryConfirmationPayments: DeliveryConfirmationPayments; /// Delivery confirmation callback. type OnMessagesDelivered: OnMessagesDelivered; - // Types that are used by inbound_lane (on target chain). - - /// Source header chain, as it is represented on target chain. - type SourceHeaderChain: SourceHeaderChain; - /// Message dispatch. + /// Message dispatch handler. type MessageDispatch: MessageDispatch; } - /// Shortcut to messages proof type for Config. - pub type MessagesProofOf = - <>::SourceHeaderChain as SourceHeaderChain>::MessagesProof; - /// Shortcut to messages delivery proof type for Config. - pub type MessagesDeliveryProofOf = - <>::TargetHeaderChain as TargetHeaderChain< - >::OutboundPayload, - ::AccountId, - >>::MessagesDeliveryProof; + /// Shortcut to this chain type for Config. + pub type ThisChainOf = >::ThisChain; + /// Shortcut to bridged chain type for Config. + pub type BridgedChainOf = >::BridgedChain; + /// Shortcut to bridged header chain type for Config. + pub type BridgedHeaderChainOf = >::BridgedHeaderChain; #[pallet::pallet] pub struct Pallet(PhantomData<(T, I)>); @@ -265,11 +232,11 @@ pub mod pallet { /// The call may succeed, but some messages may not be delivered e.g. if they are not fit /// into the unrewarded relayers vector. #[pallet::call_index(2)] - #[pallet::weight(T::WeightInfo::receive_messages_proof_weight(proof, *messages_count, *dispatch_weight))] + #[pallet::weight(T::WeightInfo::receive_messages_proof_weight(&**proof, *messages_count, *dispatch_weight))] pub fn receive_messages_proof( origin: OriginFor, - relayer_id_at_bridged_chain: T::InboundRelayer, - proof: MessagesProofOf, + relayer_id_at_bridged_chain: AccountIdOf>, + proof: Box>>>, messages_count: u32, dispatch_weight: Weight, ) -> DispatchResultWithPostInfo { @@ -278,7 +245,8 @@ pub mod pallet { // reject transactions that are declaring too many messages ensure!( - MessageNonce::from(messages_count) <= T::MaxUnconfirmedMessagesAtInboundLane::get(), + MessageNonce::from(messages_count) <= + BridgedChainOf::::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, Error::::TooManyMessagesInTheProof ); @@ -296,22 +264,19 @@ pub mod pallet { // The DeclaredWeight is exactly what's computed here. Unfortunately it is impossible // to get pre-computed value (and it has been already computed by the executive). let declared_weight = T::WeightInfo::receive_messages_proof_weight( - &proof, + &*proof, messages_count, dispatch_weight, ); let mut actual_weight = declared_weight; // verify messages proof && convert proof into messages - let messages = verify_and_decode_messages_proof::< - T::SourceHeaderChain, - T::InboundPayload, - >(proof, messages_count) - .map_err(|err| { - log::trace!(target: LOG_TARGET, "Rejecting invalid messages proof: {:?}", err,); + let messages = verify_and_decode_messages_proof::(*proof, messages_count) + .map_err(|err| { + log::trace!(target: LOG_TARGET, "Rejecting invalid messages proof: {:?}", err,); - Error::::InvalidMessagesProof - })?; + Error::::InvalidMessagesProof + })?; // dispatch messages and (optionally) update lane(s) state(s) let mut total_messages = 0; @@ -424,14 +389,14 @@ pub mod pallet { ))] pub fn receive_messages_delivery_proof( origin: OriginFor, - proof: MessagesDeliveryProofOf, + proof: FromBridgedChainMessagesDeliveryProof>>, mut relayers_state: UnrewardedRelayersState, ) -> DispatchResultWithPostInfo { Self::ensure_not_halted().map_err(Error::::BridgeModule)?; let proof_size = proof.size(); let confirmation_relayer = ensure_signed(origin)?; - let (lane_id, lane_data) = T::TargetHeaderChain::verify_messages_delivery_proof(proof) + let (lane_id, lane_data) = proofs::verify_messages_delivery_proof::(proof) .map_err(|err| { log::trace!( target: LOG_TARGET, @@ -542,8 +507,6 @@ pub mod pallet { InactiveOutboundLane, /// The inbound message dispatcher is inactive. MessageDispatchInactive, - /// Message has been treated as invalid by chain verifier. - MessageRejectedByChainVerifier(VerificationError), /// Message has been treated as invalid by the pallet logic. MessageRejectedByPallet(VerificationError), /// Submitter has failed to pay fee for delivering and dispatching messages. @@ -674,7 +637,9 @@ pub mod pallet { } /// Return inbound lane data. - pub fn inbound_lane_data(lane: LaneId) -> InboundLaneData { + pub fn inbound_lane_data( + lane: LaneId, + ) -> InboundLaneData>> { InboundLanes::::get(lane).0 } } @@ -714,18 +679,6 @@ where // let's check if outbound lane is active ensure!(T::ActiveOutboundLanes::get().contains(&lane), Error::::InactiveOutboundLane); - // let's first check if message can be delivered to target chain - T::TargetHeaderChain::verify_message(message).map_err(|err| { - log::trace!( - target: LOG_TARGET, - "Message to lane {:?} is rejected by target chain: {:?}", - lane, - err, - ); - - Error::::MessageRejectedByChainVerifier(err) - })?; - Ok(SendMessageArgs { lane_id: lane, payload: StoredMessagePayload::::try_from(message.encode()).map_err(|_| { @@ -785,7 +738,7 @@ fn outbound_lane, I: 'static>( /// Runtime inbound lane storage. struct RuntimeInboundLaneStorage, I: 'static = ()> { lane_id: LaneId, - cached_data: Option>, + cached_data: Option>>>, _phantom: PhantomData, } @@ -802,39 +755,39 @@ impl, I: 'static> RuntimeInboundLaneStorage { /// maximal configured. /// /// Maximal inbound lane state set size is configured by the - /// `MaxUnrewardedRelayerEntriesAtInboundLane` constant from the pallet configuration. The PoV + /// `MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX` constant from the pallet configuration. The PoV /// of the call includes the maximal size of inbound lane state. If the actual size is smaller, /// we may subtract extra bytes from this component. pub fn extra_proof_size_bytes(&mut self) -> u64 { let max_encoded_len = StoredInboundLaneData::::max_encoded_len(); let relayers_count = self.get_or_init_data().relayers.len(); let actual_encoded_len = - InboundLaneData::::encoded_size_hint(relayers_count) + InboundLaneData::>>::encoded_size_hint(relayers_count) .unwrap_or(usize::MAX); max_encoded_len.saturating_sub(actual_encoded_len) as _ } } impl, I: 'static> InboundLaneStorage for RuntimeInboundLaneStorage { - type Relayer = T::InboundRelayer; + type Relayer = AccountIdOf>; fn id(&self) -> LaneId { self.lane_id } fn max_unrewarded_relayer_entries(&self) -> MessageNonce { - T::MaxUnrewardedRelayerEntriesAtInboundLane::get() + BridgedChainOf::::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX } fn max_unconfirmed_messages(&self) -> MessageNonce { - T::MaxUnconfirmedMessagesAtInboundLane::get() + BridgedChainOf::::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX } - fn get_or_init_data(&mut self) -> InboundLaneData { + fn get_or_init_data(&mut self) -> InboundLaneData>> { match self.cached_data { Some(ref data) => data.clone(), None => { - let data: InboundLaneData = + let data: InboundLaneData>> = InboundLanes::::get(self.lane_id).into(); self.cached_data = Some(data.clone()); data @@ -842,7 +795,7 @@ impl, I: 'static> InboundLaneStorage for RuntimeInboundLaneStorage< } } - fn set_data(&mut self, data: InboundLaneData) { + fn set_data(&mut self, data: InboundLaneData>>) { self.cached_data = Some(data.clone()); InboundLanes::::insert(self.lane_id, StoredInboundLaneData::(data)) } @@ -887,14 +840,14 @@ impl, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorag } /// Verify messages proof and return proved messages with decoded payload. -fn verify_and_decode_messages_proof( - proof: Chain::MessagesProof, +fn verify_and_decode_messages_proof, I: 'static>( + proof: FromBridgedChainMessagesProof>>, messages_count: u32, -) -> Result>, VerificationError> { - // `receive_messages_proof` weight formula and `MaxUnconfirmedMessagesAtInboundLane` check - // guarantees that the `message_count` is sane and Vec may be allocated. +) -> Result>, VerificationError> { + // `receive_messages_proof` weight formula and `MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX` + // check guarantees that the `message_count` is sane and Vec may be allocated. // (tx with too many messages will either be rejected from the pool, or will fail earlier) - Chain::verify_messages_proof(proof, messages_count).map(|messages_by_lane| { + proofs::verify_messages_proof::(proof, messages_count).map(|messages_by_lane| { messages_by_lane .into_iter() .map(|(lane, lane_data)| { @@ -909,1209 +862,3 @@ fn verify_and_decode_messages_proof::set_block_number(1); - System::::reset_events(); - } - - fn send_regular_message(lane_id: LaneId) { - get_ready_for_events(); - - let outbound_lane = outbound_lane::(lane_id); - let message_nonce = outbound_lane.data().latest_generated_nonce + 1; - let prev_enqueued_messages = outbound_lane.data().queued_messages().saturating_len(); - let valid_message = Pallet::::validate_message(lane_id, ®ULAR_PAYLOAD) - .expect("validate_message has failed"); - let artifacts = Pallet::::send_message(valid_message); - assert_eq!(artifacts.enqueued_messages, prev_enqueued_messages + 1); - - // check event with assigned nonce - assert_eq!( - System::::events(), - vec![EventRecord { - phase: Phase::Initialization, - event: TestEvent::Messages(Event::MessageAccepted { - lane_id, - nonce: message_nonce - }), - topics: vec![], - }], - ); - } - - fn receive_messages_delivery_proof() { - System::::set_block_number(1); - System::::reset_events(); - - assert_ok!(Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - TestMessagesDeliveryProof(Ok(( - TEST_LANE_ID, - InboundLaneData { - last_confirmed_nonce: 1, - relayers: vec![UnrewardedRelayer { - relayer: 0, - messages: DeliveredMessages::new(1), - }] - .into_iter() - .collect(), - }, - ))), - UnrewardedRelayersState { - unrewarded_relayer_entries: 1, - messages_in_oldest_entry: 1, - total_messages: 1, - last_delivered_nonce: 1, - }, - )); - - assert_eq!( - System::::events(), - vec![EventRecord { - phase: Phase::Initialization, - event: TestEvent::Messages(Event::MessagesDelivered { - lane_id: TEST_LANE_ID, - messages: DeliveredMessages::new(1), - }), - topics: vec![], - }], - ); - } - - #[test] - fn pallet_rejects_transactions_if_halted() { - run_test(|| { - // send message first to be able to check that delivery_proof fails later - send_regular_message(TEST_LANE_ID); - - PalletOperatingMode::::put(MessagesOperatingMode::Basic( - BasicOperatingMode::Halted, - )); - - assert_noop!( - Pallet::::validate_message(TEST_LANE_ID, ®ULAR_PAYLOAD), - Error::::NotOperatingNormally, - ); - - assert_noop!( - Pallet::::receive_messages_proof( - RuntimeOrigin::signed(1), - TEST_RELAYER_A, - Ok(vec![message(2, REGULAR_PAYLOAD)]).into(), - 1, - REGULAR_PAYLOAD.declared_weight, - ), - Error::::BridgeModule(bp_runtime::OwnedBridgeModuleError::Halted), - ); - - assert_noop!( - Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - TestMessagesDeliveryProof(Ok(( - TEST_LANE_ID, - InboundLaneData { - last_confirmed_nonce: 1, - relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)] - .into_iter() - .collect(), - }, - ))), - UnrewardedRelayersState { - unrewarded_relayer_entries: 1, - messages_in_oldest_entry: 1, - total_messages: 1, - last_delivered_nonce: 1, - }, - ), - Error::::BridgeModule(bp_runtime::OwnedBridgeModuleError::Halted), - ); - }); - } - - #[test] - fn pallet_rejects_new_messages_in_rejecting_outbound_messages_operating_mode() { - run_test(|| { - // send message first to be able to check that delivery_proof fails later - send_regular_message(TEST_LANE_ID); - - PalletOperatingMode::::put( - MessagesOperatingMode::RejectingOutboundMessages, - ); - - assert_noop!( - Pallet::::validate_message(TEST_LANE_ID, ®ULAR_PAYLOAD), - Error::::NotOperatingNormally, - ); - - assert_ok!(Pallet::::receive_messages_proof( - RuntimeOrigin::signed(1), - TEST_RELAYER_A, - Ok(vec![message(1, REGULAR_PAYLOAD)]).into(), - 1, - REGULAR_PAYLOAD.declared_weight, - ),); - - assert_ok!(Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - TestMessagesDeliveryProof(Ok(( - TEST_LANE_ID, - InboundLaneData { - last_confirmed_nonce: 1, - relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)] - .into_iter() - .collect(), - }, - ))), - UnrewardedRelayersState { - unrewarded_relayer_entries: 1, - messages_in_oldest_entry: 1, - total_messages: 1, - last_delivered_nonce: 1, - }, - )); - }); - } - - #[test] - fn send_message_works() { - run_test(|| { - send_regular_message(TEST_LANE_ID); - }); - } - - #[test] - fn send_message_rejects_too_large_message() { - run_test(|| { - let mut message_payload = message_payload(1, 0); - // the payload isn't simply extra, so it'll definitely overflow - // `MAX_OUTBOUND_PAYLOAD_SIZE` if we add `MAX_OUTBOUND_PAYLOAD_SIZE` bytes to extra - message_payload - .extra - .extend_from_slice(&[0u8; MAX_OUTBOUND_PAYLOAD_SIZE as usize]); - assert_noop!( - Pallet::::validate_message(TEST_LANE_ID, &message_payload.clone(),), - Error::::MessageRejectedByPallet( - VerificationError::MessageTooLarge - ), - ); - - // let's check that we're able to send `MAX_OUTBOUND_PAYLOAD_SIZE` messages - while message_payload.encoded_size() as u32 > MAX_OUTBOUND_PAYLOAD_SIZE { - message_payload.extra.pop(); - } - assert_eq!(message_payload.encoded_size() as u32, MAX_OUTBOUND_PAYLOAD_SIZE); - - let valid_message = - Pallet::::validate_message(TEST_LANE_ID, &message_payload) - .expect("validate_message has failed"); - Pallet::::send_message(valid_message); - }) - } - - #[test] - fn chain_verifier_rejects_invalid_message_in_send_message() { - run_test(|| { - // messages with this payload are rejected by target chain verifier - assert_noop!( - Pallet::::validate_message( - TEST_LANE_ID, - &PAYLOAD_REJECTED_BY_TARGET_CHAIN, - ), - Error::::MessageRejectedByChainVerifier(VerificationError::Other( - mock::TEST_ERROR - )), - ); - }); - } - - #[test] - fn receive_messages_proof_works() { - run_test(|| { - assert_ok!(Pallet::::receive_messages_proof( - RuntimeOrigin::signed(1), - TEST_RELAYER_A, - Ok(vec![message(1, REGULAR_PAYLOAD)]).into(), - 1, - REGULAR_PAYLOAD.declared_weight, - )); - - assert_eq!(InboundLanes::::get(TEST_LANE_ID).0.last_delivered_nonce(), 1); - - assert!(TestDeliveryPayments::is_reward_paid(1)); - }); - } - - #[test] - fn receive_messages_proof_updates_confirmed_message_nonce() { - run_test(|| { - // say we have received 10 messages && last confirmed message is 8 - InboundLanes::::insert( - TEST_LANE_ID, - InboundLaneData { - last_confirmed_nonce: 8, - relayers: vec![ - unrewarded_relayer(9, 9, TEST_RELAYER_A), - unrewarded_relayer(10, 10, TEST_RELAYER_B), - ] - .into_iter() - .collect(), - }, - ); - assert_eq!( - inbound_unrewarded_relayers_state(TEST_LANE_ID), - UnrewardedRelayersState { - unrewarded_relayer_entries: 2, - messages_in_oldest_entry: 1, - total_messages: 2, - last_delivered_nonce: 10, - }, - ); - - // message proof includes outbound lane state with latest confirmed message updated to 9 - let mut message_proof: TestMessagesProof = - Ok(vec![message(11, REGULAR_PAYLOAD)]).into(); - message_proof.result.as_mut().unwrap()[0].1.lane_state = - Some(OutboundLaneData { latest_received_nonce: 9, ..Default::default() }); - - assert_ok!(Pallet::::receive_messages_proof( - RuntimeOrigin::signed(1), - TEST_RELAYER_A, - message_proof, - 1, - REGULAR_PAYLOAD.declared_weight, - )); - - assert_eq!( - InboundLanes::::get(TEST_LANE_ID).0, - InboundLaneData { - last_confirmed_nonce: 9, - relayers: vec![ - unrewarded_relayer(10, 10, TEST_RELAYER_B), - unrewarded_relayer(11, 11, TEST_RELAYER_A) - ] - .into_iter() - .collect(), - }, - ); - assert_eq!( - inbound_unrewarded_relayers_state(TEST_LANE_ID), - UnrewardedRelayersState { - unrewarded_relayer_entries: 2, - messages_in_oldest_entry: 1, - total_messages: 2, - last_delivered_nonce: 11, - }, - ); - }); - } - - #[test] - fn receive_messages_fails_if_dispatcher_is_inactive() { - run_test(|| { - TestMessageDispatch::deactivate(); - assert_noop!( - Pallet::::receive_messages_proof( - RuntimeOrigin::signed(1), - TEST_RELAYER_A, - Ok(vec![message(1, REGULAR_PAYLOAD)]).into(), - 1, - REGULAR_PAYLOAD.declared_weight, - ), - Error::::MessageDispatchInactive, - ); - }); - } - - #[test] - fn receive_messages_proof_does_not_accept_message_if_dispatch_weight_is_not_enough() { - run_test(|| { - let mut declared_weight = REGULAR_PAYLOAD.declared_weight; - *declared_weight.ref_time_mut() -= 1; - assert_noop!( - Pallet::::receive_messages_proof( - RuntimeOrigin::signed(1), - TEST_RELAYER_A, - Ok(vec![message(1, REGULAR_PAYLOAD)]).into(), - 1, - declared_weight, - ), - Error::::InsufficientDispatchWeight - ); - assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 0); - }); - } - - #[test] - fn receive_messages_proof_rejects_invalid_proof() { - run_test(|| { - assert_noop!( - Pallet::::receive_messages_proof( - RuntimeOrigin::signed(1), - TEST_RELAYER_A, - Err(()).into(), - 1, - Weight::zero(), - ), - Error::::InvalidMessagesProof, - ); - }); - } - - #[test] - fn receive_messages_proof_rejects_proof_with_too_many_messages() { - run_test(|| { - assert_noop!( - Pallet::::receive_messages_proof( - RuntimeOrigin::signed(1), - TEST_RELAYER_A, - Ok(vec![message(1, REGULAR_PAYLOAD)]).into(), - u32::MAX, - Weight::zero(), - ), - Error::::TooManyMessagesInTheProof, - ); - }); - } - - #[test] - fn receive_messages_delivery_proof_works() { - run_test(|| { - send_regular_message(TEST_LANE_ID); - receive_messages_delivery_proof(); - - assert_eq!( - OutboundLanes::::get(TEST_LANE_ID).latest_received_nonce, - 1, - ); - }); - } - - #[test] - fn receive_messages_delivery_proof_rewards_relayers() { - run_test(|| { - send_regular_message(TEST_LANE_ID); - send_regular_message(TEST_LANE_ID); - - // this reports delivery of message 1 => reward is paid to TEST_RELAYER_A - let single_message_delivery_proof = TestMessagesDeliveryProof(Ok(( - TEST_LANE_ID, - InboundLaneData { - relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)].into_iter().collect(), - ..Default::default() - }, - ))); - let single_message_delivery_proof_size = single_message_delivery_proof.size(); - let result = Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - single_message_delivery_proof, - UnrewardedRelayersState { - unrewarded_relayer_entries: 1, - messages_in_oldest_entry: 1, - total_messages: 1, - last_delivered_nonce: 1, - }, - ); - assert_ok!(result); - assert_eq!( - result.unwrap().actual_weight.unwrap(), - TestWeightInfo::receive_messages_delivery_proof_weight( - &PreComputedSize(single_message_delivery_proof_size as _), - &UnrewardedRelayersState { - unrewarded_relayer_entries: 1, - total_messages: 1, - ..Default::default() - }, - ) - ); - assert!(TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_A, 1)); - assert!(!TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_B, 1)); - assert_eq!(TestOnMessagesDelivered::call_arguments(), Some((TEST_LANE_ID, 1))); - - // this reports delivery of both message 1 and message 2 => reward is paid only to - // TEST_RELAYER_B - let two_messages_delivery_proof = TestMessagesDeliveryProof(Ok(( - TEST_LANE_ID, - InboundLaneData { - relayers: vec![ - unrewarded_relayer(1, 1, TEST_RELAYER_A), - unrewarded_relayer(2, 2, TEST_RELAYER_B), - ] - .into_iter() - .collect(), - ..Default::default() - }, - ))); - let two_messages_delivery_proof_size = two_messages_delivery_proof.size(); - let result = Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - two_messages_delivery_proof, - UnrewardedRelayersState { - unrewarded_relayer_entries: 2, - messages_in_oldest_entry: 1, - total_messages: 2, - last_delivered_nonce: 2, - }, - ); - assert_ok!(result); - // even though the pre-dispatch weight was for two messages, the actual weight is - // for single message only - assert_eq!( - result.unwrap().actual_weight.unwrap(), - TestWeightInfo::receive_messages_delivery_proof_weight( - &PreComputedSize(two_messages_delivery_proof_size as _), - &UnrewardedRelayersState { - unrewarded_relayer_entries: 1, - total_messages: 1, - ..Default::default() - }, - ) - ); - assert!(!TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_A, 1)); - assert!(TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_B, 1)); - assert_eq!(TestOnMessagesDelivered::call_arguments(), Some((TEST_LANE_ID, 0))); - }); - } - - #[test] - fn receive_messages_delivery_proof_rejects_invalid_proof() { - run_test(|| { - assert_noop!( - Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - TestMessagesDeliveryProof(Err(())), - Default::default(), - ), - Error::::InvalidMessagesDeliveryProof, - ); - }); - } - - #[test] - fn receive_messages_delivery_proof_rejects_proof_if_declared_relayers_state_is_invalid() { - run_test(|| { - // when number of relayers entries is invalid - assert_noop!( - Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - TestMessagesDeliveryProof(Ok(( - TEST_LANE_ID, - InboundLaneData { - relayers: vec![ - unrewarded_relayer(1, 1, TEST_RELAYER_A), - unrewarded_relayer(2, 2, TEST_RELAYER_B) - ] - .into_iter() - .collect(), - ..Default::default() - } - ))), - UnrewardedRelayersState { - unrewarded_relayer_entries: 1, - total_messages: 2, - last_delivered_nonce: 2, - ..Default::default() - }, - ), - Error::::InvalidUnrewardedRelayersState, - ); - - // when number of messages is invalid - assert_noop!( - Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - TestMessagesDeliveryProof(Ok(( - TEST_LANE_ID, - InboundLaneData { - relayers: vec![ - unrewarded_relayer(1, 1, TEST_RELAYER_A), - unrewarded_relayer(2, 2, TEST_RELAYER_B) - ] - .into_iter() - .collect(), - ..Default::default() - } - ))), - UnrewardedRelayersState { - unrewarded_relayer_entries: 2, - total_messages: 1, - last_delivered_nonce: 2, - ..Default::default() - }, - ), - Error::::InvalidUnrewardedRelayersState, - ); - - // when last delivered nonce is invalid - assert_noop!( - Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - TestMessagesDeliveryProof(Ok(( - TEST_LANE_ID, - InboundLaneData { - relayers: vec![ - unrewarded_relayer(1, 1, TEST_RELAYER_A), - unrewarded_relayer(2, 2, TEST_RELAYER_B) - ] - .into_iter() - .collect(), - ..Default::default() - } - ))), - UnrewardedRelayersState { - unrewarded_relayer_entries: 2, - total_messages: 2, - last_delivered_nonce: 8, - ..Default::default() - }, - ), - Error::::InvalidUnrewardedRelayersState, - ); - }); - } - - #[test] - fn receive_messages_accepts_single_message_with_invalid_payload() { - run_test(|| { - let mut invalid_message = message(1, REGULAR_PAYLOAD); - invalid_message.payload = Vec::new(); - - assert_ok!(Pallet::::receive_messages_proof( - RuntimeOrigin::signed(1), - TEST_RELAYER_A, - Ok(vec![invalid_message]).into(), - 1, - Weight::zero(), /* weight may be zero in this case (all messages are - * improperly encoded) */ - ),); - - assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 1,); - }); - } - - #[test] - fn receive_messages_accepts_batch_with_message_with_invalid_payload() { - run_test(|| { - let mut invalid_message = message(2, REGULAR_PAYLOAD); - invalid_message.payload = Vec::new(); - - assert_ok!(Pallet::::receive_messages_proof( - RuntimeOrigin::signed(1), - TEST_RELAYER_A, - Ok( - vec![message(1, REGULAR_PAYLOAD), invalid_message, message(3, REGULAR_PAYLOAD),] - ) - .into(), - 3, - REGULAR_PAYLOAD.declared_weight + REGULAR_PAYLOAD.declared_weight, - ),); - - assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 3,); - }); - } - - #[test] - fn actual_dispatch_weight_does_not_overflow() { - run_test(|| { - let message1 = message(1, message_payload(0, u64::MAX / 2)); - let message2 = message(2, message_payload(0, u64::MAX / 2)); - let message3 = message(3, message_payload(0, u64::MAX / 2)); - - assert_noop!( - Pallet::::receive_messages_proof( - RuntimeOrigin::signed(1), - TEST_RELAYER_A, - // this may cause overflow if source chain storage is invalid - Ok(vec![message1, message2, message3]).into(), - 3, - Weight::MAX, - ), - Error::::InsufficientDispatchWeight - ); - assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 0); - }); - } - - #[test] - fn ref_time_refund_from_receive_messages_proof_works() { - run_test(|| { - fn submit_with_unspent_weight( - nonce: MessageNonce, - unspent_weight: u64, - ) -> (Weight, Weight) { - let mut payload = REGULAR_PAYLOAD; - *payload.dispatch_result.unspent_weight.ref_time_mut() = unspent_weight; - let proof = Ok(vec![message(nonce, payload)]).into(); - let messages_count = 1; - let pre_dispatch_weight = - ::WeightInfo::receive_messages_proof_weight( - &proof, - messages_count, - REGULAR_PAYLOAD.declared_weight, - ); - let result = Pallet::::receive_messages_proof( - RuntimeOrigin::signed(1), - TEST_RELAYER_A, - proof, - messages_count, - REGULAR_PAYLOAD.declared_weight, - ) - .expect("delivery has failed"); - let post_dispatch_weight = - result.actual_weight.expect("receive_messages_proof always returns Some"); - - // message delivery transactions are never free - assert_eq!(result.pays_fee, Pays::Yes); - - (pre_dispatch_weight, post_dispatch_weight) - } - - // when dispatch is returning `unspent_weight < declared_weight` - let (pre, post) = submit_with_unspent_weight(1, 1); - assert_eq!(post.ref_time(), pre.ref_time() - 1); - - // when dispatch is returning `unspent_weight = declared_weight` - let (pre, post) = - submit_with_unspent_weight(2, REGULAR_PAYLOAD.declared_weight.ref_time()); - assert_eq!( - post.ref_time(), - pre.ref_time() - REGULAR_PAYLOAD.declared_weight.ref_time() - ); - - // when dispatch is returning `unspent_weight > declared_weight` - let (pre, post) = - submit_with_unspent_weight(3, REGULAR_PAYLOAD.declared_weight.ref_time() + 1); - assert_eq!( - post.ref_time(), - pre.ref_time() - REGULAR_PAYLOAD.declared_weight.ref_time() - ); - - // when there's no unspent weight - let (pre, post) = submit_with_unspent_weight(4, 0); - assert_eq!(post.ref_time(), pre.ref_time()); - - // when dispatch is returning `unspent_weight < declared_weight` - let (pre, post) = submit_with_unspent_weight(5, 1); - assert_eq!(post.ref_time(), pre.ref_time() - 1); - }); - } - - #[test] - fn proof_size_refund_from_receive_messages_proof_works() { - run_test(|| { - let max_entries = crate::mock::MaxUnrewardedRelayerEntriesAtInboundLane::get() as usize; - - // if there's maximal number of unrewarded relayer entries at the inbound lane, then - // `proof_size` is unchanged in post-dispatch weight - let proof: TestMessagesProof = Ok(vec![message(101, REGULAR_PAYLOAD)]).into(); - let messages_count = 1; - let pre_dispatch_weight = - ::WeightInfo::receive_messages_proof_weight( - &proof, - messages_count, - REGULAR_PAYLOAD.declared_weight, - ); - InboundLanes::::insert( - TEST_LANE_ID, - StoredInboundLaneData(InboundLaneData { - relayers: vec![ - UnrewardedRelayer { - relayer: 42, - messages: DeliveredMessages { begin: 0, end: 100 } - }; - max_entries - ] - .into_iter() - .collect(), - last_confirmed_nonce: 0, - }), - ); - let post_dispatch_weight = Pallet::::receive_messages_proof( - RuntimeOrigin::signed(1), - TEST_RELAYER_A, - proof.clone(), - messages_count, - REGULAR_PAYLOAD.declared_weight, - ) - .unwrap() - .actual_weight - .unwrap(); - assert_eq!(post_dispatch_weight.proof_size(), pre_dispatch_weight.proof_size()); - - // if count of unrewarded relayer entries is less than maximal, then some `proof_size` - // must be refunded - InboundLanes::::insert( - TEST_LANE_ID, - StoredInboundLaneData(InboundLaneData { - relayers: vec![ - UnrewardedRelayer { - relayer: 42, - messages: DeliveredMessages { begin: 0, end: 100 } - }; - max_entries - 1 - ] - .into_iter() - .collect(), - last_confirmed_nonce: 0, - }), - ); - let post_dispatch_weight = Pallet::::receive_messages_proof( - RuntimeOrigin::signed(1), - TEST_RELAYER_A, - proof, - messages_count, - REGULAR_PAYLOAD.declared_weight, - ) - .unwrap() - .actual_weight - .unwrap(); - assert!( - post_dispatch_weight.proof_size() < pre_dispatch_weight.proof_size(), - "Expected post-dispatch PoV {} to be less than pre-dispatch PoV {}", - post_dispatch_weight.proof_size(), - pre_dispatch_weight.proof_size(), - ); - }); - } - - #[test] - fn messages_delivered_callbacks_are_called() { - run_test(|| { - send_regular_message(TEST_LANE_ID); - send_regular_message(TEST_LANE_ID); - send_regular_message(TEST_LANE_ID); - - // messages 1+2 are confirmed in 1 tx, message 3 in a separate tx - // dispatch of message 2 has failed - let mut delivered_messages_1_and_2 = DeliveredMessages::new(1); - delivered_messages_1_and_2.note_dispatched_message(); - let messages_1_and_2_proof = Ok(( - TEST_LANE_ID, - InboundLaneData { - last_confirmed_nonce: 0, - relayers: vec![UnrewardedRelayer { - relayer: 0, - messages: delivered_messages_1_and_2.clone(), - }] - .into_iter() - .collect(), - }, - )); - let delivered_message_3 = DeliveredMessages::new(3); - let messages_3_proof = Ok(( - TEST_LANE_ID, - InboundLaneData { - last_confirmed_nonce: 0, - relayers: vec![UnrewardedRelayer { relayer: 0, messages: delivered_message_3 }] - .into_iter() - .collect(), - }, - )); - - // first tx with messages 1+2 - assert_ok!(Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - TestMessagesDeliveryProof(messages_1_and_2_proof), - UnrewardedRelayersState { - unrewarded_relayer_entries: 1, - messages_in_oldest_entry: 2, - total_messages: 2, - last_delivered_nonce: 2, - }, - )); - // second tx with message 3 - assert_ok!(Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - TestMessagesDeliveryProof(messages_3_proof), - UnrewardedRelayersState { - unrewarded_relayer_entries: 1, - messages_in_oldest_entry: 1, - total_messages: 1, - last_delivered_nonce: 3, - }, - )); - }); - } - - #[test] - fn receive_messages_delivery_proof_rejects_proof_if_trying_to_confirm_more_messages_than_expected( - ) { - run_test(|| { - // send message first to be able to check that delivery_proof fails later - send_regular_message(TEST_LANE_ID); - - // 1) InboundLaneData declares that the `last_confirmed_nonce` is 1; - // 2) InboundLaneData has no entries => `InboundLaneData::last_delivered_nonce()` - // returns `last_confirmed_nonce`; - // 3) it means that we're going to confirm delivery of messages 1..=1; - // 4) so the number of declared messages (see `UnrewardedRelayersState`) is `0` and - // number of actually confirmed messages is `1`. - assert_noop!( - Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - TestMessagesDeliveryProof(Ok(( - TEST_LANE_ID, - InboundLaneData { last_confirmed_nonce: 1, relayers: Default::default() }, - ))), - UnrewardedRelayersState { last_delivered_nonce: 1, ..Default::default() }, - ), - Error::::ReceptionConfirmation( - ReceptionConfirmationError::TryingToConfirmMoreMessagesThanExpected - ), - ); - }); - } - - #[test] - fn storage_keys_computed_properly() { - assert_eq!( - PalletOperatingMode::::storage_value_final_key().to_vec(), - bp_messages::storage_keys::operating_mode_key("Messages").0, - ); - - assert_eq!( - OutboundMessages::::storage_map_final_key(MessageKey { - lane_id: TEST_LANE_ID, - nonce: 42 - }), - bp_messages::storage_keys::message_key("Messages", &TEST_LANE_ID, 42).0, - ); - - assert_eq!( - OutboundLanes::::storage_map_final_key(TEST_LANE_ID), - bp_messages::storage_keys::outbound_lane_data_key("Messages", &TEST_LANE_ID).0, - ); - - assert_eq!( - InboundLanes::::storage_map_final_key(TEST_LANE_ID), - bp_messages::storage_keys::inbound_lane_data_key("Messages", &TEST_LANE_ID).0, - ); - } - - #[test] - fn inbound_message_details_works() { - run_test(|| { - assert_eq!( - Pallet::::inbound_message_data( - TEST_LANE_ID, - REGULAR_PAYLOAD.encode(), - OutboundMessageDetails { nonce: 0, dispatch_weight: Weight::zero(), size: 0 }, - ), - InboundMessageDetails { dispatch_weight: REGULAR_PAYLOAD.declared_weight }, - ); - }); - } - - #[test] - fn on_idle_callback_respects_remaining_weight() { - run_test(|| { - send_regular_message(TEST_LANE_ID); - send_regular_message(TEST_LANE_ID); - send_regular_message(TEST_LANE_ID); - send_regular_message(TEST_LANE_ID); - - assert_ok!(Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - TestMessagesDeliveryProof(Ok(( - TEST_LANE_ID, - InboundLaneData { - last_confirmed_nonce: 4, - relayers: vec![unrewarded_relayer(1, 4, TEST_RELAYER_A)] - .into_iter() - .collect(), - }, - ))), - UnrewardedRelayersState { - unrewarded_relayer_entries: 1, - messages_in_oldest_entry: 4, - total_messages: 4, - last_delivered_nonce: 4, - }, - )); - - // all 4 messages may be pruned now - assert_eq!( - outbound_lane::(TEST_LANE_ID).data().latest_received_nonce, - 4 - ); - assert_eq!( - outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, - 1 - ); - System::::set_block_number(2); - - // if passed wight is too low to do anything - let dbw = DbWeight::get(); - assert_eq!( - Pallet::::on_idle(0, dbw.reads_writes(1, 1)), - Weight::zero(), - ); - assert_eq!( - outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, - 1 - ); - - // if passed wight is enough to prune single message - assert_eq!( - Pallet::::on_idle(0, dbw.reads_writes(1, 2)), - dbw.reads_writes(1, 2), - ); - assert_eq!( - outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, - 2 - ); - - // if passed wight is enough to prune two more messages - assert_eq!( - Pallet::::on_idle(0, dbw.reads_writes(1, 3)), - dbw.reads_writes(1, 3), - ); - assert_eq!( - outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, - 4 - ); - - // if passed wight is enough to prune many messages - assert_eq!( - Pallet::::on_idle(0, dbw.reads_writes(100, 100)), - dbw.reads_writes(1, 2), - ); - assert_eq!( - outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, - 5 - ); - }); - } - - #[test] - fn on_idle_callback_is_rotating_lanes_to_prune() { - run_test(|| { - // send + receive confirmation for lane 1 - send_regular_message(TEST_LANE_ID); - receive_messages_delivery_proof(); - // send + receive confirmation for lane 2 - send_regular_message(TEST_LANE_ID_2); - assert_ok!(Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - TestMessagesDeliveryProof(Ok(( - TEST_LANE_ID_2, - InboundLaneData { - last_confirmed_nonce: 1, - relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)] - .into_iter() - .collect(), - }, - ))), - UnrewardedRelayersState { - unrewarded_relayer_entries: 1, - messages_in_oldest_entry: 1, - total_messages: 1, - last_delivered_nonce: 1, - }, - )); - - // nothing is pruned yet - assert_eq!( - outbound_lane::(TEST_LANE_ID).data().latest_received_nonce, - 1 - ); - assert_eq!( - outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, - 1 - ); - assert_eq!( - outbound_lane::(TEST_LANE_ID_2).data().latest_received_nonce, - 1 - ); - assert_eq!( - outbound_lane::(TEST_LANE_ID_2).data().oldest_unpruned_nonce, - 1 - ); - - // in block#2.on_idle lane messages of lane 1 are pruned - let dbw = DbWeight::get(); - System::::set_block_number(2); - assert_eq!( - Pallet::::on_idle(0, dbw.reads_writes(100, 100)), - dbw.reads_writes(1, 2), - ); - assert_eq!( - outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, - 2 - ); - assert_eq!( - outbound_lane::(TEST_LANE_ID_2).data().oldest_unpruned_nonce, - 1 - ); - - // in block#3.on_idle lane messages of lane 2 are pruned - System::::set_block_number(3); - - assert_eq!( - Pallet::::on_idle(0, dbw.reads_writes(100, 100)), - dbw.reads_writes(1, 2), - ); - assert_eq!( - outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, - 2 - ); - assert_eq!( - outbound_lane::(TEST_LANE_ID_2).data().oldest_unpruned_nonce, - 2 - ); - }); - } - - #[test] - fn outbound_message_from_unconfigured_lane_is_rejected() { - run_test(|| { - assert_noop!( - Pallet::::validate_message(TEST_LANE_ID_3, ®ULAR_PAYLOAD,), - Error::::InactiveOutboundLane, - ); - }); - } - - #[test] - fn test_bridge_messages_call_is_correctly_defined() { - let account_id = 1; - let message_proof: TestMessagesProof = Ok(vec![message(1, REGULAR_PAYLOAD)]).into(); - let message_delivery_proof = TestMessagesDeliveryProof(Ok(( - TEST_LANE_ID, - InboundLaneData { - last_confirmed_nonce: 1, - relayers: vec![UnrewardedRelayer { - relayer: 0, - messages: DeliveredMessages::new(1), - }] - .into_iter() - .collect(), - }, - ))); - let unrewarded_relayer_state = UnrewardedRelayersState { - unrewarded_relayer_entries: 1, - total_messages: 1, - last_delivered_nonce: 1, - ..Default::default() - }; - - let direct_receive_messages_proof_call = Call::::receive_messages_proof { - relayer_id_at_bridged_chain: account_id, - proof: message_proof.clone(), - messages_count: 1, - dispatch_weight: REGULAR_PAYLOAD.declared_weight, - }; - let indirect_receive_messages_proof_call = BridgeMessagesCall::< - AccountId, - TestMessagesProof, - TestMessagesDeliveryProof, - >::receive_messages_proof { - relayer_id_at_bridged_chain: account_id, - proof: message_proof, - messages_count: 1, - dispatch_weight: REGULAR_PAYLOAD.declared_weight, - }; - assert_eq!( - direct_receive_messages_proof_call.encode(), - indirect_receive_messages_proof_call.encode() - ); - - let direct_receive_messages_delivery_proof_call = - Call::::receive_messages_delivery_proof { - proof: message_delivery_proof.clone(), - relayers_state: unrewarded_relayer_state.clone(), - }; - let indirect_receive_messages_delivery_proof_call = BridgeMessagesCall::< - AccountId, - TestMessagesProof, - TestMessagesDeliveryProof, - >::receive_messages_delivery_proof { - proof: message_delivery_proof, - relayers_state: unrewarded_relayer_state, - }; - assert_eq!( - direct_receive_messages_delivery_proof_call.encode(), - indirect_receive_messages_delivery_proof_call.encode() - ); - } - - generate_owned_bridge_module_tests!( - MessagesOperatingMode::Basic(BasicOperatingMode::Normal), - MessagesOperatingMode::Basic(BasicOperatingMode::Halted) - ); - - #[test] - fn inbound_storage_extra_proof_size_bytes_works() { - fn relayer_entry() -> UnrewardedRelayer { - UnrewardedRelayer { relayer: 42u64, messages: DeliveredMessages { begin: 0, end: 100 } } - } - - fn storage(relayer_entries: usize) -> RuntimeInboundLaneStorage { - RuntimeInboundLaneStorage { - lane_id: Default::default(), - cached_data: Some(InboundLaneData { - relayers: vec![relayer_entry(); relayer_entries].into_iter().collect(), - last_confirmed_nonce: 0, - }), - _phantom: Default::default(), - } - } - - let max_entries = crate::mock::MaxUnrewardedRelayerEntriesAtInboundLane::get() as usize; - - // when we have exactly `MaxUnrewardedRelayerEntriesAtInboundLane` unrewarded relayers - assert_eq!(storage(max_entries).extra_proof_size_bytes(), 0); - - // when we have less than `MaxUnrewardedRelayerEntriesAtInboundLane` unrewarded relayers - assert_eq!( - storage(max_entries - 1).extra_proof_size_bytes(), - relayer_entry().encode().len() as u64 - ); - assert_eq!( - storage(max_entries - 2).extra_proof_size_bytes(), - 2 * relayer_entry().encode().len() as u64 - ); - - // when we have more than `MaxUnrewardedRelayerEntriesAtInboundLane` unrewarded relayers - // (shall not happen in practice) - assert_eq!(storage(max_entries + 1).extra_proof_size_bytes(), 0); - } - - #[test] - fn maybe_outbound_lanes_count_returns_correct_value() { - assert_eq!( - MaybeOutboundLanesCount::::get(), - Some(mock::ActiveOutboundLanes::get().len() as u32) - ); - } -} diff --git a/bridges/modules/messages/src/outbound_lane.rs b/bridges/modules/messages/src/outbound_lane.rs index acef5546d2a64fa8a3fb38c6b41ae30819cdeaa2..fcdddf199dc65b37dd014745b6a1630709ad8f8b 100644 --- a/bridges/modules/messages/src/outbound_lane.rs +++ b/bridges/modules/messages/src/outbound_lane.rs @@ -18,16 +18,18 @@ use crate::{Config, LOG_TARGET}; -use bp_messages::{DeliveredMessages, LaneId, MessageNonce, OutboundLaneData, UnrewardedRelayer}; +use bp_messages::{ + ChainWithMessages, DeliveredMessages, LaneId, MessageNonce, OutboundLaneData, UnrewardedRelayer, +}; use codec::{Decode, Encode}; use frame_support::{ + traits::Get, weights::{RuntimeDbWeight, Weight}, BoundedVec, PalletError, }; -use num_traits::Zero; use scale_info::TypeInfo; -use sp_runtime::RuntimeDebug; -use sp_std::collections::vec_deque::VecDeque; +use sp_runtime::{traits::Zero, RuntimeDebug}; +use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData}; /// Outbound lane storage. pub trait OutboundLaneStorage { @@ -48,8 +50,17 @@ pub trait OutboundLaneStorage { fn remove_message(&mut self, nonce: &MessageNonce); } +/// Limit for the `StoredMessagePayload` vector. +pub struct StoredMessagePayloadLimit(PhantomData<(T, I)>); + +impl, I: 'static> Get for StoredMessagePayloadLimit { + fn get() -> u32 { + T::BridgedChain::maximal_incoming_message_size() + } +} + /// Outbound message data wrapper that implements `MaxEncodedLen`. -pub type StoredMessagePayload = BoundedVec>::MaximalOutboundPayloadSize>; +pub type StoredMessagePayload = BoundedVec>; /// Result of messages receival confirmation. #[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, PalletError, TypeInfo)] @@ -204,11 +215,11 @@ fn ensure_unrewarded_relayers_are_correct( mod tests { use super::*; use crate::{ - mock::{ + outbound_lane, + tests::mock::{ outbound_message_data, run_test, unrewarded_relayer, TestRelayer, TestRuntime, REGULAR_PAYLOAD, TEST_LANE_ID, }, - outbound_lane, }; use frame_support::weights::constants::RocksDbWeight; use sp_std::ops::RangeInclusive; @@ -263,12 +274,43 @@ mod tests { assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 3); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 0); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); assert_eq!( lane.confirm_delivery(3, 3, &unrewarded_relayers(1..=3)), Ok(Some(delivered_messages(1..=3))), ); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 3); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); + }); + } + + #[test] + fn confirm_partial_delivery_works() { + run_test(|| { + let mut lane = outbound_lane::(TEST_LANE_ID); + assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1); + assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 2); + assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 3); + assert_eq!(lane.storage.data().latest_generated_nonce, 3); + assert_eq!(lane.storage.data().latest_received_nonce, 0); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); + + assert_eq!( + lane.confirm_delivery(3, 2, &unrewarded_relayers(1..=2)), + Ok(Some(delivered_messages(1..=2))), + ); + assert_eq!(lane.storage.data().latest_generated_nonce, 3); + assert_eq!(lane.storage.data().latest_received_nonce, 2); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); + + assert_eq!( + lane.confirm_delivery(3, 3, &unrewarded_relayers(3..=3)), + Ok(Some(delivered_messages(3..=3))), + ); + assert_eq!(lane.storage.data().latest_generated_nonce, 3); + assert_eq!(lane.storage.data().latest_received_nonce, 3); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); }); } @@ -281,6 +323,7 @@ mod tests { lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 0); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); assert_eq!( lane.confirm_delivery(3, 3, &unrewarded_relayers(1..=3)), Ok(Some(delivered_messages(1..=3))), @@ -288,10 +331,12 @@ mod tests { assert_eq!(lane.confirm_delivery(3, 3, &unrewarded_relayers(1..=3)), Ok(None),); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 3); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); assert_eq!(lane.confirm_delivery(1, 2, &unrewarded_relayers(1..=1)), Ok(None),); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 3); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); }); } @@ -310,8 +355,8 @@ mod tests { 3, &unrewarded_relayers(1..=1) .into_iter() - .chain(unrewarded_relayers(2..=30).into_iter()) - .chain(unrewarded_relayers(3..=3).into_iter()) + .chain(unrewarded_relayers(2..=30)) + .chain(unrewarded_relayers(3..=3)) .collect(), ), Err(ReceptionConfirmationError::FailedToConfirmFutureMessages), @@ -326,8 +371,8 @@ mod tests { 3, &unrewarded_relayers(1..=1) .into_iter() - .chain(unrewarded_relayers(2..=1).into_iter()) - .chain(unrewarded_relayers(2..=3).into_iter()) + .chain(unrewarded_relayers(2..=1)) + .chain(unrewarded_relayers(2..=3)) .collect(), ), Err(ReceptionConfirmationError::EmptyUnrewardedRelayerEntry), @@ -341,8 +386,8 @@ mod tests { 3, &unrewarded_relayers(1..=1) .into_iter() - .chain(unrewarded_relayers(3..=3).into_iter()) - .chain(unrewarded_relayers(2..=2).into_iter()) + .chain(unrewarded_relayers(3..=3)) + .chain(unrewarded_relayers(2..=2)) .collect(), ), Err(ReceptionConfirmationError::NonConsecutiveUnrewardedRelayerEntries), diff --git a/bridges/modules/messages/src/proofs.rs b/bridges/modules/messages/src/proofs.rs new file mode 100644 index 0000000000000000000000000000000000000000..a3318833fa611a6515469172dcc24f114bbbf4ad --- /dev/null +++ b/bridges/modules/messages/src/proofs.rs @@ -0,0 +1,562 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Tools for messages and delivery proof verification. + +use crate::{BridgedChainOf, BridgedHeaderChainOf, Config}; + +use bp_header_chain::{HeaderChain, HeaderChainError}; +use bp_messages::{ + source_chain::FromBridgedChainMessagesDeliveryProof, + target_chain::{FromBridgedChainMessagesProof, ProvedLaneMessages, ProvedMessages}, + ChainWithMessages, InboundLaneData, LaneId, Message, MessageKey, MessageNonce, MessagePayload, + OutboundLaneData, VerificationError, +}; +use bp_runtime::{ + HashOf, HasherOf, RangeInclusiveExt, RawStorageProof, StorageProofChecker, StorageProofError, +}; +use codec::Decode; +use sp_std::vec::Vec; + +/// 'Parsed' message delivery proof - inbound lane id and its state. +pub(crate) type ParsedMessagesDeliveryProofFromBridgedChain = + (LaneId, InboundLaneData<::AccountId>); + +/// Verify proof of Bridged -> This chain messages. +/// +/// This function is used when Bridged chain is directly using GRANDPA finality. For Bridged +/// parachains, please use the `verify_messages_proof_from_parachain`. +/// +/// The `messages_count` argument verification (sane limits) is supposed to be made +/// outside of this function. This function only verifies that the proof declares exactly +/// `messages_count` messages. +pub fn verify_messages_proof, I: 'static>( + proof: FromBridgedChainMessagesProof>>, + messages_count: u32, +) -> Result, VerificationError> { + let FromBridgedChainMessagesProof { + bridged_header_hash, + storage_proof, + lane, + nonces_start, + nonces_end, + } = proof; + let mut parser: MessagesStorageProofAdapter = + MessagesStorageProofAdapter::try_new_with_verified_storage_proof( + bridged_header_hash, + storage_proof, + ) + .map_err(VerificationError::HeaderChain)?; + let nonces_range = nonces_start..=nonces_end; + + // receiving proofs where end < begin is ok (if proof includes outbound lane state) + let messages_in_the_proof = nonces_range.saturating_len(); + if messages_in_the_proof != MessageNonce::from(messages_count) { + return Err(VerificationError::MessagesCountMismatch) + } + + // Read messages first. All messages that are claimed to be in the proof must + // be in the proof. So any error in `read_value`, or even missing value is fatal. + // + // Mind that we allow proofs with no messages if outbound lane state is proved. + let mut messages = Vec::with_capacity(messages_in_the_proof as _); + for nonce in nonces_range { + let message_key = MessageKey { lane_id: lane, nonce }; + let message_payload = parser + .read_and_decode_message_payload(&message_key) + .map_err(VerificationError::MessageStorage)?; + messages.push(Message { key: message_key, payload: message_payload }); + } + + // Now let's check if proof contains outbound lane state proof. It is optional, so + // we simply ignore `read_value` errors and missing value. + let proved_lane_messages = ProvedLaneMessages { + lane_state: parser + .read_and_decode_outbound_lane_data(&lane) + .map_err(VerificationError::OutboundLaneStorage)?, + messages, + }; + + // Now we may actually check if the proof is empty or not. + if proved_lane_messages.lane_state.is_none() && proved_lane_messages.messages.is_empty() { + return Err(VerificationError::EmptyMessageProof) + } + + // Check that the storage proof doesn't have any untouched keys. + parser.ensure_no_unused_keys().map_err(VerificationError::StorageProof)?; + + // We only support single lane messages in this generated_schema + let mut proved_messages = ProvedMessages::new(); + proved_messages.insert(lane, proved_lane_messages); + + Ok(proved_messages) +} + +/// Verify proof of This -> Bridged chain messages delivery. +pub fn verify_messages_delivery_proof, I: 'static>( + proof: FromBridgedChainMessagesDeliveryProof>>, +) -> Result, VerificationError> { + let FromBridgedChainMessagesDeliveryProof { bridged_header_hash, storage_proof, lane } = proof; + let mut parser: MessagesStorageProofAdapter = + MessagesStorageProofAdapter::try_new_with_verified_storage_proof( + bridged_header_hash, + storage_proof, + ) + .map_err(VerificationError::HeaderChain)?; + // Messages delivery proof is just proof of single storage key read => any error + // is fatal. + let storage_inbound_lane_data_key = bp_messages::storage_keys::inbound_lane_data_key( + T::ThisChain::WITH_CHAIN_MESSAGES_PALLET_NAME, + &lane, + ); + let inbound_lane_data = parser + .read_and_decode_mandatory_value(&storage_inbound_lane_data_key) + .map_err(VerificationError::InboundLaneStorage)?; + + // check that the storage proof doesn't have any untouched trie nodes + parser.ensure_no_unused_keys().map_err(VerificationError::StorageProof)?; + + Ok((lane, inbound_lane_data)) +} + +/// Abstraction over storage proof manipulation, hiding implementation details of actual storage +/// proofs. +trait StorageProofAdapter, I: 'static> { + fn read_and_decode_mandatory_value( + &mut self, + key: &impl AsRef<[u8]>, + ) -> Result; + fn read_and_decode_optional_value( + &mut self, + key: &impl AsRef<[u8]>, + ) -> Result, StorageProofError>; + fn ensure_no_unused_keys(self) -> Result<(), StorageProofError>; + + fn read_and_decode_outbound_lane_data( + &mut self, + lane_id: &LaneId, + ) -> Result, StorageProofError> { + let storage_outbound_lane_data_key = bp_messages::storage_keys::outbound_lane_data_key( + T::ThisChain::WITH_CHAIN_MESSAGES_PALLET_NAME, + lane_id, + ); + self.read_and_decode_optional_value(&storage_outbound_lane_data_key) + } + + fn read_and_decode_message_payload( + &mut self, + message_key: &MessageKey, + ) -> Result { + let storage_message_key = bp_messages::storage_keys::message_key( + T::ThisChain::WITH_CHAIN_MESSAGES_PALLET_NAME, + &message_key.lane_id, + message_key.nonce, + ); + self.read_and_decode_mandatory_value(&storage_message_key) + } +} + +/// Actual storage proof adapter for messages proofs. +type MessagesStorageProofAdapter = StorageProofCheckerAdapter; + +/// A `StorageProofAdapter` implementation for raw storage proofs. +struct StorageProofCheckerAdapter, I: 'static> { + storage: StorageProofChecker>>, + _dummy: sp_std::marker::PhantomData<(T, I)>, +} + +impl, I: 'static> StorageProofCheckerAdapter { + fn try_new_with_verified_storage_proof( + bridged_header_hash: HashOf>, + storage_proof: RawStorageProof, + ) -> Result { + BridgedHeaderChainOf::::verify_storage_proof(bridged_header_hash, storage_proof).map( + |storage| StorageProofCheckerAdapter:: { storage, _dummy: Default::default() }, + ) + } +} + +impl, I: 'static> StorageProofAdapter for StorageProofCheckerAdapter { + fn read_and_decode_optional_value( + &mut self, + key: &impl AsRef<[u8]>, + ) -> Result, StorageProofError> { + self.storage.read_and_decode_opt_value(key.as_ref()) + } + + fn read_and_decode_mandatory_value( + &mut self, + key: &impl AsRef<[u8]>, + ) -> Result { + self.storage.read_and_decode_mandatory_value(key.as_ref()) + } + + fn ensure_no_unused_keys(self) -> Result<(), StorageProofError> { + self.storage.ensure_no_unused_nodes() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::tests::{ + messages_generation::{ + encode_all_messages, encode_lane_data, generate_dummy_message, + prepare_messages_storage_proof, + }, + mock::*, + }; + + use bp_header_chain::StoredHeaderDataBuilder; + use bp_runtime::{HeaderId, StorageProofError}; + use codec::Encode; + use sp_runtime::traits::Header; + + fn using_messages_proof( + nonces_end: MessageNonce, + outbound_lane_data: Option, + encode_message: impl Fn(MessageNonce, &MessagePayload) -> Option>, + encode_outbound_lane_data: impl Fn(&OutboundLaneData) -> Vec, + add_duplicate_key: bool, + add_unused_key: bool, + test: impl Fn(FromBridgedChainMessagesProof) -> R, + ) -> R { + let (state_root, storage_proof) = prepare_messages_storage_proof::( + TEST_LANE_ID, + 1..=nonces_end, + outbound_lane_data, + bp_runtime::UnverifiedStorageProofParams::default(), + generate_dummy_message, + encode_message, + encode_outbound_lane_data, + add_duplicate_key, + add_unused_key, + ); + + sp_io::TestExternalities::new(Default::default()).execute_with(move || { + let bridged_header = BridgedChainHeader::new( + 0, + Default::default(), + state_root, + Default::default(), + Default::default(), + ); + let bridged_header_hash = bridged_header.hash(); + + pallet_bridge_grandpa::BestFinalized::::put(HeaderId( + 0, + bridged_header_hash, + )); + pallet_bridge_grandpa::ImportedHeaders::::insert( + bridged_header_hash, + bridged_header.build(), + ); + test(FromBridgedChainMessagesProof { + bridged_header_hash, + storage_proof, + lane: TEST_LANE_ID, + nonces_start: 1, + nonces_end, + }) + }) + } + + #[test] + fn messages_proof_is_rejected_if_declared_less_than_actual_number_of_messages() { + assert_eq!( + using_messages_proof( + 10, + None, + encode_all_messages, + encode_lane_data, + false, + false, + |proof| { verify_messages_proof::(proof, 5) } + ), + Err(VerificationError::MessagesCountMismatch), + ); + } + + #[test] + fn messages_proof_is_rejected_if_declared_more_than_actual_number_of_messages() { + assert_eq!( + using_messages_proof( + 10, + None, + encode_all_messages, + encode_lane_data, + false, + false, + |proof| { verify_messages_proof::(proof, 15) } + ), + Err(VerificationError::MessagesCountMismatch), + ); + } + + #[test] + fn message_proof_is_rejected_if_header_is_missing_from_the_chain() { + assert_eq!( + using_messages_proof( + 10, + None, + encode_all_messages, + encode_lane_data, + false, + false, + |proof| { + let bridged_header_hash = + pallet_bridge_grandpa::BestFinalized::::get().unwrap().1; + pallet_bridge_grandpa::ImportedHeaders::::remove( + bridged_header_hash, + ); + verify_messages_proof::(proof, 10) + } + ), + Err(VerificationError::HeaderChain(HeaderChainError::UnknownHeader)), + ); + } + + #[test] + fn message_proof_is_rejected_if_header_state_root_mismatches() { + assert_eq!( + using_messages_proof( + 10, + None, + encode_all_messages, + encode_lane_data, + false, + false, + |proof| { + let bridged_header_hash = + pallet_bridge_grandpa::BestFinalized::::get().unwrap().1; + pallet_bridge_grandpa::ImportedHeaders::::insert( + bridged_header_hash, + BridgedChainHeader::new( + 0, + Default::default(), + Default::default(), + Default::default(), + Default::default(), + ) + .build(), + ); + verify_messages_proof::(proof, 10) + } + ), + Err(VerificationError::HeaderChain(HeaderChainError::StorageProof( + StorageProofError::StorageRootMismatch + ))), + ); + } + + #[test] + fn message_proof_is_rejected_if_it_has_duplicate_trie_nodes() { + assert_eq!( + using_messages_proof( + 10, + None, + encode_all_messages, + encode_lane_data, + true, + false, + |proof| { verify_messages_proof::(proof, 10) }, + ), + Err(VerificationError::HeaderChain(HeaderChainError::StorageProof( + StorageProofError::DuplicateNodes + ))), + ); + } + + #[test] + fn message_proof_is_rejected_if_it_has_unused_trie_nodes() { + assert_eq!( + using_messages_proof( + 10, + None, + encode_all_messages, + encode_lane_data, + false, + true, + |proof| { verify_messages_proof::(proof, 10) }, + ), + Err(VerificationError::StorageProof(StorageProofError::UnusedKey)), + ); + } + + #[test] + fn message_proof_is_rejected_if_required_message_is_missing() { + matches!( + using_messages_proof( + 10, + None, + |n, m| if n != 5 { Some(m.encode()) } else { None }, + encode_lane_data, + false, + false, + |proof| verify_messages_proof::(proof, 10) + ), + Err(VerificationError::MessageStorage(StorageProofError::EmptyVal)), + ); + } + + #[test] + fn message_proof_is_rejected_if_message_decode_fails() { + matches!( + using_messages_proof( + 10, + None, + |n, m| { + let mut m = m.encode(); + if n == 5 { + m = vec![42] + } + Some(m) + }, + encode_lane_data, + false, + false, + |proof| verify_messages_proof::(proof, 10), + ), + Err(VerificationError::MessageStorage(StorageProofError::DecodeError)), + ); + } + + #[test] + fn message_proof_is_rejected_if_outbound_lane_state_decode_fails() { + matches!( + using_messages_proof( + 10, + Some(OutboundLaneData { + oldest_unpruned_nonce: 1, + latest_received_nonce: 1, + latest_generated_nonce: 1, + }), + encode_all_messages, + |d| { + let mut d = d.encode(); + d.truncate(1); + d + }, + false, + false, + |proof| verify_messages_proof::(proof, 10), + ), + Err(VerificationError::OutboundLaneStorage(StorageProofError::DecodeError)), + ); + } + + #[test] + fn message_proof_is_rejected_if_it_is_empty() { + assert_eq!( + using_messages_proof( + 0, + None, + encode_all_messages, + encode_lane_data, + false, + false, + |proof| { verify_messages_proof::(proof, 0) }, + ), + Err(VerificationError::EmptyMessageProof), + ); + } + + #[test] + fn non_empty_message_proof_without_messages_is_accepted() { + assert_eq!( + using_messages_proof( + 0, + Some(OutboundLaneData { + oldest_unpruned_nonce: 1, + latest_received_nonce: 1, + latest_generated_nonce: 1, + }), + encode_all_messages, + encode_lane_data, + false, + false, + |proof| verify_messages_proof::(proof, 0), + ), + Ok(vec![( + TEST_LANE_ID, + ProvedLaneMessages { + lane_state: Some(OutboundLaneData { + oldest_unpruned_nonce: 1, + latest_received_nonce: 1, + latest_generated_nonce: 1, + }), + messages: Vec::new(), + }, + )] + .into_iter() + .collect()), + ); + } + + #[test] + fn non_empty_message_proof_is_accepted() { + assert_eq!( + using_messages_proof( + 1, + Some(OutboundLaneData { + oldest_unpruned_nonce: 1, + latest_received_nonce: 1, + latest_generated_nonce: 1, + }), + encode_all_messages, + encode_lane_data, + false, + false, + |proof| verify_messages_proof::(proof, 1), + ), + Ok(vec![( + TEST_LANE_ID, + ProvedLaneMessages { + lane_state: Some(OutboundLaneData { + oldest_unpruned_nonce: 1, + latest_received_nonce: 1, + latest_generated_nonce: 1, + }), + messages: vec![Message { + key: MessageKey { lane_id: TEST_LANE_ID, nonce: 1 }, + payload: vec![42], + }], + }, + )] + .into_iter() + .collect()), + ); + } + + #[test] + fn verify_messages_proof_does_not_panic_if_messages_count_mismatches() { + assert_eq!( + using_messages_proof( + 1, + None, + encode_all_messages, + encode_lane_data, + false, + false, + |mut proof| { + proof.nonces_end = u64::MAX; + verify_messages_proof::(proof, u32::MAX) + }, + ), + Err(VerificationError::MessagesCountMismatch), + ); + } +} diff --git a/bridges/bin/runtime-common/src/messages_generation.rs b/bridges/modules/messages/src/tests/messages_generation.rs similarity index 62% rename from bridges/bin/runtime-common/src/messages_generation.rs rename to bridges/modules/messages/src/tests/messages_generation.rs index c37aaa5d4d5378a1b76507e017c73aec3c7aabbd..6c4867fa6de39fa97b35cbd1f270bdeff4c76dff 100644 --- a/bridges/bin/runtime-common/src/messages_generation.rs +++ b/bridges/modules/messages/src/tests/messages_generation.rs @@ -16,17 +16,23 @@ //! Helpers for generating message storage proofs, that are used by tests and by benchmarks. -use crate::messages::{AccountIdOf, BridgedChain, HashOf, HasherOf, MessageBridge, ThisChain}; - use bp_messages::{ - storage_keys, InboundLaneData, LaneId, MessageKey, MessageNonce, MessagePayload, - OutboundLaneData, + storage_keys, ChainWithMessages, InboundLaneData, LaneId, MessageKey, MessageNonce, + MessagePayload, OutboundLaneData, +}; +use bp_runtime::{ + grow_storage_value, record_all_trie_keys, AccountIdOf, Chain, HashOf, HasherOf, + RawStorageProof, UnverifiedStorageProofParams, }; -use bp_runtime::{record_all_trie_keys, RawStorageProof, StorageProofSize}; use codec::Encode; use sp_std::{ops::RangeInclusive, prelude::*}; use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, TrieMut}; +/// Dummy message generation function. +pub fn generate_dummy_message(_: MessageNonce) -> MessagePayload { + vec![42] +} + /// Simple and correct message data encode function. pub fn encode_all_messages(_: MessageNonce, m: &MessagePayload) -> Option> { Some(m.encode()) @@ -40,18 +46,20 @@ pub fn encode_lane_data(d: &OutboundLaneData) -> Vec { /// Prepare storage proof of given messages. /// /// Returns state trie root and nodes with prepared messages. -pub fn prepare_messages_storage_proof( +#[allow(clippy::too_many_arguments)] +pub fn prepare_messages_storage_proof( lane: LaneId, message_nonces: RangeInclusive, outbound_lane_data: Option, - size: StorageProofSize, - message_payload: MessagePayload, + proof_params: UnverifiedStorageProofParams, + generate_message: impl Fn(MessageNonce) -> MessagePayload, encode_message: impl Fn(MessageNonce, &MessagePayload) -> Option>, encode_outbound_lane_data: impl Fn(&OutboundLaneData) -> Vec, -) -> (HashOf>, RawStorageProof) + add_duplicate_key: bool, + add_unused_key: bool, +) -> (HashOf, RawStorageProof) where - B: MessageBridge, - HashOf>: Copy + Default, + HashOf: Copy + Default, { // prepare Bridged chain storage with messages and (optionally) outbound lane state let message_count = message_nonces.end().saturating_sub(*message_nonces.start()) + 1; @@ -60,22 +68,22 @@ where let mut mdb = MemoryDB::default(); { let mut trie = - TrieDBMutBuilderV1::>>::new(&mut mdb, &mut root).build(); + TrieDBMutBuilderV1::>::new(&mut mdb, &mut root).build(); // insert messages for (i, nonce) in message_nonces.into_iter().enumerate() { let message_key = MessageKey { lane_id: lane, nonce }; - let message_payload = match encode_message(nonce, &message_payload) { + let message_payload = match encode_message(nonce, &generate_message(nonce)) { Some(message_payload) => if i == 0 { - grow_trie_leaf_value(message_payload, size) + grow_storage_value(message_payload, &proof_params) } else { message_payload }, None => continue, }; let storage_key = storage_keys::message_key( - B::BRIDGED_MESSAGES_PALLET_NAME, + ThisChain::WITH_CHAIN_MESSAGES_PALLET_NAME, &message_key.lane_id, message_key.nonce, ) @@ -89,8 +97,11 @@ where // insert outbound lane state if let Some(outbound_lane_data) = outbound_lane_data.as_ref().map(encode_outbound_lane_data) { - let storage_key = - storage_keys::outbound_lane_data_key(B::BRIDGED_MESSAGES_PALLET_NAME, &lane).0; + let storage_key = storage_keys::outbound_lane_data_key( + ThisChain::WITH_CHAIN_MESSAGES_PALLET_NAME, + &lane, + ) + .0; trie.insert(&storage_key, &outbound_lane_data) .map_err(|_| "TrieMut::insert has failed") .expect("TrieMut::insert should not fail in benchmarks"); @@ -99,52 +110,54 @@ where } // generate storage proof to be delivered to This chain - let storage_proof = record_all_trie_keys::>>, _>(&mdb, &root) - .map_err(|_| "record_all_trie_keys has failed") - .expect("record_all_trie_keys should not fail in benchmarks"); + let mut storage_proof = + record_all_trie_keys::>, _>(&mdb, &root) + .map_err(|_| "record_all_trie_keys has failed") + .expect("record_all_trie_keys should not fail in benchmarks"); + + if add_duplicate_key { + assert!(!storage_proof.is_empty()); + let node = storage_proof.pop().unwrap(); + storage_proof.push(node.clone()); + storage_proof.push(node); + } + + if add_unused_key { + storage_proof.push(b"unused_value".to_vec()); + } + (root, storage_proof) } /// Prepare storage proof of given messages delivery. /// /// Returns state trie root and nodes with prepared messages. -pub fn prepare_message_delivery_storage_proof( +pub fn prepare_message_delivery_storage_proof( lane: LaneId, - inbound_lane_data: InboundLaneData>>, - size: StorageProofSize, -) -> (HashOf>, RawStorageProof) + inbound_lane_data: InboundLaneData>, + proof_params: UnverifiedStorageProofParams, +) -> (HashOf, RawStorageProof) where - B: MessageBridge, + HashOf: Copy + Default, { // prepare Bridged chain storage with inbound lane state - let storage_key = storage_keys::inbound_lane_data_key(B::BRIDGED_MESSAGES_PALLET_NAME, &lane).0; + let storage_key = + storage_keys::inbound_lane_data_key(ThisChain::WITH_CHAIN_MESSAGES_PALLET_NAME, &lane).0; let mut root = Default::default(); let mut mdb = MemoryDB::default(); { let mut trie = - TrieDBMutBuilderV1::>>::new(&mut mdb, &mut root).build(); - let inbound_lane_data = grow_trie_leaf_value(inbound_lane_data.encode(), size); + TrieDBMutBuilderV1::>::new(&mut mdb, &mut root).build(); + let inbound_lane_data = grow_storage_value(inbound_lane_data.encode(), &proof_params); trie.insert(&storage_key, &inbound_lane_data) .map_err(|_| "TrieMut::insert has failed") .expect("TrieMut::insert should not fail in benchmarks"); } // generate storage proof to be delivered to This chain - let storage_proof = record_all_trie_keys::>>, _>(&mdb, &root) + let storage_proof = record_all_trie_keys::>, _>(&mdb, &root) .map_err(|_| "record_all_trie_keys has failed") .expect("record_all_trie_keys should not fail in benchmarks"); (root, storage_proof) } - -/// Add extra data to the trie leaf value so that it'll be of given size. -pub fn grow_trie_leaf_value(mut value: Vec, size: StorageProofSize) -> Vec { - match size { - StorageProofSize::Minimal(_) => (), - StorageProofSize::HasLargeLeaf(size) if size as usize > value.len() => { - value.extend(sp_std::iter::repeat(42u8).take(size as usize - value.len())); - }, - StorageProofSize::HasLargeLeaf(_) => (), - } - value -} diff --git a/bridges/modules/messages/src/mock.rs b/bridges/modules/messages/src/tests/mock.rs similarity index 63% rename from bridges/modules/messages/src/mock.rs rename to bridges/modules/messages/src/tests/mock.rs index 3a1e0063d5337769b75b35035116aaff6e2b2e08..99da019dc0847d0787c30ada8e614270e83ddfdb 100644 --- a/bridges/modules/messages/src/mock.rs +++ b/bridges/modules/messages/src/tests/mock.rs @@ -17,30 +17,43 @@ // From construct_runtime macro #![allow(clippy::from_over_into)] -use crate::{Config, StoredMessagePayload}; +use crate::{ + tests::messages_generation::{ + encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof, + prepare_messages_storage_proof, + }, + Config, StoredMessagePayload, +}; +use bp_header_chain::{ChainWithGrandpa, StoredHeaderData}; use bp_messages::{ calc_relayers_rewards, - source_chain::{DeliveryConfirmationPayments, OnMessagesDelivered, TargetHeaderChain}, + source_chain::{ + DeliveryConfirmationPayments, FromBridgedChainMessagesDeliveryProof, OnMessagesDelivered, + }, target_chain::{ - DeliveryPayments, DispatchMessage, DispatchMessageData, MessageDispatch, - ProvedLaneMessages, ProvedMessages, SourceHeaderChain, + DeliveryPayments, DispatchMessage, DispatchMessageData, FromBridgedChainMessagesProof, + MessageDispatch, }, - DeliveredMessages, InboundLaneData, LaneId, Message, MessageKey, MessageNonce, - UnrewardedRelayer, UnrewardedRelayersState, VerificationError, + ChainWithMessages, DeliveredMessages, InboundLaneData, LaneId, Message, MessageKey, + MessageNonce, OutboundLaneData, UnrewardedRelayer, UnrewardedRelayersState, +}; +use bp_runtime::{ + messages::MessageDispatchResult, Chain, ChainId, Size, UnverifiedStorageProofParams, }; -use bp_runtime::{messages::MessageDispatchResult, Size}; use codec::{Decode, Encode}; use frame_support::{ derive_impl, parameter_types, weights::{constants::RocksDbWeight, Weight}, }; use scale_info::TypeInfo; -use sp_runtime::BuildStorage; -use std::{ - collections::{BTreeMap, VecDeque}, - ops::RangeInclusive, +use sp_core::H256; +use sp_runtime::{ + testing::Header as SubstrateHeader, + traits::{BlakeTwo256, ConstU32}, + BuildStorage, StateVersion, }; +use std::{collections::VecDeque, ops::RangeInclusive}; pub type AccountId = u64; pub type Balance = u64; @@ -62,6 +75,77 @@ pub type TestMessageFee = u64; pub type TestRelayer = u64; pub type TestDispatchLevelResult = (); +pub struct ThisChain; + +impl Chain for ThisChain { + const ID: ChainId = *b"ttch"; + + type BlockNumber = u64; + type Hash = H256; + type Hasher = BlakeTwo256; + type Header = SubstrateHeader; + type AccountId = AccountId; + type Balance = Balance; + type Nonce = u64; + type Signature = sp_runtime::MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + + fn max_extrinsic_size() -> u32 { + u32::MAX + } + + fn max_extrinsic_weight() -> Weight { + Weight::MAX + } +} + +impl ChainWithMessages for ThisChain { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = "WithThisChainBridgeMessages"; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 128; +} + +pub struct BridgedChain; + +pub type BridgedHeaderHash = H256; +pub type BridgedChainHeader = SubstrateHeader; + +impl Chain for BridgedChain { + const ID: ChainId = *b"tbch"; + + type BlockNumber = u64; + type Hash = BridgedHeaderHash; + type Hasher = BlakeTwo256; + type Header = BridgedChainHeader; + type AccountId = TestRelayer; + type Balance = Balance; + type Nonce = u64; + type Signature = sp_runtime::MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + + fn max_extrinsic_size() -> u32 { + 4096 + } + + fn max_extrinsic_weight() -> Weight { + Weight::MAX + } +} + +impl ChainWithGrandpa for BridgedChain { + const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = "WithBridgedChainBridgeGrandpa"; + const MAX_AUTHORITIES_COUNT: u32 = 16; + const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = 4; + const MAX_MANDATORY_HEADER_SIZE: u32 = 4096; + const AVERAGE_HEADER_SIZE: u32 = 4096; +} + +impl ChainWithMessages for BridgedChain { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = "WithBridgedChainBridgeMessages"; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 128; +} + type Block = frame_system::mocking::MockBlock; use crate as pallet_bridge_messages; @@ -71,6 +155,7 @@ frame_support::construct_runtime! { { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Event}, + BridgedChainGrandpa: pallet_bridge_grandpa::{Pallet, Call, Event}, Messages: pallet_bridge_messages::{Pallet, Call, Event}, } } @@ -89,10 +174,17 @@ impl pallet_balances::Config for TestRuntime { type AccountStore = System; } +impl pallet_bridge_grandpa::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type BridgedChain = BridgedChain; + type MaxFreeHeadersPerBlock = ConstU32<4>; + type FreeHeadersInterval = ConstU32<1_024>; + type HeadersToKeep = ConstU32<8>; + type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight; +} + parameter_types! { pub const MaxMessagesToPruneAtOnce: u64 = 10; - pub const MaxUnrewardedRelayerEntriesAtInboundLane: u64 = 16; - pub const MaxUnconfirmedMessagesAtInboundLane: u64 = 128; pub const TestBridgedChainId: bp_runtime::ChainId = *b"test"; pub const ActiveOutboundLanes: &'static [LaneId] = &[TEST_LANE_ID, TEST_LANE_ID_2]; } @@ -103,24 +195,22 @@ pub type TestWeightInfo = (); impl Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type WeightInfo = TestWeightInfo; + + type ThisChain = ThisChain; + type BridgedChain = BridgedChain; + type BridgedHeaderChain = BridgedChainGrandpa; + type ActiveOutboundLanes = ActiveOutboundLanes; - type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; - type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; - type MaximalOutboundPayloadSize = frame_support::traits::ConstU32; type OutboundPayload = TestPayload; type InboundPayload = TestPayload; - type InboundRelayer = TestRelayer; type DeliveryPayments = TestDeliveryPayments; - type TargetHeaderChain = TestTargetHeaderChain; type DeliveryConfirmationPayments = TestDeliveryConfirmationPayments; type OnMessagesDelivered = TestOnMessagesDelivered; - type SourceHeaderChain = TestSourceHeaderChain; type MessageDispatch = TestMessageDispatch; - type BridgedChainId = TestBridgedChainId; } #[cfg(feature = "runtime-benchmarks")] @@ -131,29 +221,26 @@ impl crate::benchmarking::Config<()> for TestRuntime { fn prepare_message_proof( params: crate::benchmarking::MessageProofParams, - ) -> (TestMessagesProof, Weight) { - // in mock run we only care about benchmarks correctness, not the benchmark results - // => ignore size related arguments - let (messages, total_dispatch_weight) = - params.message_nonces.into_iter().map(|n| message(n, REGULAR_PAYLOAD)).fold( - (Vec::new(), Weight::zero()), - |(mut messages, total_dispatch_weight), message| { - let weight = REGULAR_PAYLOAD.declared_weight; - messages.push(message); - (messages, total_dispatch_weight.saturating_add(weight)) - }, - ); - let mut proof: TestMessagesProof = Ok(messages).into(); - proof.result.as_mut().unwrap().get_mut(0).unwrap().1.lane_state = params.outbound_lane_data; - (proof, total_dispatch_weight) + ) -> (FromBridgedChainMessagesProof, Weight) { + use bp_runtime::RangeInclusiveExt; + + let dispatch_weight = + REGULAR_PAYLOAD.declared_weight * params.message_nonces.saturating_len(); + ( + *prepare_messages_proof( + params.message_nonces.into_iter().map(|n| message(n, REGULAR_PAYLOAD)).collect(), + params.outbound_lane_data, + ), + dispatch_weight, + ) } fn prepare_message_delivery_proof( params: crate::benchmarking::MessageDeliveryProofParams, - ) -> TestMessagesDeliveryProof { + ) -> FromBridgedChainMessagesDeliveryProof { // in mock run we only care about benchmarks correctness, not the benchmark results // => ignore size related arguments - TestMessagesDeliveryProof(Ok((params.lane, params.inbound_lane_data))) + prepare_messages_delivery_proof(params.lane, params.inbound_lane_data) } fn is_relayer_rewarded(_relayer: &AccountId) -> bool { @@ -167,9 +254,6 @@ impl Size for TestPayload { } } -/// Maximal outbound payload size. -pub const MAX_OUTBOUND_PAYLOAD_SIZE: u32 = 4096; - /// Account that has balance to use in tests. pub const ENDOWED_ACCOUNT: AccountId = 0xDEAD; @@ -182,9 +266,6 @@ pub const TEST_RELAYER_B: AccountId = 101; /// Account id of additional test relayer - C. pub const TEST_RELAYER_C: AccountId = 102; -/// Error that is returned by all test implementations. -pub const TEST_ERROR: &str = "Test error"; - /// Lane that we're using in tests. pub const TEST_LANE_ID: LaneId = LaneId([0, 0, 0, 1]); @@ -197,71 +278,6 @@ pub const TEST_LANE_ID_3: LaneId = LaneId([0, 0, 0, 3]); /// Regular message payload. pub const REGULAR_PAYLOAD: TestPayload = message_payload(0, 50); -/// Payload that is rejected by `TestTargetHeaderChain`. -pub const PAYLOAD_REJECTED_BY_TARGET_CHAIN: TestPayload = message_payload(1, 50); - -/// Vec of proved messages, grouped by lane. -pub type MessagesByLaneVec = Vec<(LaneId, ProvedLaneMessages)>; - -/// Test messages proof. -#[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo)] -pub struct TestMessagesProof { - pub result: Result, -} - -impl Size for TestMessagesProof { - fn size(&self) -> u32 { - 0 - } -} - -impl From, ()>> for TestMessagesProof { - fn from(result: Result, ()>) -> Self { - Self { - result: result.map(|messages| { - let mut messages_by_lane: BTreeMap> = - BTreeMap::new(); - for message in messages { - messages_by_lane.entry(message.key.lane_id).or_default().messages.push(message); - } - messages_by_lane.into_iter().collect() - }), - } - } -} - -/// Messages delivery proof used in tests. -#[derive(Debug, Encode, Decode, Eq, Clone, PartialEq, TypeInfo)] -pub struct TestMessagesDeliveryProof(pub Result<(LaneId, InboundLaneData), ()>); - -impl Size for TestMessagesDeliveryProof { - fn size(&self) -> u32 { - 0 - } -} - -/// Target header chain that is used in tests. -#[derive(Debug, Default)] -pub struct TestTargetHeaderChain; - -impl TargetHeaderChain for TestTargetHeaderChain { - type MessagesDeliveryProof = TestMessagesDeliveryProof; - - fn verify_message(payload: &TestPayload) -> Result<(), VerificationError> { - if *payload == PAYLOAD_REJECTED_BY_TARGET_CHAIN { - Err(VerificationError::Other(TEST_ERROR)) - } else { - Ok(()) - } - } - - fn verify_messages_delivery_proof( - proof: Self::MessagesDeliveryProof, - ) -> Result<(LaneId, InboundLaneData), VerificationError> { - proof.0.map_err(|_| VerificationError::Other(TEST_ERROR)) - } -} - /// Reward payments at the target chain during delivery transaction. #[derive(Debug, Default)] pub struct TestDeliveryPayments; @@ -322,24 +338,6 @@ impl DeliveryConfirmationPayments for TestDeliveryConfirmationPayment } } -/// Source header chain that is used in tests. -#[derive(Debug)] -pub struct TestSourceHeaderChain; - -impl SourceHeaderChain for TestSourceHeaderChain { - type MessagesProof = TestMessagesProof; - - fn verify_messages_proof( - proof: Self::MessagesProof, - _messages_count: u32, - ) -> Result, VerificationError> { - proof - .result - .map(|proof| proof.into_iter().collect()) - .map_err(|_| VerificationError::Other(TEST_ERROR)) - } -} - /// Test message dispatcher. #[derive(Debug)] pub struct TestMessageDispatch; @@ -458,3 +456,75 @@ pub fn new_test_ext() -> sp_io::TestExternalities { pub fn run_test(test: impl FnOnce() -> T) -> T { new_test_ext().execute_with(test) } + +/// Prepare valid storage proof for given messages and insert appropriate header to the +/// bridged header chain. +/// +/// Since this function changes the runtime storage, you can't "inline" it in the +/// `asset_noop` macro calls. +pub fn prepare_messages_proof( + messages: Vec, + outbound_lane_data: Option, +) -> Box> { + // first - let's generate storage proof + let lane = messages.first().unwrap().key.lane_id; + let nonces_start = messages.first().unwrap().key.nonce; + let nonces_end = messages.last().unwrap().key.nonce; + let (storage_root, storage_proof) = prepare_messages_storage_proof::( + TEST_LANE_ID, + nonces_start..=nonces_end, + outbound_lane_data, + UnverifiedStorageProofParams::default(), + |nonce| messages[(nonce - nonces_start) as usize].payload.clone(), + encode_all_messages, + encode_lane_data, + false, + false, + ); + + // let's now insert bridged chain header into the storage + let bridged_header_hash = Default::default(); + pallet_bridge_grandpa::ImportedHeaders::::insert( + bridged_header_hash, + StoredHeaderData { number: 0, state_root: storage_root }, + ); + + Box::new(FromBridgedChainMessagesProof:: { + bridged_header_hash, + storage_proof, + lane, + nonces_start, + nonces_end, + }) +} + +/// Prepare valid storage proof for given messages and insert appropriate header to the +/// bridged header chain. +/// +/// Since this function changes the runtime storage, you can't "inline" it in the +/// `asset_noop` macro calls. +pub fn prepare_messages_delivery_proof( + lane: LaneId, + inbound_lane_data: InboundLaneData, +) -> FromBridgedChainMessagesDeliveryProof { + // first - let's generate storage proof + let (storage_root, storage_proof) = + prepare_message_delivery_storage_proof::( + lane, + inbound_lane_data, + UnverifiedStorageProofParams::default(), + ); + + // let's now insert bridged chain header into the storage + let bridged_header_hash = Default::default(); + pallet_bridge_grandpa::ImportedHeaders::::insert( + bridged_header_hash, + StoredHeaderData { number: 0, state_root: storage_root }, + ); + + FromBridgedChainMessagesDeliveryProof:: { + bridged_header_hash, + storage_proof, + lane, + } +} diff --git a/bridges/modules/messages/src/tests/mod.rs b/bridges/modules/messages/src/tests/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..c3bde5fc275849fab930ad0b1ec9f0b4e80ce4ea --- /dev/null +++ b/bridges/modules/messages/src/tests/mod.rs @@ -0,0 +1,26 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Tests and test helpers for messages pallet. + +#![cfg(any(feature = "test-helpers", test))] + +#[cfg(test)] +pub(crate) mod mock; +#[cfg(test)] +mod pallet_tests; + +pub mod messages_generation; diff --git a/bridges/modules/messages/src/tests/pallet_tests.rs b/bridges/modules/messages/src/tests/pallet_tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..42e1042717de07656630855c00967361be78f664 --- /dev/null +++ b/bridges/modules/messages/src/tests/pallet_tests.rs @@ -0,0 +1,1100 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Pallet-level tests. + +use crate::{ + outbound_lane, + outbound_lane::ReceptionConfirmationError, + tests::mock::{self, RuntimeEvent as TestEvent, *}, + weights_ext::WeightInfoExt, + Call, Config, Error, Event, InboundLanes, MaybeOutboundLanesCount, OutboundLanes, + OutboundMessages, Pallet, PalletOperatingMode, PalletOwner, RuntimeInboundLaneStorage, + StoredInboundLaneData, +}; + +use bp_messages::{ + source_chain::{FromBridgedChainMessagesDeliveryProof, MessagesBridge}, + target_chain::FromBridgedChainMessagesProof, + BridgeMessagesCall, ChainWithMessages, DeliveredMessages, InboundLaneData, + InboundMessageDetails, LaneId, MessageKey, MessageNonce, MessagesOperatingMode, + OutboundLaneData, OutboundMessageDetails, UnrewardedRelayer, UnrewardedRelayersState, + VerificationError, +}; +use bp_runtime::{BasicOperatingMode, PreComputedSize, RangeInclusiveExt, Size}; +use bp_test_utils::generate_owned_bridge_module_tests; +use codec::Encode; +use frame_support::{ + assert_noop, assert_ok, + dispatch::Pays, + storage::generator::{StorageMap, StorageValue}, + traits::Hooks, + weights::Weight, +}; +use frame_system::{EventRecord, Pallet as System, Phase}; +use sp_core::Get; +use sp_runtime::DispatchError; + +fn get_ready_for_events() { + System::::set_block_number(1); + System::::reset_events(); +} + +fn send_regular_message(lane_id: LaneId) { + get_ready_for_events(); + + let outbound_lane = outbound_lane::(lane_id); + let message_nonce = outbound_lane.data().latest_generated_nonce + 1; + let prev_enqueued_messages = outbound_lane.data().queued_messages().saturating_len(); + let valid_message = Pallet::::validate_message(lane_id, ®ULAR_PAYLOAD) + .expect("validate_message has failed"); + let artifacts = Pallet::::send_message(valid_message); + assert_eq!(artifacts.enqueued_messages, prev_enqueued_messages + 1); + + // check event with assigned nonce + assert_eq!( + System::::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: TestEvent::Messages(Event::MessageAccepted { lane_id, nonce: message_nonce }), + topics: vec![], + }], + ); +} + +fn receive_messages_delivery_proof() { + System::::set_block_number(1); + System::::reset_events(); + + assert_ok!(Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + prepare_messages_delivery_proof( + TEST_LANE_ID, + InboundLaneData { + last_confirmed_nonce: 1, + relayers: vec![UnrewardedRelayer { + relayer: 0, + messages: DeliveredMessages::new(1), + }] + .into(), + }, + ), + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 1, + total_messages: 1, + last_delivered_nonce: 1, + }, + )); + + assert_eq!( + System::::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: TestEvent::Messages(Event::MessagesDelivered { + lane_id: TEST_LANE_ID, + messages: DeliveredMessages::new(1), + }), + topics: vec![], + }], + ); +} + +#[test] +fn pallet_rejects_transactions_if_halted() { + run_test(|| { + // send message first to be able to check that delivery_proof fails later + send_regular_message(TEST_LANE_ID); + + PalletOperatingMode::::put(MessagesOperatingMode::Basic( + BasicOperatingMode::Halted, + )); + + assert_noop!( + Pallet::::validate_message(TEST_LANE_ID, ®ULAR_PAYLOAD), + Error::::NotOperatingNormally, + ); + + let messages_proof = prepare_messages_proof(vec![message(2, REGULAR_PAYLOAD)], None); + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + messages_proof, + 1, + REGULAR_PAYLOAD.declared_weight, + ), + Error::::BridgeModule(bp_runtime::OwnedBridgeModuleError::Halted), + ); + + let delivery_proof = prepare_messages_delivery_proof( + TEST_LANE_ID, + InboundLaneData { + last_confirmed_nonce: 1, + relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)].into(), + }, + ); + assert_noop!( + Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + delivery_proof, + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 1, + total_messages: 1, + last_delivered_nonce: 1, + }, + ), + Error::::BridgeModule(bp_runtime::OwnedBridgeModuleError::Halted), + ); + }); +} + +#[test] +fn receive_messages_fails_if_dispatcher_is_inactive() { + run_test(|| { + TestMessageDispatch::deactivate(); + let proof = prepare_messages_proof(vec![message(1, REGULAR_PAYLOAD)], None); + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + proof, + 1, + REGULAR_PAYLOAD.declared_weight, + ), + Error::::MessageDispatchInactive, + ); + }); +} + +#[test] +fn pallet_rejects_new_messages_in_rejecting_outbound_messages_operating_mode() { + run_test(|| { + // send message first to be able to check that delivery_proof fails later + send_regular_message(TEST_LANE_ID); + + PalletOperatingMode::::put( + MessagesOperatingMode::RejectingOutboundMessages, + ); + + assert_noop!( + Pallet::::validate_message(TEST_LANE_ID, ®ULAR_PAYLOAD), + Error::::NotOperatingNormally, + ); + + assert_ok!(Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + prepare_messages_proof(vec![message(1, REGULAR_PAYLOAD)], None), + 1, + REGULAR_PAYLOAD.declared_weight, + ),); + + assert_ok!(Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + prepare_messages_delivery_proof( + TEST_LANE_ID, + InboundLaneData { + last_confirmed_nonce: 1, + relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)].into(), + }, + ), + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 1, + total_messages: 1, + last_delivered_nonce: 1, + }, + )); + }); +} + +#[test] +fn send_message_works() { + run_test(|| { + send_regular_message(TEST_LANE_ID); + }); +} + +#[test] +fn send_message_rejects_too_large_message() { + run_test(|| { + let mut message_payload = message_payload(1, 0); + // the payload isn't simply extra, so it'll definitely overflow + // `max_outbound_payload_size` if we add `max_outbound_payload_size` bytes to extra + let max_outbound_payload_size = BridgedChain::maximal_incoming_message_size(); + message_payload + .extra + .extend_from_slice(&vec![0u8; max_outbound_payload_size as usize]); + assert_noop!( + Pallet::::validate_message(TEST_LANE_ID, &message_payload.clone(),), + Error::::MessageRejectedByPallet(VerificationError::MessageTooLarge), + ); + + // let's check that we're able to send `max_outbound_payload_size` messages + while message_payload.encoded_size() as u32 > max_outbound_payload_size { + message_payload.extra.pop(); + } + assert_eq!(message_payload.encoded_size() as u32, max_outbound_payload_size); + + let valid_message = + Pallet::::validate_message(TEST_LANE_ID, &message_payload) + .expect("validate_message has failed"); + Pallet::::send_message(valid_message); + }) +} + +#[test] +fn receive_messages_proof_works() { + run_test(|| { + assert_ok!(Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + prepare_messages_proof(vec![message(1, REGULAR_PAYLOAD)], None), + 1, + REGULAR_PAYLOAD.declared_weight, + )); + + assert_eq!(InboundLanes::::get(TEST_LANE_ID).0.last_delivered_nonce(), 1); + + assert!(TestDeliveryPayments::is_reward_paid(1)); + }); +} + +#[test] +fn receive_messages_proof_updates_confirmed_message_nonce() { + run_test(|| { + // say we have received 10 messages && last confirmed message is 8 + InboundLanes::::insert( + TEST_LANE_ID, + InboundLaneData { + last_confirmed_nonce: 8, + relayers: vec![ + unrewarded_relayer(9, 9, TEST_RELAYER_A), + unrewarded_relayer(10, 10, TEST_RELAYER_B), + ] + .into(), + }, + ); + assert_eq!( + inbound_unrewarded_relayers_state(TEST_LANE_ID), + UnrewardedRelayersState { + unrewarded_relayer_entries: 2, + messages_in_oldest_entry: 1, + total_messages: 2, + last_delivered_nonce: 10, + }, + ); + + // message proof includes outbound lane state with latest confirmed message updated to 9 + assert_ok!(Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + prepare_messages_proof( + vec![message(11, REGULAR_PAYLOAD)], + Some(OutboundLaneData { latest_received_nonce: 9, ..Default::default() }), + ), + 1, + REGULAR_PAYLOAD.declared_weight, + )); + + assert_eq!( + InboundLanes::::get(TEST_LANE_ID).0, + InboundLaneData { + last_confirmed_nonce: 9, + relayers: vec![ + unrewarded_relayer(10, 10, TEST_RELAYER_B), + unrewarded_relayer(11, 11, TEST_RELAYER_A) + ] + .into(), + }, + ); + assert_eq!( + inbound_unrewarded_relayers_state(TEST_LANE_ID), + UnrewardedRelayersState { + unrewarded_relayer_entries: 2, + messages_in_oldest_entry: 1, + total_messages: 2, + last_delivered_nonce: 11, + }, + ); + }); +} + +#[test] +fn receive_messages_proof_does_not_accept_message_if_dispatch_weight_is_not_enough() { + run_test(|| { + let proof = prepare_messages_proof(vec![message(1, REGULAR_PAYLOAD)], None); + let mut declared_weight = REGULAR_PAYLOAD.declared_weight; + *declared_weight.ref_time_mut() -= 1; + + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + proof, + 1, + declared_weight, + ), + Error::::InsufficientDispatchWeight + ); + assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 0); + }); +} + +#[test] +fn receive_messages_proof_rejects_invalid_proof() { + run_test(|| { + let mut proof = prepare_messages_proof(vec![message(1, REGULAR_PAYLOAD)], None); + proof.nonces_end += 1; + + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + proof, + 1, + Weight::zero(), + ), + Error::::InvalidMessagesProof, + ); + }); +} + +#[test] +fn receive_messages_proof_rejects_proof_with_too_many_messages() { + run_test(|| { + let proof = prepare_messages_proof(vec![message(1, REGULAR_PAYLOAD)], None); + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + proof, + u32::MAX, + Weight::zero(), + ), + Error::::TooManyMessagesInTheProof, + ); + }); +} + +#[test] +fn receive_messages_delivery_proof_works() { + run_test(|| { + send_regular_message(TEST_LANE_ID); + receive_messages_delivery_proof(); + + assert_eq!(OutboundLanes::::get(TEST_LANE_ID).latest_received_nonce, 1,); + }); +} + +#[test] +fn receive_messages_delivery_proof_rewards_relayers() { + run_test(|| { + send_regular_message(TEST_LANE_ID); + send_regular_message(TEST_LANE_ID); + + // this reports delivery of message 1 => reward is paid to TEST_RELAYER_A + let single_message_delivery_proof = prepare_messages_delivery_proof( + TEST_LANE_ID, + InboundLaneData { + relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)].into(), + ..Default::default() + }, + ); + let single_message_delivery_proof_size = single_message_delivery_proof.size(); + let result = Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + single_message_delivery_proof, + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 1, + total_messages: 1, + last_delivered_nonce: 1, + }, + ); + assert_ok!(result); + assert_eq!( + result.unwrap().actual_weight.unwrap(), + TestWeightInfo::receive_messages_delivery_proof_weight( + &PreComputedSize(single_message_delivery_proof_size as _), + &UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 1, + ..Default::default() + }, + ) + ); + assert!(TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_A, 1)); + assert!(!TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_B, 1)); + + // this reports delivery of both message 1 and message 2 => reward is paid only to + // TEST_RELAYER_B + let two_messages_delivery_proof = prepare_messages_delivery_proof( + TEST_LANE_ID, + InboundLaneData { + relayers: vec![ + unrewarded_relayer(1, 1, TEST_RELAYER_A), + unrewarded_relayer(2, 2, TEST_RELAYER_B), + ] + .into(), + ..Default::default() + }, + ); + let two_messages_delivery_proof_size = two_messages_delivery_proof.size(); + let result = Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + two_messages_delivery_proof, + UnrewardedRelayersState { + unrewarded_relayer_entries: 2, + messages_in_oldest_entry: 1, + total_messages: 2, + last_delivered_nonce: 2, + }, + ); + assert_ok!(result); + // even though the pre-dispatch weight was for two messages, the actual weight is + // for single message only + assert_eq!( + result.unwrap().actual_weight.unwrap(), + TestWeightInfo::receive_messages_delivery_proof_weight( + &PreComputedSize(two_messages_delivery_proof_size as _), + &UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 1, + ..Default::default() + }, + ) + ); + assert!(!TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_A, 1)); + assert!(TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_B, 1)); + assert_eq!(TestOnMessagesDelivered::call_arguments(), Some((TEST_LANE_ID, 0))); + }); +} + +#[test] +fn receive_messages_delivery_proof_rejects_invalid_proof() { + run_test(|| { + let mut proof = prepare_messages_delivery_proof(TEST_LANE_ID, Default::default()); + proof.lane = bp_messages::LaneId([42, 42, 42, 42]); + + assert_noop!( + Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + proof, + Default::default(), + ), + Error::::InvalidMessagesDeliveryProof, + ); + }); +} + +#[test] +fn receive_messages_delivery_proof_rejects_proof_if_declared_relayers_state_is_invalid() { + run_test(|| { + // when number of relayers entries is invalid + let proof = prepare_messages_delivery_proof( + TEST_LANE_ID, + InboundLaneData { + relayers: vec![ + unrewarded_relayer(1, 1, TEST_RELAYER_A), + unrewarded_relayer(2, 2, TEST_RELAYER_B), + ] + .into(), + ..Default::default() + }, + ); + assert_noop!( + Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + proof, + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 2, + last_delivered_nonce: 2, + ..Default::default() + }, + ), + Error::::InvalidUnrewardedRelayersState, + ); + + // when number of messages is invalid + let proof = prepare_messages_delivery_proof( + TEST_LANE_ID, + InboundLaneData { + relayers: vec![ + unrewarded_relayer(1, 1, TEST_RELAYER_A), + unrewarded_relayer(2, 2, TEST_RELAYER_B), + ] + .into(), + ..Default::default() + }, + ); + assert_noop!( + Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + proof, + UnrewardedRelayersState { + unrewarded_relayer_entries: 2, + total_messages: 1, + last_delivered_nonce: 2, + ..Default::default() + }, + ), + Error::::InvalidUnrewardedRelayersState, + ); + + // when last delivered nonce is invalid + let proof = prepare_messages_delivery_proof( + TEST_LANE_ID, + InboundLaneData { + relayers: vec![ + unrewarded_relayer(1, 1, TEST_RELAYER_A), + unrewarded_relayer(2, 2, TEST_RELAYER_B), + ] + .into(), + ..Default::default() + }, + ); + assert_noop!( + Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + proof, + UnrewardedRelayersState { + unrewarded_relayer_entries: 2, + total_messages: 2, + last_delivered_nonce: 8, + ..Default::default() + }, + ), + Error::::InvalidUnrewardedRelayersState, + ); + }); +} + +#[test] +fn receive_messages_accepts_single_message_with_invalid_payload() { + run_test(|| { + let mut invalid_message = message(1, REGULAR_PAYLOAD); + invalid_message.payload = Vec::new(); + + assert_ok!(Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + prepare_messages_proof(vec![invalid_message], None), + 1, + Weight::zero(), /* weight may be zero in this case (all messages are + * improperly encoded) */ + ),); + + assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 1,); + }); +} + +#[test] +fn receive_messages_accepts_batch_with_message_with_invalid_payload() { + run_test(|| { + let mut invalid_message = message(2, REGULAR_PAYLOAD); + invalid_message.payload = Vec::new(); + + assert_ok!(Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + prepare_messages_proof( + vec![message(1, REGULAR_PAYLOAD), invalid_message, message(3, REGULAR_PAYLOAD),], + None + ), + 3, + REGULAR_PAYLOAD.declared_weight + REGULAR_PAYLOAD.declared_weight, + ),); + + assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 3,); + }); +} + +#[test] +fn actual_dispatch_weight_does_not_overflow() { + run_test(|| { + let message1 = message(1, message_payload(0, u64::MAX / 2)); + let message2 = message(2, message_payload(0, u64::MAX / 2)); + let message3 = message(3, message_payload(0, u64::MAX / 2)); + + let proof = prepare_messages_proof(vec![message1, message2, message3], None); + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + // this may cause overflow if source chain storage is invalid + proof, + 3, + Weight::MAX, + ), + Error::::InsufficientDispatchWeight + ); + assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 0); + }); +} + +#[test] +fn ref_time_refund_from_receive_messages_proof_works() { + run_test(|| { + fn submit_with_unspent_weight( + nonce: MessageNonce, + unspent_weight: u64, + ) -> (Weight, Weight) { + let mut payload = REGULAR_PAYLOAD; + *payload.dispatch_result.unspent_weight.ref_time_mut() = unspent_weight; + let proof = prepare_messages_proof(vec![message(nonce, payload)], None); + let messages_count = 1; + let pre_dispatch_weight = + ::WeightInfo::receive_messages_proof_weight( + &*proof, + messages_count, + REGULAR_PAYLOAD.declared_weight, + ); + let result = Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + proof, + messages_count, + REGULAR_PAYLOAD.declared_weight, + ) + .expect("delivery has failed"); + let post_dispatch_weight = + result.actual_weight.expect("receive_messages_proof always returns Some"); + + // message delivery transactions are never free + assert_eq!(result.pays_fee, Pays::Yes); + + (pre_dispatch_weight, post_dispatch_weight) + } + + // when dispatch is returning `unspent_weight < declared_weight` + let (pre, post) = submit_with_unspent_weight(1, 1); + assert_eq!(post.ref_time(), pre.ref_time() - 1); + + // when dispatch is returning `unspent_weight = declared_weight` + let (pre, post) = submit_with_unspent_weight(2, REGULAR_PAYLOAD.declared_weight.ref_time()); + assert_eq!(post.ref_time(), pre.ref_time() - REGULAR_PAYLOAD.declared_weight.ref_time()); + + // when dispatch is returning `unspent_weight > declared_weight` + let (pre, post) = + submit_with_unspent_weight(3, REGULAR_PAYLOAD.declared_weight.ref_time() + 1); + assert_eq!(post.ref_time(), pre.ref_time() - REGULAR_PAYLOAD.declared_weight.ref_time()); + + // when there's no unspent weight + let (pre, post) = submit_with_unspent_weight(4, 0); + assert_eq!(post.ref_time(), pre.ref_time()); + + // when dispatch is returning `unspent_weight < declared_weight` + let (pre, post) = submit_with_unspent_weight(5, 1); + assert_eq!(post.ref_time(), pre.ref_time() - 1); + }); +} + +#[test] +fn proof_size_refund_from_receive_messages_proof_works() { + run_test(|| { + let max_entries = BridgedChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX as usize; + + // if there's maximal number of unrewarded relayer entries at the inbound lane, then + // `proof_size` is unchanged in post-dispatch weight + let proof = prepare_messages_proof(vec![message(101, REGULAR_PAYLOAD)], None); + let messages_count = 1; + let pre_dispatch_weight = + ::WeightInfo::receive_messages_proof_weight( + &*proof, + messages_count, + REGULAR_PAYLOAD.declared_weight, + ); + InboundLanes::::insert( + TEST_LANE_ID, + StoredInboundLaneData(InboundLaneData { + relayers: vec![ + UnrewardedRelayer { + relayer: 42, + messages: DeliveredMessages { begin: 0, end: 100 } + }; + max_entries + ] + .into(), + last_confirmed_nonce: 0, + }), + ); + let post_dispatch_weight = Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + proof.clone(), + messages_count, + REGULAR_PAYLOAD.declared_weight, + ) + .unwrap() + .actual_weight + .unwrap(); + assert_eq!(post_dispatch_weight.proof_size(), pre_dispatch_weight.proof_size()); + + // if count of unrewarded relayer entries is less than maximal, then some `proof_size` + // must be refunded + InboundLanes::::insert( + TEST_LANE_ID, + StoredInboundLaneData(InboundLaneData { + relayers: vec![ + UnrewardedRelayer { + relayer: 42, + messages: DeliveredMessages { begin: 0, end: 100 } + }; + max_entries - 1 + ] + .into(), + last_confirmed_nonce: 0, + }), + ); + let post_dispatch_weight = Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + proof, + messages_count, + REGULAR_PAYLOAD.declared_weight, + ) + .unwrap() + .actual_weight + .unwrap(); + assert!( + post_dispatch_weight.proof_size() < pre_dispatch_weight.proof_size(), + "Expected post-dispatch PoV {} to be less than pre-dispatch PoV {}", + post_dispatch_weight.proof_size(), + pre_dispatch_weight.proof_size(), + ); + }); +} + +#[test] +fn receive_messages_delivery_proof_rejects_proof_if_trying_to_confirm_more_messages_than_expected() +{ + run_test(|| { + // send message first to be able to check that delivery_proof fails later + send_regular_message(TEST_LANE_ID); + + // 1) InboundLaneData declares that the `last_confirmed_nonce` is 1; + // 2) InboundLaneData has no entries => `InboundLaneData::last_delivered_nonce()` returns + // `last_confirmed_nonce`; + // 3) it means that we're going to confirm delivery of messages 1..=1; + // 4) so the number of declared messages (see `UnrewardedRelayersState`) is `0` and numer of + // actually confirmed messages is `1`. + let proof = prepare_messages_delivery_proof( + TEST_LANE_ID, + InboundLaneData { last_confirmed_nonce: 1, relayers: Default::default() }, + ); + assert_noop!( + Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + proof, + UnrewardedRelayersState { last_delivered_nonce: 1, ..Default::default() }, + ), + Error::::ReceptionConfirmation( + ReceptionConfirmationError::TryingToConfirmMoreMessagesThanExpected + ), + ); + }); +} + +#[test] +fn storage_keys_computed_properly() { + assert_eq!( + PalletOperatingMode::::storage_value_final_key().to_vec(), + bp_messages::storage_keys::operating_mode_key("Messages").0, + ); + + assert_eq!( + OutboundMessages::::storage_map_final_key(MessageKey { + lane_id: TEST_LANE_ID, + nonce: 42 + }), + bp_messages::storage_keys::message_key("Messages", &TEST_LANE_ID, 42).0, + ); + + assert_eq!( + OutboundLanes::::storage_map_final_key(TEST_LANE_ID), + bp_messages::storage_keys::outbound_lane_data_key("Messages", &TEST_LANE_ID).0, + ); + + assert_eq!( + InboundLanes::::storage_map_final_key(TEST_LANE_ID), + bp_messages::storage_keys::inbound_lane_data_key("Messages", &TEST_LANE_ID).0, + ); +} + +#[test] +fn inbound_message_details_works() { + run_test(|| { + assert_eq!( + Pallet::::inbound_message_data( + TEST_LANE_ID, + REGULAR_PAYLOAD.encode(), + OutboundMessageDetails { nonce: 0, dispatch_weight: Weight::zero(), size: 0 }, + ), + InboundMessageDetails { dispatch_weight: REGULAR_PAYLOAD.declared_weight }, + ); + }); +} + +#[test] +fn on_idle_callback_respects_remaining_weight() { + run_test(|| { + send_regular_message(TEST_LANE_ID); + send_regular_message(TEST_LANE_ID); + send_regular_message(TEST_LANE_ID); + send_regular_message(TEST_LANE_ID); + + assert_ok!(Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + prepare_messages_delivery_proof( + TEST_LANE_ID, + InboundLaneData { + last_confirmed_nonce: 4, + relayers: vec![unrewarded_relayer(1, 4, TEST_RELAYER_A)].into(), + }, + ), + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 4, + total_messages: 4, + last_delivered_nonce: 4, + }, + )); + + // all 4 messages may be pruned now + assert_eq!(outbound_lane::(TEST_LANE_ID).data().latest_received_nonce, 4); + assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 1); + System::::set_block_number(2); + + // if passed wight is too low to do anything + let dbw = DbWeight::get(); + assert_eq!(Pallet::::on_idle(0, dbw.reads_writes(1, 1)), Weight::zero(),); + assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 1); + + // if passed wight is enough to prune single message + assert_eq!( + Pallet::::on_idle(0, dbw.reads_writes(1, 2)), + dbw.reads_writes(1, 2), + ); + assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 2); + + // if passed wight is enough to prune two more messages + assert_eq!( + Pallet::::on_idle(0, dbw.reads_writes(1, 3)), + dbw.reads_writes(1, 3), + ); + assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 4); + + // if passed wight is enough to prune many messages + assert_eq!( + Pallet::::on_idle(0, dbw.reads_writes(100, 100)), + dbw.reads_writes(1, 2), + ); + assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 5); + }); +} + +#[test] +fn on_idle_callback_is_rotating_lanes_to_prune() { + run_test(|| { + // send + receive confirmation for lane 1 + send_regular_message(TEST_LANE_ID); + receive_messages_delivery_proof(); + // send + receive confirmation for lane 2 + send_regular_message(TEST_LANE_ID_2); + assert_ok!(Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + prepare_messages_delivery_proof( + TEST_LANE_ID_2, + InboundLaneData { + last_confirmed_nonce: 1, + relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)].into(), + }, + ), + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 1, + total_messages: 1, + last_delivered_nonce: 1, + }, + )); + + // nothing is pruned yet + assert_eq!(outbound_lane::(TEST_LANE_ID).data().latest_received_nonce, 1); + assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 1); + assert_eq!( + outbound_lane::(TEST_LANE_ID_2).data().latest_received_nonce, + 1 + ); + assert_eq!( + outbound_lane::(TEST_LANE_ID_2).data().oldest_unpruned_nonce, + 1 + ); + + // in block#2.on_idle lane messages of lane 1 are pruned + let dbw = DbWeight::get(); + System::::set_block_number(2); + assert_eq!( + Pallet::::on_idle(0, dbw.reads_writes(100, 100)), + dbw.reads_writes(1, 2), + ); + assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 2); + assert_eq!( + outbound_lane::(TEST_LANE_ID_2).data().oldest_unpruned_nonce, + 1 + ); + + // in block#3.on_idle lane messages of lane 2 are pruned + System::::set_block_number(3); + + assert_eq!( + Pallet::::on_idle(0, dbw.reads_writes(100, 100)), + dbw.reads_writes(1, 2), + ); + assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 2); + assert_eq!( + outbound_lane::(TEST_LANE_ID_2).data().oldest_unpruned_nonce, + 2 + ); + }); +} + +#[test] +fn outbound_message_from_unconfigured_lane_is_rejected() { + run_test(|| { + assert_noop!( + Pallet::::validate_message(TEST_LANE_ID_3, ®ULAR_PAYLOAD,), + Error::::InactiveOutboundLane, + ); + }); +} + +#[test] +fn test_bridge_messages_call_is_correctly_defined() { + run_test(|| { + let account_id = 1; + let message_proof = prepare_messages_proof(vec![message(1, REGULAR_PAYLOAD)], None); + let message_delivery_proof = prepare_messages_delivery_proof( + TEST_LANE_ID, + InboundLaneData { + last_confirmed_nonce: 1, + relayers: vec![UnrewardedRelayer { + relayer: 0, + messages: DeliveredMessages::new(1), + }] + .into(), + }, + ); + let unrewarded_relayer_state = UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 1, + last_delivered_nonce: 1, + ..Default::default() + }; + + let direct_receive_messages_proof_call = Call::::receive_messages_proof { + relayer_id_at_bridged_chain: account_id, + proof: message_proof.clone(), + messages_count: 1, + dispatch_weight: REGULAR_PAYLOAD.declared_weight, + }; + let indirect_receive_messages_proof_call = BridgeMessagesCall::< + AccountId, + FromBridgedChainMessagesProof, + FromBridgedChainMessagesDeliveryProof, + >::receive_messages_proof { + relayer_id_at_bridged_chain: account_id, + proof: *message_proof, + messages_count: 1, + dispatch_weight: REGULAR_PAYLOAD.declared_weight, + }; + assert_eq!( + direct_receive_messages_proof_call.encode(), + indirect_receive_messages_proof_call.encode() + ); + + let direct_receive_messages_delivery_proof_call = + Call::::receive_messages_delivery_proof { + proof: message_delivery_proof.clone(), + relayers_state: unrewarded_relayer_state.clone(), + }; + let indirect_receive_messages_delivery_proof_call = BridgeMessagesCall::< + AccountId, + FromBridgedChainMessagesProof, + FromBridgedChainMessagesDeliveryProof, + >::receive_messages_delivery_proof { + proof: message_delivery_proof, + relayers_state: unrewarded_relayer_state, + }; + assert_eq!( + direct_receive_messages_delivery_proof_call.encode(), + indirect_receive_messages_delivery_proof_call.encode() + ); + }); +} + +generate_owned_bridge_module_tests!( + MessagesOperatingMode::Basic(BasicOperatingMode::Normal), + MessagesOperatingMode::Basic(BasicOperatingMode::Halted) +); + +#[test] +fn inbound_storage_extra_proof_size_bytes_works() { + fn relayer_entry() -> UnrewardedRelayer { + UnrewardedRelayer { relayer: 42u64, messages: DeliveredMessages { begin: 0, end: 100 } } + } + + fn storage(relayer_entries: usize) -> RuntimeInboundLaneStorage { + RuntimeInboundLaneStorage { + lane_id: Default::default(), + cached_data: Some(InboundLaneData { + relayers: vec![relayer_entry(); relayer_entries].into(), + last_confirmed_nonce: 0, + }), + _phantom: Default::default(), + } + } + + let max_entries = BridgedChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX as usize; + + // when we have exactly `MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX` unrewarded relayers + assert_eq!(storage(max_entries).extra_proof_size_bytes(), 0); + + // when we have less than `MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX` unrewarded relayers + assert_eq!( + storage(max_entries - 1).extra_proof_size_bytes(), + relayer_entry().encode().len() as u64 + ); + assert_eq!( + storage(max_entries - 2).extra_proof_size_bytes(), + 2 * relayer_entry().encode().len() as u64 + ); + + // when we have more than `MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX` unrewarded relayers + // (shall not happen in practice) + assert_eq!(storage(max_entries + 1).extra_proof_size_bytes(), 0); +} + +#[test] +fn maybe_outbound_lanes_count_returns_correct_value() { + assert_eq!( + MaybeOutboundLanesCount::::get(), + Some(mock::ActiveOutboundLanes::get().len() as u32) + ); +} diff --git a/bridges/modules/messages/src/weights.rs b/bridges/modules/messages/src/weights.rs index 5bf7d56756079df8a5e469b9c50ba7607b65d983..72a06599b1655c52b9761c1b9af7c8d798631ddf 100644 --- a/bridges/modules/messages/src/weights.rs +++ b/bridges/modules/messages/src/weights.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for pallet_bridge_messages //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-06-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `covid`, CPU: `11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz` +//! HOSTNAME: `serban-ROG-Zephyrus`, CPU: `12th Gen Intel(R) Core(TM) i7-12700H` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -51,14 +51,13 @@ use sp_std::marker::PhantomData; /// Weight functions needed for pallet_bridge_messages. pub trait WeightInfo { fn receive_single_message_proof() -> Weight; - fn receive_two_messages_proof() -> Weight; + fn receive_n_messages_proof(n: u32) -> Weight; fn receive_single_message_proof_with_outbound_lane_state() -> Weight; - fn receive_single_message_proof_1_kb() -> Weight; - fn receive_single_message_proof_16_kb() -> Weight; + fn receive_single_n_bytes_message_proof(n: u32) -> Weight; fn receive_delivery_proof_for_single_message() -> Weight; fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight; fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight; - fn receive_single_message_proof_with_dispatch(i: u32) -> Weight; + fn receive_single_n_bytes_message_proof_with_dispatch(n: u32) -> Weight; } /// Weights for `pallet_bridge_messages` that are generated using one of the Bridge testnets. @@ -82,56 +81,39 @@ impl WeightInfo for BridgeWeight { /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 52_321 nanoseconds. - Weight::from_parts(54_478_000, 57170) + // Measured: `653` + // Estimated: `52673` + // Minimum execution time: 38_724 nanoseconds. + Weight::from_parts(40_650_000, 52673) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeUnknownMessages InboundLanes (r:1 w:1) - /// - /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: - /// 51655, mode: MaxEncodedLen) - fn receive_two_messages_proof() -> Weight { - // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 64_597 nanoseconds. - Weight::from_parts(69_267_000, 57170) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) /// - /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), - /// added: 497, mode: MaxEncodedLen) + /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49208), added: + /// 51683, mode: MaxEncodedLen) /// - /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) + /// The range of component `n` is `[1, 1004]`. /// - /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), - /// added: 2048, mode: MaxEncodedLen) - /// - /// Storage: BridgeUnknownMessages InboundLanes (r:1 w:1) - /// - /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: - /// 51655, mode: MaxEncodedLen) - fn receive_single_message_proof_with_outbound_lane_state() -> Weight { + /// The range of component `n` is `[1, 1004]`. + fn receive_n_messages_proof(n: u32) -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 64_079 nanoseconds. - Weight::from_parts(65_905_000, 57170) + // Measured: `653` + // Estimated: `52673` + // Minimum execution time: 39_354 nanoseconds. + Weight::from_parts(29_708_543, 52673) + // Standard Error: 1_185 + .saturating_add(Weight::from_parts(7_648_787, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -149,12 +131,12 @@ impl WeightInfo for BridgeWeight { /// /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: /// 51655, mode: MaxEncodedLen) - fn receive_single_message_proof_1_kb() -> Weight { + fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 50_588 nanoseconds. - Weight::from_parts(53_544_000, 57170) + // Measured: `653` + // Estimated: `52673` + // Minimum execution time: 45_578 nanoseconds. + Weight::from_parts(47_161_000, 52673) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -172,12 +154,16 @@ impl WeightInfo for BridgeWeight { /// /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: /// 51655, mode: MaxEncodedLen) - fn receive_single_message_proof_16_kb() -> Weight { + /// + /// The range of component `n` is `[1, 16384]`. + fn receive_single_n_bytes_message_proof(n: u32) -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 78_269 nanoseconds. - Weight::from_parts(81_748_000, 57170) + // Measured: `653` + // Estimated: `52673` + // Minimum execution time: 38_702 nanoseconds. + Weight::from_parts(41_040_143, 52673) + // Standard Error: 5 + .saturating_add(Weight::from_parts(1_174, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -198,16 +184,21 @@ impl WeightInfo for BridgeWeight { /// /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) /// - /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540, + /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(93), added: 2568, /// mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages OutboundMessages (r:0 w:1) + /// + /// Proof: BridgeRialtoMessages OutboundMessages (max_values: None, max_size: Some(65596), + /// added: 68071, mode: MaxEncodedLen) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `579` - // Estimated: `9584` - // Minimum execution time: 45_786 nanoseconds. - Weight::from_parts(47_382_000, 9584) + // Measured: `701` + // Estimated: `3558` + // Minimum execution time: 37_197 nanoseconds. + Weight::from_parts(38_371_000, 3558) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// @@ -226,16 +217,21 @@ impl WeightInfo for BridgeWeight { /// /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) /// - /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540, + /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(93), added: 2568, /// mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages OutboundMessages (r:0 w:2) + /// + /// Proof: BridgeRialtoMessages OutboundMessages (max_values: None, max_size: Some(65596), + /// added: 68071, mode: MaxEncodedLen) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `596` - // Estimated: `9584` - // Minimum execution time: 44_544 nanoseconds. - Weight::from_parts(45_451_000, 9584) + // Measured: `701` + // Estimated: `3558` + // Minimum execution time: 38_684 nanoseconds. + Weight::from_parts(39_929_000, 3558) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// @@ -254,16 +250,21 @@ impl WeightInfo for BridgeWeight { /// /// Storage: BridgeRelayers RelayerRewards (r:2 w:2) /// - /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540, + /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(93), added: 2568, /// mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages OutboundMessages (r:0 w:2) + /// + /// Proof: BridgeRialtoMessages OutboundMessages (max_values: None, max_size: Some(65596), + /// added: 68071, mode: MaxEncodedLen) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `596` - // Estimated: `12124` - // Minimum execution time: 47_344 nanoseconds. - Weight::from_parts(48_311_000, 12124) + // Measured: `701` + // Estimated: `6126` + // Minimum execution time: 41_363 nanoseconds. + Weight::from_parts(42_621_000, 6126) .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// @@ -280,15 +281,15 @@ impl WeightInfo for BridgeWeight { /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: /// 51655, mode: MaxEncodedLen) /// - /// The range of component `i` is `[128, 2048]`. - fn receive_single_message_proof_with_dispatch(i: u32) -> Weight { + /// The range of component `n` is `[1, 16384]`. + fn receive_single_n_bytes_message_proof_with_dispatch(n: u32) -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 52_385 nanoseconds. - Weight::from_parts(54_919_468, 57170) - // Standard Error: 108 - .saturating_add(Weight::from_parts(3_286, 0).saturating_mul(i.into())) + // Measured: `653` + // Estimated: `52673` + // Minimum execution time: 38_925 nanoseconds. + Weight::from_parts(39_617_000, 52673) + // Standard Error: 612 + .saturating_add(Weight::from_parts(372_813, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -312,33 +313,39 @@ impl WeightInfo for () { /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 52_321 nanoseconds. - Weight::from_parts(54_478_000, 57170) + // Measured: `653` + // Estimated: `52673` + // Minimum execution time: 38_724 nanoseconds. + Weight::from_parts(40_650_000, 52673) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) /// - /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), /// added: 497, mode: MaxEncodedLen) /// - /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) /// - /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), /// added: 2048, mode: MaxEncodedLen) /// - /// Storage: BridgeUnknownMessages InboundLanes (r:1 w:1) + /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) /// - /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: - /// 51655, mode: MaxEncodedLen) - fn receive_two_messages_proof() -> Weight { + /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49208), added: + /// 51683, mode: MaxEncodedLen) + /// + /// The range of component `n` is `[1, 1004]`. + /// + /// The range of component `n` is `[1, 1004]`. + fn receive_n_messages_proof(n: u32) -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 64_597 nanoseconds. - Weight::from_parts(69_267_000, 57170) + // Measured: `653` + // Estimated: `52673` + // Minimum execution time: 39_354 nanoseconds. + Weight::from_parts(29_708_543, 52673) + // Standard Error: 1_185 + .saturating_add(Weight::from_parts(7_648_787, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -358,10 +365,10 @@ impl WeightInfo for () { /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 64_079 nanoseconds. - Weight::from_parts(65_905_000, 57170) + // Measured: `653` + // Estimated: `52673` + // Minimum execution time: 45_578 nanoseconds. + Weight::from_parts(47_161_000, 52673) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -377,37 +384,20 @@ impl WeightInfo for () { /// /// Storage: BridgeUnknownMessages InboundLanes (r:1 w:1) /// - /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: - /// 51655, mode: MaxEncodedLen) - fn receive_single_message_proof_1_kb() -> Weight { - // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 50_588 nanoseconds. - Weight::from_parts(53_544_000, 57170) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) - /// - /// Proof: BridgeUnknownMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), - /// added: 497, mode: MaxEncodedLen) - /// - /// Storage: BridgeUnknownGrandpa ImportedHeaders (r:1 w:0) + /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49208), added: + /// 51683, mode: MaxEncodedLen) /// - /// Proof: BridgeUnknownGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), - /// added: 2048, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 16384]`. /// - /// Storage: BridgeUnknownMessages InboundLanes (r:1 w:1) - /// - /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: - /// 51655, mode: MaxEncodedLen) - fn receive_single_message_proof_16_kb() -> Weight { + /// The range of component `n` is `[1, 16384]`. + fn receive_single_n_bytes_message_proof(n: u32) -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 78_269 nanoseconds. - Weight::from_parts(81_748_000, 57170) + // Measured: `653` + // Estimated: `52673` + // Minimum execution time: 38_702 nanoseconds. + Weight::from_parts(41_040_143, 52673) + // Standard Error: 5 + .saturating_add(Weight::from_parts(1_174, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -428,16 +418,21 @@ impl WeightInfo for () { /// /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) /// - /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540, + /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(93), added: 2568, /// mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages OutboundMessages (r:0 w:1) + /// + /// Proof: BridgeRialtoMessages OutboundMessages (max_values: None, max_size: Some(65596), + /// added: 68071, mode: MaxEncodedLen) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `579` - // Estimated: `9584` - // Minimum execution time: 45_786 nanoseconds. - Weight::from_parts(47_382_000, 9584) + // Measured: `701` + // Estimated: `3558` + // Minimum execution time: 37_197 nanoseconds. + Weight::from_parts(38_371_000, 3558) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// @@ -456,16 +451,21 @@ impl WeightInfo for () { /// /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) /// - /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540, + /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(93), added: 2568, /// mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages OutboundMessages (r:0 w:2) + /// + /// Proof: BridgeRialtoMessages OutboundMessages (max_values: None, max_size: Some(65596), + /// added: 68071, mode: MaxEncodedLen) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `596` - // Estimated: `9584` - // Minimum execution time: 44_544 nanoseconds. - Weight::from_parts(45_451_000, 9584) + // Measured: `701` + // Estimated: `3558` + // Minimum execution time: 38_684 nanoseconds. + Weight::from_parts(39_929_000, 3558) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// @@ -484,16 +484,21 @@ impl WeightInfo for () { /// /// Storage: BridgeRelayers RelayerRewards (r:2 w:2) /// - /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540, + /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(93), added: 2568, /// mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages OutboundMessages (r:0 w:2) + /// + /// Proof: BridgeRialtoMessages OutboundMessages (max_values: None, max_size: Some(65596), + /// added: 68071, mode: MaxEncodedLen) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `596` - // Estimated: `12124` - // Minimum execution time: 47_344 nanoseconds. - Weight::from_parts(48_311_000, 12124) + // Measured: `701` + // Estimated: `6126` + // Minimum execution time: 41_363 nanoseconds. + Weight::from_parts(42_621_000, 6126) .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: BridgeUnknownMessages PalletOperatingMode (r:1 w:0) /// @@ -510,15 +515,15 @@ impl WeightInfo for () { /// Proof: BridgeUnknownMessages InboundLanes (max_values: None, max_size: Some(49180), added: /// 51655, mode: MaxEncodedLen) /// - /// The range of component `i` is `[128, 2048]`. - fn receive_single_message_proof_with_dispatch(i: u32) -> Weight { + /// The range of component `n` is `[1, 16384]`. + fn receive_single_n_bytes_message_proof_with_dispatch(n: u32) -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 52_385 nanoseconds. - Weight::from_parts(54_919_468, 57170) - // Standard Error: 108 - .saturating_add(Weight::from_parts(3_286, 0).saturating_mul(i.into())) + // Measured: `653` + // Estimated: `52673` + // Minimum execution time: 38_925 nanoseconds. + Weight::from_parts(39_617_000, 52673) + // Standard Error: 612 + .saturating_add(Weight::from_parts(372_813, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/bridges/modules/messages/src/weights_ext.rs b/bridges/modules/messages/src/weights_ext.rs index c12e04f692bf8304fb58d7c97ec50d1b860ccb56..7711e212efb06da0421f57b01ab4d1eef8b48f16 100644 --- a/bridges/modules/messages/src/weights_ext.rs +++ b/bridges/modules/messages/src/weights_ext.rs @@ -40,13 +40,6 @@ pub fn ensure_weights_are_correct() { // benchmarked using `MaxEncodedLen` approach and there are no components that cause additional // db reads - // verify `receive_messages_proof` weight components - assert_ne!(W::receive_messages_proof_overhead().ref_time(), 0); - assert_ne!(W::receive_messages_proof_overhead().proof_size(), 0); - // W::receive_messages_proof_messages_overhead(1).ref_time() may be zero because: - // the message processing code (`InboundLane::receive_message`) is minimal and may not be - // accounted by our benchmarks - assert_eq!(W::receive_messages_proof_messages_overhead(1).proof_size(), 0); // W::receive_messages_proof_outbound_lane_state_overhead().ref_time() may be zero because: // the outbound lane state processing code (`InboundLane::receive_state_update`) is minimal and // may not be accounted by our benchmarks @@ -86,6 +79,19 @@ pub fn ensure_weights_are_correct() { total_messages_in_delivery_proof_does_not_affect_proof_size::(); } +/// Ensure that we are able to dispatch maximal size messages. +pub fn ensure_maximal_message_dispatch( + max_incoming_message_size: u32, + max_incoming_message_dispatch_weight: Weight, +) { + let message_dispatch_weight = W::message_dispatch_weight(max_incoming_message_size); + assert!( + message_dispatch_weight.all_lte(max_incoming_message_dispatch_weight), + "Dispatch weight of maximal message {message_dispatch_weight:?} must be lower \ + than the hardcoded {max_incoming_message_dispatch_weight:?}", + ); +} + /// Ensure that we're able to receive maximal (by-size and by-weight) message from other chain. pub fn ensure_able_to_receive_message( max_extrinsic_size: u32, @@ -98,7 +104,8 @@ pub fn ensure_able_to_receive_message( max_incoming_message_proof_size.saturating_add(SIGNED_EXTENSIONS_SIZE); assert!( max_delivery_transaction_size <= max_extrinsic_size, - "Size of maximal message delivery transaction {max_incoming_message_proof_size} + {SIGNED_EXTENSIONS_SIZE} is larger than maximal possible transaction size {max_extrinsic_size}", + "Size of maximal message delivery transaction {max_incoming_message_proof_size} + \ + {SIGNED_EXTENSIONS_SIZE} is larger than maximal possible transaction size {max_extrinsic_size}", ); // verify that we're able to receive proof of maximal-size message with maximal dispatch weight @@ -297,13 +304,11 @@ pub trait WeightInfoExt: WeightInfo { dispatch_weight: Weight, ) -> Weight { // basic components of extrinsic weight - let transaction_overhead = Self::receive_messages_proof_overhead(); + let base_weight = Self::receive_n_messages_proof(messages_count); let transaction_overhead_from_runtime = Self::receive_messages_proof_overhead_from_runtime(); let outbound_state_delivery_weight = Self::receive_messages_proof_outbound_lane_state_overhead(); - let messages_delivery_weight = - Self::receive_messages_proof_messages_overhead(MessageNonce::from(messages_count)); let messages_dispatch_weight = dispatch_weight; // proof size overhead weight @@ -315,10 +320,9 @@ pub trait WeightInfoExt: WeightInfo { actual_proof_size.saturating_sub(expected_proof_size), ); - transaction_overhead + base_weight .saturating_add(transaction_overhead_from_runtime) .saturating_add(outbound_state_delivery_weight) - .saturating_add(messages_delivery_weight) .saturating_add(messages_dispatch_weight) .saturating_add(proof_size_overhead) } @@ -354,25 +358,6 @@ pub trait WeightInfoExt: WeightInfo { // Functions that are used by extrinsics weights formulas. - /// Returns weight overhead of message delivery transaction (`receive_messages_proof`). - fn receive_messages_proof_overhead() -> Weight { - let weight_of_two_messages_and_two_tx_overheads = - Self::receive_single_message_proof().saturating_mul(2); - let weight_of_two_messages_and_single_tx_overhead = Self::receive_two_messages_proof(); - weight_of_two_messages_and_two_tx_overheads - .saturating_sub(weight_of_two_messages_and_single_tx_overhead) - } - - /// Returns weight that needs to be accounted when receiving given a number of messages with - /// message delivery transaction (`receive_messages_proof`). - fn receive_messages_proof_messages_overhead(messages: MessageNonce) -> Weight { - let weight_of_two_messages_and_single_tx_overhead = Self::receive_two_messages_proof(); - let weight_of_single_message_and_single_tx_overhead = Self::receive_single_message_proof(); - weight_of_two_messages_and_single_tx_overhead - .saturating_sub(weight_of_single_message_and_single_tx_overhead) - .saturating_mul(messages as _) - } - /// Returns weight that needs to be accounted when message delivery transaction /// (`receive_messages_proof`) is carrying outbound lane state proof. fn receive_messages_proof_outbound_lane_state_overhead() -> Weight { @@ -426,9 +411,8 @@ pub trait WeightInfoExt: WeightInfo { /// is less than that cost). fn storage_proof_size_overhead(proof_size: u32) -> Weight { let proof_size_in_bytes = proof_size; - let byte_weight = (Self::receive_single_message_proof_16_kb() - - Self::receive_single_message_proof_1_kb()) / - (15 * 1024); + let byte_weight = Self::receive_single_n_bytes_message_proof(2) - + Self::receive_single_n_bytes_message_proof(1); proof_size_in_bytes * byte_weight } @@ -440,11 +424,9 @@ pub trait WeightInfoExt: WeightInfo { /// `receive_single_message_proof_with_dispatch` benchmark. See its requirements for /// details. fn message_dispatch_weight(message_size: u32) -> Weight { - // There may be a tiny overweight/underweight here, because we don't account how message - // size affects all steps before dispatch. But the effect should be small enough and we - // may ignore it. - Self::receive_single_message_proof_with_dispatch(message_size) - .saturating_sub(Self::receive_single_message_proof()) + let message_size_in_bytes = message_size; + Self::receive_single_n_bytes_message_proof_with_dispatch(message_size_in_bytes) + .saturating_sub(Self::receive_single_n_bytes_message_proof(message_size_in_bytes)) } } @@ -479,7 +461,7 @@ impl WeightInfoExt for crate::weights::BridgeWeight #[cfg(test)] mod tests { use super::*; - use crate::{mock::TestRuntime, weights::BridgeWeight}; + use crate::{tests::mock::TestRuntime, weights::BridgeWeight}; #[test] fn ensure_default_weights_are_correct() { diff --git a/bridges/modules/parachains/Cargo.toml b/bridges/modules/parachains/Cargo.toml index d3152f8d0a4aa9b6dc1c726441c5e139e08de162..cda0ee8106d5400c33e186265d672f1b9282dc0d 100644 --- a/bridges/modules/parachains/Cargo.toml +++ b/bridges/modules/parachains/Cargo.toml @@ -11,32 +11,31 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } +codec = { workspace = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } # Bridge Dependencies -bp-header-chain = { path = "../../primitives/header-chain", default-features = false } -bp-parachains = { path = "../../primitives/parachains", default-features = false } -bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } -bp-runtime = { path = "../../primitives/runtime", default-features = false } -pallet-bridge-grandpa = { path = "../grandpa", default-features = false } +bp-header-chain = { workspace = true } +bp-parachains = { workspace = true } +bp-polkadot-core = { workspace = true } +bp-runtime = { workspace = true } +pallet-bridge-grandpa = { workspace = true } # Substrate Dependencies -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } [dev-dependencies] -bp-header-chain = { path = "../../primitives/header-chain" } -bp-test-utils = { path = "../../primitives/test-utils" } -sp-core = { path = "../../../substrate/primitives/core" } -sp-io = { path = "../../../substrate/primitives/io" } +bp-header-chain = { workspace = true, default-features = true } +bp-test-utils = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } [features] default = ["std"] @@ -54,7 +53,6 @@ std = [ "scale-info/std", "sp-runtime/std", "sp-std/std", - "sp-trie/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/bridges/modules/parachains/src/benchmarking.rs b/bridges/modules/parachains/src/benchmarking.rs index 27e06a12a1d93486d93aa258afc1d7de4713df2c..92ece6d688cbea3bed2e5d489163f2416bef9bbc 100644 --- a/bridges/modules/parachains/src/benchmarking.rs +++ b/bridges/modules/parachains/src/benchmarking.rs @@ -22,7 +22,7 @@ use crate::{ }; use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; -use bp_runtime::StorageProofSize; +use bp_runtime::UnverifiedStorageProofParams; use frame_benchmarking::{account, benchmarks_instance_pallet}; use frame_system::RawOrigin; use sp_std::prelude::*; @@ -38,7 +38,7 @@ pub trait Config: crate::Config { fn prepare_parachain_heads_proof( parachains: &[ParaId], parachain_head_size: u32, - proof_size: StorageProofSize, + proof_params: UnverifiedStorageProofParams, ) -> (RelayBlockNumber, RelayBlockHash, ParaHeadsProof, Vec<(ParaId, ParaHash)>); } @@ -68,7 +68,7 @@ benchmarks_instance_pallet! { let (relay_block_number, relay_block_hash, parachain_heads_proof, parachains_heads) = T::prepare_parachain_heads_proof( ¶chains, DEFAULT_PARACHAIN_HEAD_SIZE, - StorageProofSize::Minimal(0), + UnverifiedStorageProofParams::default(), ); let at_relay_block = (relay_block_number, relay_block_hash); }: submit_parachain_heads(RawOrigin::Signed(sender), at_relay_block, parachains_heads, parachain_heads_proof) @@ -85,7 +85,7 @@ benchmarks_instance_pallet! { let (relay_block_number, relay_block_hash, parachain_heads_proof, parachains_heads) = T::prepare_parachain_heads_proof( ¶chains, DEFAULT_PARACHAIN_HEAD_SIZE, - StorageProofSize::HasLargeLeaf(1024), + UnverifiedStorageProofParams::from_db_size(1024), ); let at_relay_block = (relay_block_number, relay_block_hash); }: submit_parachain_heads(RawOrigin::Signed(sender), at_relay_block, parachains_heads, parachain_heads_proof) @@ -102,7 +102,7 @@ benchmarks_instance_pallet! { let (relay_block_number, relay_block_hash, parachain_heads_proof, parachains_heads) = T::prepare_parachain_heads_proof( ¶chains, DEFAULT_PARACHAIN_HEAD_SIZE, - StorageProofSize::HasLargeLeaf(16 * 1024), + UnverifiedStorageProofParams::from_db_size(16 * 1024), ); let at_relay_block = (relay_block_number, relay_block_hash); }: submit_parachain_heads(RawOrigin::Signed(sender), at_relay_block, parachains_heads, parachain_heads_proof) diff --git a/bridges/modules/parachains/src/call_ext.rs b/bridges/modules/parachains/src/call_ext.rs index fe6b319205d41491ce2df36d8a1d112eb37f94b4..0f77eaf2c5a93d372cab8af0857f10fa40ca920f 100644 --- a/bridges/modules/parachains/src/call_ext.rs +++ b/bridges/modules/parachains/src/call_ext.rs @@ -289,7 +289,7 @@ mod tests { RuntimeCall::Parachains(crate::Call::::submit_parachain_heads_ex { at_relay_block: (num, [num as u8; 32].into()), parachains, - parachain_heads_proof: ParaHeadsProof { storage_proof: Vec::new() }, + parachain_heads_proof: ParaHeadsProof { storage_proof: Default::default() }, is_free_execution_expected: false, }) .check_obsolete_submit_parachain_heads() @@ -303,7 +303,7 @@ mod tests { RuntimeCall::Parachains(crate::Call::::submit_parachain_heads_ex { at_relay_block: (num, [num as u8; 32].into()), parachains, - parachain_heads_proof: ParaHeadsProof { storage_proof: Vec::new() }, + parachain_heads_proof: ParaHeadsProof { storage_proof: Default::default() }, is_free_execution_expected: true, }) .check_obsolete_submit_parachain_heads() diff --git a/bridges/modules/parachains/src/lib.rs b/bridges/modules/parachains/src/lib.rs index d323aef3b22070d1db1e4709fe0dad8bf0360caf..e2c30ce9aecc1eb3b39fc588cc6386481f82fa7f 100644 --- a/bridges/modules/parachains/src/lib.rs +++ b/bridges/modules/parachains/src/lib.rs @@ -28,11 +28,12 @@ pub use weights::WeightInfo; pub use weights_ext::WeightInfoExt; use bp_header_chain::{HeaderChain, HeaderChainError}; -use bp_parachains::{parachain_head_storage_key_at_source, ParaInfo, ParaStoredHeaderData}; -use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}; -use bp_runtime::{Chain, HashOf, HeaderId, HeaderIdOf, Parachain, StorageProofError}; +use bp_parachains::{ParaInfo, ParaStoredHeaderData}; +use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; +use bp_runtime::{Chain, HashOf, HeaderId, HeaderIdOf, Parachain}; use frame_support::{dispatch::PostDispatchInfo, DefaultNoBound}; use pallet_bridge_grandpa::SubmitFinalityProofHelper; +use proofs::{ParachainsStorageProofAdapter, StorageProofAdapter}; use sp_std::{marker::PhantomData, vec::Vec}; #[cfg(feature = "runtime-benchmarks")] @@ -55,6 +56,7 @@ pub mod benchmarking; mod call_ext; #[cfg(test)] mod mock; +mod proofs; /// The target that will be used when publishing logs related to this pallet. pub const LOG_TARGET: &str = "runtime::bridge-parachains"; @@ -448,15 +450,15 @@ pub mod pallet { parachains.len() as _, ); - let mut is_updated_something = false; - let mut storage = GrandpaPalletOf::::storage_proof_checker( - relay_block_hash, - parachain_heads_proof.storage_proof, - ) - .map_err(Error::::HeaderChainStorageProof)?; + let mut storage: ParachainsStorageProofAdapter = + ParachainsStorageProofAdapter::try_new_with_verified_storage_proof( + relay_block_hash, + parachain_heads_proof.storage_proof, + ) + .map_err(Error::::HeaderChainStorageProof)?; for (parachain, parachain_head_hash) in parachains { - let parachain_head = match Self::read_parachain_head(&mut storage, parachain) { + let parachain_head = match storage.read_parachain_head(parachain) { Ok(Some(parachain_head)) => parachain_head, Ok(None) => { log::trace!( @@ -541,7 +543,6 @@ pub mod pallet { parachain_head_hash, )?; - is_updated_something = true; if is_free { free_parachain_heads = free_parachain_heads + 1; } @@ -572,7 +573,7 @@ pub mod pallet { // => treat this as an error // // (we can throw error here, because now all our calls are transactional) - storage.ensure_no_unused_nodes().map_err(|e| { + storage.ensure_no_unused_keys().map_err(|e| { Error::::HeaderChainStorageProof(HeaderChainError::StorageProof(e)) })?; @@ -633,16 +634,6 @@ pub mod pallet { ImportedParaHeads::::get(parachain, hash).map(|h| h.into_inner()) } - /// Read parachain head from storage proof. - fn read_parachain_head( - storage: &mut bp_runtime::StorageProofChecker, - parachain: ParaId, - ) -> Result, StorageProofError> { - let parachain_head_key = - parachain_head_storage_key_at_source(T::ParasPalletName::get(), parachain); - storage.read_and_decode_value(parachain_head_key.0.as_ref()) - } - /// Try to update parachain head. pub(super) fn update_parachain_head( parachain: ParaId, @@ -801,6 +792,7 @@ impl, I: 'static, C: Parachain> HeaderChain pub fn initialize_for_benchmarks, I: 'static, PC: Parachain>( header: HeaderOf, ) { + use bp_polkadot_core::parachains::ParaHead; use bp_runtime::HeaderIdProvider; use sp_runtime::traits::Header; @@ -844,9 +836,10 @@ pub(crate) mod tests { use bp_parachains::{ BestParaHeadHash, BridgeParachainCall, ImportedParaHeadsKeyProvider, ParasInfoKeyProvider, }; + use bp_polkadot_core::parachains::ParaHead; use bp_runtime::{ BasicOperatingMode, OwnedBridgeModuleError, StorageDoubleMapKeyProvider, - StorageMapKeyProvider, + StorageMapKeyProvider, StorageProofError, }; use bp_test_utils::{ authority_list, generate_owned_bridge_module_tests, make_default_justification, diff --git a/bridges/modules/parachains/src/mock.rs b/bridges/modules/parachains/src/mock.rs index dbb62845392d5fd2f408744f4f8a2321ec4bd34d..c49b5939093c50a17fbf369533d5ff9c01b625bc 100644 --- a/bridges/modules/parachains/src/mock.rs +++ b/bridges/modules/parachains/src/mock.rs @@ -23,7 +23,7 @@ use frame_support::{ use sp_runtime::{ testing::H256, traits::{BlakeTwo256, Header as HeaderT}, - MultiSignature, + MultiSignature, StateVersion, }; use crate as pallet_bridge_parachains; @@ -60,6 +60,8 @@ impl Chain for Parachain1 { type Nonce = u64; type Signature = MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { 0 } @@ -87,6 +89,8 @@ impl Chain for Parachain2 { type Nonce = u64; type Signature = MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { 0 } @@ -114,6 +118,8 @@ impl Chain for Parachain3 { type Nonce = u64; type Signature = MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { 0 } @@ -142,6 +148,8 @@ impl Chain for BigParachain { type Nonce = u64; type Signature = MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { 0 } @@ -222,7 +230,7 @@ impl pallet_bridge_parachains::benchmarking::Config<()> for TestRuntime { fn prepare_parachain_heads_proof( parachains: &[ParaId], _parachain_head_size: u32, - _proof_size: bp_runtime::StorageProofSize, + _proof_params: bp_runtime::UnverifiedStorageProofParams, ) -> ( crate::RelayBlockNumber, crate::RelayBlockHash, @@ -256,38 +264,7 @@ impl Chain for TestBridgedChain { type Nonce = u32; type Signature = sp_runtime::testing::TestSignature; - fn max_extrinsic_size() -> u32 { - unreachable!() - } - - fn max_extrinsic_weight() -> Weight { - unreachable!() - } -} - -impl ChainWithGrandpa for TestBridgedChain { - const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = ""; - const MAX_AUTHORITIES_COUNT: u32 = 16; - const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = 8; - const MAX_MANDATORY_HEADER_SIZE: u32 = 256; - const AVERAGE_HEADER_SIZE: u32 = 64; -} - -#[derive(Debug)] -pub struct OtherBridgedChain; - -impl Chain for OtherBridgedChain { - const ID: ChainId = *b"obch"; - - type BlockNumber = u64; - type Hash = crate::RelayBlockHash; - type Hasher = crate::RelayBlockHasher; - type Header = sp_runtime::generic::Header; - - type AccountId = AccountId; - type Balance = u32; - type Nonce = u32; - type Signature = sp_runtime::testing::TestSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; fn max_extrinsic_size() -> u32 { unreachable!() @@ -298,7 +275,7 @@ impl Chain for OtherBridgedChain { } } -impl ChainWithGrandpa for OtherBridgedChain { +impl ChainWithGrandpa for TestBridgedChain { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = ""; const MAX_AUTHORITIES_COUNT: u32 = 16; const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = 8; diff --git a/bridges/modules/parachains/src/proofs.rs b/bridges/modules/parachains/src/proofs.rs new file mode 100644 index 0000000000000000000000000000000000000000..dcf22229f3423a9a75f4be68d1af2b1bf2e7ea1e --- /dev/null +++ b/bridges/modules/parachains/src/proofs.rs @@ -0,0 +1,81 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Tools for parachain head proof verification. + +use crate::{Config, GrandpaPalletOf, RelayBlockHash, RelayBlockHasher}; +use bp_header_chain::{HeaderChain, HeaderChainError}; +use bp_parachains::parachain_head_storage_key_at_source; +use bp_polkadot_core::parachains::{ParaHead, ParaId}; +use bp_runtime::{RawStorageProof, StorageProofChecker, StorageProofError}; +use codec::Decode; +use frame_support::traits::Get; + +/// Abstraction over storage proof manipulation, hiding implementation details of actual storage +/// proofs. +pub trait StorageProofAdapter, I: 'static> { + /// Read and decode optional value from the proof. + fn read_and_decode_optional_value( + &mut self, + key: &impl AsRef<[u8]>, + ) -> Result, StorageProofError>; + + /// Checks if each key was read. + fn ensure_no_unused_keys(self) -> Result<(), StorageProofError>; + + /// Read parachain head from storage proof. + fn read_parachain_head( + &mut self, + parachain: ParaId, + ) -> Result, StorageProofError> { + let parachain_head_key = + parachain_head_storage_key_at_source(T::ParasPalletName::get(), parachain); + self.read_and_decode_optional_value(¶chain_head_key) + } +} + +/// Actual storage proof adapter for parachain proofs. +pub type ParachainsStorageProofAdapter = RawStorageProofAdapter; + +/// A `StorageProofAdapter` implementation for raw storage proofs. +pub struct RawStorageProofAdapter, I: 'static> { + storage: StorageProofChecker, + _dummy: sp_std::marker::PhantomData<(T, I)>, +} + +impl, I: 'static> RawStorageProofAdapter { + /// Try to create a new instance of `RawStorageProofAdapter`. + pub fn try_new_with_verified_storage_proof( + relay_block_hash: RelayBlockHash, + storage_proof: RawStorageProof, + ) -> Result { + GrandpaPalletOf::::verify_storage_proof(relay_block_hash, storage_proof) + .map(|storage| RawStorageProofAdapter:: { storage, _dummy: Default::default() }) + } +} + +impl, I: 'static> StorageProofAdapter for RawStorageProofAdapter { + fn read_and_decode_optional_value( + &mut self, + key: &impl AsRef<[u8]>, + ) -> Result, StorageProofError> { + self.storage.read_and_decode_opt_value(key.as_ref()) + } + + fn ensure_no_unused_keys(self) -> Result<(), StorageProofError> { + self.storage.ensure_no_unused_nodes() + } +} diff --git a/bridges/modules/parachains/src/weights.rs b/bridges/modules/parachains/src/weights.rs index abddc8768947006e574bf6bca4d2301c2047199a..1f92b7ff763c3f572efef1acf141a9eba0d3eb0e 100644 --- a/bridges/modules/parachains/src/weights.rs +++ b/bridges/modules/parachains/src/weights.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for pallet_bridge_parachains //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-06-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `covid`, CPU: `11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz` +//! HOSTNAME: `serban-ROG-Zephyrus`, CPU: `12th Gen Intel(R) Core(TM) i7-12700H` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -86,14 +86,12 @@ impl WeightInfo for BridgeWeight { /// Some(196), added: 1681, mode: MaxEncodedLen) /// /// The range of component `p` is `[1, 2]`. - fn submit_parachain_heads_with_n_parachains(p: u32) -> Weight { + fn submit_parachain_heads_with_n_parachains(_p: u32) -> Weight { // Proof Size summary in bytes: - // Measured: `366` - // Estimated: `4648` - // Minimum execution time: 36_701 nanoseconds. - Weight::from_parts(38_597_828, 4648) - // Standard Error: 190_859 - .saturating_add(Weight::from_parts(60_685, 0).saturating_mul(p.into())) + // Measured: `302` + // Estimated: `3038` + // Minimum execution time: 30_211 nanoseconds. + Weight::from_parts(32_633_893, 3038) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -123,10 +121,10 @@ impl WeightInfo for BridgeWeight { /// Some(196), added: 1681, mode: MaxEncodedLen) fn submit_parachain_heads_with_1kb_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `366` - // Estimated: `4648` - // Minimum execution time: 38_189 nanoseconds. - Weight::from_parts(39_252_000, 4648) + // Measured: `302` + // Estimated: `3038` + // Minimum execution time: 30_830 nanoseconds. + Weight::from_parts(31_801_000, 3038) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -156,10 +154,10 @@ impl WeightInfo for BridgeWeight { /// Some(196), added: 1681, mode: MaxEncodedLen) fn submit_parachain_heads_with_16kb_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `366` - // Estimated: `4648` - // Minimum execution time: 62_868 nanoseconds. - Weight::from_parts(63_581_000, 4648) + // Measured: `302` + // Estimated: `3038` + // Minimum execution time: 44_736 nanoseconds. + Weight::from_parts(45_296_000, 3038) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -193,14 +191,12 @@ impl WeightInfo for () { /// Some(196), added: 1681, mode: MaxEncodedLen) /// /// The range of component `p` is `[1, 2]`. - fn submit_parachain_heads_with_n_parachains(p: u32) -> Weight { + fn submit_parachain_heads_with_n_parachains(_p: u32) -> Weight { // Proof Size summary in bytes: - // Measured: `366` - // Estimated: `4648` - // Minimum execution time: 36_701 nanoseconds. - Weight::from_parts(38_597_828, 4648) - // Standard Error: 190_859 - .saturating_add(Weight::from_parts(60_685, 0).saturating_mul(p.into())) + // Measured: `302` + // Estimated: `3038` + // Minimum execution time: 30_211 nanoseconds. + Weight::from_parts(32_633_893, 3038) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -230,10 +226,10 @@ impl WeightInfo for () { /// Some(196), added: 1681, mode: MaxEncodedLen) fn submit_parachain_heads_with_1kb_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `366` - // Estimated: `4648` - // Minimum execution time: 38_189 nanoseconds. - Weight::from_parts(39_252_000, 4648) + // Measured: `302` + // Estimated: `3038` + // Minimum execution time: 30_830 nanoseconds. + Weight::from_parts(31_801_000, 3038) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -263,10 +259,10 @@ impl WeightInfo for () { /// Some(196), added: 1681, mode: MaxEncodedLen) fn submit_parachain_heads_with_16kb_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `366` - // Estimated: `4648` - // Minimum execution time: 62_868 nanoseconds. - Weight::from_parts(63_581_000, 4648) + // Measured: `302` + // Estimated: `3038` + // Minimum execution time: 44_736 nanoseconds. + Weight::from_parts(45_296_000, 3038) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index 08e1438d4f1946fb41f614b0e94c0ce6f1611fd5..27a28546afb482851040cbe16bd40071e86a70cb 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -11,31 +11,31 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } +codec = { workspace = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } # Bridge dependencies -bp-messages = { path = "../../primitives/messages", default-features = false } -bp-relayers = { path = "../../primitives/relayers", default-features = false } -bp-runtime = { path = "../../primitives/runtime", default-features = false } -pallet-bridge-messages = { path = "../messages", default-features = false } +bp-messages = { workspace = true } +bp-relayers = { workspace = true } +bp-runtime = { workspace = true } +pallet-bridge-messages = { workspace = true } # Substrate Dependencies -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -sp-arithmetic = { path = "../../../substrate/primitives/arithmetic", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-arithmetic = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } [dev-dependencies] -bp-runtime = { path = "../../primitives/runtime" } -pallet-balances = { path = "../../../substrate/frame/balances" } -sp-io = { path = "../../../substrate/primitives/io" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } +bp-runtime = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/bridges/modules/relayers/src/payment_adapter.rs b/bridges/modules/relayers/src/payment_adapter.rs index b2d9c676bddc493700a45fc957235dbb9516296b..f75c409aca4f3ef85fab748e4dc41af12b545562 100644 --- a/bridges/modules/relayers/src/payment_adapter.rs +++ b/bridges/modules/relayers/src/payment_adapter.rs @@ -23,6 +23,7 @@ use bp_messages::{ LaneId, MessageNonce, }; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; +use bp_runtime::Chain; use frame_support::{sp_runtime::SaturatedConversion, traits::Get}; use sp_arithmetic::traits::{Saturating, Zero}; use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData, ops::RangeInclusive}; @@ -57,7 +58,7 @@ where relayers_rewards, RewardsAccountParams::new( lane_id, - T::BridgedChainId::get(), + T::BridgedChain::ID, RewardsAccountOwner::BridgedChain, ), DeliveryReward::get(), diff --git a/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/bridges/modules/xcm-bridge-hub-router/Cargo.toml index b80240c974de9f5874e2825f5506885fea11ef3a..ec7c3b5628327f6cbb3d5b3920dba59521c6c209 100644 --- a/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -11,31 +11,31 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } +codec = { workspace = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive", "serde"] } +scale-info = { features = ["bit-vec", "derive", "serde"], workspace = true } # Bridge dependencies -bp-xcm-bridge-hub-router = { path = "../../primitives/xcm-bridge-hub-router", default-features = false } +bp-xcm-bridge-hub-router = { workspace = true } # Substrate Dependencies -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } # Polkadot Dependencies -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false } +xcm = { workspace = true } +xcm-builder = { workspace = true } [dev-dependencies] -sp-io = { path = "../../../substrate/primitives/io" } -sp-std = { path = "../../../substrate/primitives/std" } +sp-io = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index 9b22770061a9a9ffd981f186de9231d7ff41cde9..8fbf61a0a5354e808ad4a5c74094c907eb29470d 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -11,33 +11,35 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } +codec = { workspace = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } # Bridge Dependencies -bp-messages = { path = "../../primitives/messages", default-features = false } -bp-runtime = { path = "../../primitives/runtime", default-features = false } -bp-xcm-bridge-hub = { path = "../../primitives/xcm-bridge-hub", default-features = false } -pallet-bridge-messages = { path = "../messages", default-features = false } -bridge-runtime-common = { path = "../../bin/runtime-common", default-features = false } +bp-messages = { workspace = true } +bp-runtime = { workspace = true } +bp-xcm-bridge-hub = { workspace = true } +pallet-bridge-messages = { workspace = true } +bridge-runtime-common = { workspace = true } # Substrate Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } # Polkadot Dependencies -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor", default-features = false } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } [dev-dependencies] -bp-header-chain = { path = "../../primitives/header-chain" } -pallet-balances = { path = "../../../substrate/frame/balances" } -sp-io = { path = "../../../substrate/primitives/io" } +bp-header-chain = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +bp-runtime = { features = ["test-helpers"], workspace = true } +pallet-xcm-bridge-hub-router = { workspace = true } [features] default = ["std"] @@ -51,6 +53,7 @@ std = [ "frame-system/std", "log/std", "pallet-bridge-messages/std", + "pallet-xcm-bridge-hub-router/std", "scale-info/std", "sp-core/std", "sp-runtime/std", @@ -65,6 +68,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-bridge-messages/runtime-benchmarks", + "pallet-xcm-bridge-hub-router/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", @@ -74,5 +78,6 @@ try-runtime = [ "frame-system/try-runtime", "pallet-balances/try-runtime", "pallet-bridge-messages/try-runtime", + "pallet-xcm-bridge-hub-router/try-runtime", "sp-runtime/try-runtime", ] diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index 94ec8b5f106fdb9ce5e229a41579d26e789b5673..5bca3ad8e2777c2e9243867fa491922592482c9e 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -131,6 +131,7 @@ impl HaulBlob for DummyHaulBlob { mod tests { use super::*; use crate::mock::*; + use bp_runtime::RangeInclusiveExt; use frame_support::assert_ok; use xcm_executor::traits::export_xcm; @@ -138,8 +139,8 @@ mod tests { [GlobalConsensus(RelayNetwork::get()), Parachain(SIBLING_ASSET_HUB_ID)].into() } - fn universal_destination() -> InteriorLocation { - BridgedDestination::get() + fn bridged_relative_destination() -> InteriorLocation { + BridgedRelativeDestination::get() } #[test] @@ -149,7 +150,7 @@ mod tests { BridgedRelayNetwork::get(), 0, universal_source(), - universal_destination(), + bridged_relative_destination(), vec![Instruction::ClearOrigin].into(), )); }) @@ -163,7 +164,7 @@ mod tests { BridgedRelayNetwork::get(), 0, &mut None, - &mut Some(universal_destination()), + &mut Some(bridged_relative_destination()), &mut Some(Vec::new().into()), ), Err(SendError::MissingArgument), @@ -192,7 +193,7 @@ mod tests { BridgedRelayNetwork::get(), 0, &mut Some(universal_source()), - &mut Some(universal_destination()), + &mut Some(bridged_relative_destination()), &mut Some(Vec::new().into()), ) .unwrap() @@ -203,4 +204,37 @@ mod tests { ); }) } + + #[test] + fn exporter_is_compatible_with_pallet_xcm_bridge_hub_router() { + run_test(|| { + // valid routable destination + let dest = Location::new(2, BridgedUniversalDestination::get()); + let expected_lane_id = TEST_LANE_ID; + + // check before - no messages + assert_eq!( + pallet_bridge_messages::Pallet::::outbound_lane_data( + expected_lane_id + ) + .queued_messages() + .saturating_len(), + 0 + ); + + // send `ExportMessage(message)` by `pallet_xcm_bridge_hub_router`. + TestExportXcmWithXcmOverBridge::set_origin_for_execute(SiblingLocation::get()); + assert_ok!(send_xcm::(dest, Xcm::<()>::default())); + + // check after - a message ready to be relayed + assert_eq!( + pallet_bridge_messages::Pallet::::outbound_lane_data( + expected_lane_id + ) + .queued_messages() + .saturating_len(), + 1 + ); + }) + } } diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index 4c09bce56d73eea717ad5149084e2ae337e48e87..0cca32ba9e5f55a80baa4168f483ea33ba69ce58 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -20,25 +20,29 @@ use crate as pallet_xcm_bridge_hub; use bp_messages::{ target_chain::{DispatchMessage, MessageDispatch}, - LaneId, -}; -use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId, UnderlyingChainProvider}; -use bridge_runtime_common::{ - messages::{ - source::TargetHeaderChainAdapter, target::SourceHeaderChainAdapter, - BridgedChainWithMessages, HashOf, MessageBridge, ThisChainWithMessages, - }, - messages_xcm_extension::{SenderAndLane, XcmBlobHauler}, + ChainWithMessages, LaneId, MessageNonce, }; +use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId, HashOf}; +use bridge_runtime_common::messages_xcm_extension::{SenderAndLane, XcmBlobHauler}; use codec::Encode; -use frame_support::{derive_impl, parameter_types, traits::ConstU32, weights::RuntimeDbWeight}; +use frame_support::{ + assert_ok, derive_impl, parameter_types, + traits::{Everything, NeverEnsureOrigin}, + weights::RuntimeDbWeight, +}; use sp_core::H256; use sp_runtime::{ testing::Header as SubstrateHeader, - traits::{BlakeTwo256, IdentityLookup}, - AccountId32, BuildStorage, + traits::{BlakeTwo256, ConstU128, ConstU32, IdentityLookup}, + AccountId32, BuildStorage, StateVersion, }; +use sp_std::cell::RefCell; use xcm::prelude::*; +use xcm_builder::{ + AllowUnpaidExecutionFrom, FixedWeightBounds, InspectMessageQueues, NetworkExportTable, + NetworkExportTableItem, +}; +use xcm_executor::XcmExecutor; pub type AccountId = AccountId32; pub type Balance = u64; @@ -56,6 +60,7 @@ frame_support::construct_runtime! { Balances: pallet_balances::{Pallet, Event}, Messages: pallet_bridge_messages::{Pallet, Call, Event}, XcmOverBridge: pallet_xcm_bridge_hub::{Pallet}, + XcmOverBridgeRouter: pallet_xcm_bridge_hub_router, } } @@ -85,20 +90,17 @@ impl pallet_bridge_messages::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type WeightInfo = TestMessagesWeights; - type BridgedChainId = (); type ActiveOutboundLanes = ActiveOutboundLanes; - type MaxUnrewardedRelayerEntriesAtInboundLane = (); - type MaxUnconfirmedMessagesAtInboundLane = (); - type MaximalOutboundPayloadSize = ConstU32<2048>; type OutboundPayload = Vec; type InboundPayload = Vec; - type InboundRelayer = (); type DeliveryPayments = (); - type TargetHeaderChain = TargetHeaderChainAdapter; type DeliveryConfirmationPayments = (); type OnMessagesDelivered = (); - type SourceHeaderChain = SourceHeaderChainAdapter; type MessageDispatch = TestMessageDispatch; + + type ThisChain = ThisUnderlyingChain; + type BridgedChain = BridgedUnderlyingChain; + type BridgedHeaderChain = BridgedHeaderChain; } pub struct TestMessagesWeights; @@ -107,34 +109,27 @@ impl pallet_bridge_messages::WeightInfo for TestMessagesWeights { fn receive_single_message_proof() -> Weight { Weight::zero() } - fn receive_single_message_proof_with_outbound_lane_state() -> Weight { + fn receive_n_messages_proof(_: u32) -> Weight { Weight::zero() } - fn receive_delivery_proof_for_single_message() -> Weight { + fn receive_single_message_proof_with_outbound_lane_state() -> Weight { Weight::zero() } - fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { + fn receive_single_n_bytes_message_proof(_: u32) -> Weight { Weight::zero() } - fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { + fn receive_delivery_proof_for_single_message() -> Weight { Weight::zero() } - - fn receive_two_messages_proof() -> Weight { + fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { Weight::zero() } - - fn receive_single_message_proof_1_kb() -> Weight { + fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { Weight::zero() } - - fn receive_single_message_proof_16_kb() -> Weight { + fn receive_single_n_bytes_message_proof_with_dispatch(_: u32) -> Weight { Weight::zero() } - - fn receive_single_message_proof_with_dispatch(_: u32) -> Weight { - Weight::from_parts(1, 0) - } } impl pallet_bridge_messages::WeightInfoExt for TestMessagesWeights { @@ -153,15 +148,34 @@ impl pallet_bridge_messages::WeightInfoExt for TestMessagesWeights { parameter_types! { pub const RelayNetwork: NetworkId = NetworkId::Kusama; - pub const BridgedRelayNetwork: NetworkId = NetworkId::Polkadot; - pub BridgedRelayNetworkLocation: Location = (Parent, GlobalConsensus(BridgedRelayNetwork::get())).into(); - pub const NonBridgedRelayNetwork: NetworkId = NetworkId::Rococo; - pub const BridgeReserve: Balance = 100_000; pub UniversalLocation: InteriorLocation = [ GlobalConsensus(RelayNetwork::get()), Parachain(THIS_BRIDGE_HUB_ID), ].into(); + pub SiblingLocation: Location = Location::new(1, [Parachain(SIBLING_ASSET_HUB_ID)]); + + pub const BridgedRelayNetwork: NetworkId = NetworkId::Polkadot; + pub BridgedRelayNetworkLocation: Location = (Parent, GlobalConsensus(BridgedRelayNetwork::get())).into(); + pub BridgedRelativeDestination: InteriorLocation = [Parachain(BRIDGED_ASSET_HUB_ID)].into(); + pub BridgedUniversalDestination: InteriorLocation = [GlobalConsensus(BridgedRelayNetwork::get()), Parachain(BRIDGED_ASSET_HUB_ID)].into(); + pub const NonBridgedRelayNetwork: NetworkId = NetworkId::Rococo; + + pub const BridgeDeposit: Balance = 100_000; pub const Penalty: Balance = 1_000; + + // configuration for pallet_xcm_bridge_hub_router + pub BridgeHubLocation: Location = Here.into(); + pub BridgeFeeAsset: AssetId = Location::here().into(); + pub BridgeTable: Vec + = vec![ + NetworkExportTableItem::new( + BridgedRelayNetwork::get(), + None, + BridgeHubLocation::get(), + None + ) + ]; + pub UnitWeightCost: Weight = Weight::from_parts(10, 10); } impl pallet_xcm_bridge_hub::Config for TestRuntime { @@ -176,16 +190,114 @@ impl pallet_xcm_bridge_hub::Config for TestRuntime { type LanesSupport = TestXcmBlobHauler; } +impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { + type WeightInfo = (); + + type UniversalLocation = UniversalLocation; + type BridgedNetworkId = BridgedRelayNetwork; + type Bridges = NetworkExportTable; + type DestinationVersion = AlwaysLatest; + + type BridgeHubOrigin = NeverEnsureOrigin; + type ToBridgeHubSender = TestExportXcmWithXcmOverBridge; + + type ByteFee = ConstU128<0>; + type FeeAsset = BridgeFeeAsset; + + type WithBridgeHubChannel = (); +} + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = (); + type AssetTransactor = (); + type OriginConverter = (); + type IsReserve = (); + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = AllowUnpaidExecutionFrom; + type Weigher = FixedWeightBounds>; + type Trader = (); + type ResponseHandler = (); + type AssetTrap = (); + type AssetClaims = (); + type SubscriptionService = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = (); + type AssetLocker = (); + type AssetExchanger = (); + type FeeManager = (); + // We just set `MessageExporter` as our `pallet_xcm_bridge_hub` instance. + type MessageExporter = (XcmOverBridge,); + type UniversalAliases = (); + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; + type Aliasers = (); + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); + type XcmRecorder = (); +} + +thread_local! { + pub static EXECUTE_XCM_ORIGIN: RefCell> = RefCell::new(None); +} + +/// The `SendXcm` implementation directly executes XCM using `XcmExecutor`. +/// +/// We ensure that the `ExportMessage` produced by `pallet_xcm_bridge_hub_router` is compatible with +/// the `ExportXcm` implementation of `pallet_xcm_bridge_hub`. +/// +/// Note: The crucial part is that `ExportMessage` is processed by `XcmExecutor`, which calls the +/// `ExportXcm` implementation of `pallet_xcm_bridge_hub` as `MessageExporter`. +pub struct TestExportXcmWithXcmOverBridge; +impl SendXcm for TestExportXcmWithXcmOverBridge { + type Ticket = Xcm<()>; + + fn validate( + _: &mut Option, + message: &mut Option>, + ) -> SendResult { + Ok((message.take().unwrap(), Assets::new())) + } + + fn deliver(ticket: Self::Ticket) -> Result { + let xcm: Xcm = ticket.into(); + + let origin = EXECUTE_XCM_ORIGIN.with(|o| o.borrow().clone().unwrap()); + let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256); + let outcome = XcmExecutor::::prepare_and_execute( + origin, + xcm, + &mut hash, + Weight::MAX, + Weight::zero(), + ); + assert_ok!(outcome.ensure_complete()); + + Ok(hash) + } +} +impl InspectMessageQueues for TestExportXcmWithXcmOverBridge { + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { + todo!() + } +} +impl TestExportXcmWithXcmOverBridge { + pub fn set_origin_for_execute(origin: Location) { + EXECUTE_XCM_ORIGIN.with(|o| *o.borrow_mut() = Some(origin)); + } +} + parameter_types! { pub TestSenderAndLane: SenderAndLane = SenderAndLane { - location: Location::new(1, [Parachain(SIBLING_ASSET_HUB_ID)]), + location: SiblingLocation::get(), lane: TEST_LANE_ID, }; - pub BridgedDestination: InteriorLocation = [ - Parachain(BRIDGED_ASSET_HUB_ID) - ].into(); pub TestLanes: sp_std::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = sp_std::vec![ - (TestSenderAndLane::get(), (BridgedRelayNetwork::get(), BridgedDestination::get())) + (TestSenderAndLane::get(), (BridgedRelayNetwork::get(), BridgedRelativeDestination::get())) ]; } @@ -198,9 +310,9 @@ impl XcmBlobHauler for TestXcmBlobHauler { type UncongestedMessage = (); } -pub struct ThisChain; +pub struct ThisUnderlyingChain; -impl Chain for ThisChain { +impl Chain for ThisUnderlyingChain { const ID: ChainId = *b"tuch"; type BlockNumber = u64; type Hash = H256; @@ -211,6 +323,8 @@ impl Chain for ThisChain { type Nonce = u64; type Signature = sp_runtime::MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { u32::MAX } @@ -220,12 +334,19 @@ impl Chain for ThisChain { } } -pub struct BridgedChain; +impl ChainWithMessages for ThisUnderlyingChain { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = ""; + + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1000; +} + +pub struct BridgedUnderlyingChain; pub type BridgedHeaderHash = H256; pub type BridgedChainHeader = SubstrateHeader; -impl Chain for BridgedChain { - const ID: ChainId = *b"tuch"; +impl Chain for BridgedUnderlyingChain { + const ID: ChainId = *b"bgdc"; type BlockNumber = u64; type Hash = BridgedHeaderHash; type Hasher = BlakeTwo256; @@ -235,6 +356,8 @@ impl Chain for BridgedChain { type Nonce = u64; type Signature = sp_runtime::MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { 4096 } @@ -244,6 +367,12 @@ impl Chain for BridgedChain { } } +impl ChainWithMessages for BridgedUnderlyingChain { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = ""; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1000; +} + /// Test message dispatcher. pub struct TestMessageDispatch; @@ -272,42 +401,15 @@ impl MessageDispatch for TestMessageDispatch { } } -pub struct WrappedThisChain; -impl UnderlyingChainProvider for WrappedThisChain { - type Chain = ThisChain; -} -impl ThisChainWithMessages for WrappedThisChain { - type RuntimeOrigin = RuntimeOrigin; -} - -pub struct WrappedBridgedChain; -impl UnderlyingChainProvider for WrappedBridgedChain { - type Chain = BridgedChain; -} -impl BridgedChainWithMessages for WrappedBridgedChain {} - pub struct BridgedHeaderChain; -impl bp_header_chain::HeaderChain for BridgedHeaderChain { +impl bp_header_chain::HeaderChain for BridgedHeaderChain { fn finalized_header_state_root( - _hash: HashOf, - ) -> Option> { + _hash: HashOf, + ) -> Option> { unreachable!() } } -/// Bridge that is deployed on `ThisChain` and allows sending/receiving messages to/from -/// `BridgedChain`. -#[derive(Debug, PartialEq, Eq)] -pub struct OnThisChainBridge; - -impl MessageBridge for OnThisChainBridge { - const BRIDGED_MESSAGES_PALLET_NAME: &'static str = ""; - - type ThisChain = WrappedThisChain; - type BridgedChain = WrappedBridgedChain; - type BridgedHeaderChain = BridgedHeaderChain; -} - /// Run pallet test. pub fn run_test(test: impl FnOnce() -> T) -> T { sp_io::TestExternalities::new( diff --git a/bridges/primitives/beefy/Cargo.toml b/bridges/primitives/beefy/Cargo.toml index bd68076ca48fc8ccc7bb8f48611083c0930731f7..404acaff30af252f6e5c52d9b28e8ccc72d542ce 100644 --- a/bridges/primitives/beefy/Cargo.toml +++ b/bridges/primitives/beefy/Cargo.toml @@ -12,23 +12,23 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["bit-vec", "derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive"] } -serde = { default-features = false, features = ["alloc", "derive"], workspace = true } +codec = { features = ["bit-vec", "derive"], workspace = true } +scale-info = { features = ["bit-vec", "derive"], workspace = true } +serde = { features = ["alloc", "derive"], workspace = true } # Bridge Dependencies -bp-runtime = { path = "../runtime", default-features = false } +bp-runtime = { workspace = true } # Substrate Dependencies -binary-merkle-tree = { path = "../../../substrate/utils/binary-merkle-tree", default-features = false } -sp-consensus-beefy = { path = "../../../substrate/primitives/consensus/beefy", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -pallet-beefy-mmr = { path = "../../../substrate/frame/beefy-mmr", default-features = false } -pallet-mmr = { path = "../../../substrate/frame/merkle-mountain-range", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +binary-merkle-tree = { workspace = true } +sp-consensus-beefy = { workspace = true } +frame-support = { workspace = true } +pallet-beefy-mmr = { workspace = true } +pallet-mmr = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } [features] default = ["std"] diff --git a/bridges/primitives/header-chain/Cargo.toml b/bridges/primitives/header-chain/Cargo.toml index def1f7ad4dfefb14c3f8459a3d2960c3890ddcf8..081bda479495f5bbd4599b4230d45f5c4e3c5e85 100644 --- a/bridges/primitives/header-chain/Cargo.toml +++ b/bridges/primitives/header-chain/Cargo.toml @@ -11,27 +11,27 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -finality-grandpa = { version = "0.16.2", default-features = false } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { workspace = true } +finality-grandpa = { workspace = true } +scale-info = { features = ["derive"], workspace = true } serde = { features = ["alloc", "derive"], workspace = true } # Bridge dependencies -bp-runtime = { path = "../runtime", default-features = false } +bp-runtime = { workspace = true } # Substrate Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false, features = ["serde"] } -sp-consensus-grandpa = { path = "../../../substrate/primitives/consensus/grandpa", default-features = false, features = ["serde"] } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false, features = ["serde"] } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +sp-core = { features = ["serde"], workspace = true } +sp-consensus-grandpa = { features = ["serde"], workspace = true } +sp-runtime = { features = ["serde"], workspace = true } +sp-std = { workspace = true } [dev-dependencies] -bp-test-utils = { path = "../test-utils" } -hex = "0.4" -hex-literal = "0.4" +bp-test-utils = { workspace = true, default-features = true } +hex = { workspace = true, default-features = true } +hex-literal = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/bridges/primitives/header-chain/src/lib.rs b/bridges/primitives/header-chain/src/lib.rs index af2afb65a26a7f206fdbfcf22e20cb5100a8c95f..26295dee1801a127f455ed3288bd5232cb60bc10 100644 --- a/bridges/primitives/header-chain/src/lib.rs +++ b/bridges/primitives/header-chain/src/lib.rs @@ -46,7 +46,7 @@ pub mod storage_keys; pub enum HeaderChainError { /// Header with given hash is missing from the chain. UnknownHeader, - /// Storage proof related error. + /// Error generated by the `storage_proof` module. StorageProof(StorageProofError), } @@ -78,8 +78,9 @@ impl StoredHeaderDataBuilder for H { pub trait HeaderChain { /// Returns state (storage) root of given finalized header. fn finalized_header_state_root(header_hash: HashOf) -> Option>; + /// Get storage proof checker using finalized header. - fn storage_proof_checker( + fn verify_storage_proof( header_hash: HashOf, storage_proof: RawStorageProof, ) -> Result>, HeaderChainError> { @@ -409,7 +410,9 @@ mod tests { use super::*; use bp_runtime::ChainId; use frame_support::weights::Weight; - use sp_runtime::{testing::H256, traits::BlakeTwo256, DigestItem, MultiSignature}; + use sp_runtime::{ + testing::H256, traits::BlakeTwo256, DigestItem, MultiSignature, StateVersion, + }; struct TestChain; @@ -425,6 +428,8 @@ mod tests { type Nonce = u64; type Signature = MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { 0 } diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml index 20337873c2e6abac5872807adf67557be60a46e8..4a9037342bcea66d813cdb79969c4ff3172f0bab 100644 --- a/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -11,24 +11,24 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["bit-vec", "derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive"] } +codec = { features = ["bit-vec", "derive"], workspace = true } +scale-info = { features = ["bit-vec", "derive"], workspace = true } serde = { features = ["alloc", "derive"], workspace = true } # Bridge dependencies -bp-runtime = { path = "../runtime", default-features = false } -bp-header-chain = { path = "../header-chain", default-features = false } +bp-runtime = { workspace = true } +bp-header-chain = { workspace = true } # Substrate Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +sp-core = { workspace = true } +sp-std = { workspace = true } [dev-dependencies] -hex = "0.4" -hex-literal = "0.4" +hex = { workspace = true, default-features = true } +hex-literal = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs index c3f79b3ee388c4584def56056f6cdf6328032e18..9984f8ac3222780ea2fd6af56dd896beb264b2d5 100644 --- a/bridges/primitives/messages/src/lib.rs +++ b/bridges/primitives/messages/src/lib.rs @@ -38,6 +38,9 @@ pub mod source_chain; pub mod storage_keys; pub mod target_chain; +/// Hard limit on message size that can be sent over the bridge. +pub const HARD_MESSAGE_SIZE_LIMIT: u32 = 64 * 1024; + /// Substrate-based chain with messaging support. pub trait ChainWithMessages: Chain { /// Name of the bridge messages pallet (used in `construct_runtime` macro call) that is @@ -48,11 +51,63 @@ pub trait ChainWithMessages: Chain { const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str; /// Maximal number of unrewarded relayers in a single confirmation transaction at this - /// `ChainWithMessages`. + /// `ChainWithMessages`. Unrewarded means that the relayer has delivered messages, but + /// either confirmations haven't been delivered back to the source chain, or we haven't + /// received reward confirmations yet. + /// + /// This constant limits maximal number of entries in the `InboundLaneData::relayers`. Keep + /// in mind that the same relayer account may take several (non-consecutive) entries in this + /// set. const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce; /// Maximal number of unconfirmed messages in a single confirmation transaction at this - /// `ChainWithMessages`. + /// `ChainWithMessages`. Unconfirmed means that the + /// message has been delivered, but either confirmations haven't been delivered back to the + /// source chain, or we haven't received reward confirmations for these messages yet. + /// + /// This constant limits difference between last message from last entry of the + /// `InboundLaneData::relayers` and first message at the first entry. + /// + /// There is no point of making this parameter lesser than + /// `MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX`, because then maximal number of relayer entries + /// will be limited by maximal number of messages. + /// + /// This value also represents maximal number of messages in single delivery transaction. + /// Transaction that is declaring more messages than this value, will be rejected. Even if + /// these messages are from different lanes. const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce; + + /// Return maximal dispatch weight of the message we're able to receive. + fn maximal_incoming_message_dispatch_weight() -> Weight { + // we leave 1/2 of `max_extrinsic_weight` for the delivery transaction itself + Self::max_extrinsic_weight() / 2 + } + + /// Return maximal size of the message we're able to receive. + fn maximal_incoming_message_size() -> u32 { + maximal_incoming_message_size(Self::max_extrinsic_size()) + } +} + +/// Return maximal size of the message the chain with `max_extrinsic_size` is able to receive. +pub fn maximal_incoming_message_size(max_extrinsic_size: u32) -> u32 { + // The maximal size of extrinsic at Substrate-based chain depends on the + // `frame_system::Config::MaximumBlockLength` and + // `frame_system::Config::AvailableBlockRatio` constants. This check is here to be sure that + // the lane won't stuck because message is too large to fit into delivery transaction. + // + // **IMPORTANT NOTE**: the delivery transaction contains storage proof of the message, not + // the message itself. The proof is always larger than the message. But unless chain state + // is enormously large, it should be several dozens/hundreds of bytes. The delivery + // transaction also contains signatures and signed extensions. Because of this, we reserve + // 1/3 of the the maximal extrinsic size for this data. + // + // **ANOTHER IMPORTANT NOTE**: large message means not only larger proofs and heavier + // proof verification, but also heavier message decoding and dispatch. So we have a hard + // limit of `64Kb`, which in practice limits the message size on all chains. Without this + // limit the **weight** (not the size) of the message will be higher than the + // `Self::maximal_incoming_message_dispatch_weight()`. + + sp_std::cmp::min(max_extrinsic_size / 3 * 2, HARD_MESSAGE_SIZE_LIMIT) } impl ChainWithMessages for T @@ -112,7 +167,19 @@ impl OperatingMode for MessagesOperatingMode { /// Lane id which implements `TypeId`. #[derive( - Clone, Copy, Decode, Default, Encode, Eq, Ord, PartialOrd, PartialEq, TypeInfo, MaxEncodedLen, + Clone, + Copy, + Decode, + Default, + Encode, + Eq, + Ord, + PartialOrd, + PartialEq, + TypeInfo, + MaxEncodedLen, + Serialize, + Deserialize, )] pub struct LaneId(pub [u8; 4]); @@ -435,7 +502,7 @@ where AccountId: sp_std::cmp::Ord, { // remember to reward relayers that have delivered messages - // this loop is bounded by `T::MaxUnrewardedRelayerEntriesAtInboundLane` on the bridged chain + // this loop is bounded by `T::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX` on the bridged chain let mut relayers_rewards = RelayersRewards::new(); for entry in messages_relayers { let nonce_begin = sp_std::cmp::max(entry.messages.begin, *received_range.start()); @@ -486,11 +553,11 @@ pub enum VerificationError { InvalidMessageWeight, /// Declared messages count doesn't match actual value. MessagesCountMismatch, - /// Error returned while reading/decoding message data from the storage proof. + /// Error returned while reading/decoding message data from the `VerifiedStorageProof`. MessageStorage(StorageProofError), /// The message is too large. MessageTooLarge, - /// Error returned while reading/decoding outbound lane data from the storage proof. + /// Error returned while reading/decoding outbound lane data from the `VerifiedStorageProof`. OutboundLaneStorage(StorageProofError), /// Storage proof related error. StorageProof(StorageProofError), diff --git a/bridges/primitives/messages/src/source_chain.rs b/bridges/primitives/messages/src/source_chain.rs index f4aefd9735583e265c3e44713f13f81ae63ba276..64f015bdb822eb25ff42a3fdb52bf6405a5424bf 100644 --- a/bridges/primitives/messages/src/source_chain.rs +++ b/bridges/primitives/messages/src/source_chain.rs @@ -16,11 +16,11 @@ //! Primitives of messages module, that are used on the source chain. -use crate::{InboundLaneData, LaneId, MessageNonce, VerificationError}; +use crate::{LaneId, MessageNonce, UnrewardedRelayer}; -use crate::UnrewardedRelayer; -use bp_runtime::Size; -use frame_support::Parameter; +use bp_runtime::{raw_storage_proof_size, RawStorageProof, Size}; +use codec::{Decode, Encode}; +use scale_info::TypeInfo; use sp_core::RuntimeDebug; use sp_std::{ collections::{btree_map::BTreeMap, vec_deque::VecDeque}, @@ -28,42 +28,36 @@ use sp_std::{ ops::RangeInclusive, }; -/// Number of messages, delivered by relayers. -pub type RelayersRewards = BTreeMap; - -/// Target chain API. Used by source chain to verify target chain proofs. +/// Messages delivery proof from the bridged chain. /// -/// All implementations of this trait should only work with finalized data that -/// can't change. Wrong implementation may lead to invalid lane states (i.e. lane -/// that's stuck) and/or processing messages without paying fees. +/// It contains everything required to prove that our (this chain) messages have been +/// delivered to the bridged (target) chain: /// -/// The `Payload` type here means the payload of the message that is sent from the -/// source chain to the target chain. The `AccountId` type here means the account -/// type used by the source chain. -pub trait TargetHeaderChain { - /// Proof that messages have been received by target chain. - type MessagesDeliveryProof: Parameter + Size; - - /// Verify message payload before we accept it. - /// - /// **CAUTION**: this is very important function. Incorrect implementation may lead - /// to stuck lanes and/or relayers loses. - /// - /// The proper implementation must ensure that the delivery-transaction with this - /// payload would (at least) be accepted into target chain transaction pool AND - /// eventually will be successfully mined. The most obvious incorrect implementation - /// example would be implementation for BTC chain that accepts payloads larger than - /// 1MB. BTC nodes aren't accepting transactions that are larger than 1MB, so relayer - /// will be unable to craft valid transaction => this (and all subsequent) messages will - /// never be delivered. - fn verify_message(payload: &Payload) -> Result<(), VerificationError>; - - /// Verify messages delivery proof and return lane && nonce of the latest received message. - fn verify_messages_delivery_proof( - proof: Self::MessagesDeliveryProof, - ) -> Result<(LaneId, InboundLaneData), VerificationError>; +/// - hash of finalized header; +/// +/// - storage proof of the inbound lane state; +/// +/// - lane id. +#[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +pub struct FromBridgedChainMessagesDeliveryProof { + /// Hash of the bridge header the proof is for. + pub bridged_header_hash: BridgedHeaderHash, + /// Storage trie proof generated for [`Self::bridged_header_hash`]. + pub storage_proof: RawStorageProof, + /// Lane id of which messages were delivered and the proof is for. + pub lane: LaneId, +} + +impl Size for FromBridgedChainMessagesDeliveryProof { + fn size(&self) -> u32 { + use frame_support::sp_runtime::SaturatedConversion; + raw_storage_proof_size(&self.storage_proof).saturated_into() + } } +/// Number of messages, delivered by relayers. +pub type RelayersRewards = BTreeMap; + /// Manages payments that are happening at the source chain during delivery confirmation /// transaction. pub trait DeliveryConfirmationPayments { @@ -143,28 +137,10 @@ pub trait MessagesBridge { fn send_message(message: Self::SendMessageArgs) -> SendMessageArtifacts; } -/// Structure that may be used in place of `TargetHeaderChain` and -/// `MessageDeliveryAndDispatchPayment` on chains, where outbound messages are forbidden. +/// Structure that may be used in place `MessageDeliveryAndDispatchPayment` on chains, +/// where outbound messages are forbidden. pub struct ForbidOutboundMessages; -/// Error message that is used in `ForbidOutboundMessages` implementation. -const ALL_OUTBOUND_MESSAGES_REJECTED: &str = - "This chain is configured to reject all outbound messages"; - -impl TargetHeaderChain for ForbidOutboundMessages { - type MessagesDeliveryProof = (); - - fn verify_message(_payload: &Payload) -> Result<(), VerificationError> { - Err(VerificationError::Other(ALL_OUTBOUND_MESSAGES_REJECTED)) - } - - fn verify_messages_delivery_proof( - _proof: Self::MessagesDeliveryProof, - ) -> Result<(LaneId, InboundLaneData), VerificationError> { - Err(VerificationError::Other(ALL_OUTBOUND_MESSAGES_REJECTED)) - } -} - impl DeliveryConfirmationPayments for ForbidOutboundMessages { type Error = &'static str; diff --git a/bridges/primitives/messages/src/target_chain.rs b/bridges/primitives/messages/src/target_chain.rs index 388ce16ccdc06d3e2c42c3a094aae4d6180a0d09..74fecb9d9f0d89420d2ca54a4356e23c9130e614 100644 --- a/bridges/primitives/messages/src/target_chain.rs +++ b/bridges/primitives/messages/src/target_chain.rs @@ -16,17 +16,48 @@ //! Primitives of messages module, that are used on the target chain. -use crate::{ - LaneId, Message, MessageKey, MessageNonce, MessagePayload, OutboundLaneData, VerificationError, -}; +use crate::{LaneId, Message, MessageKey, MessageNonce, MessagePayload, OutboundLaneData}; -use bp_runtime::{messages::MessageDispatchResult, Size}; +use bp_runtime::{messages::MessageDispatchResult, raw_storage_proof_size, RawStorageProof, Size}; use codec::{Decode, Encode, Error as CodecError}; -use frame_support::{weights::Weight, Parameter}; +use frame_support::weights::Weight; use scale_info::TypeInfo; use sp_core::RuntimeDebug; use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, marker::PhantomData, prelude::*}; +/// Messages proof from bridged chain. +/// +/// It contains everything required to prove that bridged (source) chain has +/// sent us some messages: +/// +/// - hash of finalized header; +/// +/// - storage proof of messages and (optionally) outbound lane state; +/// +/// - lane id; +/// +/// - nonces (inclusive range) of messages which are included in this proof. +#[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +pub struct FromBridgedChainMessagesProof { + /// Hash of the finalized bridged header the proof is for. + pub bridged_header_hash: BridgedHeaderHash, + /// A storage trie proof of messages being delivered. + pub storage_proof: RawStorageProof, + /// Messages in this proof are sent over this lane. + pub lane: LaneId, + /// Nonce of the first message being delivered. + pub nonces_start: MessageNonce, + /// Nonce of the last message being delivered. + pub nonces_end: MessageNonce, +} + +impl Size for FromBridgedChainMessagesProof { + fn size(&self) -> u32 { + use frame_support::sp_runtime::SaturatedConversion; + raw_storage_proof_size(&self.storage_proof).saturated_into() + } +} + /// Proved messages from the source chain. pub type ProvedMessages = BTreeMap>; @@ -55,33 +86,6 @@ pub struct DispatchMessage { pub data: DispatchMessageData, } -/// Source chain API. Used by target chain, to verify source chain proofs. -/// -/// All implementations of this trait should only work with finalized data that -/// can't change. Wrong implementation may lead to invalid lane states (i.e. lane -/// that's stuck) and/or processing messages without paying fees. -pub trait SourceHeaderChain { - /// Proof that messages are sent from source chain. This may also include proof - /// of corresponding outbound lane states. - type MessagesProof: Parameter + Size; - - /// Verify messages proof and return proved messages. - /// - /// Returns error if either proof is incorrect, or the number of messages in the proof - /// is not matching the `messages_count`. - /// - /// Messages vector is required to be sorted by nonce within each lane. Out-of-order - /// messages will be rejected. - /// - /// The `messages_count` argument verification (sane limits) is supposed to be made - /// outside this function. This function only verifies that the proof declares exactly - /// `messages_count` messages. - fn verify_messages_proof( - proof: Self::MessagesProof, - messages_count: u32, - ) -> Result, VerificationError>; -} - /// Called when inbound message is received. pub trait MessageDispatch { /// Decoded message payload type. Valid message may contain invalid payload. In this case @@ -167,32 +171,11 @@ impl DeliveryPayments for () { } } -/// Structure that may be used in place of `SourceHeaderChain` and `MessageDispatch` on chains, +/// Structure that may be used in place of `MessageDispatch` on chains, /// where inbound messages are forbidden. -pub struct ForbidInboundMessages( - PhantomData<(MessagesProof, DispatchPayload)>, -); - -/// Error message that is used in `ForbidInboundMessages` implementation. -const ALL_INBOUND_MESSAGES_REJECTED: &str = - "This chain is configured to reject all inbound messages"; - -impl SourceHeaderChain - for ForbidInboundMessages -{ - type MessagesProof = MessagesProof; - - fn verify_messages_proof( - _proof: Self::MessagesProof, - _messages_count: u32, - ) -> Result, VerificationError> { - Err(VerificationError::Other(ALL_INBOUND_MESSAGES_REJECTED)) - } -} +pub struct ForbidInboundMessages(PhantomData); -impl MessageDispatch - for ForbidInboundMessages -{ +impl MessageDispatch for ForbidInboundMessages { type DispatchPayload = DispatchPayload; type DispatchLevelResult = (); diff --git a/bridges/primitives/parachains/Cargo.toml b/bridges/primitives/parachains/Cargo.toml index a6e71876cefbb3963ef1923469d641281cda00dc..173380c8224d2855e2022cc6b6f9266fc8094ecd 100644 --- a/bridges/primitives/parachains/Cargo.toml +++ b/bridges/primitives/parachains/Cargo.toml @@ -11,22 +11,22 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -impl-trait-for-tuples = "0.2" -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } +impl-trait-for-tuples = { workspace = true } +scale-info = { features = ["derive"], workspace = true } # Bridge dependencies -bp-header-chain = { path = "../header-chain", default-features = false } -bp-polkadot-core = { path = "../polkadot-core", default-features = false } -bp-runtime = { path = "../runtime", default-features = false } +bp-header-chain = { workspace = true } +bp-polkadot-core = { workspace = true } +bp-runtime = { workspace = true } # Substrate dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } [features] default = ["std"] diff --git a/bridges/primitives/polkadot-core/Cargo.toml b/bridges/primitives/polkadot-core/Cargo.toml index d4b2f503e9e2ca92c095649f8aa36741d02c8037..acae2f431bf20aa8babf57e586cd4bb726fe2ec8 100644 --- a/bridges/primitives/polkadot-core/Cargo.toml +++ b/bridges/primitives/polkadot-core/Cargo.toml @@ -11,26 +11,26 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -parity-util-mem = { version = "0.12.0", optional = true } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } +parity-util-mem = { optional = true, workspace = true } +scale-info = { features = ["derive"], workspace = true } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Bridge Dependencies -bp-messages = { path = "../messages", default-features = false } -bp-runtime = { path = "../runtime", default-features = false } +bp-messages = { workspace = true } +bp-runtime = { workspace = true } # Substrate Based Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } [dev-dependencies] -hex = "0.4" +hex = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/bridges/primitives/polkadot-core/src/parachains.rs b/bridges/primitives/polkadot-core/src/parachains.rs index 433cd2845abd9ae95687d6f1d024765ee3bd2ebb..d54ee108386edf50865c500eb1062c24b01c0c3e 100644 --- a/bridges/primitives/polkadot-core/src/parachains.rs +++ b/bridges/primitives/polkadot-core/src/parachains.rs @@ -22,7 +22,7 @@ //! parachains. Having pallets that are referencing polkadot, would mean that there may //! be two versions of polkadot crates included in the runtime. Which is bad. -use bp_runtime::{RawStorageProof, Size}; +use bp_runtime::{raw_storage_proof_size, RawStorageProof, Size}; use codec::{CompactAs, Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_core::Hasher; @@ -96,11 +96,7 @@ pub struct ParaHeadsProof { impl Size for ParaHeadsProof { fn size(&self) -> u32 { - u32::try_from( - self.storage_proof - .iter() - .fold(0usize, |sum, node| sum.saturating_add(node.len())), - ) - .unwrap_or(u32::MAX) + use frame_support::sp_runtime::SaturatedConversion; + raw_storage_proof_size(&self.storage_proof).saturated_into() } } diff --git a/bridges/primitives/relayers/Cargo.toml b/bridges/primitives/relayers/Cargo.toml index 5081dddce1e61eccbae540f665257e122d777dd6..3448e8a4096339966023d0f5ddd0e158380ab12a 100644 --- a/bridges/primitives/relayers/Cargo.toml +++ b/bridges/primitives/relayers/Cargo.toml @@ -11,23 +11,23 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["bit-vec", "derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive"] } +codec = { features = ["bit-vec", "derive"], workspace = true } +scale-info = { features = ["bit-vec", "derive"], workspace = true } # Bridge Dependencies -bp-messages = { path = "../messages", default-features = false } -bp-runtime = { path = "../runtime", default-features = false } +bp-messages = { workspace = true } +bp-runtime = { workspace = true } # Substrate Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } [dev-dependencies] -hex = "0.4" -hex-literal = "0.4" +hex = { workspace = true, default-features = true } +hex-literal = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml index ac65ad538b4988c71e59d081cba46d47ebdc7c39..117409b37b9457f93194585b12aabd0de00d5c7f 100644 --- a/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -11,28 +11,28 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -hash-db = { version = "0.16.0", default-features = false } -impl-trait-for-tuples = "0.2.2" +codec = { workspace = true } +hash-db = { workspace = true } +impl-trait-for-tuples = { workspace = true } log = { workspace = true } -num-traits = { version = "0.2", default-features = false } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +num-traits = { workspace = true } +scale-info = { features = ["derive"], workspace = true } serde = { features = ["alloc", "derive"], workspace = true } # Substrate Dependencies -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false, features = ["serde"] } -sp-state-machine = { path = "../../../substrate/primitives/state-machine", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } -trie-db = { version = "0.29.0", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { features = ["serde"], workspace = true } +sp-state-machine = { workspace = true } +sp-std = { workspace = true } +sp-trie = { workspace = true } +trie-db = { workspace = true } [dev-dependencies] -hex-literal = "0.4" +hex-literal = { workspace = true, default-features = true } [features] default = ["std"] @@ -53,3 +53,4 @@ std = [ "sp-trie/std", "trie-db/std", ] +test-helpers = [] diff --git a/bridges/primitives/runtime/src/chain.rs b/bridges/primitives/runtime/src/chain.rs index 369386e41b0cf9f2d911ca40fc9e6ccfb3de6e52..0db4eac79a7500bf295756efaef514f5a4429e6c 100644 --- a/bridges/primitives/runtime/src/chain.rs +++ b/bridges/primitives/runtime/src/chain.rs @@ -24,7 +24,7 @@ use sp_runtime::{ AtLeast32Bit, AtLeast32BitUnsigned, Hash as HashT, Header as HeaderT, MaybeDisplay, MaybeSerialize, MaybeSerializeDeserialize, Member, SimpleBitOps, Verify, }, - FixedPointOperand, + FixedPointOperand, StateVersion, }; use sp_std::{fmt::Debug, hash::Hash, str::FromStr, vec, vec::Vec}; @@ -196,6 +196,10 @@ pub trait Chain: Send + Sync + 'static { /// Signature type, used on this chain. type Signature: Parameter + Verify; + /// Version of the state implementation used by this chain. This is directly related with the + /// `TrieLayout` configuration used by the storage. + const STATE_VERSION: StateVersion; + /// Get the maximum size (in bytes) of a Normal extrinsic at this chain. fn max_extrinsic_size() -> u32; /// Get the maximum weight (compute time) that a Normal extrinsic at this chain can use. @@ -223,6 +227,8 @@ where type Nonce = ::Nonce; type Signature = ::Signature; + const STATE_VERSION: StateVersion = ::STATE_VERSION; + fn max_extrinsic_size() -> u32 { ::max_extrinsic_size() } diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index d13c9b40efa0b4ddf1433fdc87ce59eb13c7d9a3..8f5040ad9a1bee5efad995b4e62d5e883dfb0c9f 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -40,15 +40,18 @@ pub use chain::{ }; pub use frame_support::storage::storage_prefix as storage_value_final_key; use num_traits::{CheckedAdd, CheckedSub, One, SaturatingAdd, Zero}; +#[cfg(feature = "std")] +pub use storage_proof::craft_valid_storage_proof; +#[cfg(feature = "test-helpers")] pub use storage_proof::{ - record_all_keys as record_all_trie_keys, Error as StorageProofError, - ProofSize as StorageProofSize, RawStorageProof, StorageProofChecker, + grow_storage_proof, grow_storage_value, record_all_keys as record_all_trie_keys, + UnverifiedStorageProofParams, +}; +pub use storage_proof::{ + raw_storage_proof_size, RawStorageProof, StorageProofChecker, StorageProofError, }; pub use storage_types::BoundedStorageValue; -#[cfg(feature = "std")] -pub use storage_proof::craft_valid_storage_proof; - pub mod extensions; pub mod messages; @@ -461,38 +464,6 @@ macro_rules! generate_static_str_provider { }; } -/// Error message that is only displayable in `std` environment. -#[derive(Encode, Decode, Clone, Eq, PartialEq, PalletError, TypeInfo)] -#[scale_info(skip_type_params(T))] -pub struct StrippableError { - _phantom_data: sp_std::marker::PhantomData, - #[codec(skip)] - #[cfg(feature = "std")] - message: String, -} - -impl From for StrippableError { - fn from(_err: T) -> Self { - Self { - _phantom_data: Default::default(), - #[cfg(feature = "std")] - message: format!("{:?}", _err), - } - } -} - -impl Debug for StrippableError { - #[cfg(feature = "std")] - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - f.write_str(&self.message) - } - - #[cfg(not(feature = "std"))] - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - f.write_str("Stripped error") - } -} - /// A trait defining helper methods for `RangeInclusive` (start..=end) pub trait RangeInclusiveExt { /// Computes the length of the `RangeInclusive`, checking for underflow and overflow. diff --git a/bridges/primitives/runtime/src/storage_proof.rs b/bridges/primitives/runtime/src/storage_proof.rs index 1b706aa66c16fc73a21ce83f550bea8a8fe128e5..7bfa0d6fde01186f1fe09e66dd3ba1accf286ce5 100644 --- a/bridges/primitives/runtime/src/storage_proof.rs +++ b/bridges/primitives/runtime/src/storage_proof.rs @@ -14,33 +14,91 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -//! Logic for checking Substrate storage proofs. +//! Logic for working with storage proofs. -use crate::StrippableError; -use codec::{Decode, Encode}; use frame_support::PalletError; -use hash_db::{HashDB, Hasher, EMPTY_PREFIX}; -use scale_info::TypeInfo; -use sp_std::{boxed::Box, collections::btree_set::BTreeSet, vec::Vec}; +use sp_core::RuntimeDebug; +use sp_std::{default::Default, vec::Vec}; use sp_trie::{ - read_trie_value, LayoutV1, MemoryDB, Recorder, StorageProof, Trie, TrieConfiguration, - TrieDBBuilder, TrieError, TrieHash, + accessed_nodes_tracker::AccessedNodesTracker, read_trie_value, LayoutV1, MemoryDB, StorageProof, }; +use codec::{Decode, Encode}; +use hash_db::{HashDB, Hasher, EMPTY_PREFIX}; +use scale_info::TypeInfo; +#[cfg(feature = "test-helpers")] +use sp_trie::{recorder_ext::RecorderExt, Recorder, TrieDBBuilder, TrieError, TrieHash}; +#[cfg(feature = "test-helpers")] +use trie_db::{Trie, TrieConfiguration, TrieDBMut}; + +/// Errors that can occur when interacting with `UnverifiedStorageProof` and `VerifiedStorageProof`. +#[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq, PalletError, TypeInfo)] +pub enum StorageProofError { + /// Call to `generate_trie_proof()` failed. + UnableToGenerateTrieProof, + /// Call to `verify_trie_proof()` failed. + InvalidProof, + /// The `Vec` entries weren't sorted as expected. + UnsortedEntries, + /// The provided key wasn't found. + UnavailableKey, + /// The value associated to the provided key is `None`. + EmptyVal, + /// Error decoding value associated to a provided key. + DecodeError, + /// At least one key or node wasn't read. + UnusedKey, + + /// Expected storage root is missing from the proof. (for non-compact proofs) + StorageRootMismatch, + /// Unable to reach expected storage value using provided trie nodes. (for non-compact proofs) + StorageValueUnavailable, + /// The proof contains duplicate nodes. (for non-compact proofs) + DuplicateNodes, +} + +impl From for StorageProofError { + fn from(e: sp_trie::StorageProofError) -> Self { + match e { + sp_trie::StorageProofError::DuplicateNodes => StorageProofError::DuplicateNodes, + } + } +} + +impl From for StorageProofError { + fn from(e: sp_trie::accessed_nodes_tracker::Error) -> Self { + match e { + sp_trie::accessed_nodes_tracker::Error::UnusedNodes => StorageProofError::UnusedKey, + } + } +} + /// Raw storage proof type (just raw trie nodes). -pub type RawStorageProof = Vec>; +pub type RawStorageProof = sp_trie::RawStorageProof; + +/// Calculates size for `RawStorageProof`. +pub fn raw_storage_proof_size(raw_storage_proof: &RawStorageProof) -> usize { + raw_storage_proof + .iter() + .fold(0usize, |sum, node| sum.saturating_add(node.len())) +} -/// Storage proof size requirements. +/// Storage values size requirements. /// /// This is currently used by benchmarks when generating storage proofs. -#[derive(Clone, Copy, Debug)] -pub enum ProofSize { - /// The proof is expected to be minimal. If value size may be changed, then it is expected to - /// have given size. - Minimal(u32), - /// The proof is expected to have at least given size and grow by increasing value that is - /// stored in the trie. - HasLargeLeaf(u32), +#[cfg(feature = "test-helpers")] +#[derive(Clone, Copy, Debug, Default)] +pub struct UnverifiedStorageProofParams { + /// Expected storage proof size in bytes. + pub db_size: Option, +} + +#[cfg(feature = "test-helpers")] +impl UnverifiedStorageProofParams { + /// Make storage proof parameters that require proof of at least `db_size` bytes. + pub fn from_db_size(db_size: u32) -> Self { + Self { db_size: Some(db_size) } + } } /// This struct is used to read storage values from a subset of a Merklized database. The "proof" @@ -51,10 +109,9 @@ pub struct StorageProofChecker where H: Hasher, { - proof_nodes_count: usize, root: H::Out, db: MemoryDB, - recorder: Recorder>, + accessed_nodes_tracker: AccessedNodesTracker, } impl StorageProofChecker @@ -64,99 +121,161 @@ where /// Constructs a new storage proof checker. /// /// This returns an error if the given proof is invalid with respect to the given root. - pub fn new(root: H::Out, proof: RawStorageProof) -> Result { - // 1. we don't want extra items in the storage proof - // 2. `StorageProof` is storing all trie nodes in the `BTreeSet` - // - // => someone could simply add duplicate items to the proof and we won't be - // able to detect that by just using `StorageProof` - // - // => let's check it when we are converting our "raw proof" into `StorageProof` - let proof_nodes_count = proof.len(); - let proof = StorageProof::new(proof); - if proof_nodes_count != proof.iter_nodes().count() { - return Err(Error::DuplicateNodesInProof) - } + pub fn new(root: H::Out, proof: RawStorageProof) -> Result { + let proof = StorageProof::new_with_duplicate_nodes_check(proof)?; + + let recorder = AccessedNodesTracker::new(proof.len()); let db = proof.into_memory_db(); if !db.contains(&root, EMPTY_PREFIX) { - return Err(Error::StorageRootMismatch) + return Err(StorageProofError::StorageRootMismatch) } - let recorder = Recorder::default(); - let checker = StorageProofChecker { proof_nodes_count, root, db, recorder }; - Ok(checker) + Ok(StorageProofChecker { root, db, accessed_nodes_tracker: recorder }) } /// Returns error if the proof has some nodes that are left intact by previous `read_value` /// calls. - pub fn ensure_no_unused_nodes(mut self) -> Result<(), Error> { - let visited_nodes = self - .recorder - .drain() - .into_iter() - .map(|record| record.data) - .collect::>(); - let visited_nodes_count = visited_nodes.len(); - if self.proof_nodes_count == visited_nodes_count { - Ok(()) - } else { - Err(Error::UnusedNodesInTheProof) - } + pub fn ensure_no_unused_nodes(self) -> Result<(), StorageProofError> { + self.accessed_nodes_tracker.ensure_no_unused_nodes().map_err(Into::into) } /// Reads a value from the available subset of storage. If the value cannot be read due to an /// incomplete or otherwise invalid proof, this function returns an error. - pub fn read_value(&mut self, key: &[u8]) -> Result>, Error> { + pub fn read_value(&mut self, key: &[u8]) -> Result>, StorageProofError> { // LayoutV1 or LayoutV0 is identical for proof that only read values. - read_trie_value::, _>(&self.db, &self.root, key, Some(&mut self.recorder), None) - .map_err(|_| Error::StorageValueUnavailable) + read_trie_value::, _>( + &self.db, + &self.root, + key, + Some(&mut self.accessed_nodes_tracker), + None, + ) + .map_err(|_| StorageProofError::StorageValueUnavailable) } /// Reads and decodes a value from the available subset of storage. If the value cannot be read /// due to an incomplete or otherwise invalid proof, this function returns an error. If value is /// read, but decoding fails, this function returns an error. - pub fn read_and_decode_value(&mut self, key: &[u8]) -> Result, Error> { + pub fn read_and_decode_value( + &mut self, + key: &[u8], + ) -> Result, StorageProofError> { self.read_value(key).and_then(|v| { - v.map(|v| T::decode(&mut &v[..]).map_err(|e| Error::StorageValueDecodeFailed(e.into()))) - .transpose() + v.map(|v| { + T::decode(&mut &v[..]).map_err(|e| { + log::warn!(target: "bridge-storage-proofs", "read_and_decode_value error: {e:?}"); + StorageProofError::DecodeError + }) + }) + .transpose() }) } /// Reads and decodes a value from the available subset of storage. If the value cannot be read /// due to an incomplete or otherwise invalid proof, or if the value is `None`, this function /// returns an error. If value is read, but decoding fails, this function returns an error. - pub fn read_and_decode_mandatory_value(&mut self, key: &[u8]) -> Result { - self.read_and_decode_value(key)?.ok_or(Error::StorageValueEmpty) + pub fn read_and_decode_mandatory_value( + &mut self, + key: &[u8], + ) -> Result { + self.read_and_decode_value(key)?.ok_or(StorageProofError::EmptyVal) } /// Reads and decodes a value from the available subset of storage. If the value cannot be read /// due to an incomplete or otherwise invalid proof, this function returns `Ok(None)`. /// If value is read, but decoding fails, this function returns an error. - pub fn read_and_decode_opt_value(&mut self, key: &[u8]) -> Result, Error> { + pub fn read_and_decode_opt_value( + &mut self, + key: &[u8], + ) -> Result, StorageProofError> { match self.read_and_decode_value(key) { Ok(outbound_lane_data) => Ok(outbound_lane_data), - Err(Error::StorageValueUnavailable) => Ok(None), + Err(StorageProofError::StorageValueUnavailable) => Ok(None), Err(e) => Err(e), } } } -/// Storage proof related errors. -#[derive(Encode, Decode, Clone, Eq, PartialEq, PalletError, Debug, TypeInfo)] -pub enum Error { - /// Duplicate trie nodes are found in the proof. - DuplicateNodesInProof, - /// Unused trie nodes are found in the proof. - UnusedNodesInTheProof, - /// Expected storage root is missing from the proof. - StorageRootMismatch, - /// Unable to reach expected storage value using provided trie nodes. - StorageValueUnavailable, - /// The storage value is `None`. - StorageValueEmpty, - /// Failed to decode storage value. - StorageValueDecodeFailed(StrippableError), +/// Add extra data to the storage value so that it'll be of given size. +#[cfg(feature = "test-helpers")] +pub fn grow_storage_value(mut value: Vec, params: &UnverifiedStorageProofParams) -> Vec { + if let Some(db_size) = params.db_size { + if db_size as usize > value.len() { + value.extend(sp_std::iter::repeat(42u8).take(db_size as usize - value.len())); + } + } + value +} + +/// Insert values in the provided trie at common-prefix keys in order to inflate the resulting +/// storage proof. +/// +/// This function can add at most 15 common-prefix keys per prefix nibble (4 bits). +/// Each such key adds about 33 bytes (a node) to the proof. +#[cfg(feature = "test-helpers")] +pub fn grow_storage_proof( + trie: &mut TrieDBMut, + prefix: Vec, + num_extra_nodes: usize, +) { + use sp_trie::TrieMut; + + let mut added_nodes = 0; + for i in 0..prefix.len() { + let mut prefix = prefix[0..=i].to_vec(); + // 1 byte has 2 nibbles (4 bits each) + let first_nibble = (prefix[i] & 0xf0) >> 4; + let second_nibble = prefix[i] & 0x0f; + + // create branches at the 1st nibble + for branch in 1..=15 { + if added_nodes >= num_extra_nodes { + return + } + + // create branches at the 1st nibble + prefix[i] = (first_nibble.wrapping_add(branch) % 16) << 4; + trie.insert(&prefix, &[0; 32]) + .map_err(|_| "TrieMut::insert has failed") + .expect("TrieMut::insert should not fail in benchmarks"); + added_nodes += 1; + } + + // create branches at the 2nd nibble + for branch in 1..=15 { + if added_nodes >= num_extra_nodes { + return + } + + prefix[i] = (first_nibble << 4) | (second_nibble.wrapping_add(branch) % 16); + trie.insert(&prefix, &[0; 32]) + .map_err(|_| "TrieMut::insert has failed") + .expect("TrieMut::insert should not fail in benchmarks"); + added_nodes += 1; + } + } + + assert_eq!(added_nodes, num_extra_nodes) +} + +/// Record all keys for a given root. +#[cfg(feature = "test-helpers")] +pub fn record_all_keys( + db: &DB, + root: &TrieHash, +) -> Result>> +where + DB: hash_db::HashDBRef, +{ + let mut recorder = Recorder::::new(); + let trie = TrieDBBuilder::::new(db, root).with_recorder(&mut recorder).build(); + for x in trie.iter()? { + let (key, _) = x?; + trie.get(&key)?; + } + + Ok(recorder.into_raw_storage_proof()) } /// Return valid storage proof and state root. @@ -170,7 +289,7 @@ pub fn craft_valid_storage_proof() -> (sp_core::H256, RawStorageProof) { // construct storage proof let backend = >::from(( - vec![ + sp_std::vec![ (None, vec![(b"key1".to_vec(), Some(b"value1".to_vec()))]), (None, vec![(b"key2".to_vec(), Some(b"value2".to_vec()))]), (None, vec![(b"key3".to_vec(), Some(b"value3".to_vec()))]), @@ -180,41 +299,15 @@ pub fn craft_valid_storage_proof() -> (sp_core::H256, RawStorageProof) { ], state_version, )); - let root = backend.storage_root(std::iter::empty(), state_version).0; + let root = backend.storage_root(sp_std::iter::empty(), state_version).0; let proof = prove_read(backend, &[&b"key1"[..], &b"key2"[..], &b"key4"[..], &b"key22"[..]]).unwrap(); (root, proof.into_nodes().into_iter().collect()) } -/// Record all keys for a given root. -pub fn record_all_keys( - db: &DB, - root: &TrieHash, -) -> Result>> -where - DB: hash_db::HashDBRef, -{ - let mut recorder = Recorder::::new(); - let trie = TrieDBBuilder::::new(db, root).with_recorder(&mut recorder).build(); - for x in trie.iter()? { - let (key, _) = x?; - trie.get(&key)?; - } - - // recorder may record the same trie node multiple times and we don't want duplicate nodes - // in our proofs => let's deduplicate it by collecting to the BTreeSet first - Ok(recorder - .drain() - .into_iter() - .map(|n| n.data.to_vec()) - .collect::>() - .into_iter() - .collect()) -} - #[cfg(test)] -pub mod tests { +pub mod tests_for_storage_proof_checker { use super::*; use codec::Encode; @@ -228,29 +321,21 @@ pub mod tests { assert_eq!(checker.read_value(b"key1"), Ok(Some(b"value1".to_vec()))); assert_eq!(checker.read_value(b"key2"), Ok(Some(b"value2".to_vec()))); assert_eq!(checker.read_value(b"key4"), Ok(Some((42u64, 42u32, 42u16, 42u8).encode()))); - assert_eq!(checker.read_value(b"key11111"), Err(Error::StorageValueUnavailable)); + assert_eq!( + checker.read_value(b"key11111"), + Err(StorageProofError::StorageValueUnavailable) + ); assert_eq!(checker.read_value(b"key22"), Ok(None)); assert_eq!(checker.read_and_decode_value(b"key4"), Ok(Some((42u64, 42u32, 42u16, 42u8))),); assert!(matches!( checker.read_and_decode_value::<[u8; 64]>(b"key4"), - Err(Error::StorageValueDecodeFailed(_)), + Err(StorageProofError::DecodeError), )); // checking proof against invalid commitment fails assert_eq!( >::new(sp_core::H256::random(), proof).err(), - Some(Error::StorageRootMismatch) - ); - } - - #[test] - fn proof_with_duplicate_items_is_rejected() { - let (root, mut proof) = craft_valid_storage_proof(); - proof.push(proof.first().unwrap().clone()); - - assert_eq!( - StorageProofChecker::::new(root, proof).map(drop), - Err(Error::DuplicateNodesInProof), + Some(StorageProofError::StorageRootMismatch) ); } @@ -260,13 +345,13 @@ pub mod tests { let mut checker = StorageProofChecker::::new(root, proof.clone()).unwrap(); - checker.read_value(b"key1").unwrap(); + checker.read_value(b"key1").unwrap().unwrap(); checker.read_value(b"key2").unwrap(); checker.read_value(b"key4").unwrap(); checker.read_value(b"key22").unwrap(); assert_eq!(checker.ensure_no_unused_nodes(), Ok(())); let checker = StorageProofChecker::::new(root, proof).unwrap(); - assert_eq!(checker.ensure_no_unused_nodes(), Err(Error::UnusedNodesInTheProof)); + assert_eq!(checker.ensure_no_unused_nodes(), Err(StorageProofError::UnusedKey)); } } diff --git a/bridges/primitives/test-utils/Cargo.toml b/bridges/primitives/test-utils/Cargo.toml index 99f5ee0d1aee4528f64028bbb4ce089cfb6f4c44..5e6e3893393534aa828f323d8a28748742a7b5bb 100644 --- a/bridges/primitives/test-utils/Cargo.toml +++ b/bridges/primitives/test-utils/Cargo.toml @@ -11,19 +11,19 @@ repository.workspace = true workspace = true [dependencies] -bp-header-chain = { path = "../header-chain", default-features = false } -bp-parachains = { path = "../parachains", default-features = false } -bp-polkadot-core = { path = "../polkadot-core", default-features = false } -bp-runtime = { path = "../runtime", default-features = false } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -ed25519-dalek = { version = "2.1", default-features = false } -finality-grandpa = { version = "0.16.2", default-features = false } -sp-application-crypto = { path = "../../../substrate/primitives/application-crypto", default-features = false } -sp-consensus-grandpa = { path = "../../../substrate/primitives/consensus/grandpa", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } +bp-header-chain = { workspace = true } +bp-parachains = { workspace = true } +bp-polkadot-core = { workspace = true } +bp-runtime = { features = ["test-helpers"], workspace = true } +codec = { workspace = true } +ed25519-dalek = { workspace = true } +finality-grandpa = { workspace = true } +sp-application-crypto = { workspace = true } +sp-consensus-grandpa = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } +sp-trie = { workspace = true } [features] default = ["std"] diff --git a/bridges/primitives/test-utils/src/lib.rs b/bridges/primitives/test-utils/src/lib.rs index f4fe4a242e79c0e1c8a499c4dd18ed4a2164c656..9855c32a468954dd0f3011c029c793e5cd2cbc35 100644 --- a/bridges/primitives/test-utils/src/lib.rs +++ b/bridges/primitives/test-utils/src/lib.rs @@ -177,6 +177,7 @@ pub fn prepare_parachain_heads_proof( let mut parachains = Vec::with_capacity(heads.len()); let mut root = Default::default(); let mut mdb = MemoryDB::default(); + let mut storage_keys = vec![]; { let mut trie = TrieDBMutBuilderV1::::new(&mut mdb, &mut root).build(); for (parachain, head) in heads { @@ -185,11 +186,12 @@ pub fn prepare_parachain_heads_proof( trie.insert(&storage_key.0, &head.encode()) .map_err(|_| "TrieMut::insert has failed") .expect("TrieMut::insert should not fail in tests"); + storage_keys.push(storage_key.0); parachains.push((ParaId(parachain), head.hash())); } } - // generate storage proof to be delivered to This chain + // generate storage proof to be delivered to this chain let storage_proof = record_all_trie_keys::, _>(&mdb, &root) .map_err(|_| "record_all_trie_keys has failed") .expect("record_all_trie_keys should not fail in benchmarks"); diff --git a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml index b94e722024562e526c33d2bf1efe9b89f1a035aa..c3cf3356184be676ffae0c212fc20455395d6d09 100644 --- a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml @@ -11,12 +11,12 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["bit-vec", "derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive"] } +codec = { features = ["bit-vec", "derive"], workspace = true } +scale-info = { features = ["bit-vec", "derive"], workspace = true } # Substrate Dependencies -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } +sp-runtime = { workspace = true } +sp-core = { workspace = true } [features] default = ["std"] diff --git a/bridges/primitives/xcm-bridge-hub/Cargo.toml b/bridges/primitives/xcm-bridge-hub/Cargo.toml index 27881bc99d1f838bb5a72c02fe565ef5dc0307fd..932e9ade019741dbc6a99fcea317aaee539ed9c9 100644 --- a/bridges/primitives/xcm-bridge-hub/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] # Substrate Dependencies -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +sp-std = { workspace = true } [features] default = ["std"] diff --git a/bridges/relays/client-substrate/Cargo.toml b/bridges/relays/client-substrate/Cargo.toml index ea267ea5e302a6aaaf5c8a3b825d3f17412b22ff..969cd73d6194fcf42e03f54ae14029cfdf73d877 100644 --- a/bridges/relays/client-substrate/Cargo.toml +++ b/bridges/relays/client-substrate/Cargo.toml @@ -11,51 +11,49 @@ publish = false workspace = true [dependencies] -async-std = { version = "1.9.0", features = ["attributes"] } -async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.12" } -futures = "0.3.30" -jsonrpsee = { version = "0.22", features = ["macros", "ws-client"] } +async-std = { features = ["attributes"], workspace = true } +async-trait = { workspace = true } +codec = { workspace = true, default-features = true } +futures = { workspace = true } +jsonrpsee = { features = ["macros", "ws-client"], workspace = true } log = { workspace = true } -num-traits = "0.2" -rand = "0.8.5" -scale-info = { version = "2.11.1", features = ["derive"] } -tokio = { version = "1.37", features = ["rt-multi-thread"] } +num-traits = { workspace = true, default-features = true } +rand = { workspace = true, default-features = true } +serde_json = { workspace = true } +scale-info = { features = ["derive"], workspace = true, default-features = true } +tokio = { features = ["rt-multi-thread"], workspace = true, default-features = true } thiserror = { workspace = true } -quick_cache = "0.3" +quick_cache = { workspace = true } # Bridge dependencies -bp-header-chain = { path = "../../primitives/header-chain" } -bp-messages = { path = "../../primitives/messages" } -bp-polkadot-core = { path = "../../primitives/polkadot-core" } -bp-runtime = { path = "../../primitives/runtime" } -pallet-bridge-messages = { path = "../../modules/messages" } -finality-relay = { path = "../finality" } -relay-utils = { path = "../utils" } +bp-header-chain = { workspace = true, default-features = true } +bp-messages = { workspace = true, default-features = true } +bp-polkadot-core = { workspace = true, default-features = true } +bp-runtime = { workspace = true, default-features = true } +finality-relay = { workspace = true } +relay-utils = { workspace = true } # Substrate Dependencies -frame-support = { path = "../../../substrate/frame/support" } -frame-system = { path = "../../../substrate/frame/system" } -pallet-balances = { path = "../../../substrate/frame/balances" } -pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment" } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../substrate/frame/transaction-payment/rpc/runtime-api" } -pallet-utility = { path = "../../../substrate/frame/utility" } -sc-chain-spec = { path = "../../../substrate/client/chain-spec" } -sc-rpc-api = { path = "../../../substrate/client/rpc-api" } -sc-transaction-pool-api = { path = "../../../substrate/client/transaction-pool/api" } -sp-consensus-grandpa = { path = "../../../substrate/primitives/consensus/grandpa" } -sp-core = { path = "../../../substrate/primitives/core" } -sp-rpc = { path = "../../../substrate/primitives/rpc" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } -sp-std = { path = "../../../substrate/primitives/std" } -sp-trie = { path = "../../../substrate/primitives/trie" } -sp-version = { path = "../../../substrate/primitives/version" } +frame-support = { workspace = true, default-features = true } +pallet-transaction-payment = { workspace = true, default-features = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true, default-features = true } +pallet-utility = { workspace = true, default-features = true } +sc-chain-spec = { workspace = true, default-features = true } +sc-rpc-api = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } +sp-consensus-grandpa = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-rpc = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } +sp-trie = { workspace = true, default-features = true } +sp-version = { workspace = true, default-features = true } # Polkadot Dependencies -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm" } +xcm = { workspace = true, default-features = true } [features] default = [] diff --git a/bridges/relays/client-substrate/src/client/caching.rs b/bridges/relays/client-substrate/src/client/caching.rs index cb898cf517267a173b0ef4daf374c5b16b0757ba..a574e5985bc8280e030cfad08308a2c9bebe33a4 100644 --- a/bridges/relays/client-substrate/src/client/caching.rs +++ b/bridges/relays/client-substrate/src/client/caching.rs @@ -462,7 +462,11 @@ impl> Client for CachingClient { .await } - async fn prove_storage(&self, at: HashOf, keys: Vec) -> Result { + async fn prove_storage( + &self, + at: HashOf, + keys: Vec, + ) -> Result<(StorageProof, HashOf)> { self.backend.prove_storage(at, keys).await } } diff --git a/bridges/relays/client-substrate/src/client/rpc.rs b/bridges/relays/client-substrate/src/client/rpc.rs index bf7442a95141ff168229bffbc149f686d6b2771a..9c7f769462e5693bc944ed6a6525439f00311ee7 100644 --- a/bridges/relays/client-substrate/src/client/rpc.rs +++ b/bridges/relays/client-substrate/src/client/rpc.rs @@ -52,7 +52,10 @@ use sp_core::{ storage::{StorageData, StorageKey}, Bytes, Hasher, Pair, }; -use sp_runtime::transaction_validity::{TransactionSource, TransactionValidity}; +use sp_runtime::{ + traits::Header, + transaction_validity::{TransactionSource, TransactionValidity}, +}; use sp_trie::StorageProof; use sp_version::RuntimeVersion; use std::{cmp::Ordering, future::Future, marker::PhantomData}; @@ -635,16 +638,25 @@ impl Client for RpcClient { .map_err(|e| Error::failed_state_call::(at, method_clone, arguments_clone, e)) } - async fn prove_storage(&self, at: HashOf, keys: Vec) -> Result { + async fn prove_storage( + &self, + at: HashOf, + keys: Vec, + ) -> Result<(StorageProof, HashOf)> { + let state_root = *self.header_by_hash(at).await?.state_root(); + let keys_clone = keys.clone(); - self.jsonrpsee_execute(move |client| async move { - SubstrateStateClient::::prove_storage(&*client, keys, Some(at)) - .await - .map(|proof| StorageProof::new(proof.proof.into_iter().map(|b| b.0))) - .map_err(Into::into) - }) - .await - .map_err(|e| Error::failed_to_prove_storage::(at, keys_clone, e)) + let read_proof = self + .jsonrpsee_execute(move |client| async move { + SubstrateStateClient::::prove_storage(&*client, keys_clone, Some(at)) + .await + .map(|proof| StorageProof::new(proof.proof.into_iter().map(|b| b.0))) + .map_err(Into::into) + }) + .await + .map_err(|e| Error::failed_to_prove_storage::(at, keys.clone(), e))?; + + Ok((read_proof, state_root)) } } diff --git a/bridges/relays/client-substrate/src/client/subscription.rs b/bridges/relays/client-substrate/src/client/subscription.rs index 43a46573f987b9d58f7b98050359614767bcee3e..9f08097cb583a57a28885a7aa59a1731e997d023 100644 --- a/bridges/relays/client-substrate/src/client/subscription.rs +++ b/bridges/relays/client-substrate/src/client/subscription.rs @@ -21,7 +21,6 @@ use async_std::{ stream::StreamExt, }; use futures::{FutureExt, Stream}; -use jsonrpsee::core::ClientError; use sp_runtime::DeserializeOwned; use std::{ fmt::Debug, @@ -143,7 +142,7 @@ impl Subscription { /// Create new forwarded subscription. pub fn new_forwarded( desc: StreamDescription, - subscription: impl Stream> + Unpin + Send + 'static, + subscription: impl Stream> + Unpin + Send + 'static, ) -> Self { Self { desc: desc.clone(), diff --git a/bridges/relays/client-substrate/src/client/traits.rs b/bridges/relays/client-substrate/src/client/traits.rs index 49f5c001c3f7d80fd51892c8de73f41960557cba..6f4ef5aa951062ddd6586e0dadeb4ce7425eca5e 100644 --- a/bridges/relays/client-substrate/src/client/traits.rs +++ b/bridges/relays/client-substrate/src/client/traits.rs @@ -225,6 +225,10 @@ pub trait Client: 'static + Send + Sync + Clone + Debug { }) } - /// Returns storage proof of given storage keys. - async fn prove_storage(&self, at: HashOf, keys: Vec) -> Result; + /// Returns storage proof of given storage keys and state root. + async fn prove_storage( + &self, + at: HashOf, + keys: Vec, + ) -> Result<(StorageProof, HashOf)>; } diff --git a/bridges/relays/client-substrate/src/error.rs b/bridges/relays/client-substrate/src/error.rs index b09e2c7abdc666735d7481d3f39c9492d851f76a..ee3c73f806e65362a10185d5dd9090f5bbc4c300 100644 --- a/bridges/relays/client-substrate/src/error.rs +++ b/bridges/relays/client-substrate/src/error.rs @@ -213,9 +213,6 @@ pub enum Error { /// The bridge pallet is not yet initialized and all transactions will be rejected. #[error("Bridge pallet is not initialized.")] BridgePalletIsNotInitialized, - /// An error has happened when we have tried to parse storage proof. - #[error("Error when parsing storage proof: {0:?}.")] - StorageProofError(bp_runtime::StorageProofError), /// The Substrate transaction is invalid. #[error("Substrate transaction is invalid: {0:?}")] TransactionInvalid(#[from] TransactionValidityError), diff --git a/bridges/relays/client-substrate/src/test_chain.rs b/bridges/relays/client-substrate/src/test_chain.rs index cfd241c022a269da799e8e03c4398566d98a14a0..991202e9874c790e404b42b74102248cb5f6723f 100644 --- a/bridges/relays/client-substrate/src/test_chain.rs +++ b/bridges/relays/client-substrate/src/test_chain.rs @@ -24,7 +24,7 @@ use crate::{Chain, ChainWithBalances, ChainWithMessages}; use bp_messages::{ChainWithMessages as ChainWithMessagesBase, MessageNonce}; use bp_runtime::ChainId; -use frame_support::weights::Weight; +use frame_support::{sp_runtime::StateVersion, weights::Weight}; use std::time::Duration; /// Chain that may be used in tests. @@ -44,6 +44,8 @@ impl bp_runtime::Chain for TestChain { type Nonce = u32; type Signature = sp_runtime::testing::TestSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { 100000 } @@ -100,6 +102,8 @@ impl bp_runtime::Chain for TestParachainBase { type Nonce = u32; type Signature = sp_runtime::testing::TestSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { unreachable!() } diff --git a/bridges/relays/equivocation/Cargo.toml b/bridges/relays/equivocation/Cargo.toml index 5a067b62e0774ffb93e8b935ed287696e1fefd7c..09bdda23f2c25edabc5c4adbf6fa6739b99ddeef 100644 --- a/bridges/relays/equivocation/Cargo.toml +++ b/bridges/relays/equivocation/Cargo.toml @@ -12,12 +12,12 @@ publish = false workspace = true [dependencies] -async-std = { version = "1.9.0", features = ["attributes"] } -async-trait = "0.1.79" -bp-header-chain = { path = "../../primitives/header-chain" } -finality-relay = { path = "../finality" } -frame-support = { path = "../../../substrate/frame/support" } -futures = "0.3.30" +async-std = { features = ["attributes"], workspace = true } +async-trait = { workspace = true } +bp-header-chain = { workspace = true, default-features = true } +finality-relay = { workspace = true } +frame-support = { workspace = true, default-features = true } +futures = { workspace = true } log = { workspace = true } -num-traits = "0.2" -relay-utils = { path = "../utils" } +num-traits = { workspace = true, default-features = true } +relay-utils = { workspace = true } diff --git a/bridges/relays/finality/Cargo.toml b/bridges/relays/finality/Cargo.toml index 5ee4b10fa638f5ec226df14beca1e0c79d0055df..06c4a5dcc43e0d54410424a85e2ff72dbbf24729 100644 --- a/bridges/relays/finality/Cargo.toml +++ b/bridges/relays/finality/Cargo.toml @@ -12,14 +12,14 @@ publish = false workspace = true [dependencies] -async-std = "1.9.0" -async-trait = "0.1.79" -backoff = "0.4" -bp-header-chain = { path = "../../primitives/header-chain" } -futures = "0.3.30" +async-std = { workspace = true } +async-trait = { workspace = true } +backoff = { workspace = true } +bp-header-chain = { workspace = true, default-features = true } +futures = { workspace = true } log = { workspace = true } -num-traits = "0.2" -relay-utils = { path = "../utils" } +num-traits = { workspace = true, default-features = true } +relay-utils = { workspace = true } [dev-dependencies] -parking_lot = "0.12.1" +parking_lot = { workspace = true, default-features = true } diff --git a/bridges/relays/finality/src/base.rs b/bridges/relays/finality/src/base.rs index 4253468eaace1ef2a2adc47790f7e16c38160200..8704bff95494a88274f0e78f5df53aa15708cccf 100644 --- a/bridges/relays/finality/src/base.rs +++ b/bridges/relays/finality/src/base.rs @@ -45,7 +45,3 @@ pub trait SourceClientBase: RelayClient { /// Subscribe to new finality proofs. async fn finality_proofs(&self) -> Result; } - -/// Target client used in finality related loops. -#[async_trait] -pub trait TargetClientBase: RelayClient {} diff --git a/bridges/relays/lib-substrate-relay/Cargo.toml b/bridges/relays/lib-substrate-relay/Cargo.toml index 077d1b1ff356a871364d45c1251aec0af7680cdd..b0f93e5b5485f24b230b9b2868c6301b6ed64181 100644 --- a/bridges/relays/lib-substrate-relay/Cargo.toml +++ b/bridges/relays/lib-substrate-relay/Cargo.toml @@ -11,52 +11,50 @@ publish = false workspace = true [dependencies] -anyhow = "1.0" -async-std = "1.9.0" -async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.12" } -futures = "0.3.30" -hex = "0.4" +anyhow = { workspace = true } +async-std = { workspace = true } +async-trait = { workspace = true } +codec = { workspace = true, default-features = true } +futures = { workspace = true } +hex = { workspace = true, default-features = true } log = { workspace = true } -num-traits = "0.2" -rbtag = "0.3" -structopt = "0.3" -strum = { version = "0.26.2", features = ["derive"] } +num-traits = { workspace = true, default-features = true } +rbtag = { workspace = true } +structopt = { workspace = true } +strum = { features = ["derive"], workspace = true, default-features = true } thiserror = { workspace = true } # Bridge dependencies +bp-header-chain = { workspace = true, default-features = true } +bp-parachains = { workspace = true, default-features = true } +bp-polkadot-core = { workspace = true, default-features = true } +bp-relayers = { workspace = true, default-features = true } -bp-header-chain = { path = "../../primitives/header-chain" } -bp-parachains = { path = "../../primitives/parachains" } -bp-polkadot-core = { path = "../../primitives/polkadot-core" } -bp-relayers = { path = "../../primitives/relayers" } -bridge-runtime-common = { path = "../../bin/runtime-common" } +equivocation-detector = { workspace = true } +finality-relay = { workspace = true } +parachains-relay = { workspace = true } +relay-utils = { workspace = true } +messages-relay = { workspace = true } +relay-substrate-client = { workspace = true } -equivocation-detector = { path = "../equivocation" } -finality-grandpa = { version = "0.16.2" } -finality-relay = { path = "../finality" } -parachains-relay = { path = "../parachains" } -relay-utils = { path = "../utils" } -messages-relay = { path = "../messages" } -relay-substrate-client = { path = "../client-substrate" } +pallet-bridge-grandpa = { workspace = true, default-features = true } +pallet-bridge-messages = { workspace = true, default-features = true } +pallet-bridge-parachains = { workspace = true, default-features = true } -pallet-bridge-grandpa = { path = "../../modules/grandpa" } -pallet-bridge-messages = { path = "../../modules/messages" } -pallet-bridge-parachains = { path = "../../modules/parachains" } - -bp-runtime = { path = "../../primitives/runtime" } -bp-messages = { path = "../../primitives/messages" } +bp-runtime = { workspace = true, default-features = true } +bp-messages = { workspace = true, default-features = true } # Substrate Dependencies - -frame-support = { path = "../../../substrate/frame/support" } -frame-system = { path = "../../../substrate/frame/system" } -pallet-balances = { path = "../../../substrate/frame/balances" } -pallet-grandpa = { path = "../../../substrate/frame/grandpa" } -sp-core = { path = "../../../substrate/primitives/core" } -sp-consensus-grandpa = { path = "../../../substrate/primitives/consensus/grandpa" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } +frame-support = { workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +pallet-grandpa = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-consensus-grandpa = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-trie = { workspace = true } [dev-dependencies] -pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment" } -relay-substrate-client = { path = "../client-substrate", features = ["test-helpers"] } +scale-info = { features = ["derive"], workspace = true } +pallet-transaction-payment = { workspace = true, default-features = true } +relay-substrate-client = { features = ["test-helpers"], workspace = true } diff --git a/bridges/relays/lib-substrate-relay/src/cli/bridge.rs b/bridges/relays/lib-substrate-relay/src/cli/bridge.rs index 316f59a2b0c86e1bc78c1446bb69a90b0b0bf0f7..5631285b3c544de0e3caf85a6b74b7ee31601c56 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/bridge.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/bridge.rs @@ -19,7 +19,7 @@ use crate::{ equivocation::SubstrateEquivocationDetectionPipeline, finality::SubstrateFinalitySyncPipeline, - messages_lane::{MessagesRelayLimits, SubstrateMessageLane}, + messages::{MessagesRelayLimits, SubstrateMessageLane}, parachains::SubstrateParachainsPipeline, }; use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs index 05a061c2ea606b79464908a6af46ed75af7d80ee..338dda3c63309acbefd2616d052ae5dc4bf1d1e0 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs @@ -38,7 +38,7 @@ use futures::{FutureExt, TryFutureExt}; use crate::{ cli::{bridge::MessagesCliBridge, DefaultClient, HexLaneId, PrometheusParams}, - messages_lane::{MessagesRelayLimits, MessagesRelayParams}, + messages::{MessagesRelayLimits, MessagesRelayParams}, on_demand::OnDemandRelay, HeadersToRelay, TaggedAccount, TransactionParams, }; @@ -298,14 +298,14 @@ where .collect::>(); { let common = self.mut_base().mut_common(); - crate::messages_metrics::add_relay_balances_metrics::<_, Self::Right>( + crate::messages::metrics::add_relay_balances_metrics::<_, Self::Right>( common.left.client.clone(), &common.metrics_params, &common.left.accounts, &lanes, ) .await?; - crate::messages_metrics::add_relay_balances_metrics::<_, Self::Left>( + crate::messages::metrics::add_relay_balances_metrics::<_, Self::Left>( common.right.client.clone(), &common.metrics_params, &common.right.accounts, @@ -318,7 +318,7 @@ where let mut message_relays = Vec::with_capacity(lanes.len() * 2); for lane in lanes { let left_to_right_messages = - crate::messages_lane::run::<::MessagesLane, _, _>( + crate::messages::run::<::MessagesLane, _, _>( self.left_to_right().messages_relay_params( left_to_right_on_demand_headers.clone(), right_to_left_on_demand_headers.clone(), @@ -331,7 +331,7 @@ where message_relays.push(left_to_right_messages); let right_to_left_messages = - crate::messages_lane::run::<::MessagesLane, _, _>( + crate::messages::run::<::MessagesLane, _, _>( self.right_to_left().messages_relay_params( right_to_left_on_demand_headers.clone(), left_to_right_on_demand_headers.clone(), diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs index a17ae7c0c01f9b828d8a534da8143a1d983892c2..68bbe71ae599c901bdf7a9b6e55cf93c020adbb6 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs @@ -18,7 +18,7 @@ use crate::{ cli::{bridge::*, chain_schema::*, HexLaneId, PrometheusParams}, - messages_lane::MessagesRelayParams, + messages::MessagesRelayParams, TransactionParams, }; @@ -117,7 +117,7 @@ where let target_sign = data.target_sign.to_keypair::()?; let target_transactions_mortality = data.target_sign.transactions_mortality()?; - crate::messages_lane::run::(MessagesRelayParams { + crate::messages::run::(MessagesRelayParams { source_client, source_transaction_params: TransactionParams { signer: source_sign, @@ -161,7 +161,7 @@ where })? .id(); - crate::messages_lane::relay_messages_range::( + crate::messages::relay_messages_range::( source_client, target_client, TransactionParams { signer: source_sign, mortality: source_transactions_mortality }, @@ -197,7 +197,7 @@ where })? .id(); - crate::messages_lane::relay_messages_delivery_confirmation::( + crate::messages::relay_messages_delivery_confirmation::( source_client, target_client, TransactionParams { signer: source_sign, mortality: source_transactions_mortality }, diff --git a/bridges/relays/lib-substrate-relay/src/lib.rs b/bridges/relays/lib-substrate-relay/src/lib.rs index b3e8e7ed9a2059bb07134640aa4e0bc98494a6a1..c004540a9f4951f3aeeb43a91c74da68a3ff1064 100644 --- a/bridges/relays/lib-substrate-relay/src/lib.rs +++ b/bridges/relays/lib-substrate-relay/src/lib.rs @@ -30,10 +30,7 @@ pub mod equivocation; pub mod error; pub mod finality; pub mod finality_base; -pub mod messages_lane; -pub mod messages_metrics; -pub mod messages_source; -pub mod messages_target; +pub mod messages; pub mod on_demand; pub mod parachains; @@ -130,3 +127,17 @@ impl BatchCallBuilder for () { unreachable!("never called, because ()::new_builder() returns None; qed") } } + +/// Module for handling storage proofs compatibility. +pub mod proofs { + use bp_runtime::{HashOf, RawStorageProof}; + use relay_substrate_client::Chain; + use sp_trie::StorageProof; + + /// Converts proof to `RawStorageProof` type. + pub fn to_raw_storage_proof( + proof: (StorageProof, HashOf), + ) -> RawStorageProof { + proof.0.into_iter_nodes().collect() + } +} diff --git a/bridges/relays/lib-substrate-relay/src/messages_metrics.rs b/bridges/relays/lib-substrate-relay/src/messages/metrics.rs similarity index 100% rename from bridges/relays/lib-substrate-relay/src/messages_metrics.rs rename to bridges/relays/lib-substrate-relay/src/messages/metrics.rs diff --git a/bridges/relays/lib-substrate-relay/src/messages_lane.rs b/bridges/relays/lib-substrate-relay/src/messages/mod.rs similarity index 63% rename from bridges/relays/lib-substrate-relay/src/messages_lane.rs rename to bridges/relays/lib-substrate-relay/src/messages/mod.rs index e3786dcdc5e31dad2cdf00ba2db073adb87f78b2..e52b7020666941c9a8d9937655496acf451c5379 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_lane.rs +++ b/bridges/relays/lib-substrate-relay/src/messages/mod.rs @@ -17,20 +17,21 @@ //! Tools for supporting message lanes between two Substrate-based chains. use crate::{ - messages_source::{SubstrateMessagesProof, SubstrateMessagesSource}, - messages_target::{SubstrateMessagesDeliveryProof, SubstrateMessagesTarget}, + messages::{ + source::{SubstrateMessagesProof, SubstrateMessagesSource}, + target::{SubstrateMessagesDeliveryProof, SubstrateMessagesTarget}, + }, on_demand::OnDemandRelay, BatchCallBuilder, BatchCallBuilderConstructor, TransactionParams, }; use async_std::sync::Arc; -use bp_messages::{ChainWithMessages as _, LaneId, MessageNonce}; +use bp_messages::{ + target_chain::FromBridgedChainMessagesProof, ChainWithMessages as _, LaneId, MessageNonce, +}; use bp_runtime::{ AccountIdOf, Chain as _, EncodedOrDecodedCall, HeaderIdOf, TransactionEra, WeightExtraOps, }; -use bridge_runtime_common::messages::{ - source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, -}; use codec::Encode; use frame_support::{dispatch::GetDispatchInfo, weights::Weight}; use messages_relay::{message_lane::MessageLane, message_lane_loop::BatchTransaction}; @@ -48,6 +49,10 @@ use sp_core::Pair; use sp_runtime::traits::Zero; use std::{fmt::Debug, marker::PhantomData, ops::RangeInclusive}; +pub mod metrics; +pub mod source; +pub mod target; + /// Substrate -> Substrate messages synchronization pipeline. pub trait SubstrateMessageLane: 'static + Clone + Debug + Send + Sync { /// Messages of this chain are relayed to the `TargetChain`. @@ -383,11 +388,10 @@ pub struct DirectReceiveMessagesProofCallBuilder { impl ReceiveMessagesProofCallBuilder

for DirectReceiveMessagesProofCallBuilder where P: SubstrateMessageLane, - R: BridgeMessagesConfig>, + R: BridgeMessagesConfig, I: 'static, - R::SourceHeaderChain: bp_messages::target_chain::SourceHeaderChain< - MessagesProof = FromBridgedChainMessagesProof>, - >, + R::BridgedChain: + bp_runtime::Chain, Hash = HashOf>, CallOf: From> + GetDispatchInfo, { fn build_receive_messages_proof_call( @@ -399,7 +403,7 @@ where ) -> CallOf { let call: CallOf = BridgeMessagesCall::::receive_messages_proof { relayer_id_at_bridged_chain: relayer_id_at_source, - proof: proof.1, + proof: proof.1.into(), messages_count, dispatch_weight, } @@ -432,26 +436,26 @@ macro_rules! generate_receive_message_proof_call_builder { ($pipeline:ident, $mocked_builder:ident, $bridge_messages:path, $receive_messages_proof:path) => { pub struct $mocked_builder; - impl $crate::messages_lane::ReceiveMessagesProofCallBuilder<$pipeline> + impl $crate::messages::ReceiveMessagesProofCallBuilder<$pipeline> for $mocked_builder { fn build_receive_messages_proof_call( relayer_id_at_source: relay_substrate_client::AccountIdOf< - <$pipeline as $crate::messages_lane::SubstrateMessageLane>::SourceChain + <$pipeline as $crate::messages::SubstrateMessageLane>::SourceChain >, - proof: $crate::messages_source::SubstrateMessagesProof< - <$pipeline as $crate::messages_lane::SubstrateMessageLane>::SourceChain + proof: $crate::messages::source::SubstrateMessagesProof< + <$pipeline as $crate::messages::SubstrateMessageLane>::SourceChain >, messages_count: u32, dispatch_weight: bp_messages::Weight, _trace_call: bool, ) -> relay_substrate_client::CallOf< - <$pipeline as $crate::messages_lane::SubstrateMessageLane>::TargetChain + <$pipeline as $crate::messages::SubstrateMessageLane>::TargetChain > { bp_runtime::paste::item! { $bridge_messages($receive_messages_proof { relayer_id_at_bridged_chain: relayer_id_at_source, - proof: proof.1, + proof: proof.1.into(), messages_count: messages_count, dispatch_weight: dispatch_weight, }) @@ -483,11 +487,7 @@ where P: SubstrateMessageLane, R: BridgeMessagesConfig, I: 'static, - R::TargetHeaderChain: bp_messages::source_chain::TargetHeaderChain< - R::OutboundPayload, - R::AccountId, - MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof>, - >, + R::BridgedChain: bp_runtime::Chain>, CallOf: From> + GetDispatchInfo, { fn build_receive_messages_delivery_proof_call( @@ -496,7 +496,7 @@ where ) -> CallOf { let call: CallOf = BridgeMessagesCall::::receive_messages_delivery_proof { - proof: proof.1, + proof: proof.1.into(), relayers_state: proof.0, } .into(); @@ -528,16 +528,16 @@ macro_rules! generate_receive_message_delivery_proof_call_builder { ($pipeline:ident, $mocked_builder:ident, $bridge_messages:path, $receive_messages_delivery_proof:path) => { pub struct $mocked_builder; - impl $crate::messages_lane::ReceiveMessagesDeliveryProofCallBuilder<$pipeline> + impl $crate::messages::ReceiveMessagesDeliveryProofCallBuilder<$pipeline> for $mocked_builder { fn build_receive_messages_delivery_proof_call( - proof: $crate::messages_target::SubstrateMessagesDeliveryProof< - <$pipeline as $crate::messages_lane::SubstrateMessageLane>::TargetChain + proof: $crate::messages::target::SubstrateMessagesDeliveryProof< + <$pipeline as $crate::messages::SubstrateMessageLane>::TargetChain >, _trace_call: bool, ) -> relay_substrate_client::CallOf< - <$pipeline as $crate::messages_lane::SubstrateMessageLane>::SourceChain + <$pipeline as $crate::messages::SubstrateMessageLane>::SourceChain > { bp_runtime::paste::item! { $bridge_messages($receive_messages_delivery_proof { @@ -643,13 +643,7 @@ where Weight::zero(), FromBridgedChainMessagesProof { bridged_header_hash: Default::default(), - // we may use per-chain `EXTRA_STORAGE_PROOF_SIZE`, but since we don't need - // exact values, this global estimation is fine - storage_proof: vec![vec![ - 42u8; - pallet_bridge_messages::EXTRA_STORAGE_PROOF_SIZE - as usize - ]], + storage_proof: Default::default(), lane: Default::default(), nonces_start: 1, nonces_end: messages as u64, @@ -675,3 +669,362 @@ where ) .map_err(Into::into) } + +#[cfg(test)] +mod tests { + use super::*; + use bp_messages::{ + source_chain::FromBridgedChainMessagesDeliveryProof, UnrewardedRelayersState, + }; + use relay_substrate_client::calls::{UtilityCall as MockUtilityCall, UtilityCall}; + + #[derive(codec::Decode, codec::Encode, Clone, Debug, PartialEq)] + pub enum RuntimeCall { + #[codec(index = 53)] + BridgeMessages(CodegenBridgeMessagesCall), + #[codec(index = 123)] + Utility(UtilityCall), + } + pub type CodegenBridgeMessagesCall = bp_messages::BridgeMessagesCall< + u64, + Box>, + FromBridgedChainMessagesDeliveryProof, + >; + + impl From> for RuntimeCall { + fn from(value: MockUtilityCall) -> RuntimeCall { + match value { + MockUtilityCall::batch_all(calls) => + RuntimeCall::Utility(UtilityCall::::batch_all(calls)), + } + } + } + + #[test] + fn ensure_macro_compatibility_for_generate_receive_message_proof_call_builder() { + // data + let receive_messages_proof = FromBridgedChainMessagesProof { + bridged_header_hash: Default::default(), + storage_proof: Default::default(), + lane: LaneId([0, 0, 0, 0]), + nonces_start: 0, + nonces_end: 0, + }; + let account = 1234; + let messages_count = 0; + let dispatch_weight = Default::default(); + + // construct pallet Call directly + let pallet_receive_messages_proof = + pallet_bridge_messages::Call::::receive_messages_proof { + relayer_id_at_bridged_chain: account, + proof: receive_messages_proof.clone().into(), + messages_count, + dispatch_weight, + }; + + // construct mock enum Call + let mock_enum_receive_messages_proof = CodegenBridgeMessagesCall::receive_messages_proof { + relayer_id_at_bridged_chain: account, + proof: receive_messages_proof.clone().into(), + messages_count, + dispatch_weight, + }; + + // now we should be able to use macro `generate_receive_message_proof_call_builder` + let relayer_call_builder_receive_messages_proof = relayer::ThisChainToBridgedChainMessageLaneReceiveMessagesProofCallBuilder::build_receive_messages_proof_call( + account, + (Default::default(), receive_messages_proof), + messages_count, + dispatch_weight, + false, + ); + + // ensure they are all equal + assert_eq!( + pallet_receive_messages_proof.encode(), + mock_enum_receive_messages_proof.encode() + ); + match relayer_call_builder_receive_messages_proof { + RuntimeCall::BridgeMessages(call) => match call { + call @ CodegenBridgeMessagesCall::receive_messages_proof { .. } => + assert_eq!(pallet_receive_messages_proof.encode(), call.encode()), + _ => panic!("Unexpected CodegenBridgeMessagesCall type"), + }, + _ => panic!("Unexpected RuntimeCall type"), + }; + } + + #[test] + fn ensure_macro_compatibility_for_generate_receive_message_delivery_proof_call_builder() { + // data + let receive_messages_delivery_proof = FromBridgedChainMessagesDeliveryProof { + bridged_header_hash: Default::default(), + storage_proof: Default::default(), + lane: LaneId([0, 0, 0, 0]), + }; + let relayers_state = UnrewardedRelayersState { + unrewarded_relayer_entries: 0, + messages_in_oldest_entry: 0, + total_messages: 0, + last_delivered_nonce: 0, + }; + + // construct pallet Call directly + let pallet_receive_messages_delivery_proof = + pallet_bridge_messages::Call::::receive_messages_delivery_proof { + proof: receive_messages_delivery_proof.clone(), + relayers_state: relayers_state.clone(), + }; + + // construct mock enum Call + let mock_enum_receive_messages_delivery_proof = + CodegenBridgeMessagesCall::receive_messages_delivery_proof { + proof: receive_messages_delivery_proof.clone(), + relayers_state: relayers_state.clone(), + }; + + // now we should be able to use macro `generate_receive_message_proof_call_builder` + let relayer_call_builder_receive_messages_delivery_proof = relayer::ThisChainToBridgedChainMessageLaneReceiveMessagesDeliveryProofCallBuilder::build_receive_messages_delivery_proof_call( + (relayers_state, receive_messages_delivery_proof), + false, + ); + + // ensure they are all equal + assert_eq!( + pallet_receive_messages_delivery_proof.encode(), + mock_enum_receive_messages_delivery_proof.encode() + ); + match relayer_call_builder_receive_messages_delivery_proof { + RuntimeCall::BridgeMessages(call) => match call { + call @ CodegenBridgeMessagesCall::receive_messages_delivery_proof { .. } => + assert_eq!(pallet_receive_messages_delivery_proof.encode(), call.encode()), + _ => panic!("Unexpected CodegenBridgeMessagesCall type"), + }, + _ => panic!("Unexpected RuntimeCall type"), + }; + } + + // mock runtime with `pallet_bridge_messages` + mod mock { + use super::super::*; + use bp_messages::target_chain::ForbidInboundMessages; + use bp_runtime::ChainId; + use frame_support::derive_impl; + use sp_core::H256; + use sp_runtime::{ + generic, testing::Header as SubstrateHeader, traits::BlakeTwo256, StateVersion, + }; + + type Block = frame_system::mocking::MockBlock; + pub type SignedBlock = generic::SignedBlock; + + frame_support::construct_runtime! { + pub enum TestRuntime + { + System: frame_system, + Messages: pallet_bridge_messages, + } + } + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] + impl frame_system::Config for TestRuntime { + type Block = Block; + } + + impl pallet_bridge_messages::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type ThisChain = ThisUnderlyingChain; + type BridgedChain = BridgedUnderlyingChain; + type BridgedHeaderChain = BridgedHeaderChain; + type ActiveOutboundLanes = (); + type OutboundPayload = Vec; + type InboundPayload = Vec; + type DeliveryPayments = (); + type DeliveryConfirmationPayments = (); + type OnMessagesDelivered = (); + type MessageDispatch = ForbidInboundMessages>; + } + + pub struct ThisUnderlyingChain; + + impl bp_runtime::Chain for ThisUnderlyingChain { + const ID: ChainId = *b"tuch"; + type BlockNumber = u64; + type Hash = H256; + type Hasher = BlakeTwo256; + type Header = SubstrateHeader; + type AccountId = u64; + type Balance = u64; + type Nonce = u64; + type Signature = sp_runtime::MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { + u32::MAX + } + fn max_extrinsic_weight() -> Weight { + Weight::MAX + } + } + + impl bp_messages::ChainWithMessages for ThisUnderlyingChain { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = ""; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1000; + } + + pub struct BridgedUnderlyingChain; + + pub type BridgedHeaderHash = H256; + pub type BridgedChainHeader = SubstrateHeader; + + impl bp_runtime::Chain for BridgedUnderlyingChain { + const ID: ChainId = *b"bgdc"; + type BlockNumber = u64; + type Hash = BridgedHeaderHash; + type Hasher = BlakeTwo256; + type Header = BridgedChainHeader; + type AccountId = u64; + type Balance = u64; + type Nonce = u64; + type Signature = sp_runtime::MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { + 4096 + } + fn max_extrinsic_weight() -> Weight { + Weight::MAX + } + } + + impl bp_messages::ChainWithMessages for BridgedUnderlyingChain { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = ""; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1000; + } + + pub struct BridgedHeaderChain; + + impl bp_header_chain::HeaderChain for BridgedHeaderChain { + fn finalized_header_state_root( + _hash: HashOf, + ) -> Option> { + unreachable!() + } + } + } + + // relayer configuration + mod relayer { + use super::*; + use crate::{ + messages::{ + tests::{mock, RuntimeCall}, + SubstrateMessageLane, + }, + UtilityPalletBatchCallBuilder, + }; + use bp_runtime::UnderlyingChainProvider; + use relay_substrate_client::{MockedRuntimeUtilityPallet, SignParam, UnsignedTransaction}; + use std::time::Duration; + + #[derive(Clone)] + pub struct ThisChain; + impl UnderlyingChainProvider for ThisChain { + type Chain = mock::ThisUnderlyingChain; + } + impl relay_substrate_client::Chain for ThisChain { + const NAME: &'static str = ""; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = ""; + const FREE_HEADERS_INTERVAL_METHOD: &'static str = ""; + const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(0); + type SignedBlock = mock::SignedBlock; + type Call = RuntimeCall; + } + impl relay_substrate_client::ChainWithTransactions for ThisChain { + type AccountKeyPair = sp_core::sr25519::Pair; + type SignedTransaction = (); + + fn sign_transaction( + _: SignParam, + _: UnsignedTransaction, + ) -> Result + where + Self: Sized, + { + todo!() + } + } + impl relay_substrate_client::ChainWithMessages for ThisChain { + const WITH_CHAIN_RELAYERS_PALLET_NAME: Option<&'static str> = None; + const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = ""; + const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = ""; + } + impl relay_substrate_client::ChainWithUtilityPallet for ThisChain { + type UtilityPallet = MockedRuntimeUtilityPallet; + } + + #[derive(Clone)] + pub struct BridgedChain; + impl UnderlyingChainProvider for BridgedChain { + type Chain = mock::BridgedUnderlyingChain; + } + impl relay_substrate_client::Chain for BridgedChain { + const NAME: &'static str = ""; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = ""; + const FREE_HEADERS_INTERVAL_METHOD: &'static str = ""; + const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(0); + type SignedBlock = mock::SignedBlock; + type Call = RuntimeCall; + } + impl relay_substrate_client::ChainWithTransactions for BridgedChain { + type AccountKeyPair = sp_core::sr25519::Pair; + type SignedTransaction = (); + + fn sign_transaction( + _: SignParam, + _: UnsignedTransaction, + ) -> Result + where + Self: Sized, + { + todo!() + } + } + impl relay_substrate_client::ChainWithMessages for BridgedChain { + const WITH_CHAIN_RELAYERS_PALLET_NAME: Option<&'static str> = None; + const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = ""; + const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = ""; + } + impl relay_substrate_client::ChainWithUtilityPallet for BridgedChain { + type UtilityPallet = MockedRuntimeUtilityPallet; + } + + #[derive(Clone, Debug)] + pub struct ThisChainToBridgedChainMessageLane; + impl SubstrateMessageLane for ThisChainToBridgedChainMessageLane { + type SourceChain = ThisChain; + type TargetChain = BridgedChain; + type ReceiveMessagesProofCallBuilder = + ThisChainToBridgedChainMessageLaneReceiveMessagesProofCallBuilder; + type ReceiveMessagesDeliveryProofCallBuilder = + ThisChainToBridgedChainMessageLaneReceiveMessagesDeliveryProofCallBuilder; + type SourceBatchCallBuilder = UtilityPalletBatchCallBuilder; + type TargetBatchCallBuilder = UtilityPalletBatchCallBuilder; + } + + generate_receive_message_proof_call_builder!( + ThisChainToBridgedChainMessageLane, + ThisChainToBridgedChainMessageLaneReceiveMessagesProofCallBuilder, + RuntimeCall::BridgeMessages, + CodegenBridgeMessagesCall::receive_messages_proof + ); + generate_receive_message_delivery_proof_call_builder!( + ThisChainToBridgedChainMessageLane, + ThisChainToBridgedChainMessageLaneReceiveMessagesDeliveryProofCallBuilder, + RuntimeCall::BridgeMessages, + CodegenBridgeMessagesCall::receive_messages_delivery_proof + ); + } +} diff --git a/bridges/relays/lib-substrate-relay/src/messages_source.rs b/bridges/relays/lib-substrate-relay/src/messages/source.rs similarity index 97% rename from bridges/relays/lib-substrate-relay/src/messages_source.rs rename to bridges/relays/lib-substrate-relay/src/messages/source.rs index 1f597e278da404a5c3d8d0dff0032030d96ed433..b75fc86d5eee20d247de3cbc26f324ed46e9ad2d 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_source.rs +++ b/bridges/relays/lib-substrate-relay/src/messages/source.rs @@ -20,11 +20,12 @@ use crate::{ finality_base::best_synced_header_id, - messages_lane::{ + messages::{ BatchProofTransaction, MessageLaneAdapter, ReceiveMessagesDeliveryProofCallBuilder, SubstrateMessageLane, }, on_demand::OnDemandRelay, + proofs::to_raw_storage_proof, TransactionParams, }; @@ -32,11 +33,11 @@ use async_std::sync::Arc; use async_trait::async_trait; use bp_messages::{ storage_keys::{operating_mode_key, outbound_lane_data_key}, + target_chain::FromBridgedChainMessagesProof, ChainWithMessages as _, InboundMessageDetails, LaneId, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, }; -use bp_runtime::{BasicOperatingMode, HeaderIdProvider}; -use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof; +use bp_runtime::{BasicOperatingMode, HeaderIdProvider, RangeInclusiveExt}; use codec::Encode; use frame_support::weights::Weight; use messages_relay::{ @@ -320,34 +321,27 @@ where ), SubstrateError, > { - let mut storage_keys = - Vec::with_capacity(nonces.end().saturating_sub(*nonces.start()) as usize + 1); - let mut message_nonce = *nonces.start(); - while message_nonce <= *nonces.end() { + let mut storage_keys = Vec::with_capacity(nonces.saturating_len() as usize); + for message_nonce in nonces.clone() { let message_key = bp_messages::storage_keys::message_key( P::TargetChain::WITH_CHAIN_MESSAGES_PALLET_NAME, &self.lane_id, message_nonce, ); storage_keys.push(message_key); - message_nonce += 1; } if proof_parameters.outbound_state_proof_required { - storage_keys.push(bp_messages::storage_keys::outbound_lane_data_key( + storage_keys.push(outbound_lane_data_key( P::TargetChain::WITH_CHAIN_MESSAGES_PALLET_NAME, &self.lane_id, )); } - let proof = self - .source_client - .prove_storage(id.1, storage_keys) - .await? - .into_iter_nodes() - .collect(); + let storage_proof = + self.source_client.prove_storage(id.hash(), storage_keys.clone()).await?; let proof = FromBridgedChainMessagesProof { bridged_header_hash: id.1, - storage_proof: proof, + storage_proof: to_raw_storage_proof::(storage_proof), lane: self.lane_id, nonces_start: *nonces.start(), nonces_end: *nonces.end(), diff --git a/bridges/relays/lib-substrate-relay/src/messages_target.rs b/bridges/relays/lib-substrate-relay/src/messages/target.rs similarity index 94% rename from bridges/relays/lib-substrate-relay/src/messages_target.rs rename to bridges/relays/lib-substrate-relay/src/messages/target.rs index e1c7645eac6834ed8768ef6f416ce415c37653cf..a6bf169cffb67ae149d9d4c8c5a2348dc18f5b39 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_target.rs +++ b/bridges/relays/lib-substrate-relay/src/messages/target.rs @@ -19,24 +19,25 @@ //! `` chain. use crate::{ - messages_lane::{ + messages::{ + source::{ + ensure_messages_pallet_active, read_client_state_from_both_chains, + SubstrateMessagesProof, + }, BatchProofTransaction, MessageLaneAdapter, ReceiveMessagesProofCallBuilder, SubstrateMessageLane, }, - messages_source::{ - ensure_messages_pallet_active, read_client_state_from_both_chains, SubstrateMessagesProof, - }, on_demand::OnDemandRelay, + proofs::to_raw_storage_proof, TransactionParams, }; use async_std::sync::Arc; use async_trait::async_trait; use bp_messages::{ - storage_keys::inbound_lane_data_key, ChainWithMessages as _, InboundLaneData, LaneId, - MessageNonce, UnrewardedRelayersState, + source_chain::FromBridgedChainMessagesDeliveryProof, storage_keys::inbound_lane_data_key, + ChainWithMessages as _, InboundLaneData, LaneId, MessageNonce, UnrewardedRelayersState, }; -use bridge_runtime_common::messages::source::FromBridgedChainMessagesDeliveryProof; use messages_relay::{ message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf}, message_lane_loop::{NoncesSubmitArtifacts, TargetClient, TargetClientState}, @@ -47,7 +48,7 @@ use relay_substrate_client::{ }; use relay_utils::relay_loop::Client as RelayClient; use sp_core::Pair; -use std::ops::RangeInclusive; +use std::{convert::TryFrom, ops::RangeInclusive}; /// Message receiving proof returned by the target Substrate node. pub type SubstrateMessagesDeliveryProof = @@ -231,19 +232,16 @@ where SubstrateError, > { let (id, relayers_state) = self.unrewarded_relayers_state(id).await?; - let inbound_data_key = bp_messages::storage_keys::inbound_lane_data_key( + let storage_keys = vec![inbound_lane_data_key( P::SourceChain::WITH_CHAIN_MESSAGES_PALLET_NAME, &self.lane_id, - ); - let proof = self - .target_client - .prove_storage(id.hash(), vec![inbound_data_key]) - .await? - .into_iter_nodes() - .collect(); + )]; + + let storage_proof = + self.target_client.prove_storage(id.hash(), storage_keys.clone()).await?; let proof = FromBridgedChainMessagesDeliveryProof { bridged_header_hash: id.1, - storage_proof: proof, + storage_proof: to_raw_storage_proof::(storage_proof), lane: self.lane_id, }; Ok((id, (relayers_state, proof))) diff --git a/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs b/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs index 654cb6628d5f062d5790a2d14ffa1ae6fadb7475..4579222a2c681c49e076f67d2eacaeb1dc8b9fca 100644 --- a/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs +++ b/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs @@ -17,7 +17,7 @@ //! On-demand Substrate -> Substrate parachain finality relay. use crate::{ - messages_source::best_finalized_peer_header_at_self, + messages::source::best_finalized_peer_header_at_self, on_demand::OnDemandRelay, parachains::{ source::ParachainsSource, target::ParachainsTarget, ParachainsPipelineAdapter, @@ -681,7 +681,7 @@ impl<'a, P: SubstrateParachainsPipeline, SourceRelayClnt, TargetClnt> async fn best_finalized_relay_block_at_target( &self, ) -> Result, SubstrateError> { - Ok(crate::messages_source::read_client_state::( + Ok(crate::messages::source::read_client_state::( &self.0.target_client, ) .await? diff --git a/bridges/relays/lib-substrate-relay/src/parachains/source.rs b/bridges/relays/lib-substrate-relay/src/parachains/source.rs index 11b9d6dbf5bd3fe12a4249ac9c2f9864291392d7..1aa12d1c913d11e13e95908db44c6302942fa94a 100644 --- a/bridges/relays/lib-substrate-relay/src/parachains/source.rs +++ b/bridges/relays/lib-substrate-relay/src/parachains/source.rs @@ -16,8 +16,10 @@ //! Parachain heads source. -use crate::parachains::{ParachainsPipelineAdapter, SubstrateParachainsPipeline}; - +use crate::{ + parachains::{ParachainsPipelineAdapter, SubstrateParachainsPipeline}, + proofs::to_raw_storage_proof, +}; use async_std::sync::{Arc, Mutex}; use async_trait::async_trait; use bp_parachains::parachain_head_storage_key_at_source; @@ -153,12 +155,9 @@ where let parachain = ParaId(P::SourceParachain::PARACHAIN_ID); let storage_key = parachain_head_storage_key_at_source(P::SourceRelayChain::PARAS_PALLET_NAME, parachain); - let parachain_heads_proof = self - .client - .prove_storage(at_block.hash(), vec![storage_key.clone()]) - .await? - .into_iter_nodes() - .collect(); + + let storage_proof = + self.client.prove_storage(at_block.hash(), vec![storage_key.clone()]).await?; // why we're reading parachain head here once again (it has already been read at the // `parachain_head`)? that's because `parachain_head` sometimes returns obsolete parachain @@ -178,6 +177,11 @@ where })?; let parachain_head_hash = parachain_head.hash(); - Ok((ParaHeadsProof { storage_proof: parachain_heads_proof }, parachain_head_hash)) + Ok(( + ParaHeadsProof { + storage_proof: to_raw_storage_proof::(storage_proof), + }, + parachain_head_hash, + )) } } diff --git a/bridges/relays/messages/Cargo.toml b/bridges/relays/messages/Cargo.toml index 570e11c0da6feeaa7bbbbd76a845df51444a10cb..c7a132bb3bae7ebc34728de8c94c41fb39c89751 100644 --- a/bridges/relays/messages/Cargo.toml +++ b/bridges/relays/messages/Cargo.toml @@ -11,19 +11,18 @@ publish = false workspace = true [dependencies] -async-std = { version = "1.9.0", features = ["attributes"] } -async-trait = "0.1.79" -env_logger = "0.11" -futures = "0.3.30" -hex = "0.4" +async-std = { features = ["attributes"], workspace = true } +async-trait = { workspace = true } +futures = { workspace = true } +hex = { workspace = true, default-features = true } log = { workspace = true } -num-traits = "0.2" -parking_lot = "0.12.1" +num-traits = { workspace = true, default-features = true } +parking_lot = { workspace = true, default-features = true } # Bridge Dependencies -bp-messages = { path = "../../primitives/messages" } -finality-relay = { path = "../finality" } -relay-utils = { path = "../utils" } +bp-messages = { workspace = true, default-features = true } +finality-relay = { workspace = true } +relay-utils = { workspace = true } -sp-arithmetic = { path = "../../../substrate/primitives/arithmetic" } +sp-arithmetic = { workspace = true, default-features = true } diff --git a/bridges/relays/parachains/Cargo.toml b/bridges/relays/parachains/Cargo.toml index 8d38e4e6bd07c2420adcf233729c1bac9bb77c37..ed03bdbb0f65e6f5e3b15c63f6ccd680c89e6626 100644 --- a/bridges/relays/parachains/Cargo.toml +++ b/bridges/relays/parachains/Cargo.toml @@ -11,18 +11,18 @@ publish = false workspace = true [dependencies] -async-std = "1.9.0" -async-trait = "0.1.79" -futures = "0.3.30" +async-std = { workspace = true } +async-trait = { workspace = true } +futures = { workspace = true } log = { workspace = true } -relay-utils = { path = "../utils" } +relay-utils = { workspace = true } # Bridge dependencies -bp-polkadot-core = { path = "../../primitives/polkadot-core" } -relay-substrate-client = { path = "../client-substrate" } +bp-polkadot-core = { workspace = true, default-features = true } +relay-substrate-client = { workspace = true } [dev-dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12" } -relay-substrate-client = { path = "../client-substrate", features = ["test-helpers"] } -sp-core = { path = "../../../substrate/primitives/core" } +codec = { workspace = true, default-features = true } +relay-substrate-client = { features = ["test-helpers"], workspace = true } +sp-core = { workspace = true, default-features = true } diff --git a/bridges/relays/parachains/src/parachains_loop.rs b/bridges/relays/parachains/src/parachains_loop.rs index fd73ca2d46c00f8e05bb05a14a7fa4104ef898c4..0fd1d72c7075bc29632280615f203e0c0028359b 100644 --- a/bridges/relays/parachains/src/parachains_loop.rs +++ b/bridges/relays/parachains/src/parachains_loop.rs @@ -680,7 +680,6 @@ impl SubmittedHeadsTracker

{ mod tests { use super::*; use async_std::sync::{Arc, Mutex}; - use codec::Encode; use futures::{SinkExt, StreamExt}; use relay_substrate_client::test_chain::{TestChain, TestParachain}; use relay_utils::{HeaderId, MaybeConnectionError}; @@ -821,8 +820,7 @@ mod tests { let head_result = SourceClient::::parachain_head(self, at_block).await?; let head = head_result.as_available().unwrap(); - let storage_proof = vec![head.hash().encode()]; - let proof = (ParaHeadsProof { storage_proof }, head.hash()); + let proof = (ParaHeadsProof { storage_proof: Default::default() }, head.hash()); self.data.lock().await.source_proof.clone().map(|_| proof) } } diff --git a/bridges/relays/utils/Cargo.toml b/bridges/relays/utils/Cargo.toml index 4765730a0b4f9906fd163600a7937f8d6aad661f..2c3f37750486c61603f975ff3c9b0719a9c913b3 100644 --- a/bridges/relays/utils/Cargo.toml +++ b/bridges/relays/utils/Cargo.toml @@ -11,29 +11,29 @@ publish = false workspace = true [dependencies] -ansi_term = "0.12" -anyhow = "1.0" -async-std = "1.9.0" -async-trait = "0.1.79" -backoff = "0.4" -isahc = "1.2" -env_logger = "0.11.3" -futures = "0.3.30" -jsonpath_lib = "0.3" +anyhow = { workspace = true } +async-std = { workspace = true } +async-trait = { workspace = true } +backoff = { workspace = true } +console = { workspace = true } +isahc = { workspace = true } +env_logger = { workspace = true } +futures = { workspace = true } +jsonpath_lib = { workspace = true } log = { workspace = true } -num-traits = "0.2" -parking_lot = "0.12.1" +num-traits = { workspace = true, default-features = true } +parking_lot = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } -sysinfo = "0.30" -time = { version = "0.3", features = ["formatting", "local-offset", "std"] } -tokio = { version = "1.37", features = ["rt"] } +sysinfo = { workspace = true } +time = { features = ["formatting", "local-offset", "std"], workspace = true } +tokio = { features = ["rt"], workspace = true, default-features = true } thiserror = { workspace = true } # Bridge dependencies -bp-runtime = { path = "../../primitives/runtime" } +bp-runtime = { workspace = true, default-features = true } # Substrate dependencies -sp-runtime = { path = "../../../substrate/primitives/runtime" } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../substrate/utils/prometheus" } +sp-runtime = { workspace = true, default-features = true } +prometheus-endpoint = { workspace = true, default-features = true } diff --git a/bridges/relays/utils/src/initialize.rs b/bridges/relays/utils/src/initialize.rs index 64d710242710b722b3b5be67dc439f814cd7e9df..cd0377caa3d6e2a6b4451a3b87b2749989fd6d24 100644 --- a/bridges/relays/utils/src/initialize.rs +++ b/bridges/relays/utils/src/initialize.rs @@ -16,6 +16,7 @@ //! Relayer initialization functions. +use console::style; use parking_lot::Mutex; use std::{cell::RefCell, fmt::Display, io::Write}; @@ -55,7 +56,7 @@ pub fn initialize_logger(with_timestamp: bool) { let timestamp = if cfg!(windows) { Either::Left(timestamp) } else { - Either::Right(ansi_term::Colour::Fixed(8).bold().paint(timestamp)) + Either::Right(style(timestamp).black().bright().bold().to_string()) }; writeln!( @@ -120,7 +121,7 @@ fn color_target(target: &str) -> impl Display + '_ { if cfg!(windows) { Either::Left(target) } else { - Either::Right(ansi_term::Colour::Fixed(8).paint(target)) + Either::Right(style(target).black().bright().to_string()) } } @@ -129,13 +130,12 @@ fn color_level(level: log::Level) -> impl Display { Either::Left(level) } else { let s = level.to_string(); - use ansi_term::Colour as Color; Either::Right(match level { - log::Level::Error => Color::Fixed(9).bold().paint(s), - log::Level::Warn => Color::Fixed(11).bold().paint(s), - log::Level::Info => Color::Fixed(10).paint(s), - log::Level::Debug => Color::Fixed(14).paint(s), - log::Level::Trace => Color::Fixed(12).paint(s), + log::Level::Error => style(s).red().bright().bold().to_string(), + log::Level::Warn => style(s).yellow().bright().bold().to_string(), + log::Level::Info => style(s).green().bright().to_string(), + log::Level::Debug => style(s).cyan().bright().to_string(), + log::Level::Trace => style(s).blue().bright().to_string(), }) } } diff --git a/bridges/snowbridge/pallets/ethereum-client/Cargo.toml b/bridges/snowbridge/pallets/ethereum-client/Cargo.toml index cab2b06b0931e6d28df83434b3319c8384bd3679..666ac3fbc8a2ab32b485c088c37b536e751cdd46 100644 --- a/bridges/snowbridge/pallets/ethereum-client/Cargo.toml +++ b/bridges/snowbridge/pallets/ethereum-client/Cargo.toml @@ -17,34 +17,34 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { optional = true, workspace = true, default-features = true } serde_json = { optional = true, workspace = true, default-features = true } -codec = { version = "3.6.12", package = "parity-scale-codec", default-features = false, features = ["derive"] } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } -hex-literal = { version = "0.4.1", optional = true } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } +hex-literal = { optional = true, workspace = true, default-features = true } log = { workspace = true } -frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../substrate/frame/system", default-features = false } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-io = { path = "../../../../substrate/primitives/io", default-features = false, optional = true } +frame-benchmarking = { optional = true, workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-core = { workspace = true } +sp-std = { workspace = true } +sp-runtime = { workspace = true } +sp-io = { optional = true, workspace = true } -snowbridge-core = { path = "../../primitives/core", default-features = false } -snowbridge-ethereum = { path = "../../primitives/ethereum", default-features = false } -snowbridge-pallet-ethereum-client-fixtures = { path = "fixtures", default-features = false, optional = true } -snowbridge-beacon-primitives = { path = "../../primitives/beacon", default-features = false } -static_assertions = { version = "1.1.0", default-features = false } -pallet-timestamp = { path = "../../../../substrate/frame/timestamp", default-features = false, optional = true } +snowbridge-core = { workspace = true } +snowbridge-ethereum = { workspace = true } +snowbridge-pallet-ethereum-client-fixtures = { optional = true, workspace = true } +snowbridge-beacon-primitives = { workspace = true } +static_assertions = { workspace = true } +pallet-timestamp = { optional = true, workspace = true } [dev-dependencies] -rand = "0.8.5" -sp-keyring = { path = "../../../../substrate/primitives/keyring" } +rand = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } -hex-literal = "0.4.1" -pallet-timestamp = { path = "../../../../substrate/frame/timestamp" } -snowbridge-pallet-ethereum-client-fixtures = { path = "fixtures" } -sp-io = { path = "../../../../substrate/primitives/io" } +hex-literal = { workspace = true, default-features = true } +pallet-timestamp = { workspace = true, default-features = true } +snowbridge-pallet-ethereum-client-fixtures = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } serde = { workspace = true, default-features = true } [features] diff --git a/bridges/snowbridge/pallets/ethereum-client/fixtures/Cargo.toml b/bridges/snowbridge/pallets/ethereum-client/fixtures/Cargo.toml index 858e2513a961288dd24c47e7d57ada1506b212d2..bd4176875733f64f61026e165a2a03b221193bad 100644 --- a/bridges/snowbridge/pallets/ethereum-client/fixtures/Cargo.toml +++ b/bridges/snowbridge/pallets/ethereum-client/fixtures/Cargo.toml @@ -15,11 +15,11 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -hex-literal = { version = "0.4.1" } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -snowbridge-core = { path = "../../../primitives/core", default-features = false } -snowbridge-beacon-primitives = { path = "../../../primitives/beacon", default-features = false } +hex-literal = { workspace = true, default-features = true } +sp-core = { workspace = true } +sp-std = { workspace = true } +snowbridge-core = { workspace = true } +snowbridge-beacon-primitives = { workspace = true } [features] default = ["std"] diff --git a/bridges/snowbridge/pallets/inbound-queue/Cargo.toml b/bridges/snowbridge/pallets/inbound-queue/Cargo.toml index d63398770f207051ebb5adb72f4f574c767e8770..1b08bb39b4346a76e58c0a695b4c71126bd40510 100644 --- a/bridges/snowbridge/pallets/inbound-queue/Cargo.toml +++ b/bridges/snowbridge/pallets/inbound-queue/Cargo.toml @@ -16,35 +16,35 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { optional = true, workspace = true, default-features = true } -codec = { version = "3.6.12", package = "parity-scale-codec", default-features = false, features = ["derive"] } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } -hex-literal = { version = "0.4.1", optional = true } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } +hex-literal = { optional = true, workspace = true, default-features = true } log = { workspace = true } -alloy-primitives = { version = "0.4.2", default-features = false, features = ["rlp"] } -alloy-sol-types = { version = "0.4.2", default-features = false } +alloy-primitives = { features = ["rlp"], workspace = true } +alloy-sol-types = { workspace = true } -frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../substrate/frame/system", default-features = false } -pallet-balances = { path = "../../../../substrate/frame/balances", default-features = false } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } -sp-io = { path = "../../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-balances = { workspace = true } +sp-core = { workspace = true } +sp-std = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } -xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../polkadot/xcm/xcm-executor", default-features = false } +xcm = { workspace = true } +xcm-executor = { workspace = true } -snowbridge-core = { path = "../../primitives/core", default-features = false } -snowbridge-router-primitives = { path = "../../primitives/router", default-features = false } -snowbridge-beacon-primitives = { path = "../../primitives/beacon", default-features = false } -snowbridge-pallet-inbound-queue-fixtures = { path = "fixtures", default-features = false, optional = true } +snowbridge-core = { workspace = true } +snowbridge-router-primitives = { workspace = true } +snowbridge-beacon-primitives = { workspace = true } +snowbridge-pallet-inbound-queue-fixtures = { optional = true, workspace = true } [dev-dependencies] -frame-benchmarking = { path = "../../../../substrate/frame/benchmarking" } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -snowbridge-pallet-ethereum-client = { path = "../ethereum-client" } -hex-literal = { version = "0.4.1" } +frame-benchmarking = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +snowbridge-pallet-ethereum-client = { workspace = true, default-features = true } +hex-literal = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml b/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml index e84246fb5a551b2512c4e00cb4ca00171e8c3f75..b66b57c3620ad5488d58b90a8f337ecd88f07e5d 100644 --- a/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml +++ b/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml @@ -15,11 +15,11 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -hex-literal = { version = "0.4.1" } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -snowbridge-core = { path = "../../../primitives/core", default-features = false } -snowbridge-beacon-primitives = { path = "../../../primitives/beacon", default-features = false } +hex-literal = { workspace = true, default-features = true } +sp-core = { workspace = true } +sp-std = { workspace = true } +snowbridge-core = { workspace = true } +snowbridge-beacon-primitives = { workspace = true } [features] default = ["std"] diff --git a/bridges/snowbridge/pallets/outbound-queue/Cargo.toml b/bridges/snowbridge/pallets/outbound-queue/Cargo.toml index 15c6c3a5b32b0fc2bd1a95fd842bab78f07a697a..78546e258daa30e966ddef1ed48c35cebcc17d65 100644 --- a/bridges/snowbridge/pallets/outbound-queue/Cargo.toml +++ b/bridges/snowbridge/pallets/outbound-queue/Cargo.toml @@ -16,27 +16,27 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { features = ["alloc", "derive"], workspace = true } -codec = { version = "3.6.12", package = "parity-scale-codec", default-features = false, features = ["derive"] } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } -frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../substrate/frame/system", default-features = false } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-io = { path = "../../../../substrate/primitives/io", default-features = false } -sp-arithmetic = { path = "../../../../substrate/primitives/arithmetic", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-core = { workspace = true } +sp-std = { workspace = true } +sp-runtime = { workspace = true } +sp-io = { workspace = true } +sp-arithmetic = { workspace = true } -bridge-hub-common = { path = "../../../../cumulus/parachains/runtimes/bridge-hubs/common", default-features = false } +bridge-hub-common = { workspace = true } -snowbridge-core = { path = "../../primitives/core", default-features = false, features = ["serde"] } -snowbridge-outbound-queue-merkle-tree = { path = "merkle-tree", default-features = false } -ethabi = { package = "ethabi-decode", version = "1.0.0", default-features = false } +snowbridge-core = { features = ["serde"], workspace = true } +snowbridge-outbound-queue-merkle-tree = { workspace = true } +ethabi = { workspace = true } [dev-dependencies] -pallet-message-queue = { path = "../../../../substrate/frame/message-queue", default-features = false } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } +pallet-message-queue = { workspace = true } +sp-keyring = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml index 1b1a9905928f8b5ea8eaccc15d18813f87406494..00cc700fbe832cea4e77ddabe3a148c42bd30bef 100644 --- a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml +++ b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml @@ -15,18 +15,18 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { version = "3.6.12", package = "parity-scale-codec", default-features = false, features = ["derive"] } -scale-info = { version = "2.7.0", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } +sp-core = { workspace = true } +sp-runtime = { workspace = true } [dev-dependencies] -hex-literal = { version = "0.4.1" } -env_logger = "0.11" -hex = "0.4" -array-bytes = "6.2.2" -sp-crypto-hashing = { path = "../../../../../substrate/primitives/crypto/hashing" } +hex-literal = { workspace = true, default-features = true } +env_logger = { workspace = true } +hex = { workspace = true, default-features = true } +array-bytes = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/bridges/snowbridge/pallets/outbound-queue/runtime-api/Cargo.toml b/bridges/snowbridge/pallets/outbound-queue/runtime-api/Cargo.toml index b8d704f1cb92d570ea8e8b06cd00410bea7746bb..d35bdde5a81e7a80a228efff19c3c1de0eceefef 100644 --- a/bridges/snowbridge/pallets/outbound-queue/runtime-api/Cargo.toml +++ b/bridges/snowbridge/pallets/outbound-queue/runtime-api/Cargo.toml @@ -15,12 +15,12 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { version = "3.6.12", package = "parity-scale-codec", features = ["derive"], default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -snowbridge-outbound-queue-merkle-tree = { path = "../merkle-tree", default-features = false } -snowbridge-core = { path = "../../../primitives/core", default-features = false } +codec = { features = ["derive"], workspace = true } +sp-std = { workspace = true } +sp-api = { workspace = true } +frame-support = { workspace = true } +snowbridge-outbound-queue-merkle-tree = { workspace = true } +snowbridge-core = { workspace = true } [features] default = ["std"] diff --git a/bridges/snowbridge/pallets/system/Cargo.toml b/bridges/snowbridge/pallets/system/Cargo.toml index 5bbbb1d9310da4c3617ec4b03ea63620c30feb20..f1e749afb9977c440ba7bbfa55c8a8acbc8c0cda 100644 --- a/bridges/snowbridge/pallets/system/Cargo.toml +++ b/bridges/snowbridge/pallets/system/Cargo.toml @@ -15,33 +15,33 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ +codec = { features = [ "derive", -] } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../substrate/frame/system", default-features = false } +], workspace = true } +scale-info = { features = ["derive"], workspace = true } +frame-benchmarking = { optional = true, workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } log = { workspace = true } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } -sp-io = { path = "../../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } +sp-core = { workspace = true } +sp-std = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } -xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../polkadot/xcm/xcm-executor", default-features = false } +xcm = { workspace = true } +xcm-executor = { workspace = true } -snowbridge-core = { path = "../../primitives/core", default-features = false } +snowbridge-core = { workspace = true } [dev-dependencies] -hex = "0.4.1" -hex-literal = { version = "0.4.1" } -pallet-balances = { path = "../../../../substrate/frame/balances" } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -polkadot-primitives = { path = "../../../../polkadot/primitives" } -pallet-message-queue = { path = "../../../../substrate/frame/message-queue" } -snowbridge-pallet-outbound-queue = { path = "../outbound-queue" } +hex = { workspace = true, default-features = true } +hex-literal = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +pallet-message-queue = { workspace = true, default-features = true } +snowbridge-pallet-outbound-queue = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/bridges/snowbridge/pallets/system/runtime-api/Cargo.toml b/bridges/snowbridge/pallets/system/runtime-api/Cargo.toml index 42df5edfb7b2d4e5abaf0e30850ecbd3ebd04b98..7c524dd2edadb6132be50616f7e6855ad463c8b4 100644 --- a/bridges/snowbridge/pallets/system/runtime-api/Cargo.toml +++ b/bridges/snowbridge/pallets/system/runtime-api/Cargo.toml @@ -15,13 +15,13 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ +codec = { features = [ "derive", -] } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -snowbridge-core = { path = "../../../primitives/core", default-features = false } +], workspace = true } +sp-std = { workspace = true } +sp-api = { workspace = true } +xcm = { workspace = true } +snowbridge-core = { workspace = true } [features] default = ["std"] diff --git a/bridges/snowbridge/primitives/beacon/Cargo.toml b/bridges/snowbridge/primitives/beacon/Cargo.toml index 18123910c35b2e198ec03ca1aa01aef1ea0d96ca..9ced99fbf3fdddd8f64877606f957da14c70f608 100644 --- a/bridges/snowbridge/primitives/beacon/Cargo.toml +++ b/bridges/snowbridge/primitives/beacon/Cargo.toml @@ -13,26 +13,26 @@ workspace = true [dependencies] serde = { optional = true, features = ["derive"], workspace = true, default-features = true } -hex = { version = "0.4", default-features = false } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } -rlp = { version = "0.5", default-features = false } +hex = { workspace = true } +codec = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +rlp = { workspace = true } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } -sp-io = { path = "../../../../substrate/primitives/io", default-features = false } +frame-support = { workspace = true } +sp-runtime = { workspace = true } +sp-core = { workspace = true } +sp-std = { workspace = true } +sp-io = { workspace = true } -ssz_rs = { version = "0.9.0", default-features = false } -ssz_rs_derive = { version = "0.9.0", default-features = false } -byte-slice-cast = { version = "1.2.1", default-features = false } +ssz_rs = { workspace = true } +ssz_rs_derive = { workspace = true } +byte-slice-cast = { workspace = true } -snowbridge-ethereum = { path = "../ethereum", default-features = false } -milagro-bls = { package = "snowbridge-milagro-bls", version = "1.5.4", default-features = false } +snowbridge-ethereum = { workspace = true } +milagro-bls = { workspace = true } [dev-dependencies] -hex-literal = { version = "0.4.1" } +hex-literal = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/bridges/snowbridge/primitives/core/Cargo.toml b/bridges/snowbridge/primitives/core/Cargo.toml index 573ab6608e5f91c0333f5ee7288cb679d6c38fb6..f9bee1ff4959ae56f73b50d4c91c2ea2e63bb0a6 100644 --- a/bridges/snowbridge/primitives/core/Cargo.toml +++ b/bridges/snowbridge/primitives/core/Cargo.toml @@ -13,28 +13,28 @@ workspace = true [dependencies] serde = { optional = true, features = ["alloc", "derive"], workspace = true } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } -hex-literal = { version = "0.4.1" } +codec = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +hex-literal = { workspace = true, default-features = true } -polkadot-parachain-primitives = { path = "../../../../polkadot/parachain", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../polkadot/xcm/xcm-builder", default-features = false } +polkadot-parachain-primitives = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../substrate/frame/system", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } -sp-io = { path = "../../../../substrate/primitives/io", default-features = false } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } -sp-arithmetic = { path = "../../../../substrate/primitives/arithmetic", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } +sp-io = { workspace = true } +sp-core = { workspace = true } +sp-arithmetic = { workspace = true } -snowbridge-beacon-primitives = { path = "../beacon", default-features = false } +snowbridge-beacon-primitives = { workspace = true } -ethabi = { package = "ethabi-decode", version = "1.0.0", default-features = false } +ethabi = { workspace = true } [dev-dependencies] -hex = { version = "0.4.3" } +hex = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/bridges/snowbridge/primitives/ethereum/Cargo.toml b/bridges/snowbridge/primitives/ethereum/Cargo.toml index fb0b6cbaf3c2fba82c709fbc84ca565c53e7505e..764ce90b8139d936d16e38a2f337c05004427675 100644 --- a/bridges/snowbridge/primitives/ethereum/Cargo.toml +++ b/bridges/snowbridge/primitives/ethereum/Cargo.toml @@ -14,23 +14,23 @@ workspace = true [dependencies] serde = { optional = true, features = ["derive"], workspace = true, default-features = true } serde-big-array = { optional = true, features = ["const-generics"], workspace = true } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } -ethbloom = { version = "0.13.0", default-features = false } -ethereum-types = { version = "0.14.1", default-features = false, features = ["codec", "rlp", "serialize"] } -hex-literal = { version = "0.4.1", default-features = false } -parity-bytes = { version = "0.1.2", default-features = false } -rlp = { version = "0.5.2", default-features = false } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } +ethbloom = { workspace = true } +ethereum-types = { features = ["codec", "rlp", "serialize"], workspace = true } +hex-literal = { workspace = true } +parity-bytes = { workspace = true } +rlp = { workspace = true } -sp-io = { path = "../../../../substrate/primitives/io", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } +sp-io = { workspace = true } +sp-std = { workspace = true } +sp-runtime = { workspace = true } -ethabi = { package = "ethabi-decode", version = "1.0.0", default-features = false } +ethabi = { workspace = true } [dev-dependencies] -wasm-bindgen-test = "0.3.19" -rand = "0.8.5" +wasm-bindgen-test = { workspace = true } +rand = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } [features] diff --git a/bridges/snowbridge/primitives/router/Cargo.toml b/bridges/snowbridge/primitives/router/Cargo.toml index ec0888dd41b0cd197b49efda9f83e188916fb8fa..ee8d481cec12ae07d107c0463b778345fcfcecee 100644 --- a/bridges/snowbridge/primitives/router/Cargo.toml +++ b/bridges/snowbridge/primitives/router/Cargo.toml @@ -12,25 +12,24 @@ categories = ["cryptography::cryptocurrencies"] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +codec = { workspace = true } +scale-info = { features = ["derive"], workspace = true } log = { workspace = true } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } -sp-io = { path = "../../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } -xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../polkadot/xcm/xcm-executor", default-features = false } +xcm = { workspace = true } +xcm-executor = { workspace = true } -snowbridge-core = { path = "../core", default-features = false } +snowbridge-core = { workspace = true } -hex-literal = { version = "0.4.1" } +hex-literal = { workspace = true, default-features = true } [dev-dependencies] -rustc-hex = { version = "2.1.0" } [features] default = ["std"] diff --git a/bridges/snowbridge/runtime/runtime-common/Cargo.toml b/bridges/snowbridge/runtime/runtime-common/Cargo.toml index 2372908b86ab5134f4ea0f8373ffe00cbcc2bd32..d47cb3cb7101fb54d7bdde854ff73e628555e86b 100644 --- a/bridges/snowbridge/runtime/runtime-common/Cargo.toml +++ b/bridges/snowbridge/runtime/runtime-common/Cargo.toml @@ -13,15 +13,15 @@ workspace = true [dependencies] log = { workspace = true } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } -sp-arithmetic = { path = "../../../../substrate/primitives/arithmetic", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../polkadot/xcm/xcm-executor", default-features = false } +codec = { workspace = true } +frame-support = { workspace = true } +sp-std = { workspace = true } +sp-arithmetic = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } -snowbridge-core = { path = "../../primitives/core", default-features = false } +snowbridge-core = { workspace = true } [dev-dependencies] diff --git a/bridges/snowbridge/runtime/test-common/Cargo.toml b/bridges/snowbridge/runtime/test-common/Cargo.toml index e19c682de4542994e19e20d0c194598fc8009db5..6f8e586bf5ff12e7d870df95ffc6a0f02461357b 100644 --- a/bridges/snowbridge/runtime/test-common/Cargo.toml +++ b/bridges/snowbridge/runtime/test-common/Cargo.toml @@ -11,38 +11,38 @@ categories = ["cryptography::cryptocurrencies"] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } # Substrate -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../substrate/frame/system", default-features = false } -pallet-balances = { path = "../../../../substrate/frame/balances", default-features = false } -pallet-session = { path = "../../../../substrate/frame/session", default-features = false } -pallet-message-queue = { path = "../../../../substrate/frame/message-queue", default-features = false } -pallet-timestamp = { path = "../../../../substrate/frame/timestamp", default-features = false } -pallet-utility = { path = "../../../../substrate/frame/utility", default-features = false } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } -sp-io = { path = "../../../../substrate/primitives/io", default-features = false } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-balances = { workspace = true } +pallet-session = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-utility = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-keyring = { workspace = true, default-features = true } +sp-runtime = { workspace = true } # Polkadot -pallet-xcm = { path = "../../../../polkadot/xcm/pallet-xcm", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../polkadot/xcm/xcm-executor", default-features = false } +pallet-xcm = { workspace = true } +xcm = { workspace = true } +xcm-executor = { workspace = true } # Cumulus -cumulus-pallet-parachain-system = { path = "../../../../cumulus/pallets/parachain-system", default-features = false } -pallet-collator-selection = { path = "../../../../cumulus/pallets/collator-selection", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../../../cumulus/parachains/pallets/parachain-info", default-features = false } -parachains-runtimes-test-utils = { path = "../../../../cumulus/parachains/runtimes/test-utils", default-features = false } +cumulus-pallet-parachain-system = { workspace = true } +pallet-collator-selection = { workspace = true } +parachain-info = { workspace = true } +parachains-runtimes-test-utils = { workspace = true } # Ethereum Bridge (Snowbridge) -snowbridge-core = { path = "../../primitives/core", default-features = false } -snowbridge-pallet-ethereum-client = { path = "../../pallets/ethereum-client", default-features = false } -snowbridge-pallet-ethereum-client-fixtures = { path = "../../pallets/ethereum-client/fixtures", default-features = false } -snowbridge-pallet-outbound-queue = { path = "../../pallets/outbound-queue", default-features = false } -snowbridge-pallet-system = { path = "../../pallets/system", default-features = false } +snowbridge-core = { workspace = true } +snowbridge-pallet-ethereum-client = { workspace = true } +snowbridge-pallet-ethereum-client-fixtures = { workspace = true } +snowbridge-pallet-outbound-queue = { workspace = true } +snowbridge-pallet-system = { workspace = true } [features] default = ["std"] diff --git a/cumulus/bin/pov-validator/Cargo.toml b/cumulus/bin/pov-validator/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..9be92960ad772217635c796f0f7962384aaebfe8 --- /dev/null +++ b/cumulus/bin/pov-validator/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "cumulus-pov-validator" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +repository.workspace = true +license.workspace = true +homepage.workspace = true +description = "A tool for validating PoVs locally" + +[dependencies] +codec.workspace = true +clap = { workspace = true, features = ["derive"] } +sc-executor.workspace = true +sp-io.workspace = true +sp-core.workspace = true +sp-maybe-compressed-blob.workspace = true +polkadot-node-primitives.workspace = true +polkadot-parachain-primitives.workspace = true +polkadot-primitives.workspace = true +anyhow.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true + +[lints] +workspace = true diff --git a/cumulus/bin/pov-validator/src/main.rs b/cumulus/bin/pov-validator/src/main.rs new file mode 100644 index 0000000000000000000000000000000000000000..1c08f218f6b8ae38d86764b6e5ed148944addcd9 --- /dev/null +++ b/cumulus/bin/pov-validator/src/main.rs @@ -0,0 +1,154 @@ +// This file is part of Cumulus. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use clap::Parser; +use codec::{Decode, Encode}; +use polkadot_node_primitives::{BlockData, PoV, POV_BOMB_LIMIT, VALIDATION_CODE_BOMB_LIMIT}; +use polkadot_parachain_primitives::primitives::ValidationParams; +use polkadot_primitives::{BlockNumber as RBlockNumber, Hash as RHash, HeadData}; +use sc_executor::WasmExecutor; +use sp_core::traits::{CallContext, CodeExecutor, RuntimeCode, WrappedRuntimeCode}; +use std::{fs, path::PathBuf, time::Instant}; +use tracing::level_filters::LevelFilter; + +/// Tool for validating a `PoV` locally. +#[derive(Parser)] +struct Cli { + /// The path to the validation code that should be used to validate the `PoV`. + /// + /// The validation code can either be downloaded from the relay chain that the parachain is + /// connected to or by building the runtime manually to obtain the WASM binary. + #[arg(long)] + validation_code: PathBuf, + + /// The path to the `PoV` to validate. + /// + /// The `PoV`'s can be obtained by running `polkadot-parachains --collator --chain YOUR_CHAIN + /// --export-pov-to-path PATH_TO_EXPORT` and then choose one of the exported `PoV`'s. + #[arg(long)] + pov: PathBuf, +} + +fn main() -> anyhow::Result<()> { + let _ = tracing_subscriber::fmt() + .with_env_filter( + tracing_subscriber::EnvFilter::from_default_env() + .add_directive(LevelFilter::INFO.into()), + ) + .with_writer(std::io::stderr) + .try_init(); + + let cli = Cli::parse(); + + let validation_code = fs::read(&cli.validation_code).map_err(|error| { + tracing::error!(%error, path = %cli.validation_code.display(), "Failed to read validation code"); + anyhow::anyhow!("Failed to read validation code") + })?; + + let validation_code = + sp_maybe_compressed_blob::decompress(&validation_code, VALIDATION_CODE_BOMB_LIMIT) + .map_err(|error| { + tracing::error!(%error, "Failed to decompress validation code"); + anyhow::anyhow!("Failed to decompress validation code") + })?; + + let pov_file = fs::read(&cli.pov).map_err(|error| { + tracing::error!(%error, path = %cli.pov.display(), "Failed to read PoV"); + anyhow::anyhow!("Failed to read PoV") + })?; + + let executor = WasmExecutor::::builder() + .with_allow_missing_host_functions(true) + .build(); + + let runtime_code = RuntimeCode { + code_fetcher: &WrappedRuntimeCode(validation_code.into()), + heap_pages: None, + // The hash is used for caching, which we need here, but we only use one wasm file. So, the + // actual hash is not that important. + hash: vec![1, 2, 3], + }; + + // We are calling `Core_version` to get the wasm file compiled. We don't care about the result. + let _ = executor + .call( + &mut sp_io::TestExternalities::default().ext(), + &runtime_code, + "Core_version", + &[], + CallContext::Offchain, + ) + .0; + + let pov_file_ptr = &mut &pov_file[..]; + let pov = PoV::decode(pov_file_ptr).map_err(|error| { + tracing::error!(%error, "Failed to decode `PoV`"); + anyhow::anyhow!("Failed to decode `PoV`") + })?; + let head_data = HeadData::decode(pov_file_ptr).map_err(|error| { + tracing::error!(%error, "Failed to `HeadData`"); + anyhow::anyhow!("Failed to decode `HeadData`") + })?; + let relay_parent_storage_root = RHash::decode(pov_file_ptr).map_err(|error| { + tracing::error!(%error, "Failed to relay storage root"); + anyhow::anyhow!("Failed to decode relay storage root") + })?; + let relay_parent_number = RBlockNumber::decode(pov_file_ptr).map_err(|error| { + tracing::error!(%error, "Failed to relay block number"); + anyhow::anyhow!("Failed to decode relay block number") + })?; + + let pov = sp_maybe_compressed_blob::decompress(&pov.block_data.0, POV_BOMB_LIMIT).map_err( + |error| { + tracing::error!(%error, "Failed to decompress `PoV`"); + anyhow::anyhow!("Failed to decompress `PoV`") + }, + )?; + + let validation_params = ValidationParams { + relay_parent_number, + relay_parent_storage_root, + parent_head: head_data, + block_data: BlockData(pov.into()), + }; + + tracing::info!("Starting validation"); + + let start = Instant::now(); + + let res = executor + .call( + &mut sp_io::TestExternalities::default().ext(), + &runtime_code, + "validate_block", + &validation_params.encode(), + CallContext::Offchain, + ) + .0; + + let duration = start.elapsed(); + + match res { + Ok(_) => tracing::info!("Validation was successful"), + Err(error) => tracing::error!(%error, "Validation failed"), + } + + tracing::info!("Validation took {}ms", duration.as_millis()); + + Ok(()) +} diff --git a/cumulus/client/cli/Cargo.toml b/cumulus/client/cli/Cargo.toml index 410ac8b983d96f0a38633ac0199208a4e249e49b..9b6f6b73960b416c481b43f053477c70e55b8495 100644 --- a/cumulus/client/cli/Cargo.toml +++ b/cumulus/client/cli/Cargo.toml @@ -10,15 +10,15 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -clap = { version = "4.5.3", features = ["derive"] } -codec = { package = "parity-scale-codec", version = "3.6.12" } -url = "2.4.0" +clap = { features = ["derive"], workspace = true } +codec = { workspace = true, default-features = true } +url = { workspace = true } # Substrate -sc-cli = { path = "../../../substrate/client/cli" } -sc-client-api = { path = "../../../substrate/client/api" } -sc-chain-spec = { path = "../../../substrate/client/chain-spec" } -sc-service = { path = "../../../substrate/client/service" } -sp-core = { path = "../../../substrate/primitives/core" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } -sp-blockchain = { path = "../../../substrate/primitives/blockchain" } +sc-cli = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-chain-spec = { workspace = true, default-features = true } +sc-service = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } diff --git a/cumulus/client/collator/Cargo.toml b/cumulus/client/collator/Cargo.toml index 39cedf87a0cb1b6fb8296c1a3bdec1483170af38..6ebde0c2c653b8279ead203bdabeafd3ab8292e1 100644 --- a/cumulus/client/collator/Cargo.toml +++ b/cumulus/client/collator/Cargo.toml @@ -10,41 +10,41 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -parking_lot = "0.12.1" -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } -futures = "0.3.30" -tracing = "0.1.25" +parking_lot = { workspace = true, default-features = true } +codec = { features = ["derive"], workspace = true, default-features = true } +futures = { workspace = true } +tracing = { workspace = true, default-features = true } # Substrate -sc-client-api = { path = "../../../substrate/client/api" } -sp-consensus = { path = "../../../substrate/primitives/consensus/common" } -sp-api = { path = "../../../substrate/primitives/api" } -sp-core = { path = "../../../substrate/primitives/core" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } +sc-client-api = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } # Polkadot -polkadot-node-primitives = { path = "../../../polkadot/node/primitives" } -polkadot-node-subsystem = { path = "../../../polkadot/node/subsystem" } -polkadot-overseer = { path = "../../../polkadot/node/overseer" } -polkadot-primitives = { path = "../../../polkadot/primitives" } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-overseer = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } # Cumulus -cumulus-client-consensus-common = { path = "../consensus/common" } -cumulus-client-network = { path = "../network" } -cumulus-primitives-core = { path = "../../primitives/core" } +cumulus-client-consensus-common = { workspace = true, default-features = true } +cumulus-client-network = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true, default-features = true } [dev-dependencies] -async-trait = "0.1.79" +async-trait = { workspace = true } # Substrate -sp-maybe-compressed-blob = { path = "../../../substrate/primitives/maybe-compressed-blob" } -sp-state-machine = { path = "../../../substrate/primitives/state-machine" } -sp-tracing = { path = "../../../substrate/primitives/tracing" } +sp-maybe-compressed-blob = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } # Polkadot -polkadot-node-subsystem-test-helpers = { path = "../../../polkadot/node/subsystem-test-helpers" } +polkadot-node-subsystem-test-helpers = { workspace = true } # Cumulus -cumulus-test-client = { path = "../../test/client" } -cumulus-test-runtime = { path = "../../test/runtime" } -cumulus-test-relay-sproof-builder = { path = "../../test/relay-sproof-builder" } +cumulus-test-client = { workspace = true } +cumulus-test-runtime = { workspace = true } +cumulus-test-relay-sproof-builder = { workspace = true, default-features = true } diff --git a/cumulus/client/consensus/aura/Cargo.toml b/cumulus/client/consensus/aura/Cargo.toml index fad30e59e869d3a4144b33cdd34c6b73990d7e9f..01e07cb395a955dfe3016aef3c8bd3ac5e2be7c9 100644 --- a/cumulus/client/consensus/aura/Cargo.toml +++ b/cumulus/client/consensus/aura/Cargo.toml @@ -10,44 +10,47 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } -futures = "0.3.28" -tracing = "0.1.37" -schnellru = "0.2.1" +async-trait = { workspace = true } +codec = { features = ["derive"], workspace = true, default-features = true } +futures = { workspace = true } +parking_lot = { workspace = true } +tracing = { workspace = true, default-features = true } +schnellru = { workspace = true } +tokio = { workspace = true, features = ["macros"] } # Substrate -sc-client-api = { path = "../../../../substrate/client/api" } -sc-consensus = { path = "../../../../substrate/client/consensus/common" } -sc-consensus-aura = { path = "../../../../substrate/client/consensus/aura" } -sc-consensus-babe = { path = "../../../../substrate/client/consensus/babe" } -sc-consensus-slots = { path = "../../../../substrate/client/consensus/slots" } -sc-telemetry = { path = "../../../../substrate/client/telemetry" } -sp-api = { path = "../../../../substrate/primitives/api" } -sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto" } -sp-block-builder = { path = "../../../../substrate/primitives/block-builder" } -sp-blockchain = { path = "../../../../substrate/primitives/blockchain" } -sp-consensus = { path = "../../../../substrate/primitives/consensus/common" } -sp-consensus-aura = { path = "../../../../substrate/primitives/consensus/aura" } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-inherents = { path = "../../../../substrate/primitives/inherents" } -sp-keystore = { path = "../../../../substrate/primitives/keystore" } -sp-runtime = { path = "../../../../substrate/primitives/runtime" } -sp-timestamp = { path = "../../../../substrate/primitives/timestamp" } -sp-state-machine = { path = "../../../../substrate/primitives/state-machine" } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../../substrate/utils/prometheus" } +sc-client-api = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sc-consensus-aura = { workspace = true, default-features = true } +sc-consensus-babe = { workspace = true, default-features = true } +sc-consensus-slots = { workspace = true, default-features = true } +sc-utils = { workspace = true, default-features = true } +sc-telemetry = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-block-builder = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-consensus-aura = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-timestamp = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } +prometheus-endpoint = { workspace = true, default-features = true } # Cumulus -cumulus-client-consensus-common = { path = "../common" } -cumulus-relay-chain-interface = { path = "../../relay-chain-interface" } -cumulus-client-consensus-proposer = { path = "../proposer" } -cumulus-client-parachain-inherent = { path = "../../parachain-inherent" } -cumulus-primitives-aura = { path = "../../../primitives/aura" } -cumulus-primitives-core = { path = "../../../primitives/core" } -cumulus-client-collator = { path = "../../collator" } +cumulus-client-consensus-common = { workspace = true, default-features = true } +cumulus-relay-chain-interface = { workspace = true, default-features = true } +cumulus-client-consensus-proposer = { workspace = true, default-features = true } +cumulus-client-parachain-inherent = { workspace = true, default-features = true } +cumulus-primitives-aura = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true, default-features = true } +cumulus-client-collator = { workspace = true, default-features = true } # Polkadot -polkadot-primitives = { path = "../../../../polkadot/primitives" } -polkadot-node-primitives = { path = "../../../../polkadot/node/primitives" } -polkadot-node-subsystem = { path = "../../../../polkadot/node/subsystem" } -polkadot-overseer = { path = "../../../../polkadot/node/overseer" } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-overseer = { workspace = true, default-features = true } diff --git a/cumulus/client/consensus/aura/src/collator.rs b/cumulus/client/consensus/aura/src/collator.rs index 776052215d9397c529699ed07040819f666e16b5..dc830e463a4f5bca1f39ec82a11d5364b148c675 100644 --- a/cumulus/client/consensus/aura/src/collator.rs +++ b/cumulus/client/consensus/aura/src/collator.rs @@ -156,15 +156,8 @@ where Ok((paras_inherent_data, other_inherent_data)) } - /// Propose, seal, and import a block, packaging it into a collation. - /// - /// Provide the slot to build at as well as any other necessary pre-digest logs, - /// the inherent data, and the proposal duration and PoV size limits. - /// - /// The Aura pre-digest should not be explicitly provided and is set internally. - /// - /// This does not announce the collation to the parachain network or the relay chain. - pub async fn collate( + /// Build and import a parachain block on the given parent header, using the given slot claim. + pub async fn build_block_and_import( &mut self, parent_header: &Block::Header, slot_claim: &SlotClaim, @@ -172,10 +165,7 @@ where inherent_data: (ParachainInherentData, InherentData), proposal_duration: Duration, max_pov_size: usize, - ) -> Result< - Option<(Collation, ParachainBlockData, Block::Hash)>, - Box, - > { + ) -> Result>, Box> { let mut digest = additional_pre_digest.into().unwrap_or_default(); digest.push(slot_claim.pre_digest.clone()); @@ -205,7 +195,6 @@ where ) .map_err(|e| e as Box)?; - let post_hash = sealed_importable.post_hash(); let block = Block::new( sealed_importable.post_header(), sealed_importable @@ -220,11 +209,46 @@ where .map_err(|e| Box::new(e) as Box) .await?; - if let Some((collation, block_data)) = self.collator_service.build_collation( - parent_header, - post_hash, - ParachainCandidate { block, proof: proposal.proof }, - ) { + Ok(Some(ParachainCandidate { block, proof: proposal.proof })) + } + + /// Propose, seal, import a block and packaging it into a collation. + /// + /// Provide the slot to build at as well as any other necessary pre-digest logs, + /// the inherent data, and the proposal duration and PoV size limits. + /// + /// The Aura pre-digest should not be explicitly provided and is set internally. + /// + /// This does not announce the collation to the parachain network or the relay chain. + pub async fn collate( + &mut self, + parent_header: &Block::Header, + slot_claim: &SlotClaim, + additional_pre_digest: impl Into>>, + inherent_data: (ParachainInherentData, InherentData), + proposal_duration: Duration, + max_pov_size: usize, + ) -> Result< + Option<(Collation, ParachainBlockData, Block::Hash)>, + Box, + > { + let maybe_candidate = self + .build_block_and_import( + parent_header, + slot_claim, + additional_pre_digest, + inherent_data, + proposal_duration, + max_pov_size, + ) + .await?; + + let Some(candidate) = maybe_candidate else { return Ok(None) }; + + let hash = candidate.block.header().hash(); + if let Some((collation, block_data)) = + self.collator_service.build_collation(parent_header, hash, candidate) + { tracing::info!( target: crate::LOG_TARGET, "PoV size {{ header: {}kb, extrinsics: {}kb, storage_proof: {}kb }}", @@ -241,7 +265,7 @@ where ); } - Ok(Some((collation, block_data, post_hash))) + Ok(Some((collation, block_data, hash))) } else { Err(Box::::from("Unable to produce collation") as Box) diff --git a/cumulus/client/consensus/aura/src/collators/basic.rs b/cumulus/client/consensus/aura/src/collators/basic.rs index 1047c6219ad132403014cacaf3d071d8009b9dbc..4efd50a04ec6ec654ce7b32ac17eb07d12df3d6c 100644 --- a/cumulus/client/consensus/aura/src/collators/basic.rs +++ b/cumulus/client/consensus/aura/src/collators/basic.rs @@ -41,7 +41,6 @@ use sc_consensus::BlockImport; use sp_api::{CallApiAt, ProvideRuntimeApi}; use sp_application_crypto::AppPublic; use sp_blockchain::HeaderBackend; -use sp_consensus::SyncOracle; use sp_consensus_aura::AuraApi; use sp_core::crypto::Pair; use sp_inherents::CreateInherentDataProviders; @@ -53,7 +52,7 @@ use std::{sync::Arc, time::Duration}; use crate::collator as collator_util; /// Parameters for [`run`]. -pub struct Params { +pub struct Params { /// Inherent data providers. Only non-consensus inherent data should be provided, i.e. /// the timestamp, slot, and paras inherents should be omitted, as they are set by this /// collator. @@ -64,8 +63,6 @@ pub struct Params { pub para_client: Arc, /// A handle to the relay-chain client. pub relay_client: RClient, - /// A chain synchronization oracle. - pub sync_oracle: SO, /// The underlying keystore, which should contain Aura consensus keys. pub keystore: KeystorePtr, /// The collator key used to sign collations before submitting to validators. @@ -89,8 +86,8 @@ pub struct Params { } /// Run bare Aura consensus as a relay-chain-driven collator. -pub fn run( - params: Params, +pub fn run( + params: Params, ) -> impl Future + Send + 'static where Block: BlockT + Send, @@ -108,7 +105,6 @@ where CIDP: CreateInherentDataProviders + Send + 'static, CIDP::InherentDataProviders: Send, BI: BlockImport + ParachainBlockImportMarker + Send + Sync + 'static, - SO: SyncOracle + Send + Sync + Clone + 'static, Proposer: ProposerInterface + Send + Sync + 'static, CS: CollatorServiceInterface + Send + Sync + 'static, P: Pair, diff --git a/cumulus/client/consensus/aura/src/collators/lookahead.rs b/cumulus/client/consensus/aura/src/collators/lookahead.rs index b6f7b07f55d3e4f2f779b7d90f933b5f897a8079..02d60538a7323b86948c4378c7d0d4cd5c634116 100644 --- a/cumulus/client/consensus/aura/src/collators/lookahead.rs +++ b/cumulus/client/consensus/aura/src/collators/lookahead.rs @@ -33,46 +33,76 @@ use codec::{Codec, Encode}; use cumulus_client_collator::service::ServiceInterface as CollatorServiceInterface; -use cumulus_client_consensus_common::{ - self as consensus_common, load_abridged_host_configuration, ParachainBlockImportMarker, - ParentSearchParams, -}; +use cumulus_client_consensus_common::{self as consensus_common, ParachainBlockImportMarker}; use cumulus_client_consensus_proposer::ProposerInterface; use cumulus_primitives_aura::AuraUnincludedSegmentApi; -use cumulus_primitives_core::{ - relay_chain::Hash as PHash, CollectCollationInfo, PersistedValidationData, -}; +use cumulus_primitives_core::{CollectCollationInfo, PersistedValidationData}; use cumulus_relay_chain_interface::RelayChainInterface; -use polkadot_node_primitives::SubmitCollationParams; -use polkadot_node_subsystem::messages::{ - CollationGenerationMessage, RuntimeApiMessage, RuntimeApiRequest, -}; +use polkadot_node_primitives::{PoV, SubmitCollationParams}; +use polkadot_node_subsystem::messages::CollationGenerationMessage; use polkadot_overseer::Handle as OverseerHandle; use polkadot_primitives::{ - AsyncBackingParams, CollatorPair, CoreIndex, CoreState, Id as ParaId, OccupiedCoreAssumption, + BlockNumber as RBlockNumber, CollatorPair, Hash as RHash, HeadData, Id as ParaId, + OccupiedCoreAssumption, }; -use futures::{channel::oneshot, prelude::*}; +use futures::prelude::*; use sc_client_api::{backend::AuxStore, BlockBackend, BlockOf}; use sc_consensus::BlockImport; -use sc_consensus_aura::standalone as aura_internal; use sp_api::ProvideRuntimeApi; use sp_application_crypto::AppPublic; use sp_blockchain::HeaderBackend; -use sp_consensus::SyncOracle; use sp_consensus_aura::{AuraApi, Slot}; use sp_core::crypto::Pair; use sp_inherents::CreateInherentDataProviders; use sp_keystore::KeystorePtr; -use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Member}; -use sp_timestamp::Timestamp; -use std::{sync::Arc, time::Duration}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Member, NumberFor}; +use std::{ + fs::{self, File}, + path::PathBuf, + sync::Arc, + time::Duration, +}; -use crate::collator::{self as collator_util, SlotClaim}; +use crate::{collator as collator_util, LOG_TARGET}; + +/// Export the given `pov` to the file system at `path`. +/// +/// The file will be named `block_hash_block_number.pov`. +/// +/// The `parent_header`, `relay_parent_storage_root` and `relay_parent_number` will also be +/// stored in the file alongside the `pov`. This enables stateless validation of the `pov`. +fn export_pov_to_path( + path: PathBuf, + pov: PoV, + block_hash: Block::Hash, + block_number: NumberFor, + parent_header: Block::Header, + relay_parent_storage_root: RHash, + relay_parent_number: RBlockNumber, +) { + if let Err(error) = fs::create_dir_all(&path) { + tracing::error!(target: LOG_TARGET, %error, path = %path.display(), "Failed to create PoV export directory"); + return + } + + let mut file = match File::create(path.join(format!("{block_hash:?}_{block_number}.pov"))) { + Ok(f) => f, + Err(error) => { + tracing::error!(target: LOG_TARGET, %error, "Failed to export PoV."); + return + }, + }; + + pov.encode_to(&mut file); + HeadData(parent_header.encode()).encode_to(&mut file); + relay_parent_storage_root.encode_to(&mut file); + relay_parent_number.encode_to(&mut file); +} /// Parameters for [`run`]. -pub struct Params { +pub struct Params { /// Inherent data providers. Only non-consensus inherent data should be provided, i.e. /// the timestamp, slot, and paras inherents should be omitted, as they are set by this /// collator. @@ -87,8 +117,6 @@ pub struct Params { pub relay_client: RClient, /// A validation code hash provider, used to get the current validation code hash. pub code_hash_provider: CHP, - /// A chain synchronization oracle. - pub sync_oracle: SO, /// The underlying keystore, which should contain Aura consensus keys. pub keystore: KeystorePtr, /// The collator key used to sign collations before submitting to validators. @@ -110,8 +138,8 @@ pub struct Params { } /// Run async-backing-friendly Aura. -pub fn run( - mut params: Params, +pub fn run( + params: Params, ) -> impl Future + Send + 'static where Block: BlockT, @@ -130,7 +158,6 @@ where CIDP: CreateInherentDataProviders + 'static, CIDP::InherentDataProviders: Send, BI: BlockImport + ParachainBlockImportMarker + Send + Sync + 'static, - SO: SyncOracle + Send + Sync + Clone + 'static, Proposer: ProposerInterface + Send + Sync + 'static, CS: CollatorServiceInterface + Send + Sync + 'static, CHP: consensus_common::ValidationCodeHashProvider + Send + 'static, @@ -138,14 +165,57 @@ where P::Public: AppPublic + Member + Codec, P::Signature: TryFrom> + Member + Codec, { - // This is an arbitrary value which is likely guaranteed to exceed any reasonable - // limit, as it would correspond to 10 non-included blocks. - // - // Since we only search for parent blocks which have already been imported, - // we can guarantee that all imported blocks respect the unincluded segment - // rules specified by the parachain's runtime and thus will never be too deep. - const PARENT_SEARCH_DEPTH: usize = 10; + run_with_export::<_, P, _, _, _, _, _, _, _, _>(ParamsWithExport { params, export_pov: None }) +} +/// Parameters for [`run_with_export`]. +pub struct ParamsWithExport { + /// The parameters. + pub params: Params, + /// When set, the collator will export every produced `POV` to this folder. + pub export_pov: Option, +} + +/// Run async-backing-friendly Aura. +/// +/// This is exactly the same as [`run`], but it supports the optional export of each produced `POV` +/// to the file system. +pub fn run_with_export( + ParamsWithExport { mut params, export_pov }: ParamsWithExport< + BI, + CIDP, + Client, + Backend, + RClient, + CHP, + Proposer, + CS, + >, +) -> impl Future + Send + 'static +where + Block: BlockT, + Client: ProvideRuntimeApi + + BlockOf + + AuxStore + + HeaderBackend + + BlockBackend + + Send + + Sync + + 'static, + Client::Api: + AuraApi + CollectCollationInfo + AuraUnincludedSegmentApi, + Backend: sc_client_api::Backend + 'static, + RClient: RelayChainInterface + Clone + 'static, + CIDP: CreateInherentDataProviders + 'static, + CIDP::InherentDataProviders: Send, + BI: BlockImport + ParachainBlockImportMarker + Send + Sync + 'static, + Proposer: ProposerInterface + Send + Sync + 'static, + CS: CollatorServiceInterface + Send + Sync + 'static, + CHP: consensus_common::ValidationCodeHashProvider + Send + 'static, + P: Pair, + P::Public: AppPublic + Member + Codec, + P::Signature: TryFrom> + Member + Codec, +{ async move { cumulus_client_collator::initialize_collator_subsystems( &mut params.overseer_handle, @@ -186,12 +256,9 @@ where while let Some(relay_parent_header) = import_notifications.next().await { let relay_parent = relay_parent_header.hash(); - // TODO: Currently we use just the first core here, but for elastic scaling - // we iterate and build on all of the cores returned. - let core_index = if let Some(core_index) = cores_scheduled_for_para( + let core_index = if let Some(core_index) = super::cores_scheduled_for_para( relay_parent, params.para_id, - &mut params.overseer_handle, &mut params.relay_client, ) .await @@ -226,42 +293,16 @@ where }, }; - let parent_search_params = ParentSearchParams { + let (included_block, initial_parent) = match crate::collators::find_parent( relay_parent, - para_id: params.para_id, - ancestry_lookback: async_backing_params(relay_parent, ¶ms.relay_client) - .await - .map(|c| c.allowed_ancestry_len as usize) - .unwrap_or(0), - max_depth: PARENT_SEARCH_DEPTH, - ignore_alternative_branches: true, - }; - - let potential_parents = - cumulus_client_consensus_common::find_potential_parents::( - parent_search_params, - &*params.para_backend, - ¶ms.relay_client, - ) - .await; - - let mut potential_parents = match potential_parents { - Err(e) => { - tracing::error!( - target: crate::LOG_TARGET, - ?relay_parent, - err = ?e, - "Could not fetch potential parents to build upon" - ); - - continue - }, - Ok(x) => x, - }; - - let included_block = match potential_parents.iter().find(|x| x.depth == 0) { - None => continue, // also serves as an `is_empty` check. - Some(b) => b.hash, + params.para_id, + &*params.para_backend, + ¶ms.relay_client, + ) + .await + { + Some(value) => value, + None => continue, }; let para_client = &*params.para_client; @@ -292,7 +333,7 @@ where relay_chain_slot_duration = ?params.relay_chain_slot_duration, "Adjusted relay-chain slot to parachain slot" ); - Some(can_build_upon::<_, _, P>( + Some(super::can_build_upon::<_, _, P>( slot_now, timestamp, block_hash, @@ -302,13 +343,6 @@ where )) }; - // Sort by depth, ascending, to choose the longest chain. - // - // If the longest chain has space, build upon that. Otherwise, don't - // build at all. - potential_parents.sort_by_key(|a| a.depth); - let Some(initial_parent) = potential_parents.pop() else { continue }; - // Build in a loop until not allowed. Note that the authorities can change // at any block, so we need to re-claim our slot every time. let mut parent_hash = initial_parent.hash; @@ -398,6 +432,18 @@ where // and provides sybil-resistance, as it should. collator.collator_service().announce_block(new_block_hash, None); + if let Some(ref export_pov) = export_pov { + export_pov_to_path::( + export_pov.clone(), + collation.proof_of_validity.clone().into_compressed(), + new_block_hash, + *block_data.header().number(), + parent_header.clone(), + *relay_parent_header.state_root(), + *relay_parent_header.number(), + ); + } + // Send a submit-collation message to the collation generation subsystem, // which then distributes this to validators. // @@ -435,124 +481,3 @@ where } } } - -// Checks if we own the slot at the given block and whether there -// is space in the unincluded segment. -async fn can_build_upon( - slot: Slot, - timestamp: Timestamp, - parent_hash: Block::Hash, - included_block: Block::Hash, - client: &Client, - keystore: &KeystorePtr, -) -> Option> -where - Client: ProvideRuntimeApi, - Client::Api: AuraApi + AuraUnincludedSegmentApi, - P: Pair, - P::Public: Codec, - P::Signature: Codec, -{ - let runtime_api = client.runtime_api(); - let authorities = runtime_api.authorities(parent_hash).ok()?; - let author_pub = aura_internal::claim_slot::

(slot, &authorities, keystore).await?; - - // Here we lean on the property that building on an empty unincluded segment must always - // be legal. Skipping the runtime API query here allows us to seamlessly run this - // collator against chains which have not yet upgraded their runtime. - if parent_hash != included_block { - if !runtime_api.can_build_upon(parent_hash, included_block, slot).ok()? { - return None - } - } - - Some(SlotClaim::unchecked::

(author_pub, slot, timestamp)) -} - -/// Reads async backing parameters from the relay chain storage at the given relay parent. -async fn async_backing_params( - relay_parent: PHash, - relay_client: &impl RelayChainInterface, -) -> Option { - match load_abridged_host_configuration(relay_parent, relay_client).await { - Ok(Some(config)) => Some(config.async_backing_params), - Ok(None) => { - tracing::error!( - target: crate::LOG_TARGET, - "Active config is missing in relay chain storage", - ); - None - }, - Err(err) => { - tracing::error!( - target: crate::LOG_TARGET, - ?err, - ?relay_parent, - "Failed to read active config from relay chain client", - ); - None - }, - } -} - -// Return all the cores assigned to the para at the provided relay parent. -async fn cores_scheduled_for_para( - relay_parent: PHash, - para_id: ParaId, - overseer_handle: &mut OverseerHandle, - relay_client: &impl RelayChainInterface, -) -> Vec { - // Get `AvailabilityCores` from runtime - let (tx, rx) = oneshot::channel(); - let request = RuntimeApiRequest::AvailabilityCores(tx); - overseer_handle - .send_msg(RuntimeApiMessage::Request(relay_parent, request), "LookaheadCollator") - .await; - - let cores = match rx.await { - Ok(Ok(cores)) => cores, - Ok(Err(error)) => { - tracing::error!( - target: crate::LOG_TARGET, - ?error, - ?relay_parent, - "Failed to query availability cores runtime API", - ); - return Vec::new() - }, - Err(oneshot::Canceled) => { - tracing::error!( - target: crate::LOG_TARGET, - ?relay_parent, - "Sender for availability cores runtime request dropped", - ); - return Vec::new() - }, - }; - - let max_candidate_depth = async_backing_params(relay_parent, relay_client) - .await - .map(|c| c.max_candidate_depth) - .unwrap_or(0); - - cores - .iter() - .enumerate() - .filter_map(|(index, core)| { - let core_para_id = match core { - CoreState::Scheduled(scheduled_core) => Some(scheduled_core.para_id), - CoreState::Occupied(occupied_core) if max_candidate_depth >= 1 => occupied_core - .next_up_on_available - .as_ref() - .map(|scheduled_core| scheduled_core.para_id), - CoreState::Free | CoreState::Occupied(_) => None, - }; - - if core_para_id == Some(para_id) { - Some(CoreIndex(index as u32)) - } else { - None - } - }) - .collect() -} diff --git a/cumulus/client/consensus/aura/src/collators/mod.rs b/cumulus/client/consensus/aura/src/collators/mod.rs index 0abc034c1ed6baf051d04d1ff04680c3192acbf3..7d430ecdc727ab2c44b84bec509938a22da4c3f8 100644 --- a/cumulus/client/consensus/aura/src/collators/mod.rs +++ b/cumulus/client/consensus/aura/src/collators/mod.rs @@ -20,13 +20,35 @@ //! included parachain block, as well as the [`lookahead`] collator, which prospectively //! builds on parachain blocks which have not yet been included in the relay chain. +use crate::collator::SlotClaim; +use codec::Codec; +use cumulus_client_consensus_common::{ + self as consensus_common, load_abridged_host_configuration, ParentSearchParams, +}; +use cumulus_primitives_aura::{AuraUnincludedSegmentApi, Slot}; +use cumulus_primitives_core::{relay_chain::Hash as ParaHash, BlockT}; use cumulus_relay_chain_interface::RelayChainInterface; use polkadot_primitives::{ - Hash as RHash, Id as ParaId, OccupiedCoreAssumption, ValidationCodeHash, + AsyncBackingParams, CoreIndex, CoreState, Hash as RelayHash, Id as ParaId, + OccupiedCoreAssumption, ValidationCodeHash, }; +use sc_consensus_aura::{standalone as aura_internal, AuraApi}; +use sp_api::ProvideRuntimeApi; +use sp_core::Pair; +use sp_keystore::KeystorePtr; +use sp_timestamp::Timestamp; pub mod basic; pub mod lookahead; +pub mod slot_based; + +// This is an arbitrary value which is likely guaranteed to exceed any reasonable +// limit, as it would correspond to 10 non-included blocks. +// +// Since we only search for parent blocks which have already been imported, +// we can guarantee that all imported blocks respect the unincluded segment +// rules specified by the parachain's runtime and thus will never be too deep. +const PARENT_SEARCH_DEPTH: usize = 10; /// Check the `local_validation_code_hash` against the validation code hash in the relay chain /// state. @@ -36,7 +58,7 @@ async fn check_validation_code_or_log( local_validation_code_hash: &ValidationCodeHash, para_id: ParaId, relay_client: &impl RelayChainInterface, - relay_parent: RHash, + relay_parent: RelayHash, ) { let state_validation_code_hash = match relay_client .validation_code_hash(relay_parent, para_id, OccupiedCoreAssumption::Included) @@ -77,3 +99,159 @@ async fn check_validation_code_or_log( }, } } + +/// Reads async backing parameters from the relay chain storage at the given relay parent. +async fn async_backing_params( + relay_parent: RelayHash, + relay_client: &impl RelayChainInterface, +) -> Option { + match load_abridged_host_configuration(relay_parent, relay_client).await { + Ok(Some(config)) => Some(config.async_backing_params), + Ok(None) => { + tracing::error!( + target: crate::LOG_TARGET, + "Active config is missing in relay chain storage", + ); + None + }, + Err(err) => { + tracing::error!( + target: crate::LOG_TARGET, + ?err, + ?relay_parent, + "Failed to read active config from relay chain client", + ); + None + }, + } +} + +// Return all the cores assigned to the para at the provided relay parent. +async fn cores_scheduled_for_para( + relay_parent: RelayHash, + para_id: ParaId, + relay_client: &impl RelayChainInterface, +) -> Vec { + // Get `AvailabilityCores` from runtime + let cores = match relay_client.availability_cores(relay_parent).await { + Ok(cores) => cores, + Err(error) => { + tracing::error!( + target: crate::LOG_TARGET, + ?error, + ?relay_parent, + "Failed to query availability cores runtime API", + ); + return Vec::new() + }, + }; + + let max_candidate_depth = async_backing_params(relay_parent, relay_client) + .await + .map(|c| c.max_candidate_depth) + .unwrap_or(0); + + cores + .iter() + .enumerate() + .filter_map(|(index, core)| { + let core_para_id = match core { + CoreState::Scheduled(scheduled_core) => Some(scheduled_core.para_id), + CoreState::Occupied(occupied_core) if max_candidate_depth > 0 => occupied_core + .next_up_on_available + .as_ref() + .map(|scheduled_core| scheduled_core.para_id), + CoreState::Free | CoreState::Occupied(_) => None, + }; + + if core_para_id == Some(para_id) { + Some(CoreIndex(index as u32)) + } else { + None + } + }) + .collect() +} + +// Checks if we own the slot at the given block and whether there +// is space in the unincluded segment. +async fn can_build_upon( + slot: Slot, + timestamp: Timestamp, + parent_hash: Block::Hash, + included_block: Block::Hash, + client: &Client, + keystore: &KeystorePtr, +) -> Option> +where + Client: ProvideRuntimeApi, + Client::Api: AuraApi + AuraUnincludedSegmentApi, + P: Pair, + P::Public: Codec, + P::Signature: Codec, +{ + let runtime_api = client.runtime_api(); + let authorities = runtime_api.authorities(parent_hash).ok()?; + let author_pub = aura_internal::claim_slot::

(slot, &authorities, keystore).await?; + + // Here we lean on the property that building on an empty unincluded segment must always + // be legal. Skipping the runtime API query here allows us to seamlessly run this + // collator against chains which have not yet upgraded their runtime. + if parent_hash != included_block && + !runtime_api.can_build_upon(parent_hash, included_block, slot).ok()? + { + return None + } + + Some(SlotClaim::unchecked::

(author_pub, slot, timestamp)) +} + +/// Use [`cumulus_client_consensus_common::find_potential_parents`] to find parachain blocks that +/// we can build on. Once a list of potential parents is retrieved, return the last one of the +/// longest chain. +async fn find_parent( + relay_parent: ParaHash, + para_id: ParaId, + para_backend: &impl sc_client_api::Backend, + relay_client: &impl RelayChainInterface, +) -> Option<(::Hash, consensus_common::PotentialParent)> +where + Block: BlockT, +{ + let parent_search_params = ParentSearchParams { + relay_parent, + para_id, + ancestry_lookback: crate::collators::async_backing_params(relay_parent, relay_client) + .await + .map_or(0, |params| params.allowed_ancestry_len as usize), + max_depth: PARENT_SEARCH_DEPTH, + ignore_alternative_branches: true, + }; + + let potential_parents = cumulus_client_consensus_common::find_potential_parents::( + parent_search_params, + para_backend, + relay_client, + ) + .await; + + let potential_parents = match potential_parents { + Err(e) => { + tracing::error!( + target: crate::LOG_TARGET, + ?relay_parent, + err = ?e, + "Could not fetch potential parents to build upon" + ); + + return None + }, + Ok(x) => x, + }; + + let included_block = potential_parents.iter().find(|x| x.depth == 0)?.hash; + potential_parents + .into_iter() + .max_by_key(|a| a.depth) + .map(|parent| (included_block, parent)) +} diff --git a/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs b/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs new file mode 100644 index 0000000000000000000000000000000000000000..1fbc0689da862999367a0c4a9bda59ed3d6525af --- /dev/null +++ b/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs @@ -0,0 +1,491 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +use codec::{Codec, Encode}; + +use cumulus_client_collator::service::ServiceInterface as CollatorServiceInterface; +use cumulus_client_consensus_common::{self as consensus_common, ParachainBlockImportMarker}; +use cumulus_client_consensus_proposer::ProposerInterface; +use cumulus_primitives_aura::AuraUnincludedSegmentApi; +use cumulus_primitives_core::{CollectCollationInfo, PersistedValidationData}; +use cumulus_relay_chain_interface::RelayChainInterface; + +use polkadot_primitives::{ + BlockId, CoreIndex, Hash as RelayHash, Header as RelayHeader, Id as ParaId, + OccupiedCoreAssumption, +}; + +use futures::prelude::*; +use sc_client_api::{backend::AuxStore, BlockBackend, BlockOf, UsageProvider}; +use sc_consensus::BlockImport; +use sp_api::ProvideRuntimeApi; +use sp_application_crypto::AppPublic; +use sp_blockchain::HeaderBackend; +use sp_consensus_aura::{AuraApi, Slot, SlotDuration}; +use sp_core::crypto::Pair; +use sp_inherents::CreateInherentDataProviders; +use sp_keystore::KeystorePtr; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Member}; +use sp_timestamp::Timestamp; +use std::{sync::Arc, time::Duration}; + +use super::CollatorMessage; +use crate::{ + collator::{self as collator_util}, + collators::{check_validation_code_or_log, cores_scheduled_for_para}, + LOG_TARGET, +}; + +/// Parameters for [`run_block_builder`]. +pub struct BuilderTaskParams< + Block: BlockT, + BI, + CIDP, + Client, + Backend, + RelayClient, + CHP, + Proposer, + CS, +> { + /// Inherent data providers. Only non-consensus inherent data should be provided, i.e. + /// the timestamp, slot, and paras inherents should be omitted, as they are set by this + /// collator. + pub create_inherent_data_providers: CIDP, + /// Used to actually import blocks. + pub block_import: BI, + /// The underlying para client. + pub para_client: Arc, + /// The para client's backend, used to access the database. + pub para_backend: Arc, + /// A handle to the relay-chain client. + pub relay_client: RelayClient, + /// A validation code hash provider, used to get the current validation code hash. + pub code_hash_provider: CHP, + /// The underlying keystore, which should contain Aura consensus keys. + pub keystore: KeystorePtr, + /// The para's ID. + pub para_id: ParaId, + /// The underlying block proposer this should call into. + pub proposer: Proposer, + /// The generic collator service used to plug into this consensus engine. + pub collator_service: CS, + /// The amount of time to spend authoring each block. + pub authoring_duration: Duration, + /// Channel to send built blocks to the collation task. + pub collator_sender: sc_utils::mpsc::TracingUnboundedSender>, + /// Slot duration of the relay chain + pub relay_chain_slot_duration: Duration, + /// Drift every slot by this duration. + /// This is a time quantity that is subtracted from the actual timestamp when computing + /// the time left to enter a new slot. In practice, this *left-shifts* the clock time with the + /// intent to keep our "clock" slightly behind the relay chain one and thus reducing the + /// likelihood of encountering unfavorable notification arrival timings (i.e. we don't want to + /// wait for relay chain notifications because we woke up too early). + pub slot_drift: Duration, +} + +#[derive(Debug)] +struct SlotInfo { + pub timestamp: Timestamp, + pub slot: Slot, + pub slot_duration: SlotDuration, +} + +#[derive(Debug)] +struct SlotTimer { + client: Arc, + drift: Duration, + _marker: std::marker::PhantomData<(Block, Box)>, +} + +/// Returns current duration since Unix epoch. +fn duration_now() -> Duration { + use std::time::SystemTime; + let now = SystemTime::now(); + now.duration_since(SystemTime::UNIX_EPOCH).unwrap_or_else(|e| { + panic!("Current time {:?} is before Unix epoch. Something is wrong: {:?}", now, e) + }) +} + +/// Returns the duration until the next slot from now. +fn time_until_next_slot(slot_duration: Duration, drift: Duration) -> Duration { + let now = duration_now().as_millis() - drift.as_millis(); + + let next_slot = (now + slot_duration.as_millis()) / slot_duration.as_millis(); + let remaining_millis = next_slot * slot_duration.as_millis() - now; + Duration::from_millis(remaining_millis as u64) +} + +impl SlotTimer +where + Block: BlockT, + Client: ProvideRuntimeApi + Send + Sync + 'static + UsageProvider, + Client::Api: AuraApi, + P: Pair, + P::Public: AppPublic + Member + Codec, + P::Signature: TryFrom> + Member + Codec, +{ + pub fn new_with_drift(client: Arc, drift: Duration) -> Self { + Self { client, drift, _marker: Default::default() } + } + + /// Returns a future that resolves when the next slot arrives. + pub async fn wait_until_next_slot(&self) -> Result { + let Ok(slot_duration) = crate::slot_duration(&*self.client) else { + tracing::error!(target: crate::LOG_TARGET, "Failed to fetch slot duration from runtime."); + return Err(()) + }; + + let time_until_next_slot = time_until_next_slot(slot_duration.as_duration(), self.drift); + tokio::time::sleep(time_until_next_slot).await; + let timestamp = sp_timestamp::Timestamp::current(); + Ok(SlotInfo { + slot: Slot::from_timestamp(timestamp, slot_duration), + timestamp, + slot_duration, + }) + } +} + +/// Run block-builder. +pub fn run_block_builder( + params: BuilderTaskParams, +) -> impl Future + Send + 'static +where + Block: BlockT, + Client: ProvideRuntimeApi + + UsageProvider + + BlockOf + + AuxStore + + HeaderBackend + + BlockBackend + + Send + + Sync + + 'static, + Client::Api: + AuraApi + CollectCollationInfo + AuraUnincludedSegmentApi, + Backend: sc_client_api::Backend + 'static, + RelayClient: RelayChainInterface + Clone + 'static, + CIDP: CreateInherentDataProviders + 'static, + CIDP::InherentDataProviders: Send, + BI: BlockImport + ParachainBlockImportMarker + Send + Sync + 'static, + Proposer: ProposerInterface + Send + Sync + 'static, + CS: CollatorServiceInterface + Send + Sync + 'static, + CHP: consensus_common::ValidationCodeHashProvider + Send + 'static, + P: Pair, + P::Public: AppPublic + Member + Codec, + P::Signature: TryFrom> + Member + Codec, +{ + async move { + tracing::info!(target: LOG_TARGET, "Starting slot-based block-builder task."); + let BuilderTaskParams { + relay_client, + create_inherent_data_providers, + para_client, + keystore, + block_import, + para_id, + proposer, + collator_service, + collator_sender, + code_hash_provider, + authoring_duration, + para_backend, + relay_chain_slot_duration, + slot_drift, + } = params; + + let slot_timer = SlotTimer::<_, _, P>::new_with_drift(para_client.clone(), slot_drift); + + let mut collator = { + let params = collator_util::Params { + create_inherent_data_providers, + block_import, + relay_client: relay_client.clone(), + keystore: keystore.clone(), + para_id, + proposer, + collator_service, + }; + + collator_util::Collator::::new(params) + }; + + let mut relay_chain_fetcher = RelayChainCachingFetcher::new(relay_client.clone(), para_id); + + loop { + // We wait here until the next slot arrives. + let Ok(para_slot) = slot_timer.wait_until_next_slot().await else { + return; + }; + + let Some(expected_cores) = + expected_core_count(relay_chain_slot_duration, para_slot.slot_duration) + else { + return + }; + + let Ok(RelayChainData { + relay_parent_header, + max_pov_size, + relay_parent_hash: relay_parent, + scheduled_cores, + }) = relay_chain_fetcher.get_relay_chain_data().await + else { + continue; + }; + + if scheduled_cores.is_empty() { + tracing::debug!(target: LOG_TARGET, "Parachain not scheduled, skipping slot."); + continue; + } + + let core_index_in_scheduled: u64 = *para_slot.slot % expected_cores; + let Some(core_index) = scheduled_cores.get(core_index_in_scheduled as usize) else { + tracing::debug!(target: LOG_TARGET, core_index_in_scheduled, core_len = scheduled_cores.len(), "Para is scheduled, but not enough cores available."); + continue; + }; + + let Some((included_block, parent)) = + crate::collators::find_parent(relay_parent, para_id, &*para_backend, &relay_client) + .await + else { + continue + }; + + let parent_header = parent.header; + let parent_hash = parent.hash; + + // We mainly call this to inform users at genesis if there is a mismatch with the + // on-chain data. + collator.collator_service().check_block_status(parent_hash, &parent_header); + + let slot_claim = match crate::collators::can_build_upon::<_, _, P>( + para_slot.slot, + para_slot.timestamp, + parent_hash, + included_block, + &*para_client, + &keystore, + ) + .await + { + Some(slot) => slot, + None => { + tracing::debug!( + target: crate::LOG_TARGET, + ?core_index, + slot_info = ?para_slot, + unincluded_segment_len = parent.depth, + relay_parent = %relay_parent, + included = %included_block, + parent = %parent_hash, + "Not building block." + ); + continue + }, + }; + + tracing::debug!( + target: crate::LOG_TARGET, + ?core_index, + slot_info = ?para_slot, + unincluded_segment_len = parent.depth, + relay_parent = %relay_parent, + included = %included_block, + parent = %parent_hash, + "Building block." + ); + + let validation_data = PersistedValidationData { + parent_head: parent_header.encode().into(), + relay_parent_number: *relay_parent_header.number(), + relay_parent_storage_root: *relay_parent_header.state_root(), + max_pov_size, + }; + + let (parachain_inherent_data, other_inherent_data) = match collator + .create_inherent_data( + relay_parent, + &validation_data, + parent_hash, + slot_claim.timestamp(), + ) + .await + { + Err(err) => { + tracing::error!(target: crate::LOG_TARGET, ?err); + break + }, + Ok(x) => x, + }; + + let validation_code_hash = match code_hash_provider.code_hash_at(parent_hash) { + None => { + tracing::error!(target: crate::LOG_TARGET, ?parent_hash, "Could not fetch validation code hash"); + break + }, + Some(v) => v, + }; + + check_validation_code_or_log( + &validation_code_hash, + para_id, + &relay_client, + relay_parent, + ) + .await; + + let Ok(Some(candidate)) = collator + .build_block_and_import( + &parent_header, + &slot_claim, + None, + (parachain_inherent_data, other_inherent_data), + authoring_duration, + // Set the block limit to 50% of the maximum PoV size. + // + // TODO: If we got benchmarking that includes the proof size, + // we should be able to use the maximum pov size. + (validation_data.max_pov_size / 2) as usize, + ) + .await + else { + tracing::error!(target: crate::LOG_TARGET, "Unable to build block at slot."); + continue; + }; + + let new_block_hash = candidate.block.header().hash(); + + // Announce the newly built block to our peers. + collator.collator_service().announce_block(new_block_hash, None); + + if let Err(err) = collator_sender.unbounded_send(CollatorMessage { + relay_parent, + parent_header, + parachain_candidate: candidate, + validation_code_hash, + core_index: *core_index, + }) { + tracing::error!(target: crate::LOG_TARGET, ?err, "Unable to send block to collation task."); + return + } + } + } +} + +/// Calculate the expected core count based on the slot duration of the relay and parachain. +/// +/// If `slot_duration` is smaller than `relay_chain_slot_duration` that means that we produce more +/// than one parachain block per relay chain block. In order to get these backed, we need multiple +/// cores. This method calculates how many cores we should expect to have scheduled under the +/// assumption that we have a fixed number of cores assigned to our parachain. +fn expected_core_count( + relay_chain_slot_duration: Duration, + slot_duration: SlotDuration, +) -> Option { + let slot_duration_millis = slot_duration.as_millis(); + u64::try_from(relay_chain_slot_duration.as_millis()) + .map_err(|e| tracing::error!("Unable to calculate expected parachain core count: {e}")) + .map(|relay_slot_duration| (relay_slot_duration / slot_duration_millis).max(1)) + .ok() +} + +/// Contains relay chain data necessary for parachain block building. +#[derive(Clone)] +struct RelayChainData { + /// Current relay chain parent header. + pub relay_parent_header: RelayHeader, + /// The cores this para is scheduled on in the context of the relay parent. + pub scheduled_cores: Vec, + /// Maximum configured PoV size on the relay chain. + pub max_pov_size: u32, + /// Current relay chain parent header. + pub relay_parent_hash: RelayHash, +} + +/// Simple helper to fetch relay chain data and cache it based on the current relay chain best block +/// hash. +struct RelayChainCachingFetcher { + relay_client: RI, + para_id: ParaId, + last_data: Option<(RelayHash, RelayChainData)>, +} + +impl RelayChainCachingFetcher +where + RI: RelayChainInterface + Clone + 'static, +{ + pub fn new(relay_client: RI, para_id: ParaId) -> Self { + Self { relay_client, para_id, last_data: None } + } + + /// Fetch required [`RelayChainData`] from the relay chain. + /// If this data has been fetched in the past for the incoming hash, it will reuse + /// cached data. + pub async fn get_relay_chain_data(&mut self) -> Result { + let Ok(relay_parent) = self.relay_client.best_block_hash().await else { + tracing::warn!(target: crate::LOG_TARGET, "Unable to fetch latest relay chain block hash."); + return Err(()) + }; + + match &self.last_data { + Some((last_seen_hash, data)) if *last_seen_hash == relay_parent => { + tracing::trace!(target: crate::LOG_TARGET, %relay_parent, "Using cached data for relay parent."); + Ok(data.clone()) + }, + _ => { + tracing::trace!(target: crate::LOG_TARGET, %relay_parent, "Relay chain best block changed, fetching new data from relay chain."); + let data = self.update_for_relay_parent(relay_parent).await?; + self.last_data = Some((relay_parent, data.clone())); + Ok(data) + }, + } + } + + /// Fetch fresh data from the relay chain for the given relay parent hash. + async fn update_for_relay_parent(&self, relay_parent: RelayHash) -> Result { + let scheduled_cores = + cores_scheduled_for_para(relay_parent, self.para_id, &self.relay_client).await; + let Ok(Some(relay_parent_header)) = + self.relay_client.header(BlockId::Hash(relay_parent)).await + else { + tracing::warn!(target: crate::LOG_TARGET, "Unable to fetch latest relay chain block header."); + return Err(()) + }; + + let max_pov_size = match self + .relay_client + .persisted_validation_data(relay_parent, self.para_id, OccupiedCoreAssumption::Included) + .await + { + Ok(None) => return Err(()), + Ok(Some(pvd)) => pvd.max_pov_size, + Err(err) => { + tracing::error!(target: crate::LOG_TARGET, ?err, "Failed to gather information from relay-client"); + return Err(()) + }, + }; + + Ok(RelayChainData { + relay_parent_hash: relay_parent, + relay_parent_header, + scheduled_cores, + max_pov_size, + }) + } +} diff --git a/cumulus/client/consensus/aura/src/collators/slot_based/collation_task.rs b/cumulus/client/consensus/aura/src/collators/slot_based/collation_task.rs new file mode 100644 index 0000000000000000000000000000000000000000..5b8151f6302c411469a3258135de2618fc6f5d48 --- /dev/null +++ b/cumulus/client/consensus/aura/src/collators/slot_based/collation_task.rs @@ -0,0 +1,140 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +use codec::Encode; + +use cumulus_client_collator::service::ServiceInterface as CollatorServiceInterface; +use cumulus_relay_chain_interface::RelayChainInterface; + +use polkadot_node_primitives::{MaybeCompressedPoV, SubmitCollationParams}; +use polkadot_node_subsystem::messages::CollationGenerationMessage; +use polkadot_overseer::Handle as OverseerHandle; +use polkadot_primitives::{CollatorPair, Id as ParaId}; + +use futures::prelude::*; + +use sc_utils::mpsc::TracingUnboundedReceiver; +use sp_runtime::traits::{Block as BlockT, Header}; + +use super::CollatorMessage; + +const LOG_TARGET: &str = "aura::cumulus::collation_task"; + +/// Parameters for the collation task. +pub struct Params { + /// A handle to the relay-chain client. + pub relay_client: RClient, + /// The collator key used to sign collations before submitting to validators. + pub collator_key: CollatorPair, + /// The para's ID. + pub para_id: ParaId, + /// Whether we should reinitialize the collator config (i.e. we are transitioning to aura). + pub reinitialize: bool, + /// Collator service interface + pub collator_service: CS, + /// Receiver channel for communication with the block builder task. + pub collator_receiver: TracingUnboundedReceiver>, +} + +/// Asynchronously executes the collation task for a parachain. +/// +/// This function initializes the collator subsystems necessary for producing and submitting +/// collations to the relay chain. It listens for new best relay chain block notifications and +/// handles collator messages. If our parachain is scheduled on a core and we have a candidate, +/// the task will build a collation and send it to the relay chain. +pub async fn run_collation_task(mut params: Params) +where + Block: BlockT, + CS: CollatorServiceInterface + Send + Sync + 'static, + RClient: RelayChainInterface + Clone + 'static, +{ + let Ok(mut overseer_handle) = params.relay_client.overseer_handle() else { + tracing::error!(target: LOG_TARGET, "Failed to get overseer handle."); + return + }; + + cumulus_client_collator::initialize_collator_subsystems( + &mut overseer_handle, + params.collator_key, + params.para_id, + params.reinitialize, + ) + .await; + + let collator_service = params.collator_service; + while let Some(collator_message) = params.collator_receiver.next().await { + handle_collation_message(collator_message, &collator_service, &mut overseer_handle).await; + } +} + +/// Handle an incoming collation message from the block builder task. +/// This builds the collation from the [`CollatorMessage`] and submits it to +/// the collation-generation subsystem of the relay chain. +async fn handle_collation_message( + message: CollatorMessage, + collator_service: &impl CollatorServiceInterface, + overseer_handle: &mut OverseerHandle, +) { + let CollatorMessage { + parent_header, + parachain_candidate, + validation_code_hash, + relay_parent, + core_index, + } = message; + + let hash = parachain_candidate.block.header().hash(); + let number = *parachain_candidate.block.header().number(); + let (collation, block_data) = + match collator_service.build_collation(&parent_header, hash, parachain_candidate) { + Some(collation) => collation, + None => { + tracing::warn!(target: LOG_TARGET, %hash, ?number, ?core_index, "Unable to build collation."); + return; + }, + }; + + tracing::info!( + target: LOG_TARGET, + "PoV size {{ header: {:.2}kB, extrinsics: {:.2}kB, storage_proof: {:.2}kB }}", + block_data.header().encoded_size() as f64 / 1024f64, + block_data.extrinsics().encoded_size() as f64 / 1024f64, + block_data.storage_proof().encoded_size() as f64 / 1024f64, + ); + + if let MaybeCompressedPoV::Compressed(ref pov) = collation.proof_of_validity { + tracing::info!( + target: LOG_TARGET, + "Compressed PoV size: {}kb", + pov.block_data.0.len() as f64 / 1024f64, + ); + } + + tracing::debug!(target: LOG_TARGET, ?core_index, %hash, %number, "Submitting collation for core."); + overseer_handle + .send_msg( + CollationGenerationMessage::SubmitCollation(SubmitCollationParams { + relay_parent, + collation, + parent_head: parent_header.encode().into(), + validation_code_hash, + core_index, + result_sender: None, + }), + "SubmitCollation", + ) + .await; +} diff --git a/cumulus/client/consensus/aura/src/collators/slot_based/mod.rs b/cumulus/client/consensus/aura/src/collators/slot_based/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..0fe49d58d25be672d8541b486c0aa8f22d825c30 --- /dev/null +++ b/cumulus/client/consensus/aura/src/collators/slot_based/mod.rs @@ -0,0 +1,178 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! A collator for Aura that looks ahead of the most recently included parachain block +//! when determining what to build upon. +//! +//! The block building mechanism consists of two parts: +//! 1. A block-builder task that builds parachain blocks at each of our slots. +//! 2. A collator task that transforms the blocks into a collation and submits them to the relay +//! chain. +//! +//! Blocks are built on every parachain slot if there is a core scheduled on the relay chain. At the +//! beginning of each block building loop, we determine how many blocks we expect to build per relay +//! chain block. The collator implementation then expects that we have that many cores scheduled +//! during the relay chain block. After the block is built, the block builder task sends it to +//! the collation task which compresses it and submits it to the collation-generation subsystem. + +use codec::Codec; +use consensus_common::ParachainCandidate; +use cumulus_client_collator::service::ServiceInterface as CollatorServiceInterface; +use cumulus_client_consensus_common::{self as consensus_common, ParachainBlockImportMarker}; +use cumulus_client_consensus_proposer::ProposerInterface; +use cumulus_primitives_aura::AuraUnincludedSegmentApi; +use cumulus_primitives_core::CollectCollationInfo; +use cumulus_relay_chain_interface::RelayChainInterface; +use polkadot_primitives::{ + CollatorPair, CoreIndex, Hash as RelayHash, Id as ParaId, ValidationCodeHash, +}; + +use sc_client_api::{backend::AuxStore, BlockBackend, BlockOf, UsageProvider}; +use sc_consensus::BlockImport; +use sc_utils::mpsc::tracing_unbounded; + +use sp_api::ProvideRuntimeApi; +use sp_application_crypto::AppPublic; +use sp_blockchain::HeaderBackend; +use sp_consensus_aura::AuraApi; +use sp_core::crypto::Pair; +use sp_inherents::CreateInherentDataProviders; +use sp_keystore::KeystorePtr; +use sp_runtime::traits::{Block as BlockT, Member}; + +use std::{sync::Arc, time::Duration}; + +use self::{block_builder_task::run_block_builder, collation_task::run_collation_task}; + +mod block_builder_task; +mod collation_task; + +/// Parameters for [`run`]. +pub struct Params { + /// Inherent data providers. Only non-consensus inherent data should be provided, i.e. + /// the timestamp, slot, and paras inherents should be omitted, as they are set by this + /// collator. + pub create_inherent_data_providers: CIDP, + /// Used to actually import blocks. + pub block_import: BI, + /// The underlying para client. + pub para_client: Arc, + /// The para client's backend, used to access the database. + pub para_backend: Arc, + /// A handle to the relay-chain client. + pub relay_client: RClient, + /// A validation code hash provider, used to get the current validation code hash. + pub code_hash_provider: CHP, + /// The underlying keystore, which should contain Aura consensus keys. + pub keystore: KeystorePtr, + /// The collator key used to sign collations before submitting to validators. + pub collator_key: CollatorPair, + /// The para's ID. + pub para_id: ParaId, + /// The length of slots in the relay chain. + pub relay_chain_slot_duration: Duration, + /// The underlying block proposer this should call into. + pub proposer: Proposer, + /// The generic collator service used to plug into this consensus engine. + pub collator_service: CS, + /// The amount of time to spend authoring each block. + pub authoring_duration: Duration, + /// Whether we should reinitialize the collator config (i.e. we are transitioning to aura). + pub reinitialize: bool, + /// Drift slots by a fixed duration. This can be used to create more preferrable authoring + /// timings. + pub slot_drift: Duration, +} + +/// Run aura-based block building and collation task. +pub fn run( + params: Params, +) -> (impl futures::Future, impl futures::Future) +where + Block: BlockT, + Client: ProvideRuntimeApi + + BlockOf + + AuxStore + + HeaderBackend + + BlockBackend + + UsageProvider + + Send + + Sync + + 'static, + Client::Api: + AuraApi + CollectCollationInfo + AuraUnincludedSegmentApi, + Backend: sc_client_api::Backend + 'static, + RClient: RelayChainInterface + Clone + 'static, + CIDP: CreateInherentDataProviders + 'static, + CIDP::InherentDataProviders: Send, + BI: BlockImport + ParachainBlockImportMarker + Send + Sync + 'static, + Proposer: ProposerInterface + Send + Sync + 'static, + CS: CollatorServiceInterface + Send + Sync + Clone + 'static, + CHP: consensus_common::ValidationCodeHashProvider + Send + 'static, + P: Pair + 'static, + P::Public: AppPublic + Member + Codec, + P::Signature: TryFrom> + Member + Codec, +{ + let (tx, rx) = tracing_unbounded("mpsc_builder_to_collator", 100); + let collator_task_params = collation_task::Params { + relay_client: params.relay_client.clone(), + collator_key: params.collator_key, + para_id: params.para_id, + reinitialize: params.reinitialize, + collator_service: params.collator_service.clone(), + collator_receiver: rx, + }; + + let collation_task_fut = run_collation_task::(collator_task_params); + + let block_builder_params = block_builder_task::BuilderTaskParams { + create_inherent_data_providers: params.create_inherent_data_providers, + block_import: params.block_import, + para_client: params.para_client, + para_backend: params.para_backend, + relay_client: params.relay_client, + code_hash_provider: params.code_hash_provider, + keystore: params.keystore, + para_id: params.para_id, + proposer: params.proposer, + collator_service: params.collator_service, + authoring_duration: params.authoring_duration, + collator_sender: tx, + relay_chain_slot_duration: params.relay_chain_slot_duration, + slot_drift: params.slot_drift, + }; + + let block_builder_fut = + run_block_builder::(block_builder_params); + + (collation_task_fut, block_builder_fut) +} + +/// Message to be sent from the block builder to the collation task. +/// +/// Contains all data necessary to submit a collation to the relay chain. +struct CollatorMessage { + /// The hash of the relay chain block that provides the context for the parachain block. + pub relay_parent: RelayHash, + /// The header of the parent block. + pub parent_header: Block::Header, + /// The parachain block candidate. + pub parachain_candidate: ParachainCandidate, + /// The validation code hash at the parent block. + pub validation_code_hash: ValidationCodeHash, + /// Core index that this block should be submitted on + pub core_index: CoreIndex, +} diff --git a/cumulus/client/consensus/aura/src/equivocation_import_queue.rs b/cumulus/client/consensus/aura/src/equivocation_import_queue.rs index be554bdcfc79b986f11da24404a47556031657b2..68f2d37c8748863be879134d3fd0849adf5efb11 100644 --- a/cumulus/client/consensus/aura/src/equivocation_import_queue.rs +++ b/cumulus/client/consensus/aura/src/equivocation_import_queue.rs @@ -21,6 +21,7 @@ /// should be thrown out and which ones should be kept. use codec::Codec; use cumulus_client_consensus_common::ParachainBlockImportMarker; +use parking_lot::Mutex; use schnellru::{ByLength, LruMap}; use sc_consensus::{ @@ -70,7 +71,7 @@ impl NaiveEquivocationDefender { struct Verifier { client: Arc, create_inherent_data_providers: CIDP, - defender: NaiveEquivocationDefender, + defender: Mutex, telemetry: Option, _phantom: std::marker::PhantomData (Block, P)>, } @@ -88,7 +89,7 @@ where CIDP: CreateInherentDataProviders, { async fn verify( - &mut self, + &self, mut block_params: BlockImportParams, ) -> Result, String> { // Skip checks that include execution, if being told so, or when importing only state. @@ -137,7 +138,7 @@ where block_params.post_hash = Some(post_hash); // Check for and reject egregious amounts of equivocations. - if self.defender.insert_and_check(slot) { + if self.defender.lock().insert_and_check(slot) { return Err(format!( "Rejecting block {:?} due to excessive equivocations at slot", post_hash, @@ -243,7 +244,7 @@ where let verifier = Verifier:: { client, create_inherent_data_providers, - defender: NaiveEquivocationDefender::default(), + defender: Mutex::new(NaiveEquivocationDefender::default()), telemetry, _phantom: std::marker::PhantomData, }; diff --git a/cumulus/client/consensus/common/Cargo.toml b/cumulus/client/consensus/common/Cargo.toml index 09c2f58d45e4e04ca420d6280c39eed12e39ad4f..4bc2f1d1e600e5f82faaf7cfa84a3b831cf085b7 100644 --- a/cumulus/client/consensus/common/Cargo.toml +++ b/cumulus/client/consensus/common/Cargo.toml @@ -10,42 +10,42 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } -dyn-clone = "1.0.16" -futures = "0.3.28" +async-trait = { workspace = true } +codec = { features = ["derive"], workspace = true, default-features = true } +dyn-clone = { workspace = true } +futures = { workspace = true } log = { workspace = true, default-features = true } -tracing = "0.1.37" +tracing = { workspace = true, default-features = true } # Substrate -sc-client-api = { path = "../../../../substrate/client/api" } -sc-consensus = { path = "../../../../substrate/client/consensus/common" } -sc-consensus-babe = { path = "../../../../substrate/client/consensus/babe" } -sp-blockchain = { path = "../../../../substrate/primitives/blockchain" } -sp-consensus = { path = "../../../../substrate/primitives/consensus/common" } -sp-consensus-slots = { path = "../../../../substrate/primitives/consensus/slots" } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-runtime = { path = "../../../../substrate/primitives/runtime" } -sp-timestamp = { path = "../../../../substrate/primitives/timestamp" } -sp-trie = { path = "../../../../substrate/primitives/trie" } -sp-version = { path = "../../../../substrate/primitives/version" } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../../substrate/utils/prometheus" } +sc-client-api = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sc-consensus-babe = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-consensus-slots = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-timestamp = { workspace = true, default-features = true } +sp-trie = { workspace = true, default-features = true } +sp-version = { workspace = true, default-features = true } +prometheus-endpoint = { workspace = true, default-features = true } # Polkadot -polkadot-primitives = { path = "../../../../polkadot/primitives" } +polkadot-primitives = { workspace = true, default-features = true } # Cumulus -cumulus-primitives-core = { path = "../../../primitives/core" } -cumulus-relay-chain-interface = { path = "../../relay-chain-interface" } -cumulus-client-pov-recovery = { path = "../../pov-recovery" } -schnellru = "0.2.1" +cumulus-primitives-core = { workspace = true, default-features = true } +cumulus-relay-chain-interface = { workspace = true, default-features = true } +cumulus-client-pov-recovery = { workspace = true, default-features = true } +schnellru = { workspace = true } [dev-dependencies] -futures-timer = "3.0.2" +futures-timer = { workspace = true } # Substrate -sp-tracing = { path = "../../../../substrate/primitives/tracing" } +sp-tracing = { workspace = true, default-features = true } # Cumulus -cumulus-test-client = { path = "../../../test/client" } -cumulus-test-relay-sproof-builder = { path = "../../../test/relay-sproof-builder" } +cumulus-test-client = { workspace = true } +cumulus-test-relay-sproof-builder = { workspace = true, default-features = true } diff --git a/cumulus/client/consensus/common/src/import_queue.rs b/cumulus/client/consensus/common/src/import_queue.rs index 8024b7695a285a414c89cea74561ece91dfd48de..488693604fefccbe2c9b37a22c8ee3c4809383f2 100644 --- a/cumulus/client/consensus/common/src/import_queue.rs +++ b/cumulus/client/consensus/common/src/import_queue.rs @@ -50,7 +50,7 @@ pub struct VerifyNothing; #[async_trait::async_trait] impl Verifier for VerifyNothing { async fn verify( - &mut self, + &self, params: BlockImportParams, ) -> Result, String> { Ok(params) diff --git a/cumulus/client/consensus/common/src/lib.rs b/cumulus/client/consensus/common/src/lib.rs index cebe34e7ea58828372a9261e3be94866e119546a..e12750dcc553f9983f3432c9bf2ad156318a4cc8 100644 --- a/cumulus/client/consensus/common/src/lib.rs +++ b/cumulus/client/consensus/common/src/lib.rs @@ -19,16 +19,13 @@ use polkadot_primitives::{ Block as PBlock, Hash as PHash, Header as PHeader, PersistedValidationData, ValidationCodeHash, }; -use cumulus_primitives_core::{ - relay_chain::{self, BlockId as RBlockId, OccupiedCoreAssumption}, - AbridgedHostConfiguration, ParaId, -}; +use cumulus_primitives_core::{relay_chain, AbridgedHostConfiguration}; use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface}; -use sc_client_api::{Backend, HeaderBackend}; +use sc_client_api::Backend; use sc_consensus::{shared_data::SharedData, BlockImport, ImportResult}; -use sp_blockchain::Backend as BlockchainBackend; use sp_consensus_slots::Slot; + use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use sp_timestamp::Timestamp; @@ -36,9 +33,12 @@ use std::{sync::Arc, time::Duration}; mod level_monitor; mod parachain_consensus; +mod parent_search; #[cfg(test)] mod tests; +pub use parent_search::*; + pub use parachain_consensus::run_parachain_consensus; use level_monitor::LevelMonitor; @@ -172,13 +172,13 @@ impl Clone for ParachainBlockImport { impl BlockImport for ParachainBlockImport where Block: BlockT, - BI: BlockImport + Send, + BI: BlockImport + Send + Sync, BE: Backend, { type Error = BI::Error; async fn check_block( - &mut self, + &self, block: sc_consensus::BlockCheckParams, ) -> Result { self.inner.check_block(block).await @@ -229,196 +229,6 @@ pub trait ParachainBlockImportMarker {} impl ParachainBlockImportMarker for ParachainBlockImport {} -/// Parameters when searching for suitable parents to build on top of. -#[derive(Debug)] -pub struct ParentSearchParams { - /// The relay-parent that is intended to be used. - pub relay_parent: PHash, - /// The ID of the parachain. - pub para_id: ParaId, - /// A limitation on the age of relay parents for parachain blocks that are being - /// considered. This is relative to the `relay_parent` number. - pub ancestry_lookback: usize, - /// How "deep" parents can be relative to the included parachain block at the relay-parent. - /// The included block has depth 0. - pub max_depth: usize, - /// Whether to only ignore "alternative" branches, i.e. branches of the chain - /// which do not contain the block pending availability. - pub ignore_alternative_branches: bool, -} - -/// A potential parent block returned from [`find_potential_parents`] -#[derive(Debug, PartialEq)] -pub struct PotentialParent { - /// The hash of the block. - pub hash: B::Hash, - /// The header of the block. - pub header: B::Header, - /// The depth of the block. - pub depth: usize, - /// Whether the block is the included block, is itself pending on-chain, or descends - /// from the block pending availability. - pub aligned_with_pending: bool, -} - -/// Perform a recursive search through blocks to find potential -/// parent blocks for a new block. -/// -/// This accepts a relay-chain block to be used as an anchor and a maximum search depth, -/// along with some arguments for filtering parachain blocks and performs a recursive search -/// for parachain blocks. The search begins at the last included parachain block and returns -/// a set of [`PotentialParent`]s which could be potential parents of a new block with this -/// relay-parent according to the search parameters. -/// -/// A parachain block is a potential parent if it is either the last included parachain block, the -/// pending parachain block (when `max_depth` >= 1), or all of the following hold: -/// * its parent is a potential parent -/// * its relay-parent is within `ancestry_lookback` of the targeted relay-parent. -/// * its relay-parent is within the same session as the targeted relay-parent. -/// * the block number is within `max_depth` blocks of the included block -pub async fn find_potential_parents( - params: ParentSearchParams, - client: &impl Backend, - relay_client: &impl RelayChainInterface, -) -> Result>, RelayChainError> { - // 1. Build up the ancestry record of the relay chain to compare against. - let rp_ancestry = { - let mut ancestry = Vec::with_capacity(params.ancestry_lookback + 1); - let mut current_rp = params.relay_parent; - let mut required_session = None; - - while ancestry.len() <= params.ancestry_lookback { - let header = match relay_client.header(RBlockId::hash(current_rp)).await? { - None => break, - Some(h) => h, - }; - - let session = relay_client.session_index_for_child(current_rp).await?; - if let Some(required_session) = required_session { - // Respect the relay-chain rule not to cross session boundaries. - if session != required_session { - break - } - } else { - required_session = Some(session); - } - - ancestry.push((current_rp, *header.state_root())); - current_rp = *header.parent_hash(); - - // don't iterate back into the genesis block. - if header.number == 1 { - break - } - } - - ancestry - }; - - let is_hash_in_ancestry = |hash| rp_ancestry.iter().any(|x| x.0 == hash); - let is_root_in_ancestry = |root| rp_ancestry.iter().any(|x| x.1 == root); - - // 2. Get the included and pending availability blocks. - let included_header = relay_client - .persisted_validation_data( - params.relay_parent, - params.para_id, - OccupiedCoreAssumption::TimedOut, - ) - .await?; - - let included_header = match included_header { - Some(pvd) => pvd.parent_head, - None => return Ok(Vec::new()), // this implies the para doesn't exist. - }; - - let pending_header = relay_client - .persisted_validation_data( - params.relay_parent, - params.para_id, - OccupiedCoreAssumption::Included, - ) - .await? - .and_then(|x| if x.parent_head != included_header { Some(x.parent_head) } else { None }); - - let included_header = match B::Header::decode(&mut &included_header.0[..]).ok() { - None => return Ok(Vec::new()), - Some(x) => x, - }; - // Silently swallow if pending block can't decode. - let pending_header = pending_header.and_then(|p| B::Header::decode(&mut &p.0[..]).ok()); - let included_hash = included_header.hash(); - let pending_hash = pending_header.as_ref().map(|hdr| hdr.hash()); - - let mut frontier = vec![PotentialParent:: { - hash: included_hash, - header: included_header, - depth: 0, - aligned_with_pending: true, - }]; - - // Recursive search through descendants of the included block which have acceptable - // relay parents. - let mut potential_parents = Vec::new(); - while let Some(entry) = frontier.pop() { - let is_pending = - entry.depth == 1 && pending_hash.as_ref().map_or(false, |h| &entry.hash == h); - let is_included = entry.depth == 0; - - // note: even if the pending block or included block have a relay parent - // outside of the expected part of the relay chain, they are always allowed - // because they have already been posted on chain. - let is_potential = is_pending || is_included || { - let digest = entry.header.digest(); - cumulus_primitives_core::extract_relay_parent(digest).map_or(false, is_hash_in_ancestry) || - cumulus_primitives_core::rpsr_digest::extract_relay_parent_storage_root(digest) - .map(|(r, _n)| r) - .map_or(false, is_root_in_ancestry) - }; - - let parent_aligned_with_pending = entry.aligned_with_pending; - let child_depth = entry.depth + 1; - let hash = entry.hash; - - if is_potential { - potential_parents.push(entry); - } - - if !is_potential || child_depth > params.max_depth { - continue - } - - // push children onto search frontier. - for child in client.blockchain().children(hash).ok().into_iter().flatten() { - let aligned_with_pending = parent_aligned_with_pending && - if child_depth == 1 { - pending_hash.as_ref().map_or(true, |h| &child == h) - } else { - true - }; - - if params.ignore_alternative_branches && !aligned_with_pending { - continue - } - - let header = match client.blockchain().header(child) { - Ok(Some(h)) => h, - Ok(None) => continue, - Err(_) => continue, - }; - - frontier.push(PotentialParent { - hash: child, - header, - depth: child_depth, - aligned_with_pending, - }); - } - } - - Ok(potential_parents) -} - /// Get the relay-parent slot and timestamp from a header. pub fn relay_slot_and_timestamp( relay_parent_header: &PHeader, diff --git a/cumulus/client/consensus/common/src/parachain_consensus.rs b/cumulus/client/consensus/common/src/parachain_consensus.rs index b4b315bb32be6ea18d7ae9399cafe4640096f2b4..944917673b119732a587adf3596ae59b829e30b5 100644 --- a/cumulus/client/consensus/common/src/parachain_consensus.rs +++ b/cumulus/client/consensus/common/src/parachain_consensus.rs @@ -375,60 +375,61 @@ async fn handle_new_best_parachain_head( target: LOG_TARGET, block_hash = ?hash, "Skipping set new best block, because block is already the best.", - ) - } else { - // Make sure the block is already known or otherwise we skip setting new best. - match parachain.block_status(hash) { - Ok(BlockStatus::InChainWithState) => { - unset_best_header.take(); - tracing::debug!( - target: LOG_TARGET, - ?hash, - "Importing block as new best for parachain.", - ); - import_block_as_new_best(hash, parachain_head, parachain).await; - }, - Ok(BlockStatus::InChainPruned) => { - tracing::error!( - target: LOG_TARGET, - block_hash = ?hash, - "Trying to set pruned block as new best!", - ); - }, - Ok(BlockStatus::Unknown) => { - *unset_best_header = Some(parachain_head); + ); + return; + } - tracing::debug!( - target: LOG_TARGET, - block_hash = ?hash, - "Parachain block not yet imported, waiting for import to enact as best block.", - ); - - if let Some(ref mut recovery_chan_tx) = recovery_chan_tx { - // Best effort channel to actively encourage block recovery. - // An error here is not fatal; the relay chain continuously re-announces - // the best block, thus we will have other opportunities to retry. - let req = RecoveryRequest { hash, kind: RecoveryKind::Full }; - if let Err(err) = recovery_chan_tx.try_send(req) { - tracing::warn!( - target: LOG_TARGET, - block_hash = ?hash, - error = ?err, - "Unable to notify block recovery subsystem" - ) - } + // Make sure the block is already known or otherwise we skip setting new best. + match parachain.block_status(hash) { + Ok(BlockStatus::InChainWithState) => { + unset_best_header.take(); + tracing::debug!( + target: LOG_TARGET, + included = ?hash, + "Importing block as new best for parachain.", + ); + import_block_as_new_best(hash, parachain_head, parachain).await; + }, + Ok(BlockStatus::InChainPruned) => { + tracing::error!( + target: LOG_TARGET, + block_hash = ?hash, + "Trying to set pruned block as new best!", + ); + }, + Ok(BlockStatus::Unknown) => { + *unset_best_header = Some(parachain_head); + + tracing::debug!( + target: LOG_TARGET, + block_hash = ?hash, + "Parachain block not yet imported, waiting for import to enact as best block.", + ); + + if let Some(ref mut recovery_chan_tx) = recovery_chan_tx { + // Best effort channel to actively encourage block recovery. + // An error here is not fatal; the relay chain continuously re-announces + // the best block, thus we will have other opportunities to retry. + let req = RecoveryRequest { hash, kind: RecoveryKind::Full }; + if let Err(err) = recovery_chan_tx.try_send(req) { + tracing::warn!( + target: LOG_TARGET, + block_hash = ?hash, + error = ?err, + "Unable to notify block recovery subsystem" + ) } - }, - Err(e) => { - tracing::error!( - target: LOG_TARGET, - block_hash = ?hash, - error = ?e, - "Failed to get block status of block.", - ); - }, - _ => {}, - } + } + }, + Err(e) => { + tracing::error!( + target: LOG_TARGET, + block_hash = ?hash, + error = ?e, + "Failed to get block status of block.", + ); + }, + _ => {}, } } diff --git a/cumulus/client/consensus/common/src/parent_search.rs b/cumulus/client/consensus/common/src/parent_search.rs new file mode 100644 index 0000000000000000000000000000000000000000..c371ec62f8455cacc7d6a2d7b1ba71e142661fff --- /dev/null +++ b/cumulus/client/consensus/common/src/parent_search.rs @@ -0,0 +1,418 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +use codec::Decode; +use polkadot_primitives::Hash as RelayHash; + +use cumulus_primitives_core::{ + relay_chain::{BlockId as RBlockId, OccupiedCoreAssumption}, + ParaId, +}; +use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface}; + +use sc_client_api::{Backend, HeaderBackend}; + +use sp_blockchain::{Backend as BlockchainBackend, TreeRoute}; + +use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; + +const PARENT_SEARCH_LOG_TARGET: &str = "consensus::common::find_potential_parents"; + +/// Parameters when searching for suitable parents to build on top of. +#[derive(Debug)] +pub struct ParentSearchParams { + /// The relay-parent that is intended to be used. + pub relay_parent: RelayHash, + /// The ID of the parachain. + pub para_id: ParaId, + /// A limitation on the age of relay parents for parachain blocks that are being + /// considered. This is relative to the `relay_parent` number. + pub ancestry_lookback: usize, + /// How "deep" parents can be relative to the included parachain block at the relay-parent. + /// The included block has depth 0. + pub max_depth: usize, + /// Whether to only ignore "alternative" branches, i.e. branches of the chain + /// which do not contain the block pending availability. + pub ignore_alternative_branches: bool, +} + +/// A potential parent block returned from [`find_potential_parents`] +#[derive(PartialEq)] +pub struct PotentialParent { + /// The hash of the block. + pub hash: B::Hash, + /// The header of the block. + pub header: B::Header, + /// The depth of the block with respect to the included block. + pub depth: usize, + /// Whether the block is the included block, is itself pending on-chain, or descends + /// from the block pending availability. + pub aligned_with_pending: bool, +} + +impl std::fmt::Debug for PotentialParent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("PotentialParent") + .field("hash", &self.hash) + .field("depth", &self.depth) + .field("aligned_with_pending", &self.aligned_with_pending) + .field("number", &self.header.number()) + .finish() + } +} + +/// Perform a recursive search through blocks to find potential +/// parent blocks for a new block. +/// +/// This accepts a relay-chain block to be used as an anchor and a maximum search depth, +/// along with some arguments for filtering parachain blocks and performs a recursive search +/// for parachain blocks. The search begins at the last included parachain block and returns +/// a set of [`PotentialParent`]s which could be potential parents of a new block with this +/// relay-parent according to the search parameters. +/// +/// A parachain block is a potential parent if it is either the last included parachain block, the +/// pending parachain block (when `max_depth` >= 1), or all of the following hold: +/// * its parent is a potential parent +/// * its relay-parent is within `ancestry_lookback` of the targeted relay-parent. +/// * its relay-parent is within the same session as the targeted relay-parent. +/// * the block number is within `max_depth` blocks of the included block +pub async fn find_potential_parents( + params: ParentSearchParams, + backend: &impl Backend, + relay_client: &impl RelayChainInterface, +) -> Result>, RelayChainError> { + tracing::trace!("Parent search parameters: {params:?}"); + // Get the included block. + let Some((included_header, included_hash)) = + fetch_included_from_relay_chain(relay_client, backend, params.para_id, params.relay_parent) + .await? + else { + return Ok(Default::default()) + }; + + let only_included = vec![PotentialParent { + hash: included_hash, + header: included_header.clone(), + depth: 0, + aligned_with_pending: true, + }]; + + if params.max_depth == 0 { + return Ok(only_included) + }; + + // Pending header and hash. + let maybe_pending = { + // Fetch the most recent pending header from the relay chain. We use + // `OccupiedCoreAssumption::Included` so the candidate pending availability gets enacted + // before being returned to us. + let pending_header = relay_client + .persisted_validation_data( + params.relay_parent, + params.para_id, + OccupiedCoreAssumption::Included, + ) + .await? + .and_then(|p| B::Header::decode(&mut &p.parent_head.0[..]).ok()) + .filter(|x| x.hash() != included_hash); + + // If the pending block is not locally known, we can't do anything. + if let Some(header) = pending_header { + let pending_hash = header.hash(); + match backend.blockchain().header(pending_hash) { + // We are supposed to ignore branches that don't contain the pending block, but we + // do not know the pending block locally. + Ok(None) | Err(_) if params.ignore_alternative_branches => { + tracing::warn!( + target: PARENT_SEARCH_LOG_TARGET, + %pending_hash, + "Failed to get header for pending block.", + ); + return Ok(Default::default()) + }, + Ok(Some(_)) => Some((header, pending_hash)), + _ => None, + } + } else { + None + } + }; + + let maybe_route_to_last_pending = maybe_pending + .as_ref() + .map(|(_, pending)| { + sp_blockchain::tree_route(backend.blockchain(), included_hash, *pending) + }) + .transpose()?; + + // If we want to ignore alternative branches there is no reason to start + // the parent search at the included block. We can add the included block and + // the path to the pending block to the potential parents directly (limited by max_depth). + let (frontier, potential_parents) = match ( + &maybe_pending, + params.ignore_alternative_branches, + &maybe_route_to_last_pending, + ) { + (Some((pending_header, pending_hash)), true, Some(ref route_to_pending)) => { + let mut potential_parents = only_included; + + // This is a defensive check, should never happen. + if !route_to_pending.retracted().is_empty() { + tracing::warn!(target: PARENT_SEARCH_LOG_TARGET, "Included block not an ancestor of pending block. This should not happen."); + return Ok(Default::default()) + } + + // Add all items on the path included -> pending - 1 to the potential parents, but + // not more than `max_depth`. + let num_parents_on_path = + route_to_pending.enacted().len().saturating_sub(1).min(params.max_depth); + for (num, block) in + route_to_pending.enacted().iter().take(num_parents_on_path).enumerate() + { + let Ok(Some(header)) = backend.blockchain().header(block.hash) else { continue }; + + potential_parents.push(PotentialParent { + hash: block.hash, + header, + depth: 1 + num, + aligned_with_pending: true, + }); + } + + // The search for additional potential parents should now start at the children of + // the pending block. + ( + vec![PotentialParent { + hash: *pending_hash, + header: pending_header.clone(), + depth: route_to_pending.enacted().len(), + aligned_with_pending: true, + }], + potential_parents, + ) + }, + _ => (only_included, Default::default()), + }; + + if potential_parents.len() > params.max_depth { + return Ok(potential_parents); + } + + // Build up the ancestry record of the relay chain to compare against. + let rp_ancestry = + build_relay_parent_ancestry(params.ancestry_lookback, params.relay_parent, relay_client) + .await?; + + Ok(search_child_branches_for_parents( + frontier, + maybe_route_to_last_pending, + included_header, + maybe_pending.map(|(_, hash)| hash), + backend, + params.max_depth, + params.ignore_alternative_branches, + rp_ancestry, + potential_parents, + )) +} + +/// Fetch the included block from the relay chain. +async fn fetch_included_from_relay_chain( + relay_client: &impl RelayChainInterface, + backend: &impl Backend, + para_id: ParaId, + relay_parent: RelayHash, +) -> Result, RelayChainError> { + // Fetch the pending header from the relay chain. We use `OccupiedCoreAssumption::TimedOut` + // so that even if there is a pending candidate, we assume it is timed out and we get the + // included head. + let included_header = relay_client + .persisted_validation_data(relay_parent, para_id, OccupiedCoreAssumption::TimedOut) + .await?; + let included_header = match included_header { + Some(pvd) => pvd.parent_head, + None => return Ok(None), // this implies the para doesn't exist. + }; + + let included_header = match B::Header::decode(&mut &included_header.0[..]).ok() { + None => return Ok(None), + Some(x) => x, + }; + + let included_hash = included_header.hash(); + // If the included block is not locally known, we can't do anything. + match backend.blockchain().header(included_hash) { + Ok(None) => { + tracing::warn!( + target: PARENT_SEARCH_LOG_TARGET, + %included_hash, + "Failed to get header for included block.", + ); + return Ok(None) + }, + Err(e) => { + tracing::warn!( + target: PARENT_SEARCH_LOG_TARGET, + %included_hash, + %e, + "Failed to get header for included block.", + ); + return Ok(None) + }, + _ => {}, + }; + + Ok(Some((included_header, included_hash))) +} + +/// Build an ancestry of relay parents that are acceptable. +/// +/// An acceptable relay parent is one that is no more than `ancestry_lookback` + 1 blocks below the +/// relay parent we want to build on. Parachain blocks anchored on relay parents older than that can +/// not be considered potential parents for block building. They have no chance of still getting +/// included, so our newly build parachain block would also not get included. +/// +/// On success, returns a vector of `(header_hash, state_root)` of the relevant relay chain +/// ancestry blocks. +async fn build_relay_parent_ancestry( + ancestry_lookback: usize, + relay_parent: RelayHash, + relay_client: &impl RelayChainInterface, +) -> Result, RelayChainError> { + let mut ancestry = Vec::with_capacity(ancestry_lookback + 1); + let mut current_rp = relay_parent; + let mut required_session = None; + while ancestry.len() <= ancestry_lookback { + let Some(header) = relay_client.header(RBlockId::hash(current_rp)).await? else { break }; + + let session = relay_client.session_index_for_child(current_rp).await?; + if required_session.get_or_insert(session) != &session { + // Respect the relay-chain rule not to cross session boundaries. + break; + } + + ancestry.push((current_rp, *header.state_root())); + current_rp = *header.parent_hash(); + + // don't iterate back into the genesis block. + if header.number == 1 { + break + } + } + Ok(ancestry) +} + +/// Start search for child blocks that can be used as parents. +pub fn search_child_branches_for_parents( + mut frontier: Vec>, + maybe_route_to_last_pending: Option>, + included_header: Block::Header, + pending_hash: Option, + backend: &impl Backend, + max_depth: usize, + ignore_alternative_branches: bool, + rp_ancestry: Vec<(RelayHash, RelayHash)>, + mut potential_parents: Vec>, +) -> Vec> { + let included_hash = included_header.hash(); + let is_hash_in_ancestry = |hash| rp_ancestry.iter().any(|x| x.0 == hash); + let is_root_in_ancestry = |root| rp_ancestry.iter().any(|x| x.1 == root); + + // The distance between pending and included block. Is later used to check if a child + // is aligned with pending when it is between pending and included block. + let pending_distance = maybe_route_to_last_pending.as_ref().map(|route| route.enacted().len()); + + // If a block is on the path included -> pending, we consider it `aligned_with_pending`. + let is_child_pending = |hash| { + maybe_route_to_last_pending + .as_ref() + .map_or(true, |route| route.enacted().iter().any(|x| x.hash == hash)) + }; + + tracing::trace!( + target: PARENT_SEARCH_LOG_TARGET, + ?included_hash, + included_num = ?included_header.number(), + ?pending_hash , + ?rp_ancestry, + "Searching relay chain ancestry." + ); + while let Some(entry) = frontier.pop() { + let is_pending = pending_hash.as_ref().map_or(false, |h| &entry.hash == h); + let is_included = included_hash == entry.hash; + + // note: even if the pending block or included block have a relay parent + // outside of the expected part of the relay chain, they are always allowed + // because they have already been posted on chain. + let is_potential = is_pending || is_included || { + let digest = entry.header.digest(); + let is_hash_in_ancestry_check = cumulus_primitives_core::extract_relay_parent(digest) + .map_or(false, is_hash_in_ancestry); + let is_root_in_ancestry_check = + cumulus_primitives_core::rpsr_digest::extract_relay_parent_storage_root(digest) + .map(|(r, _n)| r) + .map_or(false, is_root_in_ancestry); + + is_hash_in_ancestry_check || is_root_in_ancestry_check + }; + + let parent_aligned_with_pending = entry.aligned_with_pending; + let child_depth = entry.depth + 1; + let hash = entry.hash; + + tracing::trace!( + target: PARENT_SEARCH_LOG_TARGET, + ?hash, + is_potential, + is_pending, + is_included, + "Checking potential parent." + ); + + if is_potential { + potential_parents.push(entry); + } + + if !is_potential || child_depth > max_depth { + continue + } + + // push children onto search frontier. + for child in backend.blockchain().children(hash).ok().into_iter().flatten() { + tracing::trace!(target: PARENT_SEARCH_LOG_TARGET, ?child, child_depth, ?pending_distance, "Looking at child."); + + let aligned_with_pending = parent_aligned_with_pending && + (pending_distance.map_or(true, |dist| child_depth > dist) || + is_child_pending(child)); + + if ignore_alternative_branches && !aligned_with_pending { + tracing::trace!(target: PARENT_SEARCH_LOG_TARGET, ?child, "Child is not aligned with pending block."); + continue + } + + let Ok(Some(header)) = backend.blockchain().header(child) else { continue }; + + frontier.push(PotentialParent { + hash: child, + header, + depth: child_depth, + aligned_with_pending, + }); + } + } + + potential_parents +} diff --git a/cumulus/client/consensus/common/src/tests.rs b/cumulus/client/consensus/common/src/tests.rs index 2a944bc7f9fa221d63c48678f2899d50251b3655..284fa39ed1e704dd7594861c6f0c3264df75acfb 100644 --- a/cumulus/client/consensus/common/src/tests.rs +++ b/cumulus/client/consensus/common/src/tests.rs @@ -20,7 +20,7 @@ use async_trait::async_trait; use codec::Encode; use cumulus_client_pov_recovery::RecoveryKind; use cumulus_primitives_core::{ - relay_chain::{self, BlockId}, + relay_chain::{BlockId, BlockNumber, CoreState}, CumulusDigestItem, InboundDownwardMessage, InboundHrmpMessage, }; use cumulus_relay_chain_interface::{ @@ -37,6 +37,7 @@ use futures_timer::Delay; use polkadot_primitives::HeadData; use sc_client_api::{Backend as _, UsageProvider}; use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy}; +use sp_blockchain::Backend as BlockchainBackend; use sp_consensus::{BlockOrigin, BlockStatus}; use sp_version::RuntimeVersion; use std::{ @@ -46,11 +47,11 @@ use std::{ time::Duration, }; -fn relay_block_num_from_hash(hash: &PHash) -> relay_chain::BlockNumber { +fn relay_block_num_from_hash(hash: &PHash) -> BlockNumber { hash.to_low_u64_be() as u32 } -fn relay_hash_from_block_num(block_number: relay_chain::BlockNumber) -> PHash { +fn relay_hash_from_block_num(block_number: BlockNumber) -> PHash { PHash::from_low_u64_be(block_number as u64) } @@ -257,6 +258,13 @@ impl RelayChainInterface for Relaychain { })) } + async fn availability_cores( + &self, + _relay_parent: PHash, + ) -> RelayChainResult>> { + unimplemented!("Not needed for test"); + } + async fn version(&self, _: PHash) -> RelayChainResult { unimplemented!("Not needed for test") } @@ -1138,6 +1146,357 @@ fn find_potential_parents_with_max_depth() { } } +#[test] +fn find_potential_parents_unknown_included() { + sp_tracing::try_init_simple(); + + const NON_INCLUDED_CHAIN_LEN: usize = 5; + + let backend = Arc::new(Backend::new_test(1000, 1)); + let client = Arc::new(TestClientBuilder::with_backend(backend.clone()).build()); + let relay_parent = relay_hash_from_block_num(10); + // Choose different relay parent for alternative chain to get new hashes. + let search_relay_parent = relay_hash_from_block_num(11); + + let sproof = sproof_with_best_parent(&client); + let included_but_unknown = build_block(&*client, sproof, None, None, Some(relay_parent)); + + let relay_chain = Relaychain::new(); + { + let relay_inner = &mut relay_chain.inner.lock().unwrap(); + relay_inner + .relay_chain_hash_to_header + .insert(search_relay_parent, included_but_unknown.header().clone()); + } + + // Ignore alternative branch: + let potential_parents = block_on(find_potential_parents( + ParentSearchParams { + relay_parent: search_relay_parent, + para_id: ParaId::from(100), + ancestry_lookback: 1, // aligned chain is in ancestry. + max_depth: NON_INCLUDED_CHAIN_LEN, + ignore_alternative_branches: true, + }, + &*backend, + &relay_chain, + )) + .unwrap(); + + assert_eq!(potential_parents.len(), 0); +} + +#[test] +fn find_potential_parents_unknown_pending() { + sp_tracing::try_init_simple(); + + const NON_INCLUDED_CHAIN_LEN: usize = 5; + + let backend = Arc::new(Backend::new_test(1000, 1)); + let client = Arc::new(TestClientBuilder::with_backend(backend.clone()).build()); + let mut para_import = + ParachainBlockImport::new_with_delayed_best_block(client.clone(), backend.clone()); + + let relay_parent = relay_hash_from_block_num(10); + // Choose different relay parent for alternative chain to get new hashes. + let search_relay_parent = relay_hash_from_block_num(11); + let included_block = build_and_import_block_ext( + &client, + BlockOrigin::NetworkInitialSync, + true, + &mut para_import, + None, + None, + Some(relay_parent), + ); + + let sproof = sproof_with_parent_by_hash(&client, included_block.header().hash()); + let pending_but_unknown = build_block( + &*client, + sproof, + Some(included_block.header().hash()), + None, + Some(relay_parent), + ); + + let relay_chain = Relaychain::new(); + { + let relay_inner = &mut relay_chain.inner.lock().unwrap(); + relay_inner + .relay_chain_hash_to_header + .insert(search_relay_parent, included_block.header().clone()); + relay_inner + .relay_chain_hash_to_header_pending + .insert(search_relay_parent, pending_but_unknown.header().clone()); + } + + // Ignore alternative branch: + let potential_parents = block_on(find_potential_parents( + ParentSearchParams { + relay_parent: search_relay_parent, + para_id: ParaId::from(100), + ancestry_lookback: 1, // aligned chain is in ancestry. + max_depth: NON_INCLUDED_CHAIN_LEN, + ignore_alternative_branches: true, + }, + &*backend, + &relay_chain, + )) + .unwrap(); + + assert!(potential_parents.is_empty()); +} + +#[test] +fn find_potential_parents_unknown_pending_include_alternative_branches() { + sp_tracing::try_init_simple(); + + const NON_INCLUDED_CHAIN_LEN: usize = 5; + + let backend = Arc::new(Backend::new_test(1000, 1)); + let client = Arc::new(TestClientBuilder::with_backend(backend.clone()).build()); + let mut para_import = + ParachainBlockImport::new_with_delayed_best_block(client.clone(), backend.clone()); + + let relay_parent = relay_hash_from_block_num(10); + + // Choose different relay parent for alternative chain to get new hashes. + let search_relay_parent = relay_hash_from_block_num(11); + + let included_block = build_and_import_block_ext( + &client, + BlockOrigin::NetworkInitialSync, + true, + &mut para_import, + None, + None, + Some(relay_parent), + ); + + let alt_block = build_and_import_block_ext( + &client, + BlockOrigin::NetworkInitialSync, + true, + &mut para_import, + Some(included_block.header().hash()), + None, + Some(search_relay_parent), + ); + + tracing::info!(hash = %alt_block.header().hash(), "Alt block."); + let sproof = sproof_with_parent_by_hash(&client, included_block.header().hash()); + let pending_but_unknown = build_block( + &*client, + sproof, + Some(included_block.header().hash()), + None, + Some(relay_parent), + ); + + let relay_chain = Relaychain::new(); + { + let relay_inner = &mut relay_chain.inner.lock().unwrap(); + relay_inner + .relay_chain_hash_to_header + .insert(search_relay_parent, included_block.header().clone()); + relay_inner + .relay_chain_hash_to_header_pending + .insert(search_relay_parent, pending_but_unknown.header().clone()); + } + + // Ignore alternative branch: + let potential_parents = block_on(find_potential_parents( + ParentSearchParams { + relay_parent: search_relay_parent, + para_id: ParaId::from(100), + ancestry_lookback: 1, // aligned chain is in ancestry. + max_depth: NON_INCLUDED_CHAIN_LEN, + ignore_alternative_branches: false, + }, + &*backend, + &relay_chain, + )) + .unwrap(); + + let expected_parents: Vec<_> = vec![&included_block, &alt_block]; + assert_eq!(potential_parents.len(), 2); + assert_eq!(expected_parents[0].hash(), potential_parents[0].hash); + assert_eq!(expected_parents[1].hash(), potential_parents[1].hash); +} + +/// Test where there are multiple pending blocks. +#[test] +fn find_potential_parents_aligned_with_late_pending() { + sp_tracing::try_init_simple(); + + const NON_INCLUDED_CHAIN_LEN: usize = 5; + + let backend = Arc::new(Backend::new_test(1000, 1)); + let client = Arc::new(TestClientBuilder::with_backend(backend.clone()).build()); + let mut para_import = + ParachainBlockImport::new_with_delayed_best_block(client.clone(), backend.clone()); + + let relay_parent = relay_hash_from_block_num(10); + // Choose different relay parent for alternative chain to get new hashes. + let search_relay_parent = relay_hash_from_block_num(11); + let included_block = build_and_import_block_ext( + &client, + BlockOrigin::NetworkInitialSync, + true, + &mut para_import, + None, + None, + Some(relay_parent), + ); + + let in_between_block = build_and_import_block_ext( + &client, + BlockOrigin::NetworkInitialSync, + true, + &mut para_import, + Some(included_block.header().hash()), + None, + Some(relay_parent), + ); + + let pending_block = build_and_import_block_ext( + &client, + BlockOrigin::Own, + true, + &mut para_import, + Some(in_between_block.header().hash()), + None, + Some(relay_parent), + ); + + let relay_chain = Relaychain::new(); + { + let relay_inner = &mut relay_chain.inner.lock().unwrap(); + relay_inner + .relay_chain_hash_to_header + .insert(search_relay_parent, included_block.header().clone()); + relay_inner + .relay_chain_hash_to_header_pending + .insert(search_relay_parent, in_between_block.header().clone()); + relay_inner + .relay_chain_hash_to_header_pending + .insert(search_relay_parent, pending_block.header().clone()); + } + + // Build some blocks on the pending block and on the included block. + // We end up with two sibling chains, one is aligned with the pending block, + // the other is not. + let mut aligned_blocks = Vec::new(); + let mut parent = pending_block.header().hash(); + for _ in 2..NON_INCLUDED_CHAIN_LEN { + let block = build_and_import_block_ext( + &client, + BlockOrigin::Own, + true, + &mut para_import, + Some(parent), + None, + Some(relay_parent), + ); + parent = block.header().hash(); + aligned_blocks.push(block); + } + + let mut alt_blocks = Vec::new(); + let mut parent = included_block.header().hash(); + for _ in 0..NON_INCLUDED_CHAIN_LEN { + let block = build_and_import_block_ext( + &client, + BlockOrigin::NetworkInitialSync, + true, + &mut para_import, + Some(parent), + None, + Some(search_relay_parent), + ); + parent = block.header().hash(); + alt_blocks.push(block); + } + + // Ignore alternative branch: + for max_depth in 0..=NON_INCLUDED_CHAIN_LEN { + let potential_parents = block_on(find_potential_parents( + ParentSearchParams { + relay_parent: search_relay_parent, + para_id: ParaId::from(100), + ancestry_lookback: 1, // aligned chain is in ancestry. + max_depth, + ignore_alternative_branches: true, + }, + &*backend, + &relay_chain, + )) + .unwrap(); + + assert_eq!(potential_parents.len(), max_depth + 1); + let expected_parents: Vec<_> = [&included_block, &in_between_block, &pending_block] + .into_iter() + .chain(aligned_blocks.iter()) + .take(max_depth + 1) + .collect(); + + for i in 0..(max_depth + 1) { + let parent = &potential_parents[i]; + let expected = &expected_parents[i]; + + assert_eq!(parent.hash, expected.hash()); + assert_eq!(&parent.header, expected.header()); + assert_eq!(parent.depth, i); + assert!(parent.aligned_with_pending); + } + } + + // Do not ignore: + for max_depth in 0..=NON_INCLUDED_CHAIN_LEN { + let potential_parents = block_on(find_potential_parents( + ParentSearchParams { + relay_parent: search_relay_parent, + para_id: ParaId::from(100), + ancestry_lookback: 1, // aligned chain is in ancestry. + max_depth, + ignore_alternative_branches: false, + }, + &*backend, + &relay_chain, + )) + .unwrap(); + + let expected_len = 2 * max_depth + 1; + assert_eq!(potential_parents.len(), expected_len); + let expected_aligned: Vec<_> = [&included_block, &in_between_block, &pending_block] + .into_iter() + .chain(aligned_blocks.iter()) + .take(max_depth + 1) + .collect(); + let expected_alt = alt_blocks.iter().take(max_depth); + + let expected_parents: Vec<_> = + expected_aligned.clone().into_iter().chain(expected_alt).collect(); + // Check correctness. + assert_eq!(expected_parents.len(), expected_len); + + for i in 0..expected_len { + let parent = &potential_parents[i]; + let expected = expected_parents + .iter() + .find(|block| block.header().hash() == parent.hash) + .expect("missing parent"); + + let is_aligned = expected_aligned.contains(&expected); + + assert_eq!(parent.hash, expected.hash()); + assert_eq!(&parent.header, expected.header()); + + assert_eq!(parent.aligned_with_pending, is_aligned); + } + } +} + #[test] fn find_potential_parents_aligned_with_pending() { sp_tracing::try_init_simple(); @@ -1249,6 +1608,7 @@ fn find_potential_parents_aligned_with_pending() { // Do not ignore: for max_depth in 0..=NON_INCLUDED_CHAIN_LEN { + log::info!("Ran with max_depth = {max_depth}"); let potential_parents = block_on(find_potential_parents( ParentSearchParams { relay_parent: search_relay_parent, @@ -1276,6 +1636,7 @@ fn find_potential_parents_aligned_with_pending() { // Check correctness. assert_eq!(expected_parents.len(), expected_len); + potential_parents.iter().for_each(|p| log::info!("result: {:?}", p)); for i in 0..expected_len { let parent = &potential_parents[i]; let expected = expected_parents @@ -1288,6 +1649,12 @@ fn find_potential_parents_aligned_with_pending() { assert_eq!(parent.hash, expected.hash()); assert_eq!(&parent.header, expected.header()); + log::info!( + "Check hash: {:?} expected: {} is: {}", + parent.hash, + is_aligned, + parent.aligned_with_pending, + ); assert_eq!(parent.aligned_with_pending, is_aligned); } } diff --git a/cumulus/client/consensus/proposer/Cargo.toml b/cumulus/client/consensus/proposer/Cargo.toml index 42ca4e06f8f45e410006304cf1290e811e153b4c..ce91d48bf589a88e5eb0f81507e73da3d28a6b81 100644 --- a/cumulus/client/consensus/proposer/Cargo.toml +++ b/cumulus/client/consensus/proposer/Cargo.toml @@ -10,15 +10,15 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -anyhow = "1.0" -async-trait = "0.1.79" +anyhow = { workspace = true } +async-trait = { workspace = true } thiserror = { workspace = true } # Substrate -sp-consensus = { path = "../../../../substrate/primitives/consensus/common" } -sp-inherents = { path = "../../../../substrate/primitives/inherents" } -sp-runtime = { path = "../../../../substrate/primitives/runtime" } -sp-state-machine = { path = "../../../../substrate/primitives/state-machine" } +sp-consensus = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } # Cumulus -cumulus-primitives-parachain-inherent = { path = "../../../primitives/parachain-inherent" } +cumulus-primitives-parachain-inherent = { workspace = true, default-features = true } diff --git a/cumulus/client/consensus/relay-chain/Cargo.toml b/cumulus/client/consensus/relay-chain/Cargo.toml index 7c3a901db6c32131e762c3de971606fffddebc80..f3ee6fc2f7d257ff2be86c3d9a0096ea78d30be8 100644 --- a/cumulus/client/consensus/relay-chain/Cargo.toml +++ b/cumulus/client/consensus/relay-chain/Cargo.toml @@ -10,23 +10,23 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -async-trait = "0.1.79" -futures = "0.3.28" -parking_lot = "0.12.1" -tracing = "0.1.37" +async-trait = { workspace = true } +futures = { workspace = true } +parking_lot = { workspace = true, default-features = true } +tracing = { workspace = true, default-features = true } # Substrate -sc-consensus = { path = "../../../../substrate/client/consensus/common" } -sp-api = { path = "../../../../substrate/primitives/api" } -sp-block-builder = { path = "../../../../substrate/primitives/block-builder" } -sp-blockchain = { path = "../../../../substrate/primitives/blockchain" } -sp-consensus = { path = "../../../../substrate/primitives/consensus/common" } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-inherents = { path = "../../../../substrate/primitives/inherents" } -sp-runtime = { path = "../../../../substrate/primitives/runtime" } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../../substrate/utils/prometheus" } +sc-consensus = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-block-builder = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +prometheus-endpoint = { workspace = true, default-features = true } # Cumulus -cumulus-client-consensus-common = { path = "../common" } -cumulus-primitives-core = { path = "../../../primitives/core" } -cumulus-relay-chain-interface = { path = "../../relay-chain-interface" } +cumulus-client-consensus-common = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true, default-features = true } +cumulus-relay-chain-interface = { workspace = true, default-features = true } diff --git a/cumulus/client/consensus/relay-chain/src/import_queue.rs b/cumulus/client/consensus/relay-chain/src/import_queue.rs index 1b521e79d4820fbc4c6709cb177170afa60d3f37..1d6f039da4c123fc79c1132b7b96e93a96c69411 100644 --- a/cumulus/client/consensus/relay-chain/src/import_queue.rs +++ b/cumulus/client/consensus/relay-chain/src/import_queue.rs @@ -52,7 +52,7 @@ where CIDP: CreateInherentDataProviders, { async fn verify( - &mut self, + &self, mut block_params: BlockImportParams, ) -> Result, String> { block_params.fork_choice = Some(sc_consensus::ForkChoiceStrategy::Custom( diff --git a/cumulus/client/network/Cargo.toml b/cumulus/client/network/Cargo.toml index 0dd7c4fdb0f60ac2f70f0fb697c901f960515b9a..bc67678eedeb199d57aad6f35f5be386231b841e 100644 --- a/cumulus/client/network/Cargo.toml +++ b/cumulus/client/network/Cargo.toml @@ -10,51 +10,51 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } -futures = "0.3.28" -futures-timer = "3.0.2" -parking_lot = "0.12.1" -tracing = "0.1.37" +async-trait = { workspace = true } +codec = { features = ["derive"], workspace = true, default-features = true } +futures = { workspace = true } +futures-timer = { workspace = true } +parking_lot = { workspace = true, default-features = true } +tracing = { workspace = true, default-features = true } # Substrate -sc-client-api = { path = "../../../substrate/client/api" } -sp-blockchain = { path = "../../../substrate/primitives/blockchain" } -sp-consensus = { path = "../../../substrate/primitives/consensus/common" } -sp-core = { path = "../../../substrate/primitives/core" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } -sp-state-machine = { path = "../../../substrate/primitives/state-machine" } -sp-api = { path = "../../../substrate/primitives/api" } -sp-version = { path = "../../../substrate/primitives/version" } +sc-client-api = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-version = { workspace = true, default-features = true } # Polkadot -polkadot-node-primitives = { path = "../../../polkadot/node/primitives" } -polkadot-parachain-primitives = { path = "../../../polkadot/parachain" } -polkadot-primitives = { path = "../../../polkadot/primitives" } -polkadot-node-subsystem = { path = "../../../polkadot/node/subsystem" } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } # Cumulus -cumulus-relay-chain-interface = { path = "../relay-chain-interface" } +cumulus-relay-chain-interface = { workspace = true, default-features = true } [dev-dependencies] -portpicker = "0.1.1" -tokio = { version = "1.32.0", features = ["macros"] } -url = "2.4.0" -rstest = "0.18.2" +portpicker = { workspace = true } +tokio = { features = ["macros"], workspace = true, default-features = true } +url = { workspace = true } +rstest = { workspace = true } # Substrate -sc-cli = { path = "../../../substrate/client/cli" } -sc-client-api = { path = "../../../substrate/client/api" } -sp-consensus = { path = "../../../substrate/primitives/consensus/common" } -sp-core = { path = "../../../substrate/primitives/core" } -sp-keyring = { path = "../../../substrate/primitives/keyring" } -sp-keystore = { path = "../../../substrate/primitives/keystore" } -substrate-test-utils = { path = "../../../substrate/test-utils" } +sc-cli = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +substrate-test-utils = { workspace = true } # Polkadot -polkadot-test-client = { path = "../../../polkadot/node/test/client" } +polkadot-test-client = { workspace = true } # Cumulus -cumulus-primitives-core = { path = "../../primitives/core" } -cumulus-relay-chain-inprocess-interface = { path = "../relay-chain-inprocess-interface" } -cumulus-test-service = { path = "../../test/service" } +cumulus-primitives-core = { workspace = true, default-features = true } +cumulus-relay-chain-inprocess-interface = { workspace = true, default-features = true } +cumulus-test-service = { workspace = true } diff --git a/cumulus/client/network/src/tests.rs b/cumulus/client/network/src/tests.rs index eb0d7f0e01b391279648a5aea6031a275cf409a5..18d121c41d16823b0a8763132f51f9b949c41c6f 100644 --- a/cumulus/client/network/src/tests.rs +++ b/cumulus/client/network/src/tests.rs @@ -26,9 +26,10 @@ use futures::{executor::block_on, poll, task::Poll, FutureExt, Stream, StreamExt use parking_lot::Mutex; use polkadot_node_primitives::{SignedFullStatement, Statement}; use polkadot_primitives::{ - CandidateCommitments, CandidateDescriptor, CollatorPair, CommittedCandidateReceipt, - Hash as PHash, HeadData, InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, - PersistedValidationData, SessionIndex, SigningContext, ValidationCodeHash, ValidatorId, + BlockNumber, CandidateCommitments, CandidateDescriptor, CollatorPair, + CommittedCandidateReceipt, CoreState, Hash as PHash, HeadData, InboundDownwardMessage, + InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, SessionIndex, + SigningContext, ValidationCodeHash, ValidatorId, }; use polkadot_test_client::{ Client as PClient, ClientBlockImportExt, DefaultTestClientBuilderExt, FullBackend as PBackend, @@ -297,6 +298,13 @@ impl RelayChainInterface for DummyRelayChainInterface { Ok(header) } + async fn availability_cores( + &self, + _relay_parent: PHash, + ) -> RelayChainResult>> { + unimplemented!("Not needed for test"); + } + async fn version(&self, _: PHash) -> RelayChainResult { let version = self.data.lock().runtime_version; diff --git a/cumulus/client/parachain-inherent/Cargo.toml b/cumulus/client/parachain-inherent/Cargo.toml index 85619e8403458c0bfa3dae6dadc688f2cb895731..0d82cf64874322c2d9e6e2cb64ed742d35bc58e5 100644 --- a/cumulus/client/parachain-inherent/Cargo.toml +++ b/cumulus/client/parachain-inherent/Cargo.toml @@ -7,24 +7,22 @@ description = "Inherent that needs to be present in every parachain block. Conta license = "Apache-2.0" [dependencies] -async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } -scale-info = { version = "2.11.1", features = ["derive"] } -tracing = { version = "0.1.37" } +async-trait = { workspace = true } +codec = { features = ["derive"], workspace = true, default-features = true } +tracing = { workspace = true, default-features = true } # Substrate -sc-client-api = { path = "../../../substrate/client/api" } -sp-api = { path = "../../../substrate/primitives/api" } -sp-crypto-hashing = { path = "../../../substrate/primitives/crypto/hashing" } -sp-inherents = { path = "../../../substrate/primitives/inherents" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } -sp-state-machine = { path = "../../../substrate/primitives/state-machine" } -sp-std = { path = "../../../substrate/primitives/std" } -sp-storage = { path = "../../../substrate/primitives/storage" } -sp-trie = { path = "../../../substrate/primitives/trie" } +sc-client-api = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } +sp-storage = { workspace = true, default-features = true } +sp-trie = { workspace = true, default-features = true } # Cumulus -cumulus-primitives-core = { path = "../../primitives/core" } -cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" } -cumulus-relay-chain-interface = { path = "../relay-chain-interface" } -cumulus-test-relay-sproof-builder = { path = "../../test/relay-sproof-builder" } +cumulus-primitives-core = { workspace = true, default-features = true } +cumulus-primitives-parachain-inherent = { workspace = true, default-features = true } +cumulus-relay-chain-interface = { workspace = true, default-features = true } +cumulus-test-relay-sproof-builder = { workspace = true, default-features = true } diff --git a/cumulus/client/pov-recovery/Cargo.toml b/cumulus/client/pov-recovery/Cargo.toml index 539802d6938663e1268e887c17f505d23c72c1c3..a95b24bc2933aa2d8529e70ee2b37759625b1757 100644 --- a/cumulus/client/pov-recovery/Cargo.toml +++ b/cumulus/client/pov-recovery/Cargo.toml @@ -10,46 +10,46 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } -futures = "0.3.28" -futures-timer = "3.0.2" -rand = "0.8.5" -tracing = "0.1.37" +codec = { features = ["derive"], workspace = true, default-features = true } +futures = { workspace = true } +futures-timer = { workspace = true } +rand = { workspace = true, default-features = true } +tracing = { workspace = true, default-features = true } # Substrate -sc-client-api = { path = "../../../substrate/client/api" } -sc-consensus = { path = "../../../substrate/client/consensus/common" } -sp-consensus = { path = "../../../substrate/primitives/consensus/common" } -sp-maybe-compressed-blob = { path = "../../../substrate/primitives/maybe-compressed-blob" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } -sp-api = { path = "../../../substrate/primitives/api" } -sp-version = { path = "../../../substrate/primitives/version" } +sc-client-api = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-maybe-compressed-blob = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-version = { workspace = true, default-features = true } # Polkadot -polkadot-node-primitives = { path = "../../../polkadot/node/primitives" } -polkadot-node-subsystem = { path = "../../../polkadot/node/subsystem" } -polkadot-overseer = { path = "../../../polkadot/node/overseer" } -polkadot-primitives = { path = "../../../polkadot/primitives" } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-overseer = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } # Cumulus -cumulus-primitives-core = { path = "../../primitives/core" } -cumulus-relay-chain-interface = { path = "../relay-chain-interface" } -async-trait = "0.1.79" +cumulus-primitives-core = { workspace = true, default-features = true } +cumulus-relay-chain-interface = { workspace = true, default-features = true } +async-trait = { workspace = true } [dev-dependencies] -rstest = "0.18.2" -tokio = { version = "1.32.0", features = ["macros"] } -portpicker = "0.1.1" -sp-blockchain = { path = "../../../substrate/primitives/blockchain" } -cumulus-test-client = { path = "../../test/client" } -sc-utils = { path = "../../../substrate/client/utils" } -sp-tracing = { path = "../../../substrate/primitives/tracing" } -assert_matches = "1.5" +rstest = { workspace = true } +tokio = { features = ["macros"], workspace = true, default-features = true } +portpicker = { workspace = true } +sp-blockchain = { workspace = true, default-features = true } +cumulus-test-client = { workspace = true } +sc-utils = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +assert_matches = { workspace = true } # Cumulus -cumulus-test-service = { path = "../../test/service" } +cumulus-test-service = { workspace = true } # Substrate -sc-cli = { path = "../../../substrate/client/cli" } -sc-client-api = { path = "../../../substrate/client/api" } -substrate-test-utils = { path = "../../../substrate/test-utils" } +sc-cli = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +substrate-test-utils = { workspace = true } diff --git a/cumulus/client/pov-recovery/src/tests.rs b/cumulus/client/pov-recovery/src/tests.rs index 75bf308ef27aa051e42806b7f65e7ab8b45a9c1a..6f274ed18b6bc7871607cae6c5183d6d861e5117 100644 --- a/cumulus/client/pov-recovery/src/tests.rs +++ b/cumulus/client/pov-recovery/src/tests.rs @@ -17,7 +17,9 @@ use super::*; use assert_matches::assert_matches; use codec::{Decode, Encode}; -use cumulus_primitives_core::relay_chain::{BlockId, CandidateCommitments, CandidateDescriptor}; +use cumulus_primitives_core::relay_chain::{ + BlockId, CandidateCommitments, CandidateDescriptor, CoreState, +}; use cumulus_relay_chain_interface::{ InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, PHash, PHeader, PersistedValidationData, StorageValue, ValidationCodeHash, ValidatorId, @@ -478,6 +480,13 @@ impl RelayChainInterface for Relaychain { async fn header(&self, _: BlockId) -> RelayChainResult> { unimplemented!("Not needed for test"); } + + async fn availability_cores( + &self, + _: PHash, + ) -> RelayChainResult>>> { + unimplemented!("Not needed for test"); + } } fn make_candidate_chain(candidate_number_range: Range) -> Vec { diff --git a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml index 7629b6c631a3a0195760eee7fd39e754c289dd3e..6f1b74191be79a3c90100a18df1b20b850e0f4b2 100644 --- a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml +++ b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml @@ -10,39 +10,39 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -async-trait = "0.1.79" -futures = "0.3.28" -futures-timer = "3.0.2" +async-trait = { workspace = true } +futures = { workspace = true } +futures-timer = { workspace = true } # Substrate -sc-cli = { path = "../../../substrate/client/cli" } -sc-client-api = { path = "../../../substrate/client/api" } -sc-telemetry = { path = "../../../substrate/client/telemetry" } -sc-tracing = { path = "../../../substrate/client/tracing" } -sc-sysinfo = { path = "../../../substrate/client/sysinfo" } -sp-api = { path = "../../../substrate/primitives/api" } -sp-consensus = { path = "../../../substrate/primitives/consensus/common" } -sp-core = { path = "../../../substrate/primitives/core" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } -sp-state-machine = { path = "../../../substrate/primitives/state-machine" } +sc-cli = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-telemetry = { workspace = true, default-features = true } +sc-tracing = { workspace = true, default-features = true } +sc-sysinfo = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } # Polkadot -polkadot-cli = { path = "../../../polkadot/cli", default-features = false, features = ["cli"] } -polkadot-service = { path = "../../../polkadot/node/service" } +polkadot-cli = { features = ["cli"], workspace = true } +polkadot-service = { workspace = true, default-features = true } # Cumulus -cumulus-primitives-core = { path = "../../primitives/core" } -cumulus-relay-chain-interface = { path = "../relay-chain-interface" } +cumulus-primitives-core = { workspace = true, default-features = true } +cumulus-relay-chain-interface = { workspace = true, default-features = true } [dev-dependencies] # Substrate -sp-keyring = { path = "../../../substrate/primitives/keyring" } +sp-keyring = { workspace = true, default-features = true } # Polkadot -polkadot-primitives = { path = "../../../polkadot/primitives" } -polkadot-test-client = { path = "../../../polkadot/node/test/client" } -metered = { package = "prioritized-metered-channel", version = "0.6.1", default-features = false, features = ["futures_channel"] } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-test-client = { workspace = true } +metered = { features = ["futures_channel"], workspace = true } # Cumulus -cumulus-test-service = { path = "../../test/service" } +cumulus-test-service = { workspace = true } diff --git a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs index 7871623e8447a2645ef772a495d7f698660f7dc5..38ba84748c1e38b8dd3c1fcdd2f8d6351299b18c 100644 --- a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs +++ b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs @@ -14,14 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use std::{pin::Pin, sync::Arc, time::Duration}; +use std::{collections::btree_map::BTreeMap, pin::Pin, sync::Arc, time::Duration}; use async_trait::async_trait; use cumulus_primitives_core::{ relay_chain::{ - runtime_api::ParachainHost, Block as PBlock, BlockId, CommittedCandidateReceipt, - Hash as PHash, Header as PHeader, InboundHrmpMessage, OccupiedCoreAssumption, SessionIndex, - ValidationCodeHash, ValidatorId, + runtime_api::ParachainHost, Block as PBlock, BlockId, BlockNumber, + CommittedCandidateReceipt, CoreState, Hash as PHash, Header as PHeader, InboundHrmpMessage, + OccupiedCoreAssumption, SessionIndex, ValidationCodeHash, ValidatorId, }, InboundDownwardMessage, ParaId, PersistedValidationData, }; @@ -38,7 +38,7 @@ use sc_client_api::{ use sc_telemetry::TelemetryWorkerHandle; use sp_api::ProvideRuntimeApi; use sp_consensus::SyncOracle; -use sp_core::{sp_std::collections::btree_map::BTreeMap, Pair}; +use sp_core::Pair; use sp_state_machine::{Backend as StateBackend, StorageValue}; /// The timeout in seconds after that the waiting for a block should be aborted. @@ -256,6 +256,13 @@ impl RelayChainInterface for RelayChainInProcessInterface { Ok(Box::pin(notifications_stream)) } + async fn availability_cores( + &self, + relay_parent: PHash, + ) -> RelayChainResult>> { + Ok(self.full_client.runtime_api().availability_cores(relay_parent)?) + } + async fn candidates_pending_availability( &self, hash: PHash, diff --git a/cumulus/client/relay-chain-interface/Cargo.toml b/cumulus/client/relay-chain-interface/Cargo.toml index e8603693ac8da957988afac9e98468b759476665..a496fab050dd7fc3cba69c8a6812c5f07b27a6d4 100644 --- a/cumulus/client/relay-chain-interface/Cargo.toml +++ b/cumulus/client/relay-chain-interface/Cargo.toml @@ -10,18 +10,18 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -polkadot-overseer = { path = "../../../polkadot/node/overseer" } +polkadot-overseer = { workspace = true, default-features = true } -cumulus-primitives-core = { path = "../../primitives/core" } +cumulus-primitives-core = { workspace = true, default-features = true } -sp-api = { path = "../../../substrate/primitives/api" } -sp-blockchain = { path = "../../../substrate/primitives/blockchain" } -sp-state-machine = { path = "../../../substrate/primitives/state-machine" } -sc-client-api = { path = "../../../substrate/client/api" } -sp-version = { path = "../../../substrate/primitives/version", default-features = false } +sp-api = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sp-version = { workspace = true } -futures = "0.3.28" -async-trait = "0.1.79" +futures = { workspace = true } +async-trait = { workspace = true } thiserror = { workspace = true } -jsonrpsee-core = "0.22" -codec = { package = "parity-scale-codec", version = "3.6.12" } +jsonrpsee-core = { workspace = true } +codec = { workspace = true, default-features = true } diff --git a/cumulus/client/relay-chain-interface/src/lib.rs b/cumulus/client/relay-chain-interface/src/lib.rs index 46e19b40f010cce4342f54cbe08e975a52fee185..d02035e84e92f45c4da74f91912ee57abaa083ee 100644 --- a/cumulus/client/relay-chain-interface/src/lib.rs +++ b/cumulus/client/relay-chain-interface/src/lib.rs @@ -29,8 +29,8 @@ use sp_api::ApiError; use cumulus_primitives_core::relay_chain::BlockId; pub use cumulus_primitives_core::{ relay_chain::{ - CommittedCandidateReceipt, Hash as PHash, Header as PHeader, InboundHrmpMessage, - OccupiedCoreAssumption, SessionIndex, ValidationCodeHash, ValidatorId, + BlockNumber, CommittedCandidateReceipt, CoreState, Hash as PHash, Header as PHeader, + InboundHrmpMessage, OccupiedCoreAssumption, SessionIndex, ValidationCodeHash, ValidatorId, }, InboundDownwardMessage, ParaId, PersistedValidationData, }; @@ -217,6 +217,14 @@ pub trait RelayChainInterface: Send + Sync { /// Get the runtime version of the relay chain. async fn version(&self, relay_parent: PHash) -> RelayChainResult; + + /// Yields information on all availability cores as relevant to the child block. + /// + /// Cores are either free, scheduled or occupied. Free cores can have paras assigned to them. + async fn availability_cores( + &self, + relay_parent: PHash, + ) -> RelayChainResult>>; } #[async_trait] @@ -337,6 +345,13 @@ where .await } + async fn availability_cores( + &self, + relay_parent: PHash, + ) -> RelayChainResult>> { + (**self).availability_cores(relay_parent).await + } + async fn candidates_pending_availability( &self, block_id: PHash, diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index 0b541092a3de866fa68491694db51236ef72f641..95ecadc8bd06ec52b0089dd39143e78e1a27811a 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -11,44 +11,37 @@ workspace = true [dependencies] # polkadot deps -polkadot-primitives = { path = "../../../polkadot/primitives" } -polkadot-core-primitives = { path = "../../../polkadot/core-primitives" } -polkadot-overseer = { path = "../../../polkadot/node/overseer" } -polkadot-node-subsystem-util = { path = "../../../polkadot/node/subsystem-util" } -polkadot-node-network-protocol = { path = "../../../polkadot/node/network/protocol" } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-core-primitives = { workspace = true, default-features = true } +polkadot-overseer = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } -polkadot-availability-recovery = { path = "../../../polkadot/node/network/availability-recovery" } -polkadot-collator-protocol = { path = "../../../polkadot/node/network/collator-protocol" } -polkadot-network-bridge = { path = "../../../polkadot/node/network/bridge" } -polkadot-node-collation-generation = { path = "../../../polkadot/node/collation-generation" } -polkadot-node-core-runtime-api = { path = "../../../polkadot/node/core/runtime-api" } -polkadot-node-core-chain-api = { path = "../../../polkadot/node/core/chain-api" } -polkadot-node-core-prospective-parachains = { path = "../../../polkadot/node/core/prospective-parachains" } -polkadot-service = { path = "../../../polkadot/node/service" } +polkadot-network-bridge = { workspace = true, default-features = true } +polkadot-service = { workspace = true, default-features = true } # substrate deps -sc-authority-discovery = { path = "../../../substrate/client/authority-discovery" } -sc-network = { path = "../../../substrate/client/network" } -sc-network-common = { path = "../../../substrate/client/network/common" } -sc-service = { path = "../../../substrate/client/service" } -sc-client-api = { path = "../../../substrate/client/api" } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../substrate/utils/prometheus" } -sc-tracing = { path = "../../../substrate/client/tracing" } -sc-utils = { path = "../../../substrate/client/utils" } -sp-api = { path = "../../../substrate/primitives/api" } -sp-consensus-babe = { path = "../../../substrate/primitives/consensus/babe" } -sp-consensus = { path = "../../../substrate/primitives/consensus/common" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } -sp-blockchain = { path = "../../../substrate/primitives/blockchain" } -tokio = { version = "1.32.0", features = ["macros"] } +sc-authority-discovery = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-network-common = { workspace = true, default-features = true } +sc-service = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +prometheus-endpoint = { workspace = true, default-features = true } +sc-tracing = { workspace = true, default-features = true } +sc-utils = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +tokio = { features = ["macros"], workspace = true, default-features = true } # cumulus deps -cumulus-relay-chain-interface = { path = "../relay-chain-interface" } -cumulus-relay-chain-rpc-interface = { path = "../relay-chain-rpc-interface" } -cumulus-primitives-core = { path = "../../primitives/core" } +cumulus-relay-chain-interface = { workspace = true, default-features = true } +cumulus-relay-chain-rpc-interface = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true, default-features = true } -array-bytes = "6.2.2" -tracing = "0.1.37" -async-trait = "0.1.79" -futures = "0.3.28" -parking_lot = "0.12.1" +array-bytes = { workspace = true, default-features = true } +tracing = { workspace = true, default-features = true } +async-trait = { workspace = true } +futures = { workspace = true } diff --git a/cumulus/client/relay-chain-minimal-node/src/lib.rs b/cumulus/client/relay-chain-minimal-node/src/lib.rs index 9101b8154aa72a7ec8b8bda5715c15048a70cd7c..732a242e72957214ce8161d5f785d20b8c2484b3 100644 --- a/cumulus/client/relay-chain-minimal-node/src/lib.rs +++ b/cumulus/client/relay-chain-minimal-node/src/lib.rs @@ -176,8 +176,10 @@ async fn new_minimal_relay_chain, ) -> Result { let role = config.role.clone(); - let mut net_config = - sc_network::config::FullNetworkConfiguration::<_, _, Network>::new(&config.network); + let mut net_config = sc_network::config::FullNetworkConfiguration::<_, _, Network>::new( + &config.network, + config.prometheus_config.as_ref().map(|cfg| cfg.registry.clone()), + ); let metrics = Network::register_notification_metrics( config.prometheus_config.as_ref().map(|cfg| &cfg.registry), ); diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index ea6bc2ede4c041620acc18a2fcccde38b03d2388..6c0730a56a264b9805b092df203671778719bc49 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -10,39 +10,39 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -polkadot-overseer = { path = "../../../polkadot/node/overseer" } +polkadot-overseer = { workspace = true, default-features = true } -cumulus-primitives-core = { path = "../../primitives/core" } -cumulus-relay-chain-interface = { path = "../relay-chain-interface" } +cumulus-primitives-core = { workspace = true, default-features = true } +cumulus-relay-chain-interface = { workspace = true, default-features = true } -sp-api = { path = "../../../substrate/primitives/api" } -sp-core = { path = "../../../substrate/primitives/core" } -sp-consensus-babe = { path = "../../../substrate/primitives/consensus/babe" } -sp-authority-discovery = { path = "../../../substrate/primitives/authority-discovery" } -sp-state-machine = { path = "../../../substrate/primitives/state-machine" } -sp-storage = { path = "../../../substrate/primitives/storage" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } -sp-version = { path = "../../../substrate/primitives/version" } -sc-client-api = { path = "../../../substrate/client/api" } -sc-rpc-api = { path = "../../../substrate/client/rpc-api" } -sc-service = { path = "../../../substrate/client/service" } +sp-api = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-authority-discovery = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } +sp-storage = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-version = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-rpc-api = { workspace = true, default-features = true } +sc-service = { workspace = true, default-features = true } -tokio = { version = "1.32.0", features = ["sync"] } -tokio-util = { version = "0.7.8", features = ["compat"] } +tokio = { features = ["sync"], workspace = true, default-features = true } +tokio-util = { features = ["compat"], workspace = true } -futures = "0.3.28" -futures-timer = "3.0.2" -codec = { package = "parity-scale-codec", version = "3.6.12" } -jsonrpsee = { version = "0.22", features = ["ws-client"] } -tracing = "0.1.37" -async-trait = "0.1.79" -url = "2.4.0" +futures = { workspace = true } +futures-timer = { workspace = true } +codec = { workspace = true, default-features = true } +jsonrpsee = { features = ["ws-client"], workspace = true } +tracing = { workspace = true, default-features = true } +async-trait = { workspace = true } +url = { workspace = true } serde_json = { workspace = true, default-features = true } serde = { workspace = true, default-features = true } -schnellru = "0.2.1" -smoldot = { version = "0.11.0", default_features = false, features = ["std"] } -smoldot-light = { version = "0.9.0", default_features = false, features = ["std"] } -either = "1.8.1" +schnellru = { workspace = true } +smoldot = { default_features = false, features = ["std"], workspace = true } +smoldot-light = { default_features = false, features = ["std"], workspace = true } +either = { workspace = true, default-features = true } thiserror = { workspace = true } -rand = "0.8.5" -pin-project = "1.1.3" +rand = { workspace = true, default-features = true } +pin-project = { workspace = true } diff --git a/cumulus/client/relay-chain-rpc-interface/src/lib.rs b/cumulus/client/relay-chain-rpc-interface/src/lib.rs index bb7bfa5dc32268b87bfbe1788aad7b6604961276..e32ec6a41a4bf00db5e5db07235bf43bbad1dbf6 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/lib.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/lib.rs @@ -24,17 +24,16 @@ use cumulus_primitives_core::{ InboundDownwardMessage, ParaId, PersistedValidationData, }; use cumulus_relay_chain_interface::{ - PHeader, RelayChainError, RelayChainInterface, RelayChainResult, + BlockNumber, CoreState, PHeader, RelayChainError, RelayChainInterface, RelayChainResult, }; use futures::{FutureExt, Stream, StreamExt}; use polkadot_overseer::Handle; use sc_client_api::StorageProof; -use sp_core::sp_std::collections::btree_map::BTreeMap; use sp_state_machine::StorageValue; use sp_storage::StorageKey; use sp_version::RuntimeVersion; -use std::pin::Pin; +use std::{collections::btree_map::BTreeMap, pin::Pin}; use cumulus_primitives_core::relay_chain::BlockId; pub use url::Url; @@ -252,4 +251,11 @@ impl RelayChainInterface for RelayChainRpcInterface { async fn version(&self, relay_parent: RelayHash) -> RelayChainResult { self.rpc_client.runtime_version(relay_parent).await } + + async fn availability_cores( + &self, + relay_parent: RelayHash, + ) -> RelayChainResult>> { + self.rpc_client.parachain_host_availability_cores(relay_parent).await + } } diff --git a/cumulus/client/relay-chain-rpc-interface/src/light_client_worker.rs b/cumulus/client/relay-chain-rpc-interface/src/light_client_worker.rs index 9a49b60281b3c51fa1426903a0e73157a6f04e0e..2347dbb85f78ed1d8017ba076f6d77e97664c021 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/light_client_worker.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/light_client_worker.rs @@ -20,7 +20,7 @@ use futures::{channel::mpsc::Sender, prelude::*, stream::FuturesUnordered}; use jsonrpsee::core::client::{ - Client as JsonRpseeClient, ClientBuilder, ClientT, Error, ReceivedMessage, TransportReceiverT, + Client as JsonRpseeClient, ClientBuilder, ClientT, ReceivedMessage, TransportReceiverT, TransportSenderT, }; use smoldot_light::{ChainId, Client as SmoldotClient, JsonRpcResponses}; @@ -124,7 +124,7 @@ pub struct LightClientRpcWorker { } fn handle_notification( - maybe_header: Option>, + maybe_header: Option>, senders: &mut Vec>, ) -> Result<(), ()> { match maybe_header { diff --git a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs index a5d7c22a2ec89b17c2115a4dd56e4ee935ca51b4..c7eaa45958b0b002a00ec8210d5044bd56aa0569 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs @@ -24,7 +24,7 @@ use jsonrpsee::{ }; use serde::de::DeserializeOwned; use serde_json::Value as JsonValue; -use std::collections::VecDeque; +use std::collections::{btree_map::BTreeMap, VecDeque}; use tokio::sync::mpsc::Sender as TokioSender; use codec::{Decode, Encode}; @@ -47,7 +47,6 @@ use sc_client_api::StorageData; use sc_rpc_api::{state::ReadProof, system::Health}; use sc_service::TaskManager; use sp_consensus_babe::Epoch; -use sp_core::sp_std::collections::btree_map::BTreeMap; use sp_storage::StorageKey; use sp_version::RuntimeVersion; diff --git a/cumulus/client/service/Cargo.toml b/cumulus/client/service/Cargo.toml index e03e20fe5b416102aa99739cb00c0b39edf5b999..8e9e41ca89dc06401c04e36b5cc0db7ffb3e36d7 100644 --- a/cumulus/client/service/Cargo.toml +++ b/cumulus/client/service/Cargo.toml @@ -10,39 +10,39 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -futures = "0.3.28" +futures = { workspace = true } # Substrate -sc-client-api = { path = "../../../substrate/client/api" } -sc-consensus = { path = "../../../substrate/client/consensus/common" } -sc-transaction-pool = { path = "../../../substrate/client/transaction-pool" } -sc-rpc = { path = "../../../substrate/client/rpc" } -sc-service = { path = "../../../substrate/client/service" } -sc-sysinfo = { path = "../../../substrate/client/sysinfo" } -sc-telemetry = { path = "../../../substrate/client/telemetry" } -sc-network = { path = "../../../substrate/client/network" } -sc-network-sync = { path = "../../../substrate/client/network/sync" } -sc-utils = { path = "../../../substrate/client/utils" } -sc-network-transactions = { path = "../../../substrate/client/network/transactions" } -sp-api = { path = "../../../substrate/primitives/api" } -sp-blockchain = { path = "../../../substrate/primitives/blockchain" } -sp-consensus = { path = "../../../substrate/primitives/consensus/common" } -sp-core = { path = "../../../substrate/primitives/core" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } -sp-transaction-pool = { path = "../../../substrate/primitives/transaction-pool" } -sp-io = { path = "../../../substrate/primitives/io" } +sc-client-api = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sc-transaction-pool = { workspace = true, default-features = true } +sc-rpc = { workspace = true, default-features = true } +sc-service = { workspace = true, default-features = true } +sc-sysinfo = { workspace = true, default-features = true } +sc-telemetry = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-network-sync = { workspace = true, default-features = true } +sc-utils = { workspace = true, default-features = true } +sc-network-transactions = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-transaction-pool = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } # Polkadot -polkadot-primitives = { path = "../../../polkadot/primitives" } +polkadot-primitives = { workspace = true, default-features = true } # Cumulus -cumulus-client-cli = { path = "../cli" } -cumulus-client-collator = { path = "../collator" } -cumulus-client-consensus-common = { path = "../consensus/common" } -cumulus-client-pov-recovery = { path = "../pov-recovery" } -cumulus-client-network = { path = "../network" } -cumulus-primitives-core = { path = "../../primitives/core" } -cumulus-primitives-proof-size-hostfunction = { path = "../../primitives/proof-size-hostfunction" } -cumulus-relay-chain-interface = { path = "../relay-chain-interface" } -cumulus-relay-chain-inprocess-interface = { path = "../relay-chain-inprocess-interface" } -cumulus-relay-chain-minimal-node = { path = "../relay-chain-minimal-node" } +cumulus-client-cli = { workspace = true, default-features = true } +cumulus-client-collator = { workspace = true, default-features = true } +cumulus-client-consensus-common = { workspace = true, default-features = true } +cumulus-client-pov-recovery = { workspace = true, default-features = true } +cumulus-client-network = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true, default-features = true } +cumulus-primitives-proof-size-hostfunction = { workspace = true, default-features = true } +cumulus-relay-chain-interface = { workspace = true, default-features = true } +cumulus-relay-chain-inprocess-interface = { workspace = true, default-features = true } +cumulus-relay-chain-minimal-node = { workspace = true, default-features = true } diff --git a/cumulus/pallets/aura-ext/Cargo.toml b/cumulus/pallets/aura-ext/Cargo.toml index daff5ef8f482e82b80f341d5208cad51b23b7b1a..c08148928b7cec891b8f80cb856714c24b04d809 100644 --- a/cumulus/pallets/aura-ext/Cargo.toml +++ b/cumulus/pallets/aura-ext/Cargo.toml @@ -10,26 +10,25 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } # Substrate -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -pallet-aura = { path = "../../../substrate/frame/aura", default-features = false } -pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false } -sp-application-crypto = { path = "../../../substrate/primitives/application-crypto", default-features = false } -sp-consensus-aura = { path = "../../../substrate/primitives/consensus/aura", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-aura = { workspace = true } +pallet-timestamp = { workspace = true } +sp-application-crypto = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-runtime = { workspace = true } # Cumulus -cumulus-pallet-parachain-system = { path = "../parachain-system", default-features = false } +cumulus-pallet-parachain-system = { workspace = true } [dev-dependencies] # Cumulus -cumulus-pallet-parachain-system = { path = "../parachain-system" } +cumulus-pallet-parachain-system = { workspace = true, default-features = true } [features] default = ["std"] @@ -44,7 +43,6 @@ std = [ "sp-application-crypto/std", "sp-consensus-aura/std", "sp-runtime/std", - "sp-std/std", ] try-runtime = [ "cumulus-pallet-parachain-system/try-runtime", diff --git a/cumulus/pallets/aura-ext/src/consensus_hook.rs b/cumulus/pallets/aura-ext/src/consensus_hook.rs index 592029803391179785bb3b5606079d1bee6b553f..c1a8568bdd834f0e754bdad20a5a11246cc6ac31 100644 --- a/cumulus/pallets/aura-ext/src/consensus_hook.rs +++ b/cumulus/pallets/aura-ext/src/consensus_hook.rs @@ -20,6 +20,7 @@ //! The velocity `V` refers to the rate of block processing by the relay chain. use super::{pallet, Aura}; +use core::{marker::PhantomData, num::NonZeroU32}; use cumulus_pallet_parachain_system::{ self as parachain_system, consensus_hook::{ConsensusHook, UnincludedSegmentCapacity}, @@ -27,7 +28,6 @@ use cumulus_pallet_parachain_system::{ }; use frame_support::pallet_prelude::*; use sp_consensus_aura::{Slot, SlotDuration}; -use sp_std::{marker::PhantomData, num::NonZeroU32}; /// A consensus hook for a fixed block processing velocity and unincluded segment capacity. /// @@ -65,16 +65,26 @@ where let para_slot_from_relay = Slot::from_timestamp(relay_chain_timestamp.into(), para_slot_duration); - // Perform checks. - assert_eq!(slot, para_slot_from_relay, "slot number mismatch"); - if authored > velocity + 1 { + // Check that we are not too far in the future. Since we expect `V` parachain blocks + // during the relay chain slot, we can allow for `V` parachain slots into the future. + if *slot > *para_slot_from_relay + u64::from(velocity) { + panic!( + "Parachain slot is too far in the future: parachain_slot: {:?}, derived_from_relay_slot: {:?} velocity: {:?}", + slot, + para_slot_from_relay, + velocity + ); + } + + // We need to allow authoring multiple blocks in the same slot. + if slot != para_slot_from_relay && authored > velocity { panic!("authored blocks limit is reached for the slot") } let weight = T::DbWeight::get().reads(1); ( weight, - NonZeroU32::new(sp_std::cmp::max(C, 1)) + NonZeroU32::new(core::cmp::max(C, 1)) .expect("1 is the minimum value and non-zero; qed") .into(), ) @@ -113,6 +123,11 @@ impl< return false } + // TODO: This logic needs to be adjusted. + // It checks that we have not authored more than `V + 1` blocks in the slot. + // As a slot however, we take the parachain slot here. Velocity should + // be measured in relation to the relay chain slot. + // https://github.com/paritytech/polkadot-sdk/issues/3967 if last_slot == new_slot { authored_so_far < velocity + 1 } else { diff --git a/cumulus/pallets/aura-ext/src/lib.rs b/cumulus/pallets/aura-ext/src/lib.rs index 7ca84dff7c513c2406d3c0de7b9c0ac26048f508..4c9e61458a87c456766880351da7ecbcce30a92c 100644 --- a/cumulus/pallets/aura-ext/src/lib.rs +++ b/cumulus/pallets/aura-ext/src/lib.rs @@ -83,7 +83,7 @@ pub mod pallet { SlotInfo::::put((new_slot, authored)); - T::DbWeight::get().reads_writes(2, 1) + T::DbWeight::get().reads_writes(4, 2) } } @@ -109,7 +109,7 @@ pub mod pallet { #[derive(frame_support::DefaultNoBound)] pub struct GenesisConfig { #[serde(skip)] - pub _config: sp_std::marker::PhantomData, + pub _config: core::marker::PhantomData, } #[pallet::genesis_build] @@ -125,7 +125,7 @@ pub mod pallet { /// /// When executing the block it will verify the block seal to ensure that the correct author created /// the block. -pub struct BlockExecutor(sp_std::marker::PhantomData<(T, I)>); +pub struct BlockExecutor(core::marker::PhantomData<(T, I)>); impl ExecuteBlock for BlockExecutor where diff --git a/cumulus/pallets/collator-selection/Cargo.toml b/cumulus/pallets/collator-selection/Cargo.toml index f30802fa5d82ecb93e8610e7c7bb17a2a83cacb4..b3512dc2ae6c9a646e63d911bdf09b132f5098cd 100644 --- a/cumulus/pallets/collator-selection/Cargo.toml +++ b/cumulus/pallets/collator-selection/Cargo.toml @@ -17,29 +17,28 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { workspace = true } -codec = { default-features = false, features = ["derive"], package = "parity-scale-codec", version = "3.6.12" } -rand = { version = "0.8.5", features = ["std_rng"], default-features = false } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } +rand = { features = ["std_rng"], workspace = true } +scale-info = { features = ["derive"], workspace = true } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-staking = { path = "../../../substrate/primitives/staking", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } -pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } -pallet-session = { path = "../../../substrate/frame/session", default-features = false } +sp-runtime = { workspace = true } +sp-staking = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-authorship = { workspace = true } +pallet-balances = { workspace = true } +pallet-session = { workspace = true } -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } +frame-benchmarking = { optional = true, workspace = true } [dev-dependencies] -sp-core = { path = "../../../substrate/primitives/core" } -sp-io = { path = "../../../substrate/primitives/io" } -sp-tracing = { path = "../../../substrate/primitives/tracing" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } -pallet-timestamp = { path = "../../../substrate/frame/timestamp" } -sp-consensus-aura = { path = "../../../substrate/primitives/consensus/aura" } -pallet-aura = { path = "../../../substrate/frame/aura" } +sp-core = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +pallet-timestamp = { workspace = true, default-features = true } +sp-consensus-aura = { workspace = true, default-features = true } +pallet-aura = { workspace = true, default-features = true } [features] default = ["std"] @@ -65,7 +64,6 @@ std = [ "scale-info/std", "sp-runtime/std", "sp-staking/std", - "sp-std/std", ] try-runtime = [ diff --git a/cumulus/pallets/collator-selection/src/benchmarking.rs b/cumulus/pallets/collator-selection/src/benchmarking.rs index c6b600445282534951b2c63a6c2a87181688acd1..24823661383b55f26bf19356e72394945c01f577 100644 --- a/cumulus/pallets/collator-selection/src/benchmarking.rs +++ b/cumulus/pallets/collator-selection/src/benchmarking.rs @@ -21,13 +21,14 @@ use super::*; #[allow(unused)] use crate::Pallet as CollatorSelection; +use alloc::vec::Vec; use codec::Decode; +use core::cmp; use frame_benchmarking::{account, v2::*, whitelisted_caller, BenchmarkError}; use frame_support::traits::{Currency, EnsureOrigin, Get, ReservableCurrency}; use frame_system::{pallet_prelude::BlockNumberFor, EventRecord, RawOrigin}; use pallet_authorship::EventHandler; use pallet_session::{self as session, SessionManager}; -use sp_std::{cmp, prelude::*}; pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; diff --git a/cumulus/pallets/collator-selection/src/lib.rs b/cumulus/pallets/collator-selection/src/lib.rs index 2fa384367528a1f1306a6c34c0c45d3ef94843a2..17dc1a552c2de40455933fe8a72d05caa4317a32 100644 --- a/cumulus/pallets/collator-selection/src/lib.rs +++ b/cumulus/pallets/collator-selection/src/lib.rs @@ -81,6 +81,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + use core::marker::PhantomData; use frame_support::traits::TypedGet; pub use pallet::*; @@ -101,6 +103,7 @@ const LOG_TARGET: &str = "runtime::collator-selection"; #[frame_support::pallet] pub mod pallet { pub use crate::weights::WeightInfo; + use alloc::vec::Vec; use core::ops::Div; use frame_support::{ dispatch::{DispatchClass, DispatchResultWithPostInfo}, @@ -118,7 +121,6 @@ pub mod pallet { RuntimeDebug, }; use sp_staking::SessionIndex; - use sp_std::vec::Vec; /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); @@ -244,7 +246,7 @@ pub mod pallet { let duplicate_invulnerables = self .invulnerables .iter() - .collect::>(); + .collect::>(); assert!( duplicate_invulnerables.len() == self.invulnerables.len(), "duplicate invulnerables in genesis." diff --git a/cumulus/pallets/collator-selection/src/migration.rs b/cumulus/pallets/collator-selection/src/migration.rs index 425acdd8bfb59768241399e3be5efb44a13c8a74..c52016948069a65c641fa014a390f1a6a85d3cb3 100644 --- a/cumulus/pallets/collator-selection/src/migration.rs +++ b/cumulus/pallets/collator-selection/src/migration.rs @@ -17,6 +17,8 @@ //! A module that is responsible for migration of storage for Collator Selection. use super::*; +#[cfg(feature = "try-runtime")] +use alloc::vec::Vec; use frame_support::traits::{OnRuntimeUpgrade, UncheckedOnRuntimeUpgrade}; use log; @@ -29,8 +31,6 @@ pub mod v2 { traits::{Currency, ReservableCurrency}, }; use sp_runtime::traits::{Saturating, Zero}; - #[cfg(feature = "try-runtime")] - use sp_std::vec::Vec; /// [`UncheckedMigrationToV2`] wrapped in a /// [`VersionedMigration`](frame_support::migrations::VersionedMigration), ensuring the @@ -51,7 +51,7 @@ pub mod v2 { >; /// Migrate to V2. - pub struct UncheckedMigrationToV2(sp_std::marker::PhantomData); + pub struct UncheckedMigrationToV2(PhantomData); impl UncheckedOnRuntimeUpgrade for UncheckedMigrationToV2 { fn on_runtime_upgrade() -> Weight { let mut weight = Weight::zero(); @@ -123,10 +123,8 @@ pub mod v2 { pub mod v1 { use super::*; use frame_support::pallet_prelude::*; - #[cfg(feature = "try-runtime")] - use sp_std::prelude::*; - pub struct MigrateToV1(sp_std::marker::PhantomData); + pub struct MigrateToV1(PhantomData); impl OnRuntimeUpgrade for MigrateToV1 { fn on_runtime_upgrade() -> Weight { let on_chain_version = Pallet::::on_chain_storage_version(); diff --git a/cumulus/pallets/collator-selection/src/weights.rs b/cumulus/pallets/collator-selection/src/weights.rs index 1c01ad6cd6fe8e8ed4bc02c3c2d6703eb2882df4..12e6b755e9769cb4234bc15016c0a3b47650054f 100644 --- a/cumulus/pallets/collator-selection/src/weights.rs +++ b/cumulus/pallets/collator-selection/src/weights.rs @@ -18,11 +18,11 @@ #![allow(unused_parens)] #![allow(unused_imports)] +use core::marker::PhantomData; use frame_support::{ traits::Get, weights::{constants::RocksDbWeight, Weight}, }; -use sp_std::marker::PhantomData; // The weight info trait for `pallet_collator_selection`. pub trait WeightInfo { diff --git a/cumulus/pallets/dmp-queue/Cargo.toml b/cumulus/pallets/dmp-queue/Cargo.toml index 687cda164fb0bd3d4aefb9d6b51f6735ef3a43c3..936526290d93ecd8935620c8f1f6045faadecb64 100644 --- a/cumulus/pallets/dmp-queue/Cargo.toml +++ b/cumulus/pallets/dmp-queue/Cargo.toml @@ -14,26 +14,25 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-runtime = { workspace = true } +sp-io = { workspace = true } # Polkadot -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } +xcm = { workspace = true } # Cumulus -cumulus-primitives-core = { path = "../../primitives/core", default-features = false } +cumulus-primitives-core = { workspace = true } [dev-dependencies] -sp-core = { path = "../../../substrate/primitives/core" } -sp-tracing = { path = "../../../substrate/primitives/tracing" } +sp-core = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } [features] default = ["std"] @@ -48,7 +47,6 @@ std = [ "scale-info/std", "sp-io/std", "sp-runtime/std", - "sp-std/std", "xcm/std", ] diff --git a/cumulus/pallets/dmp-queue/src/benchmarking.rs b/cumulus/pallets/dmp-queue/src/benchmarking.rs index 91d1e0eab7e406a214088d8c0e47d03e20cd0286..432d6f3bc7ae54432e3687b7d73e70a11ec2da04 100644 --- a/cumulus/pallets/dmp-queue/src/benchmarking.rs +++ b/cumulus/pallets/dmp-queue/src/benchmarking.rs @@ -19,9 +19,9 @@ use crate::*; +use alloc::vec; use frame_benchmarking::v2::*; use frame_support::{pallet_prelude::*, traits::Hooks}; -use sp_std::vec; #[benchmarks] mod benchmarks { diff --git a/cumulus/pallets/dmp-queue/src/lib.rs b/cumulus/pallets/dmp-queue/src/lib.rs index 9b3ec684febab81fb535c52118cbadb64b61e984..cedca6f3fb97f2186318718d068a2fa120a71bc3 100644 --- a/cumulus/pallets/dmp-queue/src/lib.rs +++ b/cumulus/pallets/dmp-queue/src/lib.rs @@ -23,6 +23,8 @@ #![cfg_attr(not(feature = "std"), no_std)] #![allow(deprecated)] // The pallet itself is deprecated. +extern crate alloc; + use migration::*; pub use pallet::*; diff --git a/cumulus/pallets/dmp-queue/src/migration.rs b/cumulus/pallets/dmp-queue/src/migration.rs index 349635cce547d81c1be527cb366f67679a471945..b1945e8eb37b85e9c39cbafeba4b6d7ec15502c0 100644 --- a/cumulus/pallets/dmp-queue/src/migration.rs +++ b/cumulus/pallets/dmp-queue/src/migration.rs @@ -17,9 +17,9 @@ //! Migrates the storage from the previously deleted DMP pallet. use crate::*; +use alloc::vec::Vec; use cumulus_primitives_core::relay_chain::BlockNumber as RelayBlockNumber; use frame_support::{pallet_prelude::*, storage_alias, traits::HandleMessage}; -use sp_std::vec::Vec; pub(crate) const LOG: &str = "runtime::dmp-queue-export-xcms"; diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 1a6a19f2ab4a2523074bd02aa96053a0f7236140..30a232f01b3e5ca82eab239626e2255a683972ee 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -10,62 +10,62 @@ license = "Apache-2.0" workspace = true [dependencies] -bytes = { version = "1.4.0", default-features = false } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -environmental = { version = "1.1.4", default-features = false } -impl-trait-for-tuples = "0.2.1" +bytes = { workspace = true } +codec = { features = ["derive"], workspace = true } +environmental = { workspace = true } +impl-trait-for-tuples = { workspace = true } log = { workspace = true } -trie-db = { version = "0.29.0", default-features = false } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +trie-db = { workspace = true } +scale-info = { features = ["derive"], workspace = true } # Substrate -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-externalities = { path = "../../../substrate/primitives/externalities", default-features = false } -sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-state-machine = { path = "../../../substrate/primitives/state-machine", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } -sp-version = { path = "../../../substrate/primitives/version", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-message-queue = { workspace = true } +sp-core = { workspace = true } +sp-externalities = { workspace = true } +sp-inherents = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +sp-state-machine = { workspace = true } +sp-std = { workspace = true } +sp-trie = { workspace = true } +sp-version = { workspace = true } # Polkadot -polkadot-parachain-primitives = { path = "../../../polkadot/parachain", default-features = false, features = ["wasm-api"] } -polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains", default-features = false } -polkadot-runtime-common = { path = "../../../polkadot/runtime/common", default-features = false, optional = true } -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false } +polkadot-parachain-primitives = { features = ["wasm-api"], workspace = true } +polkadot-runtime-parachains = { workspace = true } +polkadot-runtime-common = { optional = true, workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } # Cumulus -cumulus-pallet-parachain-system-proc-macro = { path = "proc-macro", default-features = false } -cumulus-primitives-core = { path = "../../primitives/core", default-features = false } -cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent", default-features = false } -cumulus-primitives-proof-size-hostfunction = { path = "../../primitives/proof-size-hostfunction", default-features = false } +cumulus-pallet-parachain-system-proc-macro = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-parachain-inherent = { workspace = true } +cumulus-primitives-proof-size-hostfunction = { workspace = true } [dev-dependencies] -assert_matches = "1.5" -hex-literal = "0.4.1" -lazy_static = "1.4" -trie-standardmap = "0.16.0" -rand = "0.8.5" -futures = "0.3.28" +assert_matches = { workspace = true } +hex-literal = { workspace = true, default-features = true } +lazy_static = { workspace = true } +trie-standardmap = { workspace = true } +rand = { workspace = true, default-features = true } +futures = { workspace = true } # Substrate -sc-client-api = { path = "../../../substrate/client/api" } -sp-keyring = { path = "../../../substrate/primitives/keyring" } -sp-crypto-hashing = { path = "../../../substrate/primitives/crypto/hashing" } -sp-tracing = { path = "../../../substrate/primitives/tracing" } -sp-version = { path = "../../../substrate/primitives/version" } -sp-consensus-slots = { path = "../../../substrate/primitives/consensus/slots" } +sc-client-api = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +sp-version = { workspace = true, default-features = true } +sp-consensus-slots = { workspace = true, default-features = true } # Cumulus -cumulus-test-client = { path = "../../test/client" } -cumulus-test-relay-sproof-builder = { path = "../../test/relay-sproof-builder" } -cumulus-test-runtime = { path = "../../test/runtime" } +cumulus-test-client = { workspace = true } +cumulus-test-relay-sproof-builder = { workspace = true, default-features = true } +cumulus-test-runtime = { workspace = true } [features] default = ["std"] diff --git a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml index 0a90c30e0331261026125f429efe70eff07ac069..da6f0fd03efb79b03e4815433084ca8b79f6595d 100644 --- a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml +++ b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml @@ -14,9 +14,9 @@ proc-macro = true [dependencies] syn = { workspace = true } -proc-macro2 = "1.0.64" +proc-macro2 = { workspace = true } quote = { workspace = true } -proc-macro-crate = "3.0.0" +proc-macro-crate = { workspace = true } [features] default = ["std"] diff --git a/cumulus/pallets/parachain-system/proc-macro/src/lib.rs b/cumulus/pallets/parachain-system/proc-macro/src/lib.rs index 8ab5d81efdcf486dff67db6a1f5a62a5a8454ae8..f284fbdc64c600f130b0e5bb531021ecfd2e0e73 100644 --- a/cumulus/pallets/parachain-system/proc-macro/src/lib.rs +++ b/cumulus/pallets/parachain-system/proc-macro/src/lib.rs @@ -122,8 +122,8 @@ pub fn register_validate_block(input: proc_macro::TokenStream) -> proc_macro::To #[no_mangle] unsafe fn validate_block(arguments: *mut u8, arguments_len: usize) -> u64 { // We convert the `arguments` into a boxed slice and then into `Bytes`. - let args = #crate_::validate_block::sp_std::boxed::Box::from_raw( - #crate_::validate_block::sp_std::slice::from_raw_parts_mut( + let args = #crate_::validate_block::Box::from_raw( + #crate_::validate_block::slice::from_raw_parts_mut( arguments, arguments_len, ) diff --git a/cumulus/pallets/parachain-system/src/consensus_hook.rs b/cumulus/pallets/parachain-system/src/consensus_hook.rs index 91353fc7bbda7ce05cfb5259e05bde64c758bbe4..3062396a4e7865bf4e3545b39c6ad9fa6ded6a24 100644 --- a/cumulus/pallets/parachain-system/src/consensus_hook.rs +++ b/cumulus/pallets/parachain-system/src/consensus_hook.rs @@ -18,8 +18,8 @@ //! of parachain blocks ready to submit to the relay chain, as well as some basic implementations. use super::relay_state_snapshot::RelayChainStateProof; +use core::num::NonZeroU32; use frame_support::weights::Weight; -use sp_std::num::NonZeroU32; /// The possible capacity of the unincluded segment. #[derive(Clone)] @@ -95,7 +95,7 @@ impl ConsensusHook for FixedCapacityUnincludedSegment { fn on_state_proof(_state_proof: &RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity) { ( Weight::zero(), - NonZeroU32::new(sp_std::cmp::max(N, 1)) + NonZeroU32::new(core::cmp::max(N, 1)) .expect("1 is the minimum value and non-zero; qed") .into(), ) diff --git a/cumulus/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index bbb74a1b053886b90740562e077ce40804eb01fd..9e0a68d09a14a685da6a66facdd0ac2822d4c6d4 100644 --- a/cumulus/pallets/parachain-system/src/lib.rs +++ b/cumulus/pallets/parachain-system/src/lib.rs @@ -27,7 +27,11 @@ //! //! Users must ensure that they register this pallet as an inherent provider. +extern crate alloc; + +use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec}; use codec::{Decode, Encode}; +use core::cmp; use cumulus_primitives_core::{ relay_chain, AbridgedHostConfiguration, ChannelInfo, ChannelStatus, CollationInfo, GetChannelInfo, InboundDownwardMessage, InboundHrmpMessage, ListChannelInfos, MessageSendError, @@ -54,7 +58,6 @@ use sp_runtime::{ }, BoundedSlice, FixedU128, RuntimeDebug, Saturating, }; -use sp_std::{cmp, collections::btree_map::BTreeMap, prelude::*}; use xcm::{latest::XcmHash, VersionedLocation, VersionedXcm}; use xcm_builder::InspectMessageQueues; @@ -938,7 +941,7 @@ pub mod pallet { #[derive(frame_support::DefaultNoBound)] pub struct GenesisConfig { #[serde(skip)] - pub _config: sp_std::marker::PhantomData, + pub _config: core::marker::PhantomData, } #[pallet::genesis_build] @@ -1530,7 +1533,7 @@ impl Pallet { } /// Type that implements `SetCode`. -pub struct ParachainSetCode(sp_std::marker::PhantomData); +pub struct ParachainSetCode(core::marker::PhantomData); impl frame_system::SetCode for ParachainSetCode { fn set_code(code: Vec) -> DispatchResult { Pallet::::schedule_code_upgrade(code) @@ -1645,7 +1648,7 @@ pub trait CheckInherents { /// Struct that always returns `Ok` on inherents check, needed for backwards-compatibility. #[doc(hidden)] -pub struct DummyCheckInherents(sp_std::marker::PhantomData); +pub struct DummyCheckInherents(core::marker::PhantomData); #[allow(deprecated)] impl CheckInherents for DummyCheckInherents { @@ -1718,7 +1721,7 @@ pub type RelaychainBlockNumberProvider = RelaychainDataProvider; /// of [`RelayChainState`]. /// - [`current_block_number`](Self::current_block_number): Will return /// [`Pallet::last_relay_block_number()`]. -pub struct RelaychainDataProvider(sp_std::marker::PhantomData); +pub struct RelaychainDataProvider(core::marker::PhantomData); impl BlockNumberProvider for RelaychainDataProvider { type BlockNumber = relay_chain::BlockNumber; diff --git a/cumulus/pallets/parachain-system/src/mock.rs b/cumulus/pallets/parachain-system/src/mock.rs index da904c0079a00a39dcca24c2d408d0bb381b2252..7bea72224b8ba36c6155597f4b957a2ed3a8d822 100644 --- a/cumulus/pallets/parachain-system/src/mock.rs +++ b/cumulus/pallets/parachain-system/src/mock.rs @@ -20,7 +20,9 @@ use super::*; +use alloc::collections::vec_deque::VecDeque; use codec::Encode; +use core::num::NonZeroU32; use cumulus_primitives_core::{ relay_chain::BlockNumber as RelayBlockNumber, AggregateMessageOrigin, InboundDownwardMessage, InboundHrmpMessage, PersistedValidationData, @@ -37,7 +39,6 @@ use frame_support::{ }; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use sp_runtime::{traits::BlakeTwo256, BuildStorage}; -use sp_std::{collections::vec_deque::VecDeque, num::NonZeroU32}; use sp_version::RuntimeVersion; use std::cell::RefCell; diff --git a/cumulus/pallets/parachain-system/src/relay_state_snapshot.rs b/cumulus/pallets/parachain-system/src/relay_state_snapshot.rs index 60eccfb072f41e87223d54f34b5c7eb59c00b2ad..323aaf6503808c954300e27179aa16bc531047c9 100644 --- a/cumulus/pallets/parachain-system/src/relay_state_snapshot.rs +++ b/cumulus/pallets/parachain-system/src/relay_state_snapshot.rs @@ -16,6 +16,7 @@ //! Relay chain state proof provides means for accessing part of relay chain storage for reads. +use alloc::vec::Vec; use codec::{Decode, Encode}; use cumulus_primitives_core::{ relay_chain, AbridgedHostConfiguration, AbridgedHrmpChannel, ParaId, @@ -23,7 +24,6 @@ use cumulus_primitives_core::{ use scale_info::TypeInfo; use sp_runtime::traits::HashingFor; use sp_state_machine::{Backend, TrieBackend, TrieBackendBuilder}; -use sp_std::vec::Vec; use sp_trie::{HashDBT, MemoryDB, StorageProof, EMPTY_PREFIX}; /// The capacity of the upward message queue of a parachain on the relay chain. diff --git a/cumulus/pallets/parachain-system/src/tests.rs b/cumulus/pallets/parachain-system/src/tests.rs index 5ff15036fb6e48b5e1a0567730b1f9035357edc2..51c6e83c113191250c3c2ebe60e2dfad1263d682 100755 --- a/cumulus/pallets/parachain-system/src/tests.rs +++ b/cumulus/pallets/parachain-system/src/tests.rs @@ -19,6 +19,7 @@ use super::*; use crate::mock::*; +use core::num::NonZeroU32; use cumulus_primitives_core::{AbridgedHrmpChannel, InboundDownwardMessage, InboundHrmpMessage}; use frame_support::{assert_ok, parameter_types, weights::Weight}; use frame_system::RawOrigin; @@ -26,7 +27,6 @@ use hex_literal::hex; use rand::Rng; use relay_chain::HrmpChannelId; use sp_core::H256; -use sp_std::num::NonZeroU32; #[test] #[should_panic] diff --git a/cumulus/pallets/parachain-system/src/unincluded_segment.rs b/cumulus/pallets/parachain-system/src/unincluded_segment.rs index 1e83a945c4ee37f2ad8ee1c45d11892f47c40be4..814bb83aa1acb0541c9cf73ead07e3e3cca84680 100644 --- a/cumulus/pallets/parachain-system/src/unincluded_segment.rs +++ b/cumulus/pallets/parachain-system/src/unincluded_segment.rs @@ -21,11 +21,12 @@ //! sent to relay chain. use super::relay_state_snapshot::{MessagingStateSnapshot, RelayDispatchQueueRemainingCapacity}; +use alloc::collections::btree_map::BTreeMap; use codec::{Decode, Encode}; +use core::marker::PhantomData; use cumulus_primitives_core::{relay_chain, ParaId}; use scale_info::TypeInfo; use sp_runtime::RuntimeDebug; -use sp_std::{collections::btree_map::BTreeMap, marker::PhantomData}; /// Constraints on outbound HRMP channel. #[derive(Clone, RuntimeDebug)] @@ -398,6 +399,7 @@ pub(crate) fn size_after_included(included_hash: H, segment: &[Anc #[cfg(test)] mod tests { use super::*; + use alloc::{vec, vec::Vec}; use assert_matches::assert_matches; #[test] diff --git a/cumulus/pallets/parachain-system/src/validate_block/implementation.rs b/cumulus/pallets/parachain-system/src/validate_block/implementation.rs index 956962fce157d3c5d090dd4bd8de78bba4d80405..42311ca9d8340d038df126175df096777cf989a9 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/implementation.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/implementation.rs @@ -26,6 +26,7 @@ use polkadot_parachain_primitives::primitives::{ HeadData, RelayChainBlockNumber, ValidationResult, }; +use alloc::vec::Vec; use codec::Encode; use frame_support::traits::{ExecuteBlock, ExtrinsicCall, Get, IsSubType}; @@ -33,7 +34,6 @@ use sp_core::storage::{ChildInfo, StateVersion}; use sp_externalities::{set_and_run_with_externalities, Externalities}; use sp_io::KillStorageResult; use sp_runtime::traits::{Block as BlockT, Extrinsic, HashingFor, Header as HeaderT}; -use sp_std::prelude::*; use sp_trie::{MemoryDB, ProofSizeProvider}; use trie_recorder::SizeOnlyRecorderProvider; @@ -124,7 +124,7 @@ where Err(_) => panic!("Compact proof decoding failure."), }; - sp_std::mem::drop(storage_proof); + core::mem::drop(storage_proof); let mut recorder = SizeOnlyRecorderProvider::new(); let cache_provider = trie_cache::CacheProvider::new(); @@ -294,7 +294,7 @@ fn host_storage_read(key: &[u8], value_out: &mut [u8], value_offset: u32) -> Opt Some(value) => { let value_offset = value_offset as usize; let data = &value[value_offset.min(value.len())..]; - let written = sp_std::cmp::min(data.len(), value_out.len()); + let written = core::cmp::min(data.len(), value_out.len()); value_out[..written].copy_from_slice(&data[..written]); Some(value.len() as u32) }, @@ -368,7 +368,7 @@ fn host_default_child_storage_read( Some(value) => { let value_offset = value_offset as usize; let data = &value[value_offset.min(value.len())..]; - let written = sp_std::cmp::min(data.len(), value_out.len()); + let written = core::cmp::min(data.len(), value_out.len()); value_out[..written].copy_from_slice(&data[..written]); Some(value.len() as u32) }, diff --git a/cumulus/pallets/parachain-system/src/validate_block/mod.rs b/cumulus/pallets/parachain-system/src/validate_block/mod.rs index 763a4cffd77f92171c1f102cfc70485a02e5f27e..3a00d4d352a69830ff225221d2fb63450c96b9e9 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/mod.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/mod.rs @@ -30,6 +30,9 @@ mod trie_cache; #[doc(hidden)] mod trie_recorder; +#[cfg(not(feature = "std"))] +#[doc(hidden)] +pub use alloc::{boxed::Box, slice}; #[cfg(not(feature = "std"))] #[doc(hidden)] pub use bytes; diff --git a/cumulus/pallets/parachain-system/src/validate_block/trie_cache.rs b/cumulus/pallets/parachain-system/src/validate_block/trie_cache.rs index 5d785910fbe026fba487980d1244262146f86a5b..5999b3ce87f9d285412ea8bccdf1258ae1f66733 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/trie_cache.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/trie_cache.rs @@ -15,12 +15,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use sp_state_machine::TrieCacheProvider; -use sp_std::{ +use alloc::{ boxed::Box, - cell::{RefCell, RefMut}, collections::btree_map::{BTreeMap, Entry}, }; +use core::cell::{RefCell, RefMut}; +use sp_state_machine::TrieCacheProvider; use sp_trie::NodeCodec; use trie_db::{node::NodeOwned, Hasher}; diff --git a/cumulus/pallets/parachain-system/src/validate_block/trie_recorder.rs b/cumulus/pallets/parachain-system/src/validate_block/trie_recorder.rs index 48310670c074d1be2ec86f582c0c84622abc086c..19801340719526ac6775a9a92fc0b3d879f84afb 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/trie_recorder.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/trie_recorder.rs @@ -22,11 +22,11 @@ use codec::Encode; -use sp_std::{ - cell::{RefCell, RefMut}, +use alloc::{ collections::{btree_map::BTreeMap, btree_set::BTreeSet}, rc::Rc, }; +use core::cell::{RefCell, RefMut}; use sp_trie::{NodeCodec, ProofSizeProvider, StorageProof}; use trie_db::{Hasher, RecordedForKey, TrieAccess}; diff --git a/cumulus/pallets/parachain-system/src/weights.rs b/cumulus/pallets/parachain-system/src/weights.rs index da7f64237e9b6a8b39096b761f6ff923f903529a..5c61879b4d36b903f9f9d81cde76ff3ce42cc747 100644 --- a/cumulus/pallets/parachain-system/src/weights.rs +++ b/cumulus/pallets/parachain-system/src/weights.rs @@ -50,7 +50,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions needed for cumulus_pallet_parachain_system. pub trait WeightInfo { diff --git a/cumulus/pallets/session-benchmarking/Cargo.toml b/cumulus/pallets/session-benchmarking/Cargo.toml index 62c923de59f25d7fc6ba8db15df48e625e16e118..e182ac45edebd9c22df15d18f9d3548176c538c5 100644 --- a/cumulus/pallets/session-benchmarking/Cargo.toml +++ b/cumulus/pallets/session-benchmarking/Cargo.toml @@ -16,13 +16,12 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } -pallet-session = { path = "../../../substrate/frame/session", default-features = false } +codec = { workspace = true } +sp-runtime = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-benchmarking = { optional = true, workspace = true } +pallet-session = { workspace = true } [features] default = ["std"] @@ -39,5 +38,4 @@ std = [ "frame-system/std", "pallet-session/std", "sp-runtime/std", - "sp-std/std", ] diff --git a/cumulus/pallets/session-benchmarking/src/inner.rs b/cumulus/pallets/session-benchmarking/src/inner.rs index 36411d3d71afa2c1ae74870a1eed5ad1ad916a8c..8d5954304878dfd5ff4c4bf912168d70e4e5e53f 100644 --- a/cumulus/pallets/session-benchmarking/src/inner.rs +++ b/cumulus/pallets/session-benchmarking/src/inner.rs @@ -15,7 +15,7 @@ //! Benchmarking setup for pallet-session. -use sp_std::{prelude::*, vec}; +use alloc::{vec, vec::Vec}; use codec::Decode; use frame_benchmarking::{benchmarks, whitelisted_caller}; diff --git a/cumulus/pallets/session-benchmarking/src/lib.rs b/cumulus/pallets/session-benchmarking/src/lib.rs index a95d6fb7d591460f2055f076f60199b213b055b8..f5bfef006169035797d17957beb574200fd153ab 100644 --- a/cumulus/pallets/session-benchmarking/src/lib.rs +++ b/cumulus/pallets/session-benchmarking/src/lib.rs @@ -20,6 +20,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + #[cfg(feature = "runtime-benchmarks")] pub mod inner; diff --git a/cumulus/pallets/solo-to-para/Cargo.toml b/cumulus/pallets/solo-to-para/Cargo.toml index 17b0fb2a01662d517a49d1bfd669ed071caf0ed7..5fd1939e93a03397dda15bae0eb638f823cbb1ce 100644 --- a/cumulus/pallets/solo-to-para/Cargo.toml +++ b/cumulus/pallets/solo-to-para/Cargo.toml @@ -10,21 +10,20 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } # Substrate -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-sudo = { workspace = true } +sp-runtime = { workspace = true } # Polkadot -polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false } +polkadot-primitives = { workspace = true } # Cumulus -cumulus-pallet-parachain-system = { path = "../parachain-system", default-features = false } +cumulus-pallet-parachain-system = { workspace = true } [features] default = ["std"] @@ -37,7 +36,6 @@ std = [ "polkadot-primitives/std", "scale-info/std", "sp-runtime/std", - "sp-std/std", ] try-runtime = [ "cumulus-pallet-parachain-system/try-runtime", diff --git a/cumulus/pallets/solo-to-para/src/lib.rs b/cumulus/pallets/solo-to-para/src/lib.rs index da948615d4e90a5f109cb56b47f796acead6535c..b42cc74f1cf32220f7767f829cd4a65c9e2e0532 100644 --- a/cumulus/pallets/solo-to-para/src/lib.rs +++ b/cumulus/pallets/solo-to-para/src/lib.rs @@ -16,12 +16,14 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + +use alloc::vec::Vec; use cumulus_pallet_parachain_system as parachain_system; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; pub use pallet::*; use polkadot_primitives::PersistedValidationData; -use sp_std::vec::Vec; #[frame_support::pallet] pub mod pallet { diff --git a/cumulus/pallets/xcm/Cargo.toml b/cumulus/pallets/xcm/Cargo.toml index 178d981702f2e6dc42d05556e20a86f50106b6ee..35d7a083b061d204de339407c6e26c4ef948dbb8 100644 --- a/cumulus/pallets/xcm/Cargo.toml +++ b/cumulus/pallets/xcm/Cargo.toml @@ -10,18 +10,17 @@ description = "Pallet for stuff specific to parachains' usage of XCM" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } +xcm = { workspace = true } -cumulus-primitives-core = { path = "../../primitives/core", default-features = false } +cumulus-primitives-core = { workspace = true } [features] default = ["std"] @@ -33,7 +32,6 @@ std = [ "scale-info/std", "sp-io/std", "sp-runtime/std", - "sp-std/std", "xcm/std", ] try-runtime = [ diff --git a/cumulus/pallets/xcm/src/lib.rs b/cumulus/pallets/xcm/src/lib.rs index 90a0ec76defe2b0df8d99faacfb611c0f7834a3b..e31df8471c26698d115d798bfc9358dbc4a1b982 100644 --- a/cumulus/pallets/xcm/src/lib.rs +++ b/cumulus/pallets/xcm/src/lib.rs @@ -25,7 +25,6 @@ use cumulus_primitives_core::ParaId; pub use pallet::*; use scale_info::TypeInfo; use sp_runtime::{traits::BadOrigin, RuntimeDebug}; -use sp_std::prelude::*; use xcm::latest::{ExecuteXcm, Outcome}; #[frame_support::pallet] diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index 87602978521fc363539b2aeb81f5b485dbe409ea..9c7470eda6da4aeaba942c25f04f4aeb13ee471e 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -10,45 +10,44 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"], default-features = false } +codec = { features = ["derive"], workspace = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } # Substrate -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-io = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +pallet-message-queue = { workspace = true } # Polkadot -polkadot-runtime-common = { path = "../../../polkadot/runtime/common", default-features = false } -polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains", default-features = false } -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false } +polkadot-runtime-common = { workspace = true } +polkadot-runtime-parachains = { workspace = true } +xcm = { workspace = true } +xcm-executor = { workspace = true } +xcm-builder = { workspace = true } # Cumulus -cumulus-primitives-core = { path = "../../primitives/core", default-features = false } +cumulus-primitives-core = { workspace = true } # Optional import for benchmarking -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } -bounded-collections = { version = "0.2.0", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +bounded-collections = { workspace = true } # Bridges -bp-xcm-bridge-hub-router = { path = "../../../bridges/primitives/xcm-bridge-hub-router", default-features = false, optional = true } +bp-xcm-bridge-hub-router = { optional = true, workspace = true } [dev-dependencies] # Substrate -sp-core = { path = "../../../substrate/primitives/core" } -pallet-balances = { path = "../../../substrate/frame/balances" } -frame-support = { path = "../../../substrate/frame/support", features = ["experimental"] } +sp-core = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +frame-support = { features = ["experimental"], workspace = true, default-features = true } # Cumulus -cumulus-pallet-parachain-system = { path = "../parachain-system" } +cumulus-pallet-parachain-system = { workspace = true, default-features = true } [features] default = ["std"] @@ -68,7 +67,6 @@ std = [ "sp-core/std", "sp-io/std", "sp-runtime/std", - "sp-std/std", "xcm-builder/std", "xcm-executor/std", "xcm/std", diff --git a/cumulus/pallets/xcmp-queue/src/benchmarking.rs b/cumulus/pallets/xcmp-queue/src/benchmarking.rs index 49e2cc8367348ad6a81c0017405f8c3148734be5..9cb1301addfe5c9bb29c1b034c76793b6eaeda64 100644 --- a/cumulus/pallets/xcmp-queue/src/benchmarking.rs +++ b/cumulus/pallets/xcmp-queue/src/benchmarking.rs @@ -17,6 +17,7 @@ use crate::*; +use alloc::vec; use codec::DecodeAll; use frame_benchmarking::v2::*; use frame_support::traits::Hooks; diff --git a/cumulus/pallets/xcmp-queue/src/bridging.rs b/cumulus/pallets/xcmp-queue/src/bridging.rs index 9db4b6e74c3987ae08a6d38eb75ffcacb9e5e713..eff4a37b0cef7033c15f2629e54fb7763a35a975 100644 --- a/cumulus/pallets/xcmp-queue/src/bridging.rs +++ b/cumulus/pallets/xcmp-queue/src/bridging.rs @@ -21,7 +21,7 @@ use frame_support::pallet_prelude::Get; /// both `OutboundXcmpStatus` and `InboundXcmpStatus` for defined `ParaId` if any of those is /// suspended. pub struct InAndOutXcmpChannelStatusProvider( - sp_std::marker::PhantomData<(SiblingBridgeHubParaId, Runtime)>, + core::marker::PhantomData<(SiblingBridgeHubParaId, Runtime)>, ); impl, Runtime: crate::Config> bp_xcm_bridge_hub_router::XcmChannelStatusProvider @@ -45,7 +45,7 @@ impl, Runtime: crate::Config> /// Adapter implementation for `bp_xcm_bridge_hub_router::XcmChannelStatusProvider` which checks /// only `OutboundXcmpStatus` for defined `SiblingParaId` if is suspended. pub struct OutXcmpChannelStatusProvider( - sp_std::marker::PhantomData<(SiblingBridgeHubParaId, Runtime)>, + core::marker::PhantomData<(SiblingBridgeHubParaId, Runtime)>, ); impl, Runtime: crate::Config> bp_xcm_bridge_hub_router::XcmChannelStatusProvider diff --git a/cumulus/pallets/xcmp-queue/src/lib.rs b/cumulus/pallets/xcmp-queue/src/lib.rs index 45126a9425d4c0400c7b76f55173339fd4c4a2bb..8c4446a925d4da281d11f09c9e3e3e3b4feb6697 100644 --- a/cumulus/pallets/xcmp-queue/src/lib.rs +++ b/cumulus/pallets/xcmp-queue/src/lib.rs @@ -50,6 +50,9 @@ pub mod bridging; pub mod weights; pub use weights::WeightInfo; +extern crate alloc; + +use alloc::vec::Vec; use bounded_collections::BoundedBTreeSet; use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen}; use cumulus_primitives_core::{ @@ -69,7 +72,6 @@ use polkadot_runtime_parachains::FeeTracker; use scale_info::TypeInfo; use sp_core::MAX_POSSIBLE_ALLOCATION; use sp_runtime::{FixedU128, RuntimeDebug, Saturating, WeakBoundedVec}; -use sp_std::prelude::*; use xcm::{latest::prelude::*, VersionedLocation, VersionedXcm, WrapVersion, MAX_XCM_DECODE_DEPTH}; use xcm_builder::InspectMessageQueues; use xcm_executor::traits::ConvertOrigin; diff --git a/cumulus/pallets/xcmp-queue/src/migration.rs b/cumulus/pallets/xcmp-queue/src/migration.rs index b64982a893029f51aeb689d94d54066165ac40a3..d0657aaea9fd0d1daab6003b9721434c8ea769e1 100644 --- a/cumulus/pallets/xcmp-queue/src/migration.rs +++ b/cumulus/pallets/xcmp-queue/src/migration.rs @@ -19,6 +19,7 @@ pub mod v5; use crate::{Config, OverweightIndex, Pallet, QueueConfig, QueueConfigData, DEFAULT_POV_SIZE}; +use alloc::vec::Vec; use cumulus_primitives_core::XcmpMessageFormat; use frame_support::{ pallet_prelude::*, diff --git a/cumulus/pallets/xcmp-queue/src/migration/v5.rs b/cumulus/pallets/xcmp-queue/src/migration/v5.rs index 247adab7108fac8a278ee81827a9e65e27c320f0..818365f36f605ea3ddceceeb8654cf11ca690e44 100644 --- a/cumulus/pallets/xcmp-queue/src/migration/v5.rs +++ b/cumulus/pallets/xcmp-queue/src/migration/v5.rs @@ -17,6 +17,7 @@ //! Migrates the storage to version 5. use crate::*; +use alloc::vec::Vec; use cumulus_primitives_core::ListChannelInfos; use frame_support::{pallet_prelude::*, traits::UncheckedOnRuntimeUpgrade}; diff --git a/cumulus/parachains/chain-specs/asset-hub-kusama.json b/cumulus/parachains/chain-specs/asset-hub-kusama.json index 36cccd9b0b0dbad4a5f6c7240a69181ec7ffe5f3..58b8ac01922712234ad81a56fde825026af904e2 100644 --- a/cumulus/parachains/chain-specs/asset-hub-kusama.json +++ b/cumulus/parachains/chain-specs/asset-hub-kusama.json @@ -7,8 +7,8 @@ "/dns/kusama-asset-hub-connect-0.polkadot.io/tcp/443/wss/p2p/12D3KooWMzvdGcUXxacLdMQzRVrsP1mJrZHcrz8LtGbhLzve84Qx", "/dns/kusama-asset-hub-connect-1.polkadot.io/tcp/30334/p2p/12D3KooWQmGf5z3DU1kKcZoLzMNgdbP31ybjuwxS1VGLKMUjq5ez", "/dns/kusama-asset-hub-connect-1.polkadot.io/tcp/443/wss/p2p/12D3KooWQmGf5z3DU1kKcZoLzMNgdbP31ybjuwxS1VGLKMUjq5ez", - "/dns/boot.stake.plus/tcp/34333/p2p/12D3KooWAzSSZ7jLqMw1WPomYEKCYANQaKemXQ8BKoFvNEvfmdqR", - "/dns/boot.stake.plus/tcp/34334/wss/p2p/12D3KooWAzSSZ7jLqMw1WPomYEKCYANQaKemXQ8BKoFvNEvfmdqR", + "/dns/asset-hub-kusama.boot.stake.plus/tcp/30332/wss/p2p/12D3KooWGfJsBTxWttMwFkyBi6ZvEzAU3mvcVAzE7yFXMZuasicr", + "/dns/asset-hub-kusama.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWK7hHQbFEhhgZURY7V4LzY6BkqLsnCCpEJ69eUF7ucPcE", "/dns/boot.metaspan.io/tcp/26052/p2p/12D3KooW9z9hKqe3mqYAp5UJMhZiCqhkTHyiR43fegnGmTJ3JAba", "/dns/boot.metaspan.io/tcp/26056/wss/p2p/12D3KooW9z9hKqe3mqYAp5UJMhZiCqhkTHyiR43fegnGmTJ3JAba", "/dns/boot.gatotech.network/tcp/33210/p2p/12D3KooWRMUYeWMPkadDG8baX9j1e95fspfp8MhPGym5BQza7Fm5", diff --git a/cumulus/parachains/chain-specs/asset-hub-polkadot.json b/cumulus/parachains/chain-specs/asset-hub-polkadot.json index f7f53f8d7246f42dda05901298831190e5d81802..3e46501b00785d9d92b3bde19e5dd08e00d7e86d 100644 --- a/cumulus/parachains/chain-specs/asset-hub-polkadot.json +++ b/cumulus/parachains/chain-specs/asset-hub-polkadot.json @@ -7,8 +7,8 @@ "/dns/polkadot-asset-hub-connect-0.polkadot.io/tcp/443/wss/p2p/12D3KooWLHqbcQtoBygf7GJgVjVa3TaeLuf7VbicNdooaCmQM2JZ", "/dns/polkadot-asset-hub-connect-1.polkadot.io/tcp/30334/p2p/12D3KooWNDrKSayoZXGGE2dRSFW2g1iGPq3fTZE2U39ma9yZGKd3", "/dns/polkadot-asset-hub-connect-1.polkadot.io/tcp/443/wss/p2p/12D3KooWNDrKSayoZXGGE2dRSFW2g1iGPq3fTZE2U39ma9yZGKd3", - "/dns/boot.stake.plus/tcp/35333/p2p/12D3KooWFrQjYaPZSSLLxEVmoaHFcrF6VoY4awG4KRSLaqy3JCdQ", - "/dns/boot.stake.plus/tcp/35334/wss/p2p/12D3KooWFrQjYaPZSSLLxEVmoaHFcrF6VoY4awG4KRSLaqy3JCdQ", + "/dns/asset-hub-polkadot.boot.stake.plus/tcp/30332/wss/p2p/12D3KooWJzTrFcc11AZKTMUmmLr5XLJ9qKVupZXkwHUMx4ULbwm2", + "/dns/asset-hub-polkadot.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWNWF2zwxWDuZfXEzL29yeXAAubFy8tCCMjPwWLCZdLRqc", "/dns/boot.metaspan.io/tcp/16052/p2p/12D3KooWLwiJuvqQUB4kYaSjLenFKH9dWZhGZ4qi7pSb3sUYU651", "/dns/boot.metaspan.io/tcp/16056/wss/p2p/12D3KooWLwiJuvqQUB4kYaSjLenFKH9dWZhGZ4qi7pSb3sUYU651", "/dns/boot.gatotech.network/tcp/33110/p2p/12D3KooWKgwQfAeDoJARdtxFNNWfbYmcu6s4yUuSifnNoDgzHZgm", diff --git a/cumulus/parachains/chain-specs/asset-hub-westend.json b/cumulus/parachains/chain-specs/asset-hub-westend.json index b4334bdfe1243eb4d6726ab3464d619aebac394a..42717974a0b34e31420fe08ad51195dd3a1b2c4e 100644 --- a/cumulus/parachains/chain-specs/asset-hub-westend.json +++ b/cumulus/parachains/chain-specs/asset-hub-westend.json @@ -9,8 +9,8 @@ "/dns/westend-asset-hub-bootnode-1.polkadot.io/tcp/30335/ws/p2p/12D3KooWGL3hpWycWyeqyL9gHNnmmsL474WkPZdqraBHu4L6fQrW", "/dns/westend-asset-hub-connect-0.polkadot.io/tcp/443/wss/p2p/12D3KooWJaAfPyiye7ZQBuHengTJJoMrcaz7Jj1UzHiKdNxA1Nkd", "/dns/westend-asset-hub-connect-1.polkadot.io/tcp/443/wss/p2p/12D3KooWGL3hpWycWyeqyL9gHNnmmsL474WkPZdqraBHu4L6fQrW", - "/dns/boot.stake.plus/tcp/33333/p2p/12D3KooWNiB27rpXX7EYongoWWUeRKzLQxWGms6MQU2B9LX7Ztzo", - "/dns/boot.stake.plus/tcp/33334/wss/p2p/12D3KooWNiB27rpXX7EYongoWWUeRKzLQxWGms6MQU2B9LX7Ztzo", + "/dns/asset-hub-westend.boot.stake.plus/tcp/30332/wss/p2p/12D3KooWG4YUe7AfSxVwyLQBRRMU99krssmGAUghqUFoVY1iPkQs", + "/dns/asset-hub-westend.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWFLR2UN6PMAUwNAjiWBAiEDoYcWRrtjDrUfRkdUssge4v", "/dns/boot.metaspan.io/tcp/36052/p2p/12D3KooWBCqfNb6Y39DXTr4UBWXyjuS3hcZM1qTbHhDXxF6HkAJJ", "/dns/boot.metaspan.io/tcp/36056/wss/p2p/12D3KooWBCqfNb6Y39DXTr4UBWXyjuS3hcZM1qTbHhDXxF6HkAJJ", "/dns/boot.gatotech.network/tcp/33310/p2p/12D3KooWMSW6hr8KcNBhGFN1bg8kYC76o67PnuDEbxRhxacW6dui", diff --git a/cumulus/parachains/chain-specs/bridge-hub-kusama.json b/cumulus/parachains/chain-specs/bridge-hub-kusama.json index 2c63b52d78395167f5a60e1b96ffede355b3eddc..36558b325bbf315144c69e8f6c4294bd6d5dfdff 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-kusama.json +++ b/cumulus/parachains/chain-specs/bridge-hub-kusama.json @@ -7,8 +7,8 @@ "/dns/kusama-bridge-hub-connect-ew1-1.polkadot.io/tcp/30334/p2p/12D3KooWPcF9Yk4gYrMju9CyWCV69hAFXbYsnxCLogwLGu9QFTRn", "/dns/kusama-bridge-hub-connect-ew1-0.polkadot.io/tcp/443/wss/p2p/12D3KooWPQQPivrqQ51kRTDc2R1mtqwKT4GGtk2rapkY4FrwHrEp", "/dns/kusama-bridge-hub-connect-ew1-1.polkadot.io/tcp/443/wss/p2p/12D3KooWPcF9Yk4gYrMju9CyWCV69hAFXbYsnxCLogwLGu9QFTRn", - "/dns/boot.stake.plus/tcp/41333/p2p/12D3KooWBzbs2jsXjG5dipktGPKaUm9XWvkmeJFsEAGkVt946Aa7", - "/dns/boot.stake.plus/tcp/41334/wss/p2p/12D3KooWBzbs2jsXjG5dipktGPKaUm9XWvkmeJFsEAGkVt946Aa7", + "/dns/bridge-hub-kusama.boot.stake.plus/tcp/30332/wss/p2p/12D3KooWCujTih2WeQr51xSpopt5LoYVyXy3bgGgcN5ftPQViBmh", + "/dns/bridge-hub-kusama.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWDSxWZ8RcuPfKSpybYHWUdhQHG328Euyo2PwkNUTXcXuw", "/dns/boot.metaspan.io/tcp/26032/p2p/12D3KooWKfuSaZrLNz43PDgM4inMALXRHTSh2WBuqQtZRq8zmT1Z", "/dns/boot.metaspan.io/tcp/26036/wss/p2p/12D3KooWKfuSaZrLNz43PDgM4inMALXRHTSh2WBuqQtZRq8zmT1Z", "/dns/boot.gatotech.network/tcp/33230/p2p/12D3KooWFQFmg8UqAYLDNc2onySB6o5LLvpbx3eXZVqz9YFxAmXs", diff --git a/cumulus/parachains/chain-specs/bridge-hub-polkadot.json b/cumulus/parachains/chain-specs/bridge-hub-polkadot.json index 7d3ba8357037d7310c56ed609cbc43e0359ca2bc..eb22e09035f34b85cecbbc923ea1e68081f14a8d 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-polkadot.json +++ b/cumulus/parachains/chain-specs/bridge-hub-polkadot.json @@ -11,8 +11,8 @@ "/dns/polkadot-bridge-hub-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWPZ38PL3PhRVcUVYDNn7nRcZF8MykmWWLBKeDV2yna1vV", "/dns/boot.gatotech.network/tcp/33130/p2p/12D3KooWCnFzfEdd7MwUNrrDv66FuS2DM5MGuiaB4y48XS7qNjF6", "/dns/boot.gatotech.network/tcp/35130/wss/p2p/12D3KooWCnFzfEdd7MwUNrrDv66FuS2DM5MGuiaB4y48XS7qNjF6", - "/dns/boot.stake.plus/tcp/42333/p2p/12D3KooWEoTCu22Uab6prbfcD1FPpPZmfhkAVeMZQJ3fHnkCVmJz", - "/dns/boot.stake.plus/tcp/42334/wss/p2p/12D3KooWEoTCu22Uab6prbfcD1FPpPZmfhkAVeMZQJ3fHnkCVmJz", + "/dns/bridge-hub-polkadot.boot.stake.plus/tcp/30332/wss/p2p/12D3KooWGqVn69EWriuszxcuBVMgTtpKUHYcULEiuLiqkC3kf35F", + "/dns/bridge-hub-polkadot.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWMiMJbunJa7ETaeanKB7hgchjQEbmhmtNPRRiHYtZHCTZ", "/dns/bridge-hub-polkadot-bootnode.turboflakes.io/tcp/30610/p2p/12D3KooWNEgaQRQHJHvGDh8Rg4RyLmDCCz3yAf2gAdHZZJAUUD8Q", "/dns/bridge-hub-polkadot-bootnode.turboflakes.io/tcp/30710/wss/p2p/12D3KooWNEgaQRQHJHvGDh8Rg4RyLmDCCz3yAf2gAdHZZJAUUD8Q", "/dns/boot.metaspan.io/tcp/16032/p2p/12D3KooWQTfRnrK3FfbrotpSP5RVJbjBHVBSu8VSzhj9qcvjaqnZ", diff --git a/cumulus/parachains/chain-specs/bridge-hub-westend.json b/cumulus/parachains/chain-specs/bridge-hub-westend.json index f98a046040f2226b5345d4d793e15ec3e24d6c43..40c7c7460c2359c855adac91a0dbf2dbec2c008b 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-westend.json +++ b/cumulus/parachains/chain-specs/bridge-hub-westend.json @@ -11,8 +11,8 @@ "/dns/westend-bridge-hub-collator-node-1.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWBpvudthz61XC4oP2YYFFJdhWohBeQ1ffn1BMSGWhapjd", "/dns/westend-bridge-hub-boot-ng.dwellir.com/tcp/30338/p2p/12D3KooWJWWRYTAwBLqYkh7iMBGDr5ouJ3MHj7M3fZ7zWS4zEk6F", "/dns/westend-bridge-hub-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWJWWRYTAwBLqYkh7iMBGDr5ouJ3MHj7M3fZ7zWS4zEk6F", - "/dns/boot.stake.plus/tcp/40333/p2p/12D3KooWPGMsGPdGJx6HrByiKUyz91wgUHmjG5UXTmkJ9tUphAQn", - "/dns/boot.stake.plus/tcp/40334/wss/p2p/12D3KooWPGMsGPdGJx6HrByiKUyz91wgUHmjG5UXTmkJ9tUphAQn", + "/dns/bridge-hub-westend.boot.stake.plus/tcp/30332/wss/p2p/12D3KooW9rqdajWEpC3i65zaTVR1ER2RmY6e26vndPsKhBB6WJ1k", + "/dns/bridge-hub-westend.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWN55mz6EQb5nrCgTiNL6nroVrRXygCiFDvHpeKk97Jqqc", "/dns/boot.gatotech.network/tcp/33330/p2p/12D3KooWJHG6qznPzTSEbuujHNcvyzBZcR9zNRPFcXWUaoVWZBEw", "/dns/boot.gatotech.network/tcp/35330/wss/p2p/12D3KooWJHG6qznPzTSEbuujHNcvyzBZcR9zNRPFcXWUaoVWZBEw", "/dns/bridge-hub-westend-bootnode.turboflakes.io/tcp/30620/p2p/12D3KooWLeExhPWCDUjcxCdzxTP5TpPbNBVG5t9MPvk1dZUM5naU", diff --git a/cumulus/parachains/chain-specs/collectives-polkadot.json b/cumulus/parachains/chain-specs/collectives-polkadot.json index a6ba01ffa394dfdba05e65014006f10eb68ea858..5ccccbec905326da8ca7b45013f38e1bb5da9926 100644 --- a/cumulus/parachains/chain-specs/collectives-polkadot.json +++ b/cumulus/parachains/chain-specs/collectives-polkadot.json @@ -7,8 +7,8 @@ "/dns/polkadot-collectives-connect-ew6-1.polkadot.io/tcp/30334/p2p/12D3KooWC9BwKMDyRUTXsE7teSmoKMgbyxqAp3zi2MTGRJR5nhCL", "/dns/polkadot-collectives-connect-ew6-0.polkadot.io/tcp/443/wss/p2p/12D3KooWLDZT5gAjMtC8fojiCwiz17SC61oeX2C7GWBCqqf9TwVD", "/dns/polkadot-collectives-connect-ew6-1.polkadot.io/tcp/443/wss/p2p/12D3KooWC9BwKMDyRUTXsE7teSmoKMgbyxqAp3zi2MTGRJR5nhCL", - "/dns/boot.stake.plus/tcp/37333/p2p/12D3KooWRgFfEtwPo3xorKGYALRHRteKNgF37iN9q8xTLPYc34LA", - "/dns/boot.stake.plus/tcp/37334/wss/p2p/12D3KooWRgFfEtwPo3xorKGYALRHRteKNgF37iN9q8xTLPYc34LA", + "/dns/collectives-polkadot.boot.stake.plus/tcp/30332/wss/p2p/12D3KooWKLVfjCpW2syecz39UPe4QkJhwME9HUehBvf8oRcT4kot", + "/dns/collectives-polkadot.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWBCewTdMPoXNvs1ky1VLidMdS28Jnh8fNbCP81FYiQHn4", "/dns/boot.metaspan.io/tcp/16072/p2p/12D3KooWJWTTu2t2yg5bFRH6tjEpfzKwZir5R9JRRjQpgFPXdDfp", "/dns/boot.metaspan.io/tcp/16076/wss/p2p/12D3KooWJWTTu2t2yg5bFRH6tjEpfzKwZir5R9JRRjQpgFPXdDfp", "/dns/boot.gatotech.network/tcp/33120/p2p/12D3KooWGZsa9tSeLQ1VeC996e1YsCPuyRYMipHQuXikPjcKcpVQ", diff --git a/cumulus/parachains/chain-specs/collectives-westend.json b/cumulus/parachains/chain-specs/collectives-westend.json index 6182218d3670cfc661fe528d715bbf222c747900..f583eddcef1f145500a68f48965cc15f8333a3a7 100644 --- a/cumulus/parachains/chain-specs/collectives-westend.json +++ b/cumulus/parachains/chain-specs/collectives-westend.json @@ -9,8 +9,8 @@ "/dns/westend-collectives-collator-node-1.parity-testnet.parity.io/tcp/30335/ws/p2p/12D3KooWAujYtHbCs4MiDD57JNTntTJnYnikfnaPa7JdnMyAUrHB", "/dns/westend-collectives-collator-0.polkadot.io/tcp/443/wss/p2p/12D3KooWBMAuyzQu3yAf8YXyoyxsSzSsgoaqAepgnNyQcPaPjPXe", "/dns/westend-collectives-collator-1.polkadot.io/tcp/443/wss/p2p/12D3KooWAujYtHbCs4MiDD57JNTntTJnYnikfnaPa7JdnMyAUrHB", - "/dns/boot.stake.plus/tcp/38333/p2p/12D3KooWQoVsFCfgu21iu6kdtQsU9T6dPn1wsyLn1U34yPerR6zQ", - "/dns/boot.stake.plus/tcp/38334/wss/p2p/12D3KooWQoVsFCfgu21iu6kdtQsU9T6dPn1wsyLn1U34yPerR6zQ", + "/dns/collectives-westend.boot.stake.plus/tcp/30332/wss/p2p/12D3KooWH4MtT6T9BE1nm2TL9ABmY3mSr61mZcge37pEch7Qw15S", + "/dns/collectives-westend.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWBMRn31J3wJh3eu96XFUiAmgP3eKUxyNCv7249NXrAarZ", "/dns/boot.metaspan.io/tcp/36072/p2p/12D3KooWEf2QXWq5pAbFJLfbnexA7KYtRRDSPkqTP64n1KtdsdV2", "/dns/boot.metaspan.io/tcp/36076/wss/p2p/12D3KooWEf2QXWq5pAbFJLfbnexA7KYtRRDSPkqTP64n1KtdsdV2", "/dns/boot.gatotech.network/tcp/33320/p2p/12D3KooWMedtdBGiSn7HLZusHwafXkZAdmWD18ciGQBfS4X1fv9K", diff --git a/cumulus/parachains/chain-specs/coretime-kusama.json b/cumulus/parachains/chain-specs/coretime-kusama.json index f9310d6c7cc6e14f54b4cc6620bece8b626725d1..3e4ffae403bdb7118fe94befc32e15f497e71fcc 100644 --- a/cumulus/parachains/chain-specs/coretime-kusama.json +++ b/cumulus/parachains/chain-specs/coretime-kusama.json @@ -9,8 +9,8 @@ "/dns/kusama-coretime-connect-a-1.polkadot.io/tcp/443/wss/p2p/12D3KooWAGFiMZDF9RxdacrkenzGdo8nhfSe9EXofHc5mHeJ9vGX", "/dns/boot.metaspan.io/tcp/33024/p2p/12D3KooWPmwMhG54ixDv2b3sCfYEJ1DWDrjaduBCBwqFFdqvVsmS", "/dns/boot.metaspan.io/tcp/33026/wss/p2p/12D3KooWPmwMhG54ixDv2b3sCfYEJ1DWDrjaduBCBwqFFdqvVsmS", - "/dns/boot.stake.plus/tcp/47333/p2p/12D3KooWKKKoyywqdkkpZzCzVWt5VXEk5PbS9tUm635L5ohyf8bU", - "/dns/boot.stake.plus/tcp/47334/wss/p2p/12D3KooWKKKoyywqdkkpZzCzVWt5VXEk5PbS9tUm635L5ohyf8bU", + "/dns/coretime-kusama.boot.stake.plus/tcp/30332/wss/p2p/12D3KooWDG2iif5zcFB7E1huEZUPAauEP34mqt8UVUacHTxC1wJY", + "/dns/coretime-kusama.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWAcZ2FG9uPa3YXzk4Mots94Zm6NYzKKaWvyAFEu2k4WMy", "/dns/coretime-kusama-boot-ng.dwellir.com/tcp/30358/p2p/12D3KooWSoPisbYQTAj79Dtsxx1qAiEFTouvXCfNJ1A3SQWQzuct", "/dns/coretime-kusama-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWSoPisbYQTAj79Dtsxx1qAiEFTouvXCfNJ1A3SQWQzuct", "/dns/boot.gatotech.network/tcp/33250/p2p/12D3KooWMpgcWr5pb7em7rWaQV4J6P2kn3YCjCeP1ESMsJPffn1a", diff --git a/cumulus/parachains/chain-specs/coretime-westend.json b/cumulus/parachains/chain-specs/coretime-westend.json index ca723aacd881cbe56dbedc123b062465c68ec40b..42f67526c29ac5bcf94fd3741a577c68667fc226 100644 --- a/cumulus/parachains/chain-specs/coretime-westend.json +++ b/cumulus/parachains/chain-specs/coretime-westend.json @@ -17,8 +17,8 @@ "/dns/boot-node.helikon.io/tcp/9422/wss/p2p/12D3KooWFBPartM873MNm1AmVK3etUz34cAE9A9rwPztPno2epQ3", "/dns/coretime-westend-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWHewSFwJueRprNZNfkncdjud9DrGzvP1qfmgPd7VK66gw", "/dns/coretime-westend-boot-ng.dwellir.com/tcp/30356/p2p/12D3KooWHewSFwJueRprNZNfkncdjud9DrGzvP1qfmgPd7VK66gw", - "/dns/boot.stake.plus/tcp/45333/p2p/12D3KooWEFQapPJXNyZMt892qXZ8YgDuHWt2vhLeRvny98oUjEto", - "/dns/boot.stake.plus/tcp/45334/wss/p2p/12D3KooWEFQapPJXNyZMt892qXZ8YgDuHWt2vhLeRvny98oUjEto", + "/dns/coretime-westend.boot.stake.plus/tcp/30332/wss/p2p/12D3KooWBFffQL6MvzM9rc8yVwR1Z8GcC9jfLhZpU2NRjsAAFeTX", + "/dns/coretime-westend.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWH2qnUkKjV9Sevp8soFXdcs6r1mj2D2DAoBH8L1ziLzs3", "/dns/coretime-westend-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWK7Zj1mCPg6h3eMp7v6akJ1o6AocRr59NLusDwBXQgrhw", "/dns/coretime-westend-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWK7Zj1mCPg6h3eMp7v6akJ1o6AocRr59NLusDwBXQgrhw", "/dns/ibp-boot-westend-coretime.luckyfriday.io/tcp/443/wss/p2p/12D3KooWBzfzNhvyRVTb9KtNYpkRf26yTRHorBZR2LmYhH5ArCey", diff --git a/cumulus/parachains/chain-specs/people-kusama.json b/cumulus/parachains/chain-specs/people-kusama.json index 3352cb25a2898f5442b1e28b340def69fc4168f2..300b9fcfb183c262ce1fc2279d6ca7bf457bc1db 100644 --- a/cumulus/parachains/chain-specs/people-kusama.json +++ b/cumulus/parachains/chain-specs/people-kusama.json @@ -26,7 +26,9 @@ "/dns/boot.metaspan.io/tcp/25068/p2p/12D3KooWDoDLtLvQi8hhFVyubPZhaYuAwSAJrPFtyGWJ2NSfBiyP", "/dns/boot.metaspan.io/tcp/25069/wss/p2p/12D3KooWDoDLtLvQi8hhFVyubPZhaYuAwSAJrPFtyGWJ2NSfBiyP", "/dns/ibp-boot-kusama-people.luckyfriday.io/tcp/30342/p2p/12D3KooWM4bRafMH2StfBEQtyj5cMWfGLYbuikCZmvKv9m1MQVPn", - "/dns/ibp-boot-kusama-people.luckyfriday.io/tcp/443/wss/p2p/12D3KooWM4bRafMH2StfBEQtyj5cMWfGLYbuikCZmvKv9m1MQVPn" + "/dns/ibp-boot-kusama-people.luckyfriday.io/tcp/443/wss/p2p/12D3KooWM4bRafMH2StfBEQtyj5cMWfGLYbuikCZmvKv9m1MQVPn", + "/dns4/people-kusama.boot.stake.plus/tcp/30332/wss/p2p/12D3KooWRuKr3ogzXwD8zE2CTWenGdy8vSfViAjYMwGiwvFCsz8n", + "/dns/people-kusama.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWFkDKdFxBJFyj9zumuJ4Mmctec2GqdYHcKYq8MTVe8dxf" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/people-polkadot.json b/cumulus/parachains/chain-specs/people-polkadot.json new file mode 100644 index 0000000000000000000000000000000000000000..6e30829eab49a10434a0191852267623c3cfc199 --- /dev/null +++ b/cumulus/parachains/chain-specs/people-polkadot.json @@ -0,0 +1,2961 @@ +{ + "name": "Polkadot People", + "id": "people-polkadot", + "chainType": "Live", + "bootNodes": [ + "/dns/polkadot-people-connect-0.polkadot.io/tcp/30334/p2p/12D3KooWP7BoJ7nAF9QnsreN8Eft1yHNUhvhxFiQyKFEUePi9mu3", + "/dns/polkadot-people-connect-1.polkadot.io/tcp/30334/p2p/12D3KooWSSfWY3fTGJvGkuNUNBSNVCdLLNJnwkZSNQt7GCRYXu4o", + "/dns/polkadot-people-connect-0.polkadot.io/tcp/443/wss/p2p/12D3KooWP7BoJ7nAF9QnsreN8Eft1yHNUhvhxFiQyKFEUePi9mu3", + "/dns/polkadot-people-connect-1.polkadot.io/tcp/443/wss/p2p/12D3KooWSSfWY3fTGJvGkuNUNBSNVCdLLNJnwkZSNQt7GCRYXu4o" + ], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "ss58Format": 0, + "tokenDecimals": 10, + "tokenSymbol": "DOT" + }, + "relay_chain": "polkadot", + "para_id": 1004, + "codeSubstitutes": {}, + "genesis": { + "raw": { + "top": { + "0x0d715f2646c8f85767b5d2764bb2782604a74d81251e398fd8a0a4d55023bb3f": "0xec030000", + "0x0d715f2646c8f85767b5d2764bb278264e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x15464cac3378d46f113cd5b7a4d71c84476f594316a7dfe49c1f352d95abdaf1": "0x00000000", + "0x15464cac3378d46f113cd5b7a4d71c844e7b9012096b41c4eb3aaf947f6ea429": "0x0200", + "0x15464cac3378d46f113cd5b7a4d71c845579297f4dfb9609e7e4c2ebab9ce40a": "0x1c00f379b621bd73c45c7d155d2a1fe6a04649e3ece7c7e03b70b3a6242bc7c12708c4107d205432aa56d2018d46daa0b820669d068b11abb5588584f05d4935071a306dd46ee404511af11b9123964dbf1ec087aef60b766f04de5d94891019778eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b86896496c8cf62f725741306fa59a240c8a721f1daa9a6374897e4530a33e5e0b0fe5baaff773e3f134d4e0c90ef5e5f37adb603bb591b7aadf67a2a757101a1b70302e89a539b16e7cf02cde91ab273572701a7fb7bf712212a75d2d48cde142e2b40", + "0x15464cac3378d46f113cd5b7a4d71c84579f5a43435b04a98d64da0cefe18505": "0x00a0acb9030000000000000000000000", + "0x1809d78346727a0ef58c0fa03bafa3234e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96": "0x00000000829f057679c4", + "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746b4def25cfda6ef3a00000000": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da924f98efe9bb1acaf26d612783a88052296c8cf62f725741306fa59a240c8a721f1daa9a6374897e4530a33e5e0b0fe5b": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9381ca18820b278a00faeab03d52440be00f379b621bd73c45c7d155d2a1fe6a04649e3ece7c7e03b70b3a6242bc7c127": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9529b5fafa1d11181be42fa36618c5bd4e89a539b16e7cf02cde91ab273572701a7fb7bf712212a75d2d48cde142e2b40": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da964a799358e9d6f2692d4b47a57ae3ef71a306dd46ee404511af11b9123964dbf1ec087aef60b766f04de5d9489101977": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9831ad22a3ac7b99bbe1efce6cdb4db35aaff773e3f134d4e0c90ef5e5f37adb603bb591b7aadf67a2a757101a1b70302": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9dfc40f350cc4563ad9ddff5ad92944278eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9fa4cae44dc9cd8d9310d27efe3f67fb108c4107d205432aa56d2018d46daa0b820669d068b11abb5588584f05d493507": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x5a283d003c70656f706c652d706f6c6b61646f74", + "0x2aeddc77fe58c98d50bd37f1b90840f94e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0x3a63": "0x", + "0x3a636f6465": "0x52bc537646db8e0528b52ffd00585cc104ae0b06b3124f107867940ef054d851429d2d9e8a3d35e90ea28b60bcdafdd3951e23ebde3a5b1034f580f84a9d1e1ef7530ccc0805df70662f231ff255939f72a121b998ab3ff8b60c4d36217bcbbde59652ca945226149911c41141309e91bc8627a179e6ebfb729290a9419b8f4e9e440e8ef9fa7c3949c01a04b31af49ec31a04ddca3c28ab41af2ec11ef4bcc6479e448d1a6432394c0daae1241987f120981a64e2dce441304e9de431bebebd9c24ae1a7479b763a61a84c32d771b6fcb4d1ed46eaa41523aac4197430f3239e649443fd5201a347cab41d8ac41d365300f9271ac06659907616ec34b103aad4152fa5583b21a44e397c3cca10751873548963c48fa0e5e3d087aad413468788d1a54c32dcb6b6a108d1aaf61d5f0ea4196d71a5433b31a0f9a5c5d0255aa4125af51c36d946ad4c0e17e5d5e43735dd835656a98604619b47a5e30d9c36a48928ca4fd4c23523f190b66f0b26a6092c298609e0c6924af39330c5a354614c24c6a1a59fdfa22c9c81a99ac61ca9e8d0e8835490673d4a85e3636251396cd1d76f0a0f61d76983030385c07f85c07aa4387075dae43878c65911c87ef402fdf41eaa08307c9b80e363a3c520de8385c8769e43a1ce541308eda61070fc27c87ba83a33c684a1b1b4cc671b80eb286ebd03636363a3cc8721d35c8c6669439aa561a0fa24e331d87ef50e3340e83f21d3cc8e43be8a0430eaf354807f7ea3b78d0e5ee411007e7a5529b1c87dbd0d0b8d7d4b80da771a7f1a091d33cb7f11b0f22f90df798719407911cc59c3bca6f3c08c6dd839eefa0c3cc0c0e9fd9c1673c48c667d883309ff16ac3867b4d0da2a94134ee6ea3c66d7810751bec41d2abebe041d075e01c361e64b94d0dca61e3386a500eafa9711d3c28731c1e34fda606e9d0e15c0db251836c78a9e43335e874721b3568c64b25b7e14135dc460d3ad9f09307d1aab337ec9ca39c6e4e53834e35e8e4344ea9e3f0a0cb71d4a0cd1d8707619588bd61df1ce5415735626fd8513548475d8277c0bcd6a0eb721a35888663d5310f9a1503580dba309fa94197d3e9d483642a04f6867dc6836ad406ec0dbb0e35c8a686e7a841386a100eaf5c0df21b8ea306ad189cb4e18b2f3548830b9eecc84441055040c10d6698411251d84942c675decdc2d4cda1eebb59bf51fdddac9beadc1bf61a1a199fa9413660fc54835447b8620c59b4eca0074f38c28e8c8a06485ca1054ab0421bb44cb123e34132358854b7983adfcd3a4cdd77b3a376a85f1fd593076555047bc36eaa4135ea12bc9344e6346a10c94b75891e3b498c7cab4159e6a41aa4d281143848d181196590e10c3ba3c582972b72d0021a98a18436ec8c3c685483acda43aba777b39ed57d373dd4ce875f87d587ae45f6869dd620ac2e81da4902fa55830e40042dca008432a6e0c5073bb32ee13b49e0e0620d43d8e20a4ab8610c3b49b45b1e64d520597d6fd88362dddecd3aacfb6e78a85d8f5f7f15b537ecebaa27a4a30190041b9c2411868ead9fbfe7efbd24a8f8f7de7b4be8ead8d6ca1aca78ef547bc3ad53ed36d38919df9e75ea7db37fcfb5e922e8ef152ee0b0be5af77b8f1f9735aa7dc7c6dded358fd9e773a511c20e9d5fc7df8fd90bba4fb9997ba575b6eb6376aae37f4e800dc8d6493b630e7eb63e96b097ffb1be090d127d1973efb526322bfa26d9687d2ce1a1ff51c0b3b7af36040eb116641b7af66ce8d95b0bdd9f9deada9f6f3b7bf79c3eae87adfd0d69f77975366a1940e3ef1528b8bca986ae8e0d7a8f4e75d3874e759b772a3a013a053ffaa953bb6281968f5ed3a9fef85df65d8f8fbe9dd33b5df6dde9a36f9d6a8f6eead4f3e8d1a3af4dac3ebb6227947d6dba1eff9c32b74f39631ed82886eeda10e856bd28f5ae1dd07b76cc4d9dca6636a5ac9d74cce59cfe7ceb94f4e77472fc5472dba86d94e6ac01e9878dd26aa739e693dbd738cabdfc4693dbcfb87dc9a14ecfbe8bc3b5b33cfa73fa9829b78f715301ec1707149fd9f4ed746967ab0191ce95b3b88edff2a7ad2cb177d93fa7505b58ca1a65d3a8e7d3bd5113feba4eeb3c8bdb5f6e1bd50eb98eff87bf7cf9f2e53bd5af4bae037abfce7536aa9d359eadb16e8d6ad7e9cce49d5a7f5fd329ffe73bd6c7fbe7db29f6cee69fafcda31c8d40d7a6dbdabbd937edeb7471b61edbae9c38f95da5c0c977a46f1fc0ef0a892cdf1a0f8f8dbd7d3bd529cbdb67a7f6db696b3c56ddedf9e3f62d8e9fb2f69c3e0e887f7860a3a007d9fe396b0dd86d54973dc7daa93ece67711dfc0e3ad07be9abf144d7694a5703226b075ffa748bebfc2d7f5cd775dd1301119d116ff936ca729d37b99fa07f6e715dcd43a79c496eff71fbab0d81ff22f7f3fe39e4b651ecabf1bc0a1bc5befde65059fc94a08bdad6d7a2db295efe754ada4eed53e6766ba7b433de9ecf94aa6cd09fb3b7c6c375b7f6c76da39ed3ce668070810c8bb3bf1aacdb289d5e8d0736eae9346b40a8be7d351e15334381ae4de7ff9cee0e1b5d9c6d1bd56d3cecacfd30626868e88867a79dc14eb1af6fa7dad7579b8d7aaed3cc658d7abe63eb4cffbc1d7a37ff3935750a366afdf9a953fccf6b3ac5fe9c7276ead4fef3d520d704c73351cd6f9fdf9546483bf4765881f8b96ea3d6570bc2deb56b67d7699d5e9b577dfc3787aa99b1d00562b3e9143b7b0dbbb3a356cfbe837fd85f9fbfdecd67df97b37dd36dbfde6def4321b0b1f36f17607d35ba3c6cddf6eca84e75d9a9531dead9d977748a9f7debd4ae90a0f2eca64ef5b36fe7f04e57f3ecec6bc3d5a78704e802b175d9b7679dda2b5bacbe7debd4ae5660c6b79b3ab5de7eea147b7b0dffc0dfbe365d7dfc37878a390174756cbb3aa289efe6af6f9dda2b5bac7e7d766abb00a3cbaf679de25fdfced99dcef4eb6bb3d5c77f73a898155082c245408313b01214a5176c40d87eb059b155b1f960ebc1c6836dca2665dbc1a6838d8a2d071b0eb61b6c536c36d86ab049b1d16083b2c56083c116c58604890d0f08ef07cf8a57c5f3c1cc620e616231ad98554c1f6453c89e904521bb926119e560b485511c482d1895314a03a909d20a484120512101816405a90b9215520e4837204d41b201490a120d4833205d2179710d6529c890b85230b1901d912d91a92053224b8272a15e184931a2c1680623198ca08c62308a6204c5e80523178c9e18b160c4c4e8c9c8c90889d111a321ed8b1607cd0c6d0d5a1a34346867d0bc6866d0c8a08d4103833686c6056d0b5a16b42d1a16b42b686268616853d0a430ad408a4306854b091214a41790644082428a01290a120c484a207141ba822404ad06231c90aa6459e8113627d9d0b6041215242290a290b220d58034041216b40833cad442894081901d8126a1a74091c02f6017700b58064c038e41cf104290980882010bd801f2834727013f3820480352241714600002d88e285151ca410907a51b94a294a628d9a054839214251a94645082529a412906a5284a30283d51624169688bc30687ed0d1b1b36356c64d8ccb08d6103c3f685cd0bdb185b1736256c5c6460bb6283627bc146b439b12561021220d992302ad2a8a041419b429b812603a6c240e01fb0155c05fb807bc03ce0292c8577c03a602a38078c03be0147e129d8065c0396a27b3ac8bcc8ba207dc9b8d886b6146452b22bb21b6c4d644e6214281a0240b7d856408d40b3a043a058d02ba810681028150a030a0525dac2b075d9c8d8b8b0956113037582b2803641574095d8d2b0ad6173c376c6d606ea84a68022418fa043d8170c0e581b303750156066606cc0d64093a04f6c67d8bc9498c0bc6c5f4a4d9496283d29a9a0a44429899293520a4a486066c0ca808d01130316060c0cd817302f60451897adca4604ac0bbc843705c685d20ab037d02718194a4e60646063606ac0cac0d280a1013b036d0175017dc19b426340a3a032a050e80ca8149406a5233633b033e812b406581c2813d406748a2ea251280e36166c2dd89ec0b6806901cb02b605c3c2e682e602bb0266054c0b56058c0a9818af085818d81430296051e82c1813302cd815cc0bac0bcc0ab6044c0958160c0ad8133030b02f3027604de82e605cf4137a0ab6457f8125014302a6057604cc085811b02a1811b02cb021605760586042c0828051c18080fd00b3a265805581f900eb01c6036c0a2605db01a6038c0a2c07180eb01b60519a0b3605e90c980db01a60527016180db61526030cca36042c065814180c3028b017602ec05ad036c088b02730273016604d602bc098c096c09e602ac094c092c09c6029c090c08ec086ae2f571c2e385c675c6fb8dc70b5e132e362c3b5864b0d5719171aae335c5e2e335c65b8c87091718de112c31586abcb0586c782eb0b9717ae31ae2e5c5cb8b85c45d7162e2d5c59b8b65c58b8aef098b8ac7069b9aa7051e112e30ae39ac225852b0a57960b0ad7132e30ae2f2e275c4db8987061b9ae5c5e5c5d5c56ae255c4ab8b8b856d71657122e24740d2e2dae235c46b88af06a7055b9887065710da1a5b8b0b8aeb8847005e1a27201e1fac123c265c555c5e583ab07170f5e1397946b07970e2e2aae1c5c38b8a25c53b4102e1b7012ae1a5c525c33b8647041b962d061b4960b8abe4263e17ac1e582ab059713d70a2e263808970a2e27db96d983c98339654a993b80494c1d4c2a660e260ee60d36265e95c783fec206b02e2fcab3c19586cd08db125b165b11de13cf89a7c44be23979297848bc23de507fe938341cfa8c7e43bba1dbd066341b7a0dad862ea3d3d068e833b497364397a1c9d064f4185a0c1d86eed260682e74167a4b53a1add0556831b05533a19bd06074109a4a03a17fd0566c5b7415ed83ee41f3e02dd139682a5a078d83be4147e9299a063d8386426fc04a602e9e0a78c548e02d580b3e021b8185c0456022f010808ce01990d0c050982ce9800730b005e10216107213bd40f997a90fae7e3d4c8c7c800811467a44408408e53744921e2246808c0c418408b6dc83e403468092140102224042f42c39324492234488d8c0c1d190186947d068431b82232048a2a407c848cf1221981c61d293a407884df64508224a4090240812244a160024440f12244a16d04316871e191c902031220412244616708608804290a407c91bb6a7070444940011011241088ef490e0266bc3324172c40850cf10447a7a40a0235bc32a01419223444ab0a4a7889f12188180676ad81e2192284942c4089123447c8f1049943c002849114a8410e26f64650ca144889e21706467582625e8f121c28449097a842451728409939e0970999725c111227e498fcf12251718c26565d81e2023431c4162a409919e227a8a88000586e80941088c50a0878c0ccbc447881e11081186650294a467498f08921cf1ac4b922320a0c9beb0421c6192e4c81220237a8894000911441821b2a4670824478ad8f1114209929d9acc0bcb64262b5a23446a322dec0888180132328411a09e204ad916131c4162e408d091244760322deb238412241f20d2035484103d46f4d0c8aab04b942c20cba8b049941051049121901c29e2034492181182c811221e2849cf0842d03381217a8628028910498e24a980912545bc8e4c8c65d27304e8c8122522002ac2488d2c8c4da2e408909125450c410448091226448e10f1469614f130dcb482e5e50a17caf0aba2bb1a1a7a563d1b327e217e8189600b964aa5923becbdf1bafb4dda54cab792f93537afb4de5ad7db2c8b662fbe8da6ab5b46d35afb9ae5b2e45ed9bb3824c307df83afe96b6bb9e583bbf0edc6045c5b77f77b9605dfdb95d6830c97f77a2fb3aced7e56f6f6dac78f97e3be8c6ef35a566fbf9dcb4f6e5bbd9dbdccba322bb3f89299b5d7e3ebf5be27e56e373f4bca392733cf6e6e9a0d0196949b5d96f51e85afadd7fdfa59d765bdf7de6b4bcb41db5d2925af5c6bdf9b533e5eee77c24e8b618d61bd8b618b61bbcbd8628bed2e86611826a194524a29e5dc297bad9818290f1013b33de5eeee940b1bae94134e2a77ae6c0877e54ac852b264e691d5ab71af36ea662e45ba3fc8d7cc71574a5eb924e65d5e665e2957ca656e6e53b3e4de6ede7e8f7b247dc8b70690bdef754bc9cdfdf649c972e7dc9e2b5bee2ea52df7d5581cbd8fda780be9ebbdba47567733efbeddf561e576f7c5bdd6ccbe9c6e6883b4fbd8d4a902b45c0268bb3994965bca0108807b795b5a5b2f4bee26691c80de5ddadbb377adddded73dba5f2ff35be696cb346ced9a7a7732338fddb5b2ddeea6cb3bda1d8db41e2def6a3c7b1f00deecdde6c9bb2dbb7771e69cbbb37bbb7bf676ef8ea494529370e16466dee6dd9d6b6d645e9ecc56ecddd6b8997b7bbbb765336f33f3f2f2eef6f62e77f74e5ec9cc9bb1b45e46ad776d568cb1dbda95fd2ed9ddf0f1b3762dcee4db7ecc6ff76d77cb96d26a29a5b5c36a2a7b9010364b09679a59ca9617ec191e6eba97e57bddefc5ebddd85e29574269c1e5d72c7963094a69068fc6760996281941cf08a48d0d40089420211282244742100225486c90bc86113d4324394224c9112322100204205052078004c9119f1e281d3a503ba06076c0e8d081079b1ea421901c118110448090146104043d43dc2c3102c4440789898dd38c8f10463e80048992253ce430d2b36446a6c7870890113d4972e809810d1a4c80981c31a2a726020961844912234b8088001d19c10894a06056004740d0b384885a6389911e2442d0908648d24304114688f484c0c81225404cea0600c8c8929e243d21d0815b01002951b284c8103d4b7a8658a2a4e7c812201e8ce811414d0d100015410428c9912544c86c004670042849114b8808c1e4c808aa009630a9d9009400044796f4342162800014a0000218a22707b60218a28709939e25448c4089104496f434512244cf122246980c21440f9100f8a40a20002284e8614244091011255822444e0e3e0820004e80141123949000e8068d5401044044003d3e46907c804808921c110113232270eee95902829a26497adedc001049a2e40893253d4d888c80c812254046845082048911224046f4e4d02449cfd3916dd1ab52a9689155a9b0222ba49a4584788ba8f812125249d5b38454ab52a9845e916d215844c542422d2424f48aa85848d545542c24242424a452c9222ba452bd222a5609a95e91555d4554fc8a08b18a8b08b19090100b0975911552759115e2222a16e2222b242424a48ab3c80a097511156f91151252a9a0ca2aa26221952ca26215ab6217d92da262954af554b0c8aa54aa5764555c6455aa2ea2802706ef2e8f8089910d8fb9f78ff3f9097acbf797eb18cab7432dc87be80c3bf897af775c81aad4782c1ecb57db9277d249de519fbe9db3b9e5256efbc6d23c03eab71cf3d14d07f4def238aadd6ed13259bbe8ed932b55d96805ea97de61d1a7b70644569f27d9fbaa40fdcf27fbacdd6e79e86d551f0ec22e6bd6a87dd875d4f18a200c3df77b85ca96afa28ca7a49177a6e95a166bc3f6d52ca7b433d6b82e6c1e627a3947ee88adf37f307bda3e73fb429b8fe5f13b7fb75ca7bd5317468acc916aa77aea975fbe1a659eab62a051ecf0ad174792ab319d6a7a611cda8731123dbb6a93de996a3a75f973a18ddf6d3a6561d49ff718f9ebf83b668279506ee23ba07eec0a952fbef30338152bffdc66c76a58e527cc035a5cc73fc240a3e09038e260a3f83df50ee8b9c66da3a2671c6c54ac1df499921136a07e5a3b4cd68e2db76a07d4b1d6b5791a5f38b8a245184f399b7db33551c618dfe3f70a10b068e2e9e26cacc503818af7df2b3f70f274e966963664f49d741a93ebe6cfe8ddd133df4e6d7e39ec14c9af7a952ed7a0c70b6a4030c04c408da74f8d7ad5d4a84783ab21c05bde99fe7969e3b651d3496fe492d332aee32678320afd39063a05bd9d9ff00ffbededd0598ba7dcd4788236147b373366cee23a9853c33ba0f7edd03b09fde26a70db37ec4f1b42bfa1ebbc29b96eb73caccc04f360d7690c746a1f3a33c13fec43971a0facbb7113bf756cc3952abe7800fc5ea9428aa724cefe45970e3b67baf476c9c146b13604e8a5c7e7164b281dfae460df40a0871e6be71dd077eb48b26fef54eca502aa9d76143c4fe255152860a7bdab50330eca0bbb76aa0e09f6cfa1b73624faab1df458a548871a907d294f7c4756216cc78ae74f13723dac1d047e17e7fae6ac6ba7fade37ea2af0a4e5f5b1ac7add505018040f3dd4866c2feb83efc1fa1ebf80ae16e5a167440f2700fd7a8197bf7cbea0e8a16b500c3df4e99444805fef0ef04b72cdd74deb356ed3a9ccd7519dba7cbd870f9dba3818e38b168671fbd69c9eed93a6eb348d10ea123aa5235f2d084ab11175cb69cc7c3f66f587e5d123e616c71fa5c7daf1d32cbbb421d0b3ea23bd83ce44f5974f6d0813d563ee7339745abbcbb11a25b797ea25a779c6a9688444d73cbae658ed548f91b8e9988fe6303a8973e2c48913922bb11b00e61d257603d0bdbf6ab7a3f37e829ec4edce7c3c25246c9a3f4d08f4cb9f1664fa553bcd67a5b99cbaf4d6826895e6aa4232b73c73cba1d38cfa64417496f1c7da5d3e31a789be3ffde26862fd217dfaacfb985f8fc5cbc7eaae39fd79ac3ffc25fa1b027dd6cef2cb31e68f1cbf10abb0a650b400cb6397a58d02dbc2d79ad02069fcd9fad8dd516b43e0d0d0aff3fa3acf92b95cb7944dc7c3dec5910e9d39cbdb9ff6837d1d5b1f56ed9cb51f3c391a215665c79e23dd76e660a35ab6cb754c1b4217a77d2bb638cd432fb95d9cee237e753caca6e6823e7f9c063676c863ebe6f7c6c48ae3376960e3d74b1c4671c64b7f33c3401128c2788610c040190f6e79a84ed1488f0e814e753618e854872a22824e75a7c50244a7785730c0e223f658aeef76cb181fbf5b3272e24e07ff6dfd91a53fe9bbec40f297dfa6533ffc65c93a907ce9ac0921f2edb27db9ebee0e7e1a0f3b65ce476a40386b3fde73b64ef0d283508002a129f4d2b73b1510ed3eb376cfd73bf943fa13d2fe2a0a987b4eb95bc8739655089f3a6579f49a55b2416738fc5ed962b59976050595975cfcad532b3d3a6d0d0838c0210e71f8d5beec8e75c9f1975f6d6877f4d011cfdecfcbb5a23ffc9d79f4e698f05fd56741b0ed0aca93effaa333b78417273ad0fc9ffdf2d457fb91398651aefcfc19d7498f7e71eb7427003d73ba1cd8760505ca3fbf9cb98e63d6ab7577f9f3d68408c9fc720a33d68058d42f2e73a809993fa673ddc561d7e98cebbaf2e2b05f4eb9ae9fd7af26f37f5e1c86805825b9b940f7a71d8b8f55f83844c4d640f85d4551c3f714bf2b1b50e151bf2b1b28f1ec446c4f09bfab195879b6f2bb92c1d0eff85d4199f2eba37d60bfcc033a697d2c1cfef96e8ee49be7ebcb0ea58e0e86b038fb1a7c1d1d5cb13cf661edba7642dfa43f044bf8d92f13b6d12c5b1f5e64d9f23fa46f329ffdb9e41ff6f7bbfe4efe73fab2a805a167107d07e40ca220f2bb225ae0051845ff53e4d98b0dfe4768f41d1017b4709ae23ba02953502e7c07b4022ec4ef985861083d1821cb774caa647976d682cca1a1204f0bb25f9e3d6a41fc7f2067c1da316b42a477ed76f0c56b3fa047d779dda9def2c8d108895578e892f3e998a81ebae53ffbe5cb17ae53b5f5c5472aa878cee26215be391ccf1a106f02132b500bf16f6fe991f3e94a1304ca4a2304bae5d2a3b3f603ba5581e8ae7480e581fa63edda9bf047971cf791e3be81e8b7ef137a68adf0fcc0a1b745b04adc22c758fe81bb6cf9f5e69cdd59c7f80738f4ebd4ca9ef663b75873ce297bcec77346d4889d2291e5d92d67e83472f59b296f91b9c5b1679c8fe5ec4f036209b19cad55b2edea89a2c7dcf221dbae7450e5b1cf9cd297b10664fae518d75dee63711de696538ba3090287865e73f8ef57738bebd75ca7ad2ceee290bcdde2464ee23a0b6a3f2c1f556fed87e59bebbc8da31162f9c82d1f558e4608f696636fd599c581d22d6fa7dbcbd91de816676a1474928fb8fdc5e932b7b421d8673eb33ea0476d08cde240cfeacc68c4f1d0af068487a4945ca7b79753aab06fa04352ede6779b8fe59877962f10aa2d300cc35ca729cc58fbc16e3d2d88e598cf6871a09316070e3d5c1c9864834347bce6f4a25a25f92ece45f2d1c575efa98fe8e8a2ae714b46a4cc759a94f9886a995f34abbb3b68bddefec5ad5b1dfbcaba35ea79fd76adad26280536f8bb7a820914d8e2efea092bbb389be3092cbee677f50494efa16ae8107a14fa17c778587fde972fd007494db24f20ea5e6597ab0dd92710bdac52a8d077918b49f609441fbd33c1cb289320c0c9ea63958202a159d7887fce4e1b72cf57d380141408ed183b97af94a11b2cd001145196e810050858868088d8315eca108f2a2861a809029cac8c18ea4cf011891d63e7aa433bc60efb732943315a08420ac23034b4b3150542b30e4187b523e29f97b868610771703234b4b35a10353eb6ec0125faf6751ddfed72fb3deb63498f97025db55ff0e70b6bac4e94c0d989fea4c64e139d327dfb4c89cad621f9f51edf99be5b2f40c049e4b88946b5fb6c1d37f1eddd7ae1db83a06fef460d5210610a2250291a1ada89febcdbbe771e37047de0440e90c00112769c2881b3f3fc498d1de84489de91fe24013bcf23f724013b415650e0791004de4dfbcbf2edd183aca080f4588374de4dbbac41565020faab41fe6eda63edd1ed6af5bcdb2cbb061530410a19aed0032e52285db1ed8e0a065f20c10636e0428b10d2b0b33bd0bb1edfbe1a057c6868e779139dd2f1ed907bdcbe1ba2df1c4250c50dad781072d199ad18ad1823ac6954f4d6f877e5c40b783a3ae4f9e12f0f5dd69a4645081fec86c2fa5c1fd1d7697cfca63fe94ffab3fcf994cf9ff4f71e954430722b4bedd2593a0d74fe7e1af884f4c8b1acb0513b23c70fb95d7db1fdf307ffbdf77c661bf01e7e572bc0c1ef88f2d8d86589fd07f6ccbf1a4fbf7ddd3c844aa794351ecca943b7b8cc777d681e9d6a9cea3b6a693e96af538efeae9c187ab838b1976bcf38cb2f8ebf7db9e91937fd02c2beaed3b376ebd3e9721df575fab2c9b5e6bc3ed37da8b7631c7d97d32032a7d479f78789ea35ef48f006387c79269b650a144cbc563b4a69cc26d797432ab3c9b5af064448563b23fe72ea7435205b3b8fda0fcc31d779cbedb3c643ab0ff603f3ad98af1664fe557da6b7775348fbf48bdb87dcaa28c328d05d1fd2d723951c011a159d60e27b342afa6a5dcd477fab099165359d8379f403ac0f5f9ce9d177746a6bd4bc3c3ac66ddf4cb7e99c49f331c7d437d3a36f97ef08f0d169d6077fa41757d3a8e9ef77e5840af88b2c419ffefc77c58230fec4da741acbdff7d358f587bfbce5bb72c2c9af174148c39b38be6a4da3a6c5c5c5595f0d4a8eff49a1dba9a50fc8abbdbb63b521fdb88e5fe638c1dc8915cf2f5fa7f4e276d54d3b7bd9c56dd150d48080da90f7cf316e779ac6ed7fee00d5133f87f4582f0fd0f9e94f13d2a4b79c721c7542449cb5d6009dec690dd0f9e9ad0149f23f426ff96a41b20e077d596b0e504df1d3e9cba0f64315e57f8afc74dadc3b1a7542515eee0e6a6552b36686cd8bdb1d7a6518b73b17b73bad056997b5e3e67da34ee87771ba5db5a0e8a563dc76713e34343434b41304faab4ffb31c20912470cfd1259bbd7da10e8ef7d9e475fad01fb562de2f440a7977517a77bceeff9b0438e464857826fdf5f8da75da7855a253b9a315700c5bbace3f1ec9dcdb35bcf2b26cae0d307319ac28a092c662c57847dc0b6ab279e3c0ffd734a5a5f9b8e87be9de670b65c04361f3ee2a3f76f175480c2f3b3b72684875efa724d6090edd79feffae8a0d304c11ed61fd2af6f15bec7c7dabd0abdf7cbd3ce96b3629db51fffd9fed51a1efacda18adc3ca01ad828e5b1ad9b6a500a6c70a32b4b59a360a34cde000860016518d0a1cfd96ddff94ba7ab638b7ed2e954371bd0a96e2bd229e907908e81a197ce814ebd976fb5bcf4e1e57ef1d2a1eb74135fbc94524ae96b23abcf7a69326810cba153c87116744ba7e1bc5ca721c73f5dfae59dea92935a5c137ec835e1b79c32e42ca7ddbe38d0c70ac2720afda706d2a52f839cc5b9d5b376f0a74bb7b8d7b076d3d92dd779d64fd0b7d556cf596777b051d35bfbc19f39e4e0acabf1646e719de54db64702878ef86efa8f75c6115fbec9fce990eb347f1e391fcca3530aeb84d07fa613248ef8254de45fdec47a26aabf2a7c3e81fa473eaa3f7cc6631a07d48f79c6fdbcc72a4d105e7d74a8f1447f1c749d8779e49af43fa7ddbc3bae1ffcd1310e5ab5e3b7fce23abeb84e66d775f955a7eb3c29df774c54cf0e3dab3fa0b363dc7eac9d557d60fd09faee3d7b90eddb759a72a4353d1ae8ecd09ba381de6e39851c3b65ad013a96b3434efbd16e390cd26e59ce3ffc650950b65a10228214f9e973dd07bae574721d7ce8efaa4b7ed6cbd0d003d1f8e9ef01653f871081714b7e14f0bd38d081e463def543bfb8259803c99fbe9a10227fb94e4fee07c75f8e713f0a785e9c8bfbe12f7ff9e43a7e78d5dd1db0b51fd1a1b3c6236ba77ae9909b9363b7b8fdf5c8751a0f5cf232ceb0608592a2d3c8edb3e6f1c75ad9a1a420d4a9d30cf3cd1ccbfc720ce34c8d5abfb88d5b67a7946bc2cf5c137e4aa95338e2aad394f3917e6d9da26ef93a6b247eba1acfcad2d628cc7b7ce6acf170d5793acd5cc7ef23fdf2f5c16f71be38eb5ba77afc3ae5b646ed7c4b88f4ab4212e6d1a167ce9a04a663f5d4a8f5ac9ab6512b9d9dd2d5aedaa9fef28c632ee33acc2fac76f031a7cedceb8e3ff3ce01aa2d7e7747563bcc1fc6ed63dc3e5fcf75ba7fe05baed33a4d25d745679f1c0dd71f7eabd658191afa1e70dee26a1ac51f5516c7305008b9086c3ed0757cf77b658bd5ae8faec747550c827da4317a076b27f4d0bb2b88edc2c72a65fa72d32367011e55e0e2cbce3ae4baa0873e48768cb75c7a27f4d1777fd8e5d1ad173da0f240fc564db263fccffbf2e565958202a17d02d1ceac43eb5dd0c7da41efae7faef320a7e32967935b5f4d03fb04a29dd5f142ac8add5268428b5e42d42f679d308589a12950d9e20b32764c5b74810c3900230b3d58ed6c54b6ac51ecd6af175e80f2fc9b103a18afacb630dd4cf566b6510d21e4f857db007dc27d41590bd61c40830510f982a1eb34acd3e685802a606b14893202b6d51ca07a08ab8a9901dde9dffa7c0e77baec817ca1c57bbbed9df1b6de1a10aaefda7db6fe08fdfa6e3b50c117bf2b1554f11de9a1f7f07b6555c69360a79e53ded879831a10aa573d7b73a52af4693cb15fb69d925e3242f475ded823c74120fcd2757a768ae607bf7459e7b3478e7f6d60f5d9e24015c0beeed3cecc958cc0fb83ee6fbb5a428a8fbfab275afc96e822207b4ae24d7ad7e730caf64ed1fc687ffea4b3c34e75d17d9e43972e7d76aa65dd2d7b9dd6691533674117011b256da776a5822dbf0e3bd5fe7c3deb140442051d3a251d607bdefe23f4f0879f3f402d93937cdf0d0fce83fbcb4922f3249660bfe1db9e848cefbbe9c17b1879124bb0efbbd9e13bfcf4729220d51880703e4ce3b1a6695e1acfacbb31cf18a37fd4782ccbb2e68c31660f61df40d9c1cbafdac16bd66d549496ece0c358a16439443704dbae8030f436bfab1f6c89a24b14660c3d5d22db2a010ad1d32db2ad12a044794a92be1bc538fe9952958d260874cca163d50773cb3bacd204b1a2d32a25f3676515f68df478a930ae8318362ddf57b22cd55b0eb5d928cba9cc305fd6ae46591d50ff05a4288c4e3d56811485d1a8fd8ee9f30752b4a5c3d8075294e5296f408ab4346a9f52eab47690d246618ed509a4a86872408ab6340a48d1179d52fd7e6bcb252045581ab55f94653521d6972f5fe2f0560552f445a37603834233a8143c1bcad42912f390b018fd6ee17ff8cbef96e729308b4452e3797280ced99d7e32f42d39c6ed185f8e113b697d70ddc55959c980bb5be5117037004aa010ae1350bca9515ba3cfc569a7cbbf3e7364d3be83edd7fa585ec10d7ec34263168effe96a40fcb976fc1ce6f87c9bac351e5bd7c3872ea850f4ed048807f87653cde270f780391e5bb77d9fda7bb91e3e74aa737ca7bd0140ac8ff7eda84e75bba9e6dbe6dbb3dd2ccc032a54b0c0c2cb18636c05b65d01018b6fdf5515617c97adaab0f2dd34000562c4848d7afc0ea0ac043be9d4fa7baf63f4f7e22b8af2d1e98d4e875fef707e757cf48e004ddeafeffab02eccd7b3cd04b339f3dd445fe7fd61be9c1eef267ae6dd9cd2e7f30e077b8f97838177137d66b59bdbacdd267b3c0e1cdff5d8a453b82698416ee332ec82cedcf2805d4d8b035da7e7cb81d91be8d17753bba88e003a7074f8f9f1469cce1c065e0e0fbd9be8736e5b778a4e7968cead76302f873efad382f8773ecf4ee1728fb26a5a1cb92d4a3ae5b24549c7b8b928e9170717b53f4c5bf6633e7c587f829e9d6b9146c5e6fa25b784038b137d0b1fbd03cb23fa560c342afa6ae128bf3954932d2d9868eb4cb16b3a05d4ffe003f507e9a121a086cf0e21b318f0c1ca8b8a27f8f6f8fda0f4253ce27bd80ebf1f940e349f1747e8db3988f7123a8d10ca5819760ad6d7d129ec1c2756f0f2f3f5d1bf52a8d39741871b5c2285faa39be53a4dad2ca31cef342733ca9dfa263ab7ea678dcc456727b6e79d098869510dbf6bd6a8e831e8318fd1359ee9a6cb63bcead384f0972f5fbe7c3bfcd5bad20499fe7c56d8a8e8af36e9df1ab5cc82adcb3e5a7509d0fc2540dbd7342a9e16277a73369647f4c7ede2485f593989ed75a6971d83407705db3aed7e6f216c7fdfdba8e5f7de882608fcf6feae4c9a19caf42d62db2e52a0e5a7fb166d97e4ae53cd6ef60c975d6a3c3c67956dfa355d6a40a87e3a859964eb72cb721f74764c2c6f599677ab25da70a84659deda0f23bc5196b3129be5d13b7feb72ebf26ebe7579b7bd7579777acba506c47f4ea7bba5ac51d2bb1d6f59dea353cf2d09a7557db628da008b19ff9c5e61c293b7bcbbfc738a45cb5bded269f42efa9220db33697f907a5352171d88df72768ba39cc5d104796ef9ab3eb4dd72a905a1de6ec51fd233f11df22a74a80db1bc236cc2df0e9d92a6d3a57e39cd0fbfe54de0b3ff909ed93187da10e9b436790efd6943a2736dc26fd5eebd25edaf362b4d10cb9f5bd54756e8d30ec41f7ffcbcfac38f318c015d9b8e570fe7747ecf4aa72c2cf0a753a809793edf9cf3694138ce2c56d82fa5b374b6a090d9762a0b87f10b975913f25cc6fda805618c99b1ba358afd5913f2dcb2a4f4283d3a713281e716166ff9b49ec72ea0f8e8b244a354729b9a1ada0f5ebd55bb8c7a073fc6da51ce89155df4f6892e9d6e9a1096d2b520d1a5af765dd5b95fe765279b1e076800058a2031a253cd442c054f612c4cd95298d6322b6564d78cc9b6533ed237fb9dde3ed32d4f6942b80b2afeb9653973fb530b32ddf2d5b66b72b242f8783b8e7865b5268637b92070d65d54372468e33f2e081c5a62f9121eec4027e832480f3d3bd72596034de832087c2b080a1e0af977e5892dff5cf5ad0151b1474d88ccba5ff3c2d1cf7b4bd6657f5a10b1427e95c5ed85fdf13f8e2f67a7f3aa0fe069b9c3f73420543f53aab23d9fcecf75462e5ed7e540f62f577d91e92d7d35866e71aa670e28beac308a08df6a7960d0b5e9aea14e9d5ccaf876ca79059b74ca4cb7f93d38a209123ffafb583bebcb972f677cf4c8b506e4e4943793afc653c3759a4608459ebcf39730dea15e4279379007428153de09a676a8cdbf8350a605a1c4dacd5515547051852f9ef4cb0515a0f058fe3141cb3f8f333b712897be3d79e9b053d172e9196f26678da7867f00ba109b7a8b8271e845f8875d1e300e7d719c6436d2c378371ff3dd1c6b6f601cebf1ac595ca94a74d664dd2dba0684eaa35b4e83eb68f80da7377c73e834cb64380b8b6525071c7494d11c9c6e19d47ef8d4e4e0376ab81c326bc544eca453371c3a3fe91c77e84cc45230155c0543c150380a4f79e89bf6a3ffc6952afe799412fa0d8e3fca2dc6b8b509fff663f3492d184fc597039f74f3ca6038d8281887710e746aabdde637aa9bb41ffd30343ffc30de04bee53fa4b76ab736e4b9559bf0c3d46e8beeb3f9741a1a101fe940fc321e2b2fb1c52f3a9583438f593a078767321c84445c87d128e8ceb596be814e61329927340ef0c8c446727648c5430b265241055681ab4e917cca4358c543ef20160f7d3ba8c543afb1c4d66d180f6b68407c3697d507881f36d128e834863b6e4c1cddf01cb8c6d228e838b8fea26fe094d7a0478ea56086e2c968049fc4bf51d9c9932d3a0caca2739c5871920e651c3a94a253964387512015704aa7681cc632b08c9f742ac621fc132705874b4eca13dfc1b1fa2e96f170fb53edf84f2e396a69d1291920fe39f80defe0cb96a95d0e35bb319b9cbc46729db57a68adbed0328617eb8c275044a9a28a952c5bbacc323a85837362853c9d1c76e1822e2f7dc683887eaa5dfdce60679234dbc975ba351e19a7e1fa9fc6535377797433423f2385c4195f593bff199799711a8e9fbe8c86dbd684585564ede0a95a5a68ab82adb3b07828332324fa4ced9af05b4e3b8be1ae3c41861932b3ba7081968f7e694136cb617cb52171669cb566a3fef04ba7321c907d193f71fb947676e2f86356cae1a30604c7cbfa83e3a5cb70fc3da2317aa80121bdac3fa4977ee2f865f84b1a90ed7fd8cb0fff1f2e7ae927a794b7d48fc6939ce527aee32f7f724b03c25f5e4a8771aafd901ebd862624bae43f7109784b03a28097f547012f65f671c3914c65d2df44bef44c06c675dad2a2536c61d12918876e55b1b4e8d4c270a60aa5881c8c929951e3e5a177a697bebb5d1e7a97bda429b9114343434ede88a1a1a1245e3adc9c22eff50052a34228acc4d66d5107a168439e478f9a9077850955fe05f1c34fa3093f0dd77934b6fda2831ad7d57cc74eb2ef20d79d306e89f5dd167535b3c8cbf1616fd8a377537ab7595bf4d031d0a9e7d029c0019bcef1a16fd8a13300884eedc395154e36cb73cd2f9667ef4edfd5c4daedeab9e621f4d54ab0386cc4e2b05f43bf39845a45d338b850cabc113d66873046e6da21c73fd6373b7d95bb28468d87dd88b72074cbb284acdaa9f621fb6ab2218c82794008a1601e906114cc833d4a583b235a56e62014eec7825c47e892638f5c43c8bdba5c363912ada46bd3c1280f9d1a11d439aae9eda453ecb3ae1970683e81441d84f2d05f51cfbe817e3263f3f2afcb9cdb763ab9a3503dbeebe16483eb633507ec77409052ce34cd6dd8f0d6786c38e5d168e440f647aefac775fe6f725d919f3ee25e89db7cb5a9798953fde480e26f9ad69dda27f7567b738e46998f741a8b156568f9ec01e023c7f2578280e5e9e77008e5b330e33905db734a4b19bfdac1ef90643ff21a1acfdb369fd3e43abd6d9bebb489eb84bee4abf16c595672fab83972de9e8fde7ccf473ea7bf973d8e9be03a95f559b63fbdc43d1f71996b3cd4378de7b9770e579910baa9539a433f75ca8643afe95474cb3b1f2eef7a3c7c379877fedd7c48a376aaa7e193337989abe11bb73fda64623ceb54c7b053323e7d762ac6a7d31197f1361db0df7366f319df4ecd6cd347eedd5dbbad766c83ebf86d380d6d08fd518551684076b88de9dabe36f7a743289dd27cfaa6f14c92c6a339a527c7e1dc37eee43ab8cd5bcbcbe91ebc7bca9cf290e6064ac64bd36160606056074ced540fc3f04b238f8929b9ce2bc5f8084647958151f00f0028e10c91c1a95d7f8c43283f7218198f992399ea133372ca591030238f29c5f8a8d2c8f8e6a7f7e44d79393a3972c0c1f9c867ed828c7cfac8b709e3305ca9cad64128bff90eaee3dfe19b0604003e4900388d4a0e806d54f293cf6c3ed2808cdca7e4ae8dfc41d91c9646ee331b007270be384a35870c4b8c8c0cb71fc37525f8e974b963b8e97469cc560332aa1dfc91c7f8e4baed5f0719512a510153aa9dea4b3ee2e6c9378750f00f23df3a28c577a7124cf581da9098daf5c3e8f0138c9f9c6e5eaa1d84f22707ea9f9e7dc961c9372f954e5bf5990ee3253f790fde35195fd2f26e60c9b75338a5d30edecd6efb92df7877fa92ef967cb520303e4bdcc927fc186e3a6b43e24f978139d51184028773d7c1e9f01d3b2051a3362d2fe73da9f11eb43cec2aef06ee70c379e882f29bda9d76e8dd75fa3d79390f4a5779393a39bce6898da3ba4af51b5d45872a0f517ee3060f373778a83e2347f9bcb92164e4a81b372acd0dd7e19b3f282fa7bbbc1b98f3a6bc1be83b780e289cdbd4ee84c36bedb61c5c873a7df39952951c3ab88d8e5aaab201c5cfa1836f3ee3530392c37d74a86e6943b2cfe1dde5e5c0bed121a583efd0e5a13bb78dd2a14eb77953dc618ee975c69d7b53dc71d46ef3da01c59fbe790e6fca439f991945f937ba12fcc869cc2207a398f16dcea29fb37640103e8e11fc1c7cd6ae8b7ef3f838aacfc867e2e7e0dbe6ecbba1f1eef4d3b7cd6928ef06a66a7c3adcd4c9a7cf4dc1f8f46c53259fbe5a10339e43071429f7eb5177821f3d2d48847f2308ddcee94e32def51831de7597d7ba26e335df5af32eea548c6b0ea3e01ff83527ead4bee636b8fded548d6b0e3b7572cd67a7605cf3ac5325d7ea6e104a0dc766340afa89e3331a051d86eba146412f71eda451d01b0ac9a1efacdd7c92d3349487be41f9cd4f5ca7fa93b3c67372fa4a4e4b95a601fb2507b25faa25246cfe2557fd88ebb8f39f5ee2bae99bd3ce46dc8cc38c38d5c37040f1672a8c8279687ee26c38e56cd3cc7839ace5dd40877392de4d77a233324e3993e1f8b568d112f364e474c4c578d464ac98ae84ef581143ad6c6a3fa6effa98751767ba8cb3c62333e2f8791b396b198d5ccbc8b58ca66b79e897f6a3e49bf336f28ddbc5197989dbc59131aed355b6189f3eda6262fc693c31a3da21c9bee4d34d26eb614c2618ae13faad06b76fe2b65135dcc44d5f6dabc1753cf2924f6ee4258e9f308fe91bd7f16fde1acfa8ae977cdb37e2473e399d57da6aa7facd27c74d346afa88eb543fe2d9ea8ff5a5d2468429cfdac8296b3cd36970b4c465be71cf35ae63331efa8803b2ff5ce3b4e71ce466a31e57998ed56e6ebfed4d77fa597b7362c52a6106446fd5eef41d5779c81fb985517e73a87a60016ce19a19d76d0f99d68e2965cab5cbbc81faa1cc6aa7fa8c42a7751ff7cb48b1e785794629a5d788d22cbb5cd332d779d99551ea3a3dca1cc34a23d7bcdb7c74350d7af9c8698c32bf4815fa8834ea12cd1cf36ea33ed2327a59de8e5dd3aaddcb216051b40b5f47b94ea5c4220b1653b080f202f8bd72c5185cb7bda675744dbad6aef3a4e6fb1d2d973fefb5a8fd50bde5943ed7b86e7b6d5feda4bfb7b5d3bc5de7691c500781cfae692ee593fe88b4faf39e3bcdd7578b9a767a91d60ea8b5cca3773d724dfac8da31ed4772e99b9c2e4715e872525681ded31a1dbb669da64c6b2b4a165a3c0fbf57b2c862e8d989df2b5878794a9a9dea9ed3b4ef5bbe4ea78fe0b31cd50e4a43f112cada911c5e4e22c19750e71135a9febcef9839ab834f637ac74d7c33132e5d7312d76dff3ac888d1a8935f1ad54ef52312d7c12749dfb6ba8d22b9ce23711d137d271da89fe4abf18ceacffb91eb7489eb84de87e49aaf3644f36e7e57f2cdbb1a5e027a560e4c1c492f394c89e49246ed76cb4f2fd128992a50ff88e49a77352a503fc9475e721adc36aa54bbad02f593461273e89acc38c80dc91eabdd35aba906792e9909e6616a14c72ac4aa525b2ab8228c2baa784a82ed40fdcc5c10aa3ceaf74a1088ae90e275fc5e1142192f84317e00bf578440e5e952f81dd70e2ed76daf0a12da76ab43c1b35bf5d775022b2222222222a25744a5a350a142850a959ed254ba4aaf62bc78f1e2c50bcc6ab55aad4c4444444444356850a142850a152adf5ee2a1002f587116d652c444abd56ab52222222222227a455e5e91193dd44f9aa8a194b6d56ab55a91888888888846afe815bd228d47ca054c34a1709429548aac56abd56a45b42222222222622c9c85b51475d1bcd46cb55aad56948888888888e8dbb101e4b4a0c876593378087af1b262a2d56ab562281c85a73015ae825dabd56ab55a7dfb4cf940d463fab0ad4e58a097222894fbe9b46db3cbe6e5b466f8103f99dbc927f462412f127a89d00b845e1ef4e243c66ad80cf0c4b7c728af4787f2cbbb8dfaf0edfb76d59ba57d63949713b3bc9bf6ac76b39b58edb659bb93ac9dc7da39ccd2a1be8b51bedd8a599c308013736edbe9e4bedd4e6c3e58f0ebf487acb3746a9d5ea3e80b9f1ca2ec00291e84102ee380eecbb142ba25350b3cb1e2c787f7017a1f1df5aa1dcb25b7d5e29c58ae84153f3e3cd0e33a5e0e40a77ad54bd7796f779a935c844e5f26390ac07882023c670ab07591c0e2786f9eb71684e32856f8de831fa487a003cd97fe8470a2154dfaa1cb08eb560853202da26fa7368d6a29df637e8ff9b94ea3fed56e6659c682ad3b7de7a0faa6bd9dbe1d9d9af55541bd7b543c2934ef1e1423ef5e13ff48de3d27ffbccfe89c57d466d40ec9a34227b703d5c436bdb3b16954bf22e9a4dacd51edb6ee94d5ce69ed50d2b1daf5f8ee157d9bf15d8f6f6fedc755df9415e8bc57852524fabe8c5256245013d240c0c205ff264d10e8cf617d35c97bed84ed5944bf3954239665f8b638eb9c8568598bf32cabc2f720bf0d42181f6429e37bef61ed48f0b12184d9c7ba62a0b0cab3cf2ecf6e3d28cf2e1bcbb34776c8539efdf576f7eeae536ef6e6ee750b08a7933b8ef8e07bdef04deb3df85e57f8de7bf0bdf7de7bad7a6c358162d7eeee5a32c2dddddddded67cef3eef96eb8bbbbbb17a3236e8b0b652cbcf7de7b4143f1de7b6f77bb394ebedddd8526530d1fb89f0fbffe5e8fe7d9a90784f6e4f71e36fae12f4f13047b0ef438cbe241f816ce4ed1d3e9bdf89e44dee80d217488c180f21520955f2ffa754bae7e3dc2f57705be42f790cae208a17befbdf7de7bfd64a08377681d6c608e582567f9c471e580dda035198d36f3ed749491b22d2b65af4666ca60b2984c263b6536b2919661d7b46484afe7d431276a147d53964f89fa58e7c5067a3ab9e388bdf57b1b094eeb3df8fa3d52bb4e338450e27477bfc70da13fa710c2f82a6c94966f4e05f9e2c1ae0f7e4f16a761b0b1ef73f91e8ce2a37c0d21e4d9a8187cac9dc5a61f156847b1dddddd597ebda3fcbae5e5d7e57a5c87febaa3e8eeeebd463441d2f09da551eb960fe8760bb6222db69d1eda994ed9aa4fe6cef49632bd5be86bb9110ff73d1fa07e589bbc975202cb6b7c0ac2d7efcb971f9e77bbbb4bf8f7cb971dcb75dac703ea9762f96a1650c08ef5d2002184924f2787f0d5ed21e97da03ff8660eefcdb45e8a17b51e21ec579b88e7f4e81472b351d6e84108897677d7fa57b761b0cd2050ca1bcf19c8a0412f5b8fd60445455dba7829a38c2e5dccd0a54b195eca20838c32ba98a18c2e4545455eba8c4146195ec6282ada3246511458acc4618ca78bb36d5a3a15b520941a102e5f74ea0b2d40b884617140b8687162b37caf70c9f2ab0101c2c5aa40b868e99c6d6868e8881de8338bdb5b40b8581a2cc3c6be5ade175cac0cf9c2c50a172b5cc2e0f205172c5cb270d1c2250c2e58b858e16285cbea71c1c2c58a12e8da74325efe4926c3065d3ae530fae6b1ea61cc24c75ab41fed356ac75fc3794bc78f445279e8720b6b2163832f8c2a9b04c2d3f06eb640fb51f33ffce58b16e739e586915ad9cc0c0dc755a43095774305cbbb799e69bc6ad4ea5f171b3c4593c251decd738a61dae99f5b913bbd75d11892140c054a06f3cf4d616cb19ab27cb131148d7abe694cf49c6a198f410ca48cc3b065dca594f156b2d2a8d2aa515de0b275a5d59afa8dc6f026a246d120fdf3d16ab492297a37cf498d22955632452fc794a56f5eac3245a62c44df99b290a0bc4c1430d0c8f80b5ed8b80b9b4cf6efe5090d6704115efeb94c14992cebc34447744447744447d444c4331c3f7937cf4b1acf3c693cc443313259e4e8abe069643e54226a141746abd3757100035a8628528464461341977f634c0ad06810786458569c07f0c10706e8ac8068d4f31aad01cfa98d8ccb307991ff9cb9ac8f79c6fa5819b7a2dbf0189f91a927afa105896ea36ea3624e5c89ca167ddfe4311a8fa9ee161d870684ca146f684162b5ea0dcd9d30c3f57837cf6f68a8463dbfa109793f4dd37443e3b1e84cc6636ca62c9426e3ede4341a8fc9a94c9e1844be55777162b4bab0596dc647d49f749a8bd607fce7313a65f2e7dc85c958412febc3863fea5b377ff3a5de6dbff952ef4ebff952effc37df4e51ef50bf75962ff9c2e0639589c2856d1b15e3711727c61486494ba39ec798aa298b29cb3f2e1be6351a8f8c73d1faa8f9e7f446c65eb888bbbc1c1a7fa62cdabe1c539677f35cf3196ebe9be7ab49d977f35ca79f9bb2bc1c2b6cf87393964ec5f873d3964e9dfcb9a9e8e5ccf8734a6338fe1ce209785196dbd082c49f369ebe2c863bbd4c4dcc62b8988721753f339cb53796e7a005996f726a65319ce9e9cc62b81a4faf2c86a3f114cb62b8d2539ac570dbd32c8be1484f47a3a7a32c86d39e92b2182e7bba65311c7d5aca6238ec698d6c86db9d18ee7a5a238be1a6f514268be1e4d3982c868b4f65b2180e3e3d6531dc7b6a238be1faa9006cd0cc8c62dc2a410c274d2e4db533810dae1765f98c16043e8c539a853d32b94e9fb8186ea68578712c9fd178609cc218aee667b89295be794e73aaa555a39e976a9a37c291c9697e616aa73271bb3856a5e14eefe6798cc633eb6a5cb4ed96038e2c728d833d8b5ccd536ed7eaac3765d99be7347c3767c62fdf4d452fad5ece4c1dadfae6f91badb6b0b1539b2a1303534d356a8d6e9aa6ba1a8f55e369704bf83b2eead8cb3fdfb80e5af9e7a4d1ea9f8f4aab6733fe79c675a62afc0be33b5396ceb4e59f77a62c3ced5013329dc3602dbc05766a56c8928a108e9265cac7f9abc54a132489a4d228192f329d638b945072bc28282384503e08a39411ca20306f3cb887c883bcb15033dba203bbb2e93a58d8dd6cfa09d563c351a241e38669b32c961b3a5b50dec387130d1c39941c07d402a972363b363fb116de7b39fcba5013956559966559267b504d592d4de0a1c626f6b0356adf7bef519a858dfd65d7fb89002fc22d3e1cc0871ea80da77934c0872d3e80c1340a14267a37fb787cf7de7b5a00d038a7d3b6ad73ed9e0bc1f13e1def705e9c1e220ff2c612830835c5d0815d1acffa6ac1c2dbe1bbf7dec332bec2c6ae03b5f96e7737db4e51a6e7d032cba7db4ceb64aa279fb2a13a087de0bb3852067dc3519a4f6854c9a1068d1ba61a35261a986c264626632dd104518c789ab1413343b3bb1996b8fabd9165b1cabb11a3c68d6ccaafd3c09143c97140d93c7bce8b630552e5e0bbbc7befbd0bcaa83e612b10bd9623b3ac6ed6cc26632d3aec705d3a50d77553936559966559267b286285ad98c083c6b35aae2bf690b19668822846847047c65a360a67590e30cb47210a55d8d8bb884544bde5d2c66bdef4eebafc72769f6bf2150b09ea45f8a8906510421e08ab16b1caaf675984724413445e2052f9f538e501008707007a98208a1179bcf77af00000ce8e1e78b841e9d841079b1c95731c39dce8818022d0a5f96e7797dfce7cb7bbbbd998f004b395f96e7757c6184bc258a6dd28f05bfd3abd3209ecceabf26ed675bac625250d8a95329acd2851362ddb48236dcbe49437e5341a65120a94df30340825db1efdeebdf74a19f6bb34ae1ad99b8f9ab207a3f53b3bd539f4f5e7ec3e300a5b672fe3c559972f53028945c69ce08bdebdf75e8ce25126e3296cec6fa177bbbb44bffe2084109ee89bb14173aa91b91193c37c3996370c0e93d7e068d4528ecd86a4c368074d4786a237180f570f73878523011079c01e2f002d8001cc8ca0efbb817fa20132d3dfbda3268bce52d8f8bbf9eb63bf9ff7bfdaf53caceb51d8d8e18b90ebe6cfd8689a195e5a93adb6b50bcaf24be59f73968dfd2179547e9d46e359e72b1bd7e6e7f03d7fb48666c6c6492606c654834669238db48c62d7b46484af796b46dbcd19e86e0a427fdeb56b8715366a5f0ac2d7efcb971ffa7d96f0ef972f4fdaf5b1deb5c31e36feae9c02beebe33e83be0d727cd9e3f6f4e3bd14797a39b2eed8f17c62286cdd8e7e3992ebf70486606cdd7ef14074aa5b2708a9e91bf6f8eae98b2d3bc074c2b6aae67671f6009d62d781dc0eae0701a86aca6a69c26af9e70bbb8815b66202b6fae7fc5e09b2482abfce58b66ec7b32f1249e51f5fd9ba1ddd3b3a159dbd0701625d121f3aac48de15308a1ea8378b4c026fcf66666e67d6fabd4a23e45f05e2ef15129b9a2a6718c306627c6db4b6b0f1db3cf44b5a81a655165cc8f76acda9a66f9ecfced99de7db15fefd735f1ffb36b05ad99509e34e33bf5c64918497bf2b270c7d67f2ab611537a8f064528128536d81062650a1085480318532ecc0245660b06208672883186188037679a10a23e80408b7cd24f3dbc5149ef81abf5d8851e5bb6daaa046082b800213be1872411a6ca07281136288610a2e5658d5c08a1224beb00216b2c00228e04003023514610b18511c71c508dd0c1966152cc67084143ef8c28a00a870c3aa094eb8400a54907ebba042141efe7641852e3cf068492c9c10b9b9cf061632d85658f0a01aa942851ab4c892250b260c40448597221da4210d5de4e90a34e8e882063bc811841b7c40842834e109465802055e72308537f4e00662642173c517322b63d8a2848d81cb12a0c0e00c2a6029c1942b7a80450d4bb0024584db668af95d5d91e5bb2d7a610952d8c268750517a402fcaeae68e273fc7641831da09e1dfefaefd278f6659fec275e6d0974049b694faa23d6f005289cb1031f4841c24e8c4a0b37f0000c25a461095a9cecac2f924dbe18fd14638cb1665d6c1d94dcbcf9ed028c2abe7fbb00a30bdfc16dca0fcfbafc218241806bc7bb380f7ac792dbe2675453fcdb2dfcabdd63a2fae7af36a051aa6740a3da49656ceddd5af9f61f58795ea7143e5f58bba0677f95e6c7faebf42e6a3d3a40f5bb3b62c713043bac3eebaffe04fd5bc2eabdf801160fe3c50fa8684ec1d6ce9eb90fcd804ef5af778ba54d2ffde428e93db030450ab69004129a10258b1de9f3e5ac169c68411bc0b80219bc10871d192bd7f8ce8732aad00533aa7cc10a2c78b1d36dffa27025084780810a3464b1dae9500f0413b080a10c48f480064bd8d92eff68fc730fc3d32c30f18625b4985206173bbbe22adbfcedd4fcdde6776abde042518f1bc857dab21242187288318527a88008608081053276e009b0d001d1123238e30d48d881d25f3549eeb449efb66d1f18a4e8b0511c5dcaf40dae1e6a0f2184109a22dcb6cda4fd5ad9e20ddf6dd00a743bb5bbd3edeae74eb7587e7df9072c895f87800f2f6757bb00243eccf7416850c1841720f1210c2fac28e3d78b2abc08e0d78b2a92f0fc849bf0a79db197b79c2f8e9dd62adb368a1fb7dff28a5c50a32c76d2295917d66e680d1b0d17d1f0187f4650a32c7ec24dc0465924356cd7c575f3bb3c3f79cb833a05df721e62279127d6dd9c23e2dfd6beb051f07140f09f5ba6465959a32c356cd3b74e45b7dc64f9c5ed73a053d02d2fc23ff05b2e02244434d9fad78b2ab478d89dde622f64a0ec598eb561fcfaf48101eb57a654f1a5df2b528af0ab015909610814baac19b7358a6735f9d6a9edbb10430d7f7d145c72decef31d9d03779eefcb4900166200052e9e700213aab0f37cbe9c1a5afca00bab2c4f9c74d979b543e2c33f3f358abbf98cc5b6df997278887d4da653dfb0f315dbfe007ead24a1cb977e5742a0e23b93cb7e5120fd7a810531164b8c524a19a325e59c96b4628c514a19db0021847008328f0161f3e48e31368c31b2c19a968561d6b42c5f9a302c6bce392deb9a13c3ae79599665cd39ad275c8b915bba3a6d1b9c1964025dee1e726b549cb3a65151d653a3e28eec8bffecf4b19bfd74ca36535c0184d0f2cec6041d4218638c114219a365c928218430c60877b03d5eeeee2b71a051d33b9b97979b4e359da21a8ff56c503b767772ebfb96c6635996b51f37d6bc9c96755dd39aa6973cb3ad531633f7906058d8164baf3e5c6982b415ddeab9356a3237e735274629766173ce795dd7ac3e2e95d0717bb7982dd4cbe6c91db96377dcfa265a735ad282dbc76e3833e9b4db3946338230e57938a30c2a645059bda5c1f7a6170e03e45dad83d0755ab54cc63333c3f7de839099773bc67ebdbcd567835178efa12c6bad406859504a191f7c29f8e229e47893afbb4b226814e61d84d9755d173fc67537f4e5eeeb8210be37bb279c4f729183710d978c464899352ac69a2dcbef437fddfc28e5c5735e979472fb685dd6b4648c3888da8fa2e77e4fca17633c423e292def4cb053d2db6ba494b223ecb8857cf2f96a5525b9850778efc9186394f2bdd70d3bf8af83968411f66ba8c5822c33e8abd50e764fae1d8ab7b8253cb98ef294b3276f39e4b7fcd278ac3a25907e105ab563292d0b42f85e9c33caf8e094e73c491d9cb553c552a3e1a8c4a917ca43490c82ce21433334a3494002a3154030381c140dc743822889b60314000f97ac504e1c0d63499005218aa29051061960080184901100a3da340168ec4a889ad9cc9a8d451a8501de3b508fbdc9eb69d2c8ebac3841d0394fe9fdde49f60ea3f47479c34ba15440f05e33f40ef432de55a3ea6a4202464a020111da83836fbb0c90712d433734ee0ec992c1f8cf235783416f96c896c8ffb59d64e45d3610e8c8b45b0d76778d828e78a6b62e8ca5bc9cb361e92c941b986a70f4b67b127d3e65acf8bfebb8aa15b32db77a8d956a5b068aea17269113e05363760b12a8d3ab0d96134f9337872e0f06d7016918c0c9115d80e6bd0cce70b6e3cb70825e86ba68585dd42cf5d492818428fd07f240888d2f00e33ae00f386e4a56949f697362ee65e370c69466d4b31da7393f29067d842d3699bd83edf7c61d452bf28a47584823de5ff2b657f2cc213c3d140b4d08c6635ec3a1fe9c521e2091fb69de78e9dd44f34478858ffa9e37063cbe3e7790a7cdbb1178660c453ac7023d40917bc659265d68bcbbd01014e48c7ea8db7d552c430ac12455fe23bf3db179129c56d283cfaf0422837877096e136057633f6ddfb2f646e76a46ece0c5ebbbd553216abb775f09f329515fdf05d5f26a305d5922947f814018a2a47a19aeeb6a37b3c99e667ca8e39079d71aec8e1a031a4df6efb12deb6fa1228da785b48ef675af016738ed13bca5dba884841f82c361489fd323feb57131c8dd2b37a3453d38f5a3a60919b904006d70eaaf79f3fa621077f4d54a463e498da4331ba02772a021075e45a7a4b2540a297fc87f6e5960577bccc247fa6aaacb7301e79c566f819edcc9a842f1bf6de4e8f2d80b31f4f34235468149d246d12d03b05711ec1c617a4274b4e13f371a3f190cd1aa84385dea414c6fe5b60e69a55ad3242adbabc2d2820360a9ac653fcc44c97e6bf97f77178eec9cc62f1c4be5e5684b64803ae4ab8650190fba05cef5dcf4a7bfe550d15fe8b2403921145cc3ee72ef02e46e8609edf522c32a25ca1d605d222ff9e90be14a551393accd34fd5afd1b0b1668207bc610d5e82291b3c9e2e0e3d3455ce3f1ffed18b957a48cecc2bd9e3830a16946f731766650e9cd7ad33772db2f9b3288fe10936f7497d1bdc6dc91a03fd31cd4f91f595935097953de7aa88200a0a227dd92c894b19bcdf0e19defb36188036686f31b67b32d0d6de21ab3d76402caf6b1e7bf5e49d7251bae8230cd55b496c183b8be174f331bffa0fd26d2dbea456a740679901e124b4004ce105c9efb0ba51de33952eb75924a603c31aad55237fbbb63fd0941361051fb7123f8e82d3d86509fb3ff7c74fdb71dd10bd3e3d0426b1a1808716fd8bcf8c1981676bf24d4350a124abdd7245c1ea61994c136d01248b69cb2de38aa31cad22adf0ec9e527ca16cac96ff7c80ab4c63575072b1458406a8d7e676127eea626505fa7ab6f93874ab3ee236464d9635bd2fd0ba2e033782e79e96b425dd920c165bbd9ab16149a6e46849a6a1ab3904e7238d143e8d41572379b53ee4faeaff522a34242f153d28e7225e43ce600f7cfa3037693f09397fc9846d2c6b09c8bac62b05dab439400a2c606409f26eb3bf18cf13e6065133a681942cf4802343290fcbd3b3d88f5ed06766678a41eeef32ccf8c04ce7357416f0785913d2b0c13eaef7e50fe199416c8b35abb78613b40efab806c05237446692c13e442abced68b7a568c33c50594177028cfab264b6bf64b7365055b857f58a8ec607d5e3bbb133a18c4f9e1668785743f86fcab61a3da96faa640e35ffda32d228f0b2f2b425115167cefcfefb8a374b38ca250754a081dde3b72cd8f6494dee119642189cada2b83ded507a511a75e0694b034a32f242cbdd0ddf74d0c38763fb36aff107abea540d777f34e71f9acacb0b82929d5633878227e0828c242b704f46de0aa4c64910b61724af0dd4c574bd7c0e4fc1c07af905fdd64060f8c8a9df2bbcd2c423765522f1531c889e637dfa099583ec619981e761eead7f038a83c883ef4b4be92b8aa2381154476e622e9eb4d7ba65fd1afae9508a6adb45d1a24cdc22204d8069a0ec353a4fba912f53acad6a15b520691b094b37ab8561ed3be0053a1692f2ae152778b4b290363ad39be2659bd9cce6e2ba6b639b272e1a52425dae6f960cc11383612f20bf7ddb95d4ba14b550d12b1a5ce24eae2973053497e5239349c3b87e40ba6833af860117f4e0fb110eaf4e54e13e7b9aad91a2e5e38c96bd5d65ccde4499a9fd47743d1f8f1e1402be2e14f4318163acd4e43f814d17bac916a72184ee1243e0577152d92f4b46cd880b385f36e4776f6eff13b3766a2210482f782839b016ca36a21470c3de539ea9e12c9c4f5521da65150a478c5e8b1db3d185bdec6fb2b1c5b7788504cff78f08283487a915241245fba8eb60f1d99df41ffc9845d7c1598a2a2b45be60cd1e5b1b95f8592a4b7403bb6c77ff4addf6227348d7a93301b4becf573eebc8f576dfe7311ab4e03257cdaac1978476dc1ffb2d1427ac028db742dc1b8e6c22ed595c5a5e5ea417fdefa4629b47fd331c7ab48eca9bfe3eb61399342a4fae99913cea6aacd87b61cd557b24c6a09a02a38833db4cd68f805e634c528b9eaa2f5020b2874b8c4885bd5347c08a20cd7cf428cd1c565862d21621c313defef8358bfd330b2b7d477206bede6a47df161166288bb277d527fcd80443d10119d998dc22cd3c355084a98e51eb0ae991210bc603fd0b1128d187e8620620545e02893370cea3fe33e2c210e9822716e9a242bc1dcf9b3c07f684762f6a340d3d7c7608a3460d9f3c51dbbc769f4b00fc46149c08204f35b927f2585de6108cd55eb0cac76e48c019ccc7555f5d8588c001e91a36d865b614036aed8dde3bf7d833bd00d232e7de0a43e2f5b99dbe834fcd1425f030663fc7e8efcff49c3d1bbf006a00c643986a63c6b78813216e6fca7983f5c648957e65f6b89bfa047fe3776f53f26a3d9cb41656f6a33156fbbf6314ed6571f4221d95100bca307abbb8b3e1e78c5ea62e2f238977264c1ffef5fb19d8aedcc033b9c860b6740a39c128c98a81ee713d8c0ce358e38770a96903e552df64e2a79565ff4f8c97e0b6d18f26e6122bfd6b6e4d94693eb4d5ce9efe4454e9859bbd1afa1263744f3e40187a15cd451ca69465179678695dbec5f797326f2fb76fffaddcb49fe56d4bd9cc7adf55a9ac045e75a705cc334b836ff0ececb51080f654bc2776b80c2b7f9af705e4e5e78a00dece5af2eaf8a3f8397422f70bc6c33a0b4561049d4748a5f499b0a0684d99f6779f357283f9fe36b1cd7bb3bd0a59e6190c47024dd24c4fdbc11043aef1acacdddd36ffe3887fa64352478b623c22fd54099d05d84df8d043040b3fa58c2240fc5a2684275b1c7b3df4147ab9c7ceb1464863354a36cd4cf00abeb3d74cf579202ce6aced00000091a57e6750e5bec9a3b73e1fddb128fa7bbb6949ec2328afd9ad6d417ca7127226a36c965e3c55f1b54f55658a034ee3d2b13612107bacbec1f8bba4b8d2de3aa49805d4a0a4e15922df500163af00d8ec1b5b17ce9a7d45a6ccd5a671ebd961fd4c40e41d41eb3f3ebc1df7455525877caf1cb12efb9d6aa0631af8e554a128e94c86749d3120285a537d6eb767c2c5f2daa04569faab88f8025566e512bdd9759aa0ceafd10ec83aa238e7a8eb85af578c4665cdc3e52594c547e90d01b25473005b88445ffec897fe5f43909192a5568d2be5e1642afbad0e861b782ee07da8abc2402818341b120c93e130783fc9811ba82f08fded539ed608cb7c11fa189fc7660f8896efaa308a792082a3e3c42dc9fc84a2b63cfa76117b4753b17db3461ee18c541069795d0a2401f1eaa2a174032bc7808218dbebbf93d88eed46babf95864c552061062be48f7ba3304b0a8b41254bddbf53131017628806abbbd9196b484b52d5344ea375a4d4abc6033bcf4966d205d2e0e37465531769c3a114578a9a088e30a852e82762bd3e26ce57c78be18db7948355d536a4838372f01a3be4249cee7ee3edd0dac4de45be724c6b0f8d59c9ad2d1f612ea3d5054d097c1e851d2df06bac5255c7ad3af937204a90d2e19c7c359fd92d366aa60018ec668e4ba1a21320f93bc6e4b6eff1a1c668493e09a0e084af9c0ad2c54b2e9677684c584b1da51846d066616c55b8e7fba5aa29591c73aadfd154ab643222a87adaaac50c0ebec6746c80d6ef93356e185e3130b21a62be3249b2de468443035c5f55962e3f31482768ea50cd0abeac4f21e817a33204064825ad7c041f9c8b7ff109d68a8fe008d0bf8255b6a2a3e69a8a9a8f9039027c55a0c8fcd8e1ba96d97fccee569d8865498b84e63e717bbd05691ca9f0aa7a27a82156d0ad86bbfd6fc53c92b0d2e7113048496b7dd3bc78e443974a370c3090ef8af35933903eac64858f1aa6ce91b6ab1f28a14f4d0197ca2525c8ce58a5f1a204bbc5426ebc8c0d1756c84d8d40fbb38b88ebd33a4317be8f599d3a9ba2cd90db7b9d5697b0eba95087dc3e3c9ad667c8f583dbf35dc389080c821e5d87d1dcd25089b81d6a2dc2821a86595edf438dabcdf4c43ad1ab329f35f8c11a73fadf5ac8d3240811a6941d0a0ac2911f70c5a4a15688788199d7d7cea26dac457bca3c71c8eece8ea6ab7d854af61fe29fcd36942e82403c305f93267e463dddda4876a6116cab405cf5d2ec4acd96ea4a0a64cf2e71714b19df70343177931e2015255bb18d1a12888380245934130218381484c30b7a572f4fa9593ca048f6bcd2d39422fd36497bc79433c26ccd73461a72533a1a23ef7f2c1795af31d882f244d17efd5a5e5340d6d1abc8b0f3a227d127d1c2cc0593b23d49df63cb0401af2067b5d796bcb6db5fbeb1348576031e5583fb777ebc25d3872cd71049d3d56d75cc3ffdf085e054fd66507e456587c9182f1e6ec09fdc4c26bf3f29213ae95f59057268d3a8b54d46edd36507b3fc57e7f4a9c8a97ab3c4290bb6118745f03782d0ea090dd303bdd8a6a9c89923f96fbafc19efa32f05f5d2670e134b2d78ab6bcb048666e598c6159517ff20f49ac121479513d24b07501c7680a193cbce26f45e342ed5c31a1b5c9087794e44f6bb666bf7d0896d88d3e7c5b2197228c250f6f00a2f03e5f9bba936a4524812c271e07f3f52064e55d5ff83cae5f9ff766a02745c728c5527349649c0029e185b1696d9fc3b47fc3a74ba4bc6206ccd503ffc8b6cef42ad187732387ff6226fe223c0be94584978ff03b7bdff853901f82358a3ee17837f789ead69063d02893c6e5683e12d4fa0b96cfec6ddf9223cdc184859be83efd8a1a81fe8bb4a38a8d43f09a86a3d2abff6f28f025b5c535ba36e29ae56f1a1d1c6148f09a88f7e5b476d8ee7305db34d23550f11ff9b97fb49ca69cd5c37781aa28c81bab192f300bd2e7a542760241596197d918b2dd345437487d45c38c748a57c11dc7a760bf5977172804a28d965e145c2b6613d1211aec947f8a05c908777aa38a3bcb95a83bfec6c91e275e98bd70ad4c99ecdd34f34caf2629fd5fc9f5ff8a915f87c8b3b8cf2371f75638144f7e495c27cf9617d54c5ea8b3adc0bf1ce43850b8bf1eea62e6bbfa461bd4e86c062e48043eb9f0d18a680e89caddba44a46d05fb628af669069db6ded934feae49cc426a6196e6d037795946911c75731d0b6d9725279cc61da09f37871ac21504035232767dcab4553db538f4148bb3b75c7efc01b0fd3d17db2a720600b6ab9d516c1b3dd3fa4c7ac9eeeb2d89a8ccbfec0fcf2f07e8c957c955ccf0e879f496ae74df73b2a698c2bb060db839adc44bba88975f214e5a4476474ae7468951f1eb6ed272e40454dcddad308752e05c531c906d4c1f2cad758ec02f31457ef07357f7d88f15727e003f8b8411b1291af8c986228b337862f2fb909680df2e7f839ffda770053095abef2b58da071959e92f13b0492940a827812d55b9af69afeb15dfdccd9c7c2f648e0b3303af6566d0fe1e261f94dc40e9540fdac8e7246d87082610539d764b47b0be824f0ee46b277f918c0e6c495d2015accffd1101f6edd22423c58b6e9f9e4ad6eb2ead3d88b2037f14c76d7c09adeb7bdfc403aa95d77edf2bae43efbaf1d5950e23fede90afe3fea18a44efb1a853487a595007891b3ce6757a7cdd0e2eaec00120544528fcba3b91ec36beee4716904e31f3ca2b4177187ad0f7513fbdb1711db0faf8b9bb09e7badea05e28bdd27e5f69dc126d7b6a3938bde8b485afb80c5f1255e1ad7a6f4ec9365d1771d262c3bbfd043d0890b2109c71fdee27b9bf1995393e921ef6f758a431c98efcb3471bdeb4d6e311b2e3255c666c7dfcadee5eb6b54c2853c7d43d06bfea1e315644e089cf8bc2f8119fd8e6f311defa38647d5a2d76addeca293dfe5ebb57dccaadb3953e2e4c9c997cb67975acccb4bafd6171cec007ee4df5677b050ef666d55d7c24ac6e7fd23f8b8122aedee9ebd712467aedc4bad979f511651d8569d63796d6815324a8f5f95c971f96d211f44eed3a496c3aab3662ab45908daf87ea7e589b8d9b30ea0083ecf34a080659d83e32123ef96ebaf4b7e1e3edac62e612fa4ffb628804757451962db9f6cd8ab2530a28303781ae8a49f4656e3849b13bd76580f49896aece13a80c57c393780af5289c938e3b4a3aa1351aa09df5b1d1f18e57ca1aa31db5114e3c3f1bdf0ee8062f5ae3ae22fcb1a33085a7072c65dc18c1c8cf97d18023a5a85fa629fcd8fe255c552c078f4416aad6308361435de489efdd7289dffcf0223ce20afa2c8542b48b8e9b9f3ce8060ba3dbe9a0197c4de463c786fd6f505c07dc03a9b85e92abcbf8bccdcc6b5bcf98b4818090827bd1011ad73e3e209d4f30cbf33ad4f72367b932ab6b7c113e7e03022373ac5a347f022d0df665091f51c1288c87070ef3eb9830851071972d43c25d890dc6869b324f128cb4e1638310d0b4bb788a0538b1df4385a59eb1bd467441f40c4a26c47e20fd1dc02cd9f580f806fbac87de09295e04fa37f21b1412835652a009fbfaf93b037ef0f7297539b801b844b1f14d21aced03626eadc019fc87137f218dc39bcd596e03486270cd3cf867425b9306a048339d518c1875b47a3b2d3f371922a6006de116973788fa9599d4daa95a24c8f078957527c1d1eb98ea8de20d10d8fe015ffdb8ce3225ed1731c2192e698f512396035c86557636e8de57995b30b54d799431d93b2c0ddaba6115fc1c82682e39219ae484d589f8075bb7573f5ab360214da4956d72591ad5ca4def783f00dcad90c441c79fc6f7710a5c1271e549d337eff8b360ccf38264c5eeb06e95d613b461f177827e84ece650b256b5a913b172a888937d8fa3faf82c0134e90a04f0156846c005bdd8d0460ab4bba3832abe246da6405b1371af364b1d940138114c9d4c57a1067baa39198e76d8f9ab16be1b7b81b42386343ec974e32b8aeb8d52fbb850aed06f0dfe4cbbcfb9e813a821ccabfda921507bdfdc952026001dc7f414d9f6e42d3c02ed87701e680a3ee02ec86b4990a9e85ba39925a5d5427763f359ae014dbcf32c5a0e30d97f08513ac01ca400a6642019b0626dfc0ae7a85a016dfb979e1c94f39b2f7277683f4bef32bfd62be4c52ecadb256956498da11d894509342af96d5522c9ffd38ea13a6c3266ccb027798d7a57671fd4adf371d197411fb87c6008ce58d4f4907e7e56612395a209cdf43653c36a735c575aeef870068a56052afc01f5daef1d48fc998a15ea61c95726fbceb31b1fd7c1fbeafa8fa5e549b302665c3b307d34d9fee7a468e7e3a43e29507b2bb76551ce0e8600d39847a555c9cbfdd153cd8c0677e082572da9d1d2479a291e56dad7d8311a6f2eb92838bc6cbc281f458c4a559f1364b058af993de2250cf6e5eee3902d1cf1f7ab315b1ec41f4713582a56d8f0b047668269d999911c03e0a231696dbf83a921c153224b9e17e0c493b31980a3d16d0054716a68691cf50eca21a56e3d5c6cc52428325ea86fbb65ff9b919ef20b080313a032e17b6495d09f70c645433d0eb9944b6f08c003880b5dc7eb1ca3c066d5adca65073ecda7c88ae3bfd4f37f9fbae44700ec7b1c2a342507f6122df7eba962a5c364480d0f021a757e37b88730b2411772a5401bc37746970c6e19dc32ba677065e8ced89db12b235746970c2e195c32ba667465e4cad09539e08c4615d8f390b32160f5a9c7e36a0f7871f9aa5161a2a59f2f33f382f67f4a73be1997c81b98917543ddbdea09eaf3f44a068a5f0bf71423309a4de2ef7b791af2c1337ae66516b3677eaaa6f826d0120d66ad9c8adbcf927a60dfb8ef9e45e4212472b11ed846952b351299db98bdebe2e88fb21c148a62f84a4e47ac53dbeb788a43aca9de27b58d27250914cc7697054c0c484d88018ef0d77748fab125f61f8c337c6c09b419afcc675ec5b108c18e00115c5ba813c50a617808dabad92493f4fc432bdb94322a9619d61e7a7e5fa944f386e74677e29bb7e274be0dbbf184c6594da53fff2423f766591c8086ae9de84cd58a60f2bd0862caff35f8bcdda09a665ec3e28d90ce12a60586d696a4f11deff232f7b2b1f5b0f018947dfa7d0869f3539333972b49f1c5e84ef0dfa21b876ec861032de4babebaab338b0b8e48d84b13cffe832cfe7e42893190595f77ccbc1c31e88f48c3eb32b8b12f65c7f454207ad5474db5ba31da9e6726e57873e1e0d55000eed439f2acb2eab18c342fd203e474c38272c9088b51c23b5ca9e5bdb9dd2975caaa2a1c7399a5a5be7f68502483e5153bea22687f2f1ec7889d59f51773a713aa64f1671a0fa26842ba866e181c5a532a673fd89e48fa809fe7bb296ae80a9605bb017920abb45ebd4f36065a22f78a33937ec4064be4de7d81442a7a030295b6d2574655e71c7f84421df78756f6619108fc1464e990c20f695e47d823a64fa2259128887a1048296f0ac51bb999a286bd63f463eb2a8006d013a9c8db5650029b2406789087b5f337b4c64d79e33ed736a9c4923631917fa4a1c9f4d2b1d43a0e8b021f51cffea20890ae2b684449311ab98f30f3cf5754178bfa180f49a66726d70a43e4b703f99a35e1435f41438835f8f02f3dd5ca647f3dc2379686d969d4c49a57658b20125299f1fa683f6407f28618a7ff55cc06068db6cc1e30f46fad76333b1c36a583d8b8deadcc92cbc9e40c14c14bcb83bcc126a9458caaa713d2c9630c892a51ddacd588fca51f310cb396f53572961dbaf464ad50af679411c610e26fb19db9e47005e4ade83444b0cc6b151c35680039037c859cdcccacee3ebfd624884fc8946f7ffaab646f977681c35e269616109b732f88f1054164254a5b95749989b77cb941f89210bc12aa71224e9649adfd26024748c2828a4063ef7e4d91be5a8409384e157e6b7c12bf647d5698b8e5eb59b77e206fdc309ba44378f21fae8c895e270b84e9f9d63bd19b836c5daa8a7e40b9271e2755f2498447db8f42c484e07f336078ba6441b139f46811b6aae5880ef6dcf390824353a35b13c87594add8566365b639243a7724cb59113f4f0e56666d52dc799b3033ec4b8a6655d04bc911c6288292156b869700279b41ff4c68d60590243d044c3a1cfc81b00a68a62ff10ff9cdf4c3d176e5e312b1c48b60195693242ccd8328f296d1b05ba63d8144926818ecde0cc966712c9c2f6c340f89e10666f688cc39180681cc987a9109c9fbfbe712c55752df5167ce808d8a0c71c03c7cfc037e624b0297f7cfefa58416c78080dcda7886ded911e3916e76c166cc6706f55bc049bb41dc9342ebc88509473d8b200c864e4b0f239481802db1cd2bd6dbed1acdd009c15f2e339432f289582da7b4544dcc1b79d9742f24dd521dcd9fe12f81061c04978dec56c894d8991414db31d5b896c3e97ef82ef8fca99914b0c526a55048a806ee453b9ddc8171d7a1d64e36fd0f4866c32911e6e809d085aa16f5e14e3d9f01c17facaff039e377accc657e174bc139639e53fc2e21e15fca2aadcfdc0d866da4bbd12686064e10b012d94d3c3b13ae921284001349991087710dfd38b97106a85065782dc963586ab6cc65bda4f8b92463d00a2e75e03e2a036fd943188b05e903cedb8d6dbe8d2abd88233bb115ed0f6bd5611b19e7640e41242167894e61fcbc744fe8680b18e531f8ac0b0ddc42b5cd755ab792d84664aa8a6b744d79637ca9df22c3292c22197044c516efffa110715b1b9f7661fa825152e1750c4a742a1d6a218b0280ce4f3b93c033a5861c9ec8f4cfcf356d3a2003811caf39d22985ff4e3960057322d68055f14ebf6cc5d77866ad7f5f4d8cc68901d7403a4aee3c068e3f31192286825ea855676c715541f04f72832a4d4164af732c2533d38b5a9b36e69298222b7a08a6a67fcf26852ba4c84065e7dbc9c5aec8e7d07914efaeebba5bedaf45ac917766b23180ca479480cac828a52a10604e1a1690382d2966643ab9ca983622c3047cba378874838b953b060122b195876bd11b5a449f59d4e116d3c2b5f44a2d7349af1d4f10b8232a9e24f411a98415b62afc301d131b185ba32c6349e0e011a05bf219025963aaefbf955b5ff7e36edd20d546ca787deef19cad088f009f15ce78e4c4359db3d83b9834bc35439306e67d98a557dcc194fbff695399b34894ec0616017f37f3d761e5772a62cd21702472db697f62a5556a9d4bfeda8811253b5ce794841fa08b68c1b248fcb6534cee438602b3af8513a2584db0fac082c2251e35135c4312c16097d74e5ab94a7d5bda62ac4aaf6826cab2b158d2fc7d189e9f886366bd8c3d7e91cc9978dbc45c9e25f4dc2bff8f23a01c9db31d60d08e9651e6dcd2f8b15c940eea6f954f2bd6a5632b3c907679ce94d990da8eca5e4af594044dc4515f7978591ba2895b4c4f9e975355b704a4a8acbab465016a56ab2f8e873717ee4aabd23a93f45aad04193aa6e096801f28db70c5caa6d6ebffb1353e69cedb8e1f3068df2147db8f2fd4dcd3a7c52ab7e3c9898900a2344743b7db6ec24658362702615b14e5d385590705717878c1a84ddd4fbb65208c96189d3d003937637c8dc1391e36f92a777e0efb10035548ab58bced9b3ea9f63f012decd70641c44a3cb4cbb9bd85e91807b360c0162ab29f9acc42b2b7403da42b6b9f86642c74088073eb7ad59383fabdf41e0fc978e399e9441f3843c40c18a4eb13012b0b2942469a4e1c9d3a5003b78f833e8ca9474f609a3a1b74b09b214653328ba592ae98e3d6fb66e40d93b6382567c8b344d5a60cbd115adc339304259ae80153b10c5fa9c68c0e29ddcecf10b8919482089b6ac092578b12b840e108267ba92361df61b380adf77ea3f6b9fe0b81f8a4074c35ef8117ca9cd79900ccdf19f48116a4473aaa0b6772a8c9eac01dabeef58ce9f6855fe07cae71b303f4842768bb2ae64f70b204001a43db9c44f42cd98b252fac1ef5b5efbe31d79df4cfc35eae4ea6c61d24927f994a68162bbd792885b3a421032218d93a84e10e13ba0b04aa1fd03138d492b26156824066cc976552ad6e71c16ddbeba71b5bb02acd21240dc9cecbd0d32207d9391771b587450bcc8bd938cf9f61f91def803688be93ace800776add900cad66745b9a25dd7b2cb5d0c04cb87d793159a546bb5033492c117af9216eb86d446aac475673f1868b8868c28f2fd921a8c1c0efae9b780e10ada7270b449790cd02e40d1656accacd72322247a984046b40e7e3a33d51cf83b4cb2a2ce89bffc610671f7c02625ac63d9206de29214b02c933b82914572b72cc5f048df6db204f3adb0b5915b80d86f3ee09d9cabbbb7ce90291fe473abb3b6330465e75719abb0c968e792a9f8f26c001cced1c1b37a617200c1825d74c75c6aa229fe62e7a7754c0587fc63e349e4789f4ea95b70e224f01200f246192756a44b91b82f138b066f563610f5c41084455f3f84f62249b807e8f8e506eb7ab04ff961b91eda8fa870e0bb6fe2b3483cfce84134398afb137772ce34029885fb5160dda41781485219655f365eca199821fa85451e2fbe8f1acef77ed229541cc1a779851f1a8b33251a15f40970d880494aaf99e4c1a914dc80524e80c45bfb1416d2f2ebdb5d6f680fe3dca0f7be210cd53f11396508f23d0c4e64ef49560da32f0bb5bc2870055c3e66b77e3e4d37080f5c485bf2e9281ec2f94e0ab4500c9f61736b8ed91dfa4e8a29d40d2f0ba7fa5f410b4eb4ce7f5662764883659dd2f5fbe30eff909d290f2f6576625256f109d1e28950c610f0fbda0b2c144263565001f62331b46f9bd4a4401c2aef6cb0a349d08b432666c34afd982a4c956b92aaec53e9f59e2527852be6d9db231bc1a578bd9ad0314902279fcc028a0a357e29f6c1355a7f5d12cf43af7417cf5aa14ad9133df82de72cbcaeeb30ad8d3a71fbe914c9459f991879650dbb0c6c2fb569c1c5406719345f7281e9ef6a2d8475210320f568710c57b8b1b1422005ecd676eb138ccb03a50dcdf5044e74fc3adea891be11eff93fc8ab44dc2a03c8112239350af6a551cd6cb9fbaf55faeb28eb498fb7d7bac5e4c2dfabfd5687b3973c51bd73fe690bc40909e7658ef0fd68f2f8d1f6c4b15e03bf0a28349814f910e3f65f8a3d9e359fb2b5b033387f58220fc779523e98b58b7f267a6e003f681a7dfbb20f04507df1b606548bb67319fff0da8d751af0294ff929cf6482d5d72d1b75ca163e52ec979b1b61b52ffb4539b2451c55344bdc50ad48e6e77151ca0b26583108754c252d4e79f961d53672d952edcfc6aa9c24e3ce9de81aa2da9c5549b63c6f55f38870663783429a9f8b2268f15c4c3089755b31e84fd1fd8b241b1c0166b35b9d7f896630414a1cb2f777b0b986dba2f1a8343c98d05940072bf790871ca55baf6ada8b52079efd815a9f3e2eb03070a62d7ec489dd1bf25ff9f0d8b7f68821a4a339da61b827ebe34f4dcb2acc27056f408d87ae0672c094519c005f3527da736659321c21427670fd0afaca1b441de18382f1a85e620bf275592757cf79ad088ea94340137f7c48341506608ea4379397598e102da2b583cbae30165eabe3777787597a4795c8346d33f50c6c5632acbd48b037f39014a0bc196c5add522eb3bb593548734958810d500623e2f5ca21700e44d5a150cc77e5d28f581d7a03ffa0e128d33b2609ae29a223249d0b6e1eda2dad021682aab9318d174bfe278e1eaeba51c10d4048cf19d3305fb2c29f16afeb7e062ce154c848001cd37864d850669df9592c0f6a194126997d53734584ae4ad1ed89cdaf6395cb868187c4dd011fc055c0d35b83afb8b7d56387e4c42c04d4408b86eb45ba1af3292430d4f0e784e01d4a900b399109bf74bfade9cc293ea79cc0e97bb70fc8155cc3e054f2b0ed0c42e0e84580fbbb8f35300b18ad445db3a5decd1df9b8b1308a24ed1d05e4a185677d4e2c9e3c8b77d6df689ceeeb363d24a40f81627c230c2f998f79b5f097d1f175f0740f7b9ba068c0fa9513de6def80785190cfcc9f7c2a3e1773cd85ecee57eca61a47a0b449651154674026e8cd1fac170ff7103061211e566ce6bcd4e9f82627d9538b955f3470fc62bf7e523453b919737b59856a8e1b78800aacd13dabc3c09ffad2e89c9fc0e9be3a9599ddc7ff41000bd44926b90ae9f3d6e8372d2373a5e3eebc323d7f87b9f19f36866259435f24a38adeabd9174cd747cc28dbd426a43ed6dee3177e04f0f3ee65ce35829b60b742c9d370cfec6ebfc6b3a86353b9b9e578d7b232be6b66a03845144bcf9e4406f0b3f89b7fe1402068770af9e7870a3cd63334b10aa108f3d2f05b8484cb986973d440225b96072336f63e5de39b9e65bdbdad02f0a7404f3d7023b806e605368b72aef6899c2c9e093425a9fc3f5d40bbfa6cf258344dff7fd755931b4e04e79a5fe3fcfd0fd39c98b202238764de15587062bf4f62c7f07d2c0c6ade623bc5581cd4098146f4a960da906f7657635f12b6178f12d030439edfb038736493008aa0d18707ada1e963d5ca34290a848157152df19ac66c03248af0a113f444a7d79ed324430b28a1586fa344e78c30d39779ebdccbc95d93db48d5176ab811e726db68b0425dcf293cea92cc8825663a530b00e5c509c5b6465322758e57a920ed0e1d07bdd179e21584b29c1164de236d32e761a977f60ec6fb017f5db33a56040b2b203a9974536dc1a60444cf700be96a47b401405c0c144091bf474acc93881f8277de8472279dab316906151d2009f3696cd4bab2e40c03e32132f7923ab28f3329ee769364fdab942547fa3d7461f2a80d294d4180e4a8c589bd4e72f59a5bdf00a3c8cb740c699bfd8c1690acfa997bcccb2f9c397e84c1d6b98642c903357c4221e16b5c9dc01b46cbb73770dd58d928b3ac9f81d4cc2cbc5f1d24f90b7e18aca737d590e42396c593b3129ac0b444db19effd5d887d490b59766a65d8557b352bb627af69fb0395e3582813f690037d74ead0c88f25ef94f0b528235adc273bb2f066ad0fb2f3cfe1243318457f83e3816862bddb5e3bb85c09e9b5a5305be109adb393617b594d9142aef9ea4ae6a620195223726cd67521a22975ae3899eb0b7106c712dc25de92740e55c8375798773fc9e953b2f7d446483c0ff40205530d8b1877526c0b0cb00f36d14cceba659c409833c3b6f21cd8b280a835fe59f95395cef52781a5f768290e0afaf7d1ba43fcdb6398709481ecef815c182ef7e819440704f2911eae3440f0c0c6090f9dd063b5234630642c5bf53f3d6ee79a53f194773b8583a013704c2ca04d4f6c449c8f7239592c542a312c34fc3d0ca976880904ac20afa36b12127242503acbdda1108ad312ecc566cc1b48ae84203c47c7e882f6dd309ed3cdb00e149ea9ca42c3234498eaea00ca0269803079061a63217570e73549e6637bce87bb30ab60f652645039e78d06235c5e746422c8cf7baf675816a5721534d5d687e4fd7aa19c117b79912bcb3bb4a094c333d33ead14f9dfd5e93ce38a83273ae2bf3441e5daf5e8a8a9c98f97b44b9ffb8fffa7c012cd09acca041d30b79286f5fd93385533cf1f1911d2309a3549cd88051653c2ff79f45b1e8c256264c9c664a02618292698aaae07d7828b9014e00b619873e469da0b3dd41302a75a7a6e20eb634e209be514b084dacd0a99830114341a8ef7ad5e19277d7ab5990a42dbcd2f47b74d46adcb6eb8f4bb08a51ed665d60cdf29426f366b395e0caaac580badef0102acc145c75478e8c2cba0d93a44172b7c5ae8ef71082af884148f633cd5259c2e0b1d3d71169e30bd0ebb72d24c7a33e7fd81556f48942f60be6975acee4e9a1fdfc68013f412c054a83e94197d166dbfa34bf56722d13152a8f4ad778ae58257128b8b7c5e8c2c10c176315635103f30de11ea979d7b2fa4b6bbd19cfaa2adf62f96fd91f4437473001c2e2257177a5688304234ab2590e2e89dffb0ff21af7cc65044c3b860dff043a969b45d8cafcc938713d8c5eae10d42bdb6f142e70ad03f646dc02579a7a9122cbde678bc9aba69ad86591049fa2c0f9aba4ad0ed4b20e871f632aa3e7f62e07e0c84a269198ec4daf132207d862447076b6b422455cd76b8b9d5a73c68f90bcab40b47401a08cc3800e83476106e91a326eb98b17f7934255fe072f282f630325fcf20a103106fd6376143b1e34c90806386f0da26a44559c4a6f3df3d95ddc56d00f193a94909f2de8b4542b5bee7bff0a317e52c8ed3345d2cb4ce516b155f6b4f513f3dc279fce0d8f5c98a1a89949a2e3dacd7b08d4f5ee60e30314d7b1728c1ba9f40285bc05718adb75c4670263e288537739cf3a59461060221978389adad76507c1b29e1860a0dec891a73e52a6ccc3cd98a57472ff320f6015d84c9a5ec00c702f0ac9f1f880e4a21d99a4908b6b9ef1b2c0335868cde3d0a21345dee76ac48e1e9bc646184251bb4be179a9803b3de06262ef522d98322931e7095ddb755c3ee581d80d660dc4b4a5443ec0c088ca3e5c46ef3b8231f4161028ec0e9e03ba8a833e6614b4189396c55b122dbf730ff6e79c6e9230808234a278f3a75225a099b0a14ad10a123b47da677fb6a08cce06e71efdaf92314e4e31c180cde1668bfd6bea1e93e312672b4c22bf80a5dc19e70ecbf40602c82a9c1c904a6708ffc661f652501a2d9dab15de0e214cbe593d55a8d008ba7910140bdb4e2907ada27a335ad2b2b8271dffa632abba853d5a84ae9f30221cde7b16f3a9e1211856b31206d5c4c0d054cbf9905430feb3b7341ef402ea1829c52f9c1cd0c03df0fd67f60b5919804152c87edc8e4f9290e43483fddc3c8846d98e4238e191be692b3f753ec721a8ce672a72eb75d6be1e091d848f2d241e1125d184cfa89e8d4823ee64b89930e73d023dbd7724bd9bd0a3470a02cb14e551fe736ed58668186ce0e68e70b49f738d118ab8f91a714f41d0fb2c90192fc40c3f0db2f3c25b948db1fa780dcbe10b977560a5a9017d876f4ee65ade4e191e5ea37412080a1d985b6f65f61c64af437921c40b42c13ba4c4707e83680765fa12112d2d2b31aff238548499b69873e6653e893658d7de0159cb82ccf81e2aed6f1ff24b0987f5feef50a8847bb18143aad87acc0a877a8f9e0ed56e1402ddb162c1c248a61e9c42aac4ecb8321a22ed1ef455145cc15799a38d852f357ba5273529a770266d554280d32afa6ec72a29da3e9d33c8dfe887f778d3bc86e48e710a0a9fc9f8d7e746a9666c2ae83e37114c79e406c3788c5fa52f748b20ede33922f83a2016db15a795d314821d5bb6780d931eee854aa4a5e8f1c251cbdf46d4e1de12a4446a4561cb68c8563a03f9ad9cd0348989a439aa27e4e0352d5523524208e53cc8ae94e29a8b5e17d5528ca9e23d120efd394840f93c6a133debd9120ba08970f2cba221a6c16ef7c693b207da1712085cde46b5d039197dc8a42822648b233b0aab34337e1605f1aa24cc156afc402bcf97a3ffbf41d6e70b0d4f39b15eba5ab031e6107c325f7257c76aae148ce9e87fca2ffb96f8362222368e145e86740588894b01916155081dc4458e5dc4f5766448354ef222a4d431a47a5a60469e11d38c6d02eeed0f2d4ded83cdf1d7f36d3a541d2f752281641f4662a4cc132ec3cab1616d8ac903a776611c0317d0b0f4d6cc6889d3f7958724e4cc168988dac5f52c25f5594e9a5e0bbcab0524a0a3c8cc6dbf75f2457653d5e8a2ed471f1f41a8e60f0363dc51af7433b8e76c848074269af094343d760b5112d8851da25324358536417959244a608ffd650bf87442ad1b10524c4772ee4e00710831082184b202d92eb24c87b8040a9b87a49721508a60b2ada1e9144b843af0b37ee8a19daedbb9f0899b55c92fe06886152050c00d3537527d5736fd891c67225bc8921d965d21405391518418449149c4d24e8db27d7bd826bade0492cd4ab35b32811ff88f8923dabf2a52df3d287a05eaa10535383177848f7a47bedc9787a60834b749cbdd0a2217c1c4dee659d957582f1062cf181d8763e15aaaa3f8c778f72d90ad29f0f3578e7e6e31858bedfc4957406bd83323bfbc5567164143e38f35f080591c468670912a0626ea14086118f564ea15ebe3ea9be8d03c5ae1ffcc5867aa8c1cc3623144f13261d7329ca7ebc25c2117e47d75bb9e8292ee740260c22cd17c489b9e5100da281d07e082c4bfcd7584b02556d21cc3a03046e14e609561727108a031cc095f78cf6abe00cfd326b86964133a722978ea998ad259061348da01a40c98e038782b2d470c1c0e39c9559e0c11c5dba8382df3331e7270c53073d65dc2144a019cc53be5be7898dd35f837b1204e01c589eaa72059cc5169169b7e23b2810032f671575b4ade86a951995f5ec5ee93d6650d4030ec53d0ef27b11036fa25b09a8f283beac692880123b981b1838113915c78f414f64593ca3a1200d2639c03b4058a0678195a7834c0614d4803796d899f9c60041d26b65c410597b53552d7f1edc4593042e9922039c5e528dcfe091a2d48e60370ac460f593cb868a01717a516536ef7ec2f29dc317c3e7a5ca504e596ed2644102e28cb45465de62c0e74dd29159463a190133ca35847c0470488f87d156ac3405d9b3c90000c1786b911dfc819fc581d4a149cc45bc500990e2eee9d21f6ec1beab369d748cbe7c2962eabd43953a485fc264324a9b2be6815e8d65077508b77a2f0188c93735d3a6b8f517841e7a6b2306be992a9998de32e41c054580162f5c8ce5570704e3507eb6e90626ffe84daaac6e641d1f4548658aab106f4b96e8ab7605155a7c9d027dc1729a84e1c5d95727df9816e558427f39333fe0bc0eab5839290ca0a5dbcd645b5d47d70436a14d7eae56d31af23a18ffe2428ac66528e3422d1020ae17ff4fdbb7074eb4da736b1314d538125bc1e0d4767c45c61289aece721b449425fe9f462b82f94a6720e706adcbb9210e71552191dd57779a137798ba8bf66bcbab38f55814a65f8be0b3c29f6b139367d202148b08d878157686897ab9004b730f2578074b95061a2d78f8fb4261ebd21a7cafbfff3800d0e87c2390448a6ec05f90c56322474e52c95bf8552a023acf373f155c11b2451c48015c1c642114a82955009d78a7f4a7ce6c8e34870cc70d42db1b73e6db41edf456cef63a00bc6b19d9cc0c588041f7a1b76d067b6e42cbe081addb0d71fdc922a30db58788c8f43b3c451a3fbb32d26a152c1099ec7666096fdd54ae3cc80e3b60e24d1f3f40acf9706cb648b268a6862c2c3809eb8b19d7706b8247c7e363c6c6d170ab71320a210e15b4d2b8b7c05761b017ba1ec186f38a191b184825274b39c0c0a2b1fb95dcd67770816e78e5aaa96b42670f256da577f91fc5d07d77368ec645472e12458678e8d7f8566fb0cd5c030be1e2571bf1eed2e680db3be4408ab5ab8d3fba12dc60b7df6ccb5ba0451f0557e98fb56740366abface141580f2619d16e944170143ee610c20d2526dc01bd94c802470f7be63446be175275c9eed67ca3b79fefa5e676b15af15976efa09ea573fe8df0489fa1d569f96a4696b5d865429b60486c1669fa9e3364cbf9380df73d6713802f388cc46b23cf8005a1c7548fdc97f5bae91fa2185c489aad87dc2194611b01545f03de60ba02e69382b8c09c39f06e0bb9a63bd9ac81bc5de820b3625c850460331cbf979eb32df86226cd21c0eb40403e9c49660a780a8b175901615850bc1f746c7b5c4fe5e75c7bae96427f882f1287f9bf9cc01f804ff5a1f5046453026edcafe595aa97a8111996074cf237ae940b26ce997195a2dbf0bc6663d2ecb84008fbb82b01f158f2c731bb0a452307b610da86c971727f3786e5bded7b6a44b42a6a7736fbc5afc47bc428f306512ee328224628586025e6b05760c350f745b4a724f50fc36056524c56bdc9e2fb957aa4a54a803ae439def6bfead16814c0b6f3ed2b87cf05749b41b39267f944a7e15dd1bc82b9b89edb92b8ad275c5ce8a46f684b632b3239403c9f3b323aaa447d3284d0150f87b3f25e6bd90485031a4cec62377f3661433306e3075959aa8cdf3e6d20ddfda83a04a32068d01252005324831597f839e85cf34ae7678f6fa76138d2b3664414585dda61af22edf62b075872334d1770f398848188c196532ec7193ec17a7e8c8cf2578e15cf4ee8ec998d8da4534274d17f7bc2b7cb0eeb291ec0bd5b805c9ac115ef623a8b8825ad30d9ddb0685322830f1123fe0532690efc0dbd4c5f459774a5245d5504169f96ba4401de551019f6824aa4a3922eac79f6f3d6f06322995794e77231d1d15f87cc38dff262830248c014c989c1ebed3ec6f0b486021a4304f6711328f8ad87f7d2c6f73ec36380429ebc04b8b3f64c6996c8e7ee3cc89bff8dafb09724c85c1dff6f8f03020cfb15bc874171668b4eb78d46939326cba69c581ad5c4cbeb37543ead59e98608cce5a2e3bddbe2bcb137f2591865ccab9d9ad0d1beee222904c35ca38315a27725edeb0f5fc3887b0c99daa075c1e38016010e99b7ececcdb7b386f2554863a6d40ed372b073213a06b607995f11458f514823997e3c0c522ce1d049c6e273ff4a5d5443942c51ff9316ccb6e73ed05c7cf61be14cceb554935c47a5189dc0956410d1850a04320d2840b773e8247d9af2b4b75a287d05314aa51cd00a898810322a21c50442a6489960dc749c8903a01fff2d718e5371ce64d4ef5fb425daba158fa1479d3cfc094a3ee2facdb0240094c4b771a26fb52ab8714d0f7d61d578fedcc6eb45995c768c9ee32212903cb959eda555e475631e80ed694b933547f3faf2d9c903001f28724dde2c2dae20a880e63c264e09913dd5e0098488967bf16a04569d4b9760bd19f28cac923bf385e01e361c2b81c28b1a55975a5e9aac6e0dfd6b80e025d3ec0d40d78d75d26ff27fbb5985deebcb89984c2c7d413611bdd78a2d88f0ac4e5baacb0134517431b50cd186c1c8f6d662a37ab70c83c9c5c7547affd8cece421f14f5e4a90a222cd37a393948235ab1e4f813ba18dde72c20620d9c3260a33e3cfe3c158bd53cc58d0393da375688666346d8e02031abec1798108869914edb4dc6f70c24e4e6c8a7d3d9d419e49f106392923e1f21e6021b4091fc02183b76fbaf4b3d93e31d015f6b4fd4bd662ee0297f53808b370e72b314bf6ca21e818cbafd721be42d3e6a69ff1a6e2ad221183b5688067d5690576b7c2cc4806d16fc983807cf157788437e2d8402d220dfea2791c01d286d97c7a869a85fee0205ac5f3283bc3db777f47828a3e25a2dd6bda68a50f338883d8b722bde17364789b5fc59319830e41cf5007f5ebddec199c53f17dc5c94352786e58927996a9722df91d1f4170fca70bb527ed82638c047e40797e484af94257be17cfa3998bd3940edc64bae5e685acb478542bff987327f23d642c225e65c236a956ee6c7457e940964f624868b1fe127525878e80531a1a459d2ae0d0ab27aaae2e5788990dc0f64a2a13a176e75c818cf7c570ab37bc86ab4093246dfe19981fe0e47053252f5da8ea70bbdaaf9b5b842651bfc040ca5dcf6519a695a466945a40c8daae3dc139890f652d357a2ae6d54ae6dc09b24109b90825568f6843ac0ff698d4462313681c9c000448331c7737c63ccbd6dce9f03a908c989f9da612f46c24ba20f566e77ab8153a605a39ca79423a14d0b7fe87a55eb9f1fa7cee5666e18fdd2d38a79521cc6ced682d7f9964f786dce2c005c16bd2c5b78519cf2e6ee2a229a0c0da372a39a69c4872eb3427bf52a0d2e703f8f389a94ae4a5f3904b6d5de3564198ae37df31ccd2d306695cde1b9f629a276d58368c111f145b37dd470aa5fbbbd6e636a8c4391fb47e43907b5f7b99442d305c45677f41cef248b175d1e9a737e9c05b29274ddc6e1f6fd4659b579be6035792306f1d6807da50e7491d07637d8969f534913314f7f276cc7c6e149e1807a16cd3363e96c0836ea77c8237d7dab148dc64a29349a9806a0ecd502108dcaec896509c1111d00204ee77efaf79db6195d8f4ba8cce2d4fa8e3b20da8b0b1b5fb43954aac8d8e5513603af3f4da6932bac75f0510eabae1589a9807d3955a17c83626f67733d886768e4f85575a5470c8d0b461ef9085f2eae088a093fba52fe619d745b4abd5e7836f70d337944c10c11d4966cdd5e930a69b01965cd96ca6515244c98d701114c0012e4348423e061422f14a30bde0c6045ea238ac78fd156a7f62afc253bcabe8171bfbb0e830a28b0cd21161b28428d1bf3cab76880f887c372e9aa2b7e9df21e70500b97188e349aedb696ae29ee7f5a592f75e50df5ffa53e076b3314ad2529ce720595067a8cef3b948e6cf75229bf11829ccb863ff70f593733547922e8c041b299e2fa3c6121ff15d592c20f0cb9457c94977cad067b6a8cd18b969ac15a342a4c2ee076c698670a357649a096012c94aeecc01378a9e636d28efd67b2aa5a315e4a2f69c9d313a9fd034b813f5ab337f88d378dbe539e45d0b193b0a3a7ce280115f918d354d87d230ad69e01c266176fa1078b91c6ac40d710f6f29c884e640746fd870aa6c5fdb4e12789478d4b3811d9563a00e135a7f739d6e2cb250d7e40ab417142107002f1534e262448854f184f0ee87845aa564405c0c12157a82c0fe81ea38e5b26e7c9671c4c3fc21515427a0048ab47e11a9b1164c890b04d4bdae6725f7c20960dfc929acea0c3795d3b8c18a722b46cc876396a03040cd845c493eb1b044b3be3b4e42a23d2f167b6c61d49837e653084a49bb37b0f847b3276806db49720ba0f91d1e2fe650fa645664d002c4acc09a6d814930eec22838027f0192cd2105076128046850e8b6fc22806e896b798137bf3da120c577abafce319eb6b1728a60332307efae730a189dbb069188e9660dbccb4b6620aee7c9282145dbe2ae4f84c5217d25b29f16c3334c11d5d351f86d268518ff9346fcf010e063cfdac9380724de906a172812ba8ebbd50c587f7e2f5998fd54ee803cb0cbc921cd8948c0eb692fa8bf87137af4e4e42527fa3b306e67d5fb984f4c54f07d5418a722d8caf90d8d9e71cfe3b7c4612c165d577ac0f737df710d2f1e085ebe6d685202fa4dad56304f317b771a2e81dcfa9760bc3e8496b23d4810580d25b42cbb70a356eddefd01503d985275adc783d9887f463da370f763e9cae1d3b946f86387530f5fbc9928e962c8cb8504c3c1294659cc69217e46e77e422068e52c3eb41b0f6a72fb913dfdc71cb58b12d1f090d302871b7b356ae6502bd5f0cb8ff2d2dac2e4ab037907d329a9eec79bfcfa89671f79880d6eae83330fadfb81b75df9ed3c75efe12d9c4f005bb9729684bb41eca8ca6e2b38228a1c7790f8d8b5ebd82c9bac06c16e4c5fdab8dc43ea20c2d8ddc8867d2b87d0a9d04f1ad7aaeb26099eb61536a94883ea465aab5e74af3ed223f7b2d649cf4ad8fa084099c1814f222c226affd2f674aec5005d962f882d866448c41cde9777133affbeae4720c342cd57655f04ae37149b49e6370efdab7dec7e793f63de3843ed46d92825fbd0586b02db1fb50631162cb67374ae5113b1fe56b24173d832decc8da7c435d8230d24b8c2f109408595b002a05ef866195ce22e1714256743f169d0c78a8541a8a49db5e46bdcd4635c73a8da26039d070879b6938b8658e57fa88bf32976c97e9207140b516c433edcaf49d12908d540e7e049ab18280c3f9dbf099d358dc13be135425a36f9905bd603f5e4e6b53dcfbd04c05e84b4cc145e2a874c0ae2ecd9e42e0a0535cfbce2096fbe43b3cfbaa14004f7729c4bdccdc45be62dd11101d1dec64f792c2cff00337c581ff4a2dca19be15ca6c087249f255615a22bceedb444add16cec4bde908d069019b63a4916765a83d9ae00ce2fa72c04f4f8903fab9c2da800a2960590e658ac0273073f481c599feb840d0e5feedd35c9b20aa4c63e98a0a459ba9da9388c4dabf10322eccc052c331d0ab7162a331034e6dbc9b9fc1c7ac1095a792128b3479100002810a6f69c9498173e253020f845c78ecea1a64ab8491c351afc9599f4e68cd4bd11dccbd511bcea160089feecf2dc69dd3025d0ab8fbdf15174557e990c5bc8d8d001352d1690c38f1da4299e642c928462fbb2e690da68476a6b498e2a5ac4d814ecd25a7a95ecf81665df56e62da354ec162e25d1f1cc1f65a1f0b72ad5010fa795f51539cfbb668e71d76b41cab485c5e6e551b663305c9074ca0e5dc18f97ca2e2288ce36f175cb505e885ae2883a0cde7991c321014a84ef372413f4ad9eb5fdb048e0cfe7f7256122718655a19a6c7ac49b9b9dd94c6a19cce7737aea937b3614d1d174c247e1a6719b41a55dc93a6bd2cce3e0dd63521c79f408ff451a6d60edfafc94cd499e7fc20b9c3e02fa8bc54bce34d0d949d8b104ed41f6d8aefc0a80c564bb16fdea53f5c00db470c3748b62c3a506d3c7ef6d26ba8c936dd02f1685b1220df8f8768ad890dfbe92b3062a887ee94090b412be611fec30c31db9093b9d2bae876014aefd30357388b30ba4bd629d2ca7d957985e4a7ccfcfb0981a73d30cfd653b64a7ee8dacf3a3c0a38333f0817516863620edb9c810630b1fda5c5003733070c906c68e0b805d952b204087cce77dda73f107b652b5c716b839b5618815dde1a923823d0a47db01035f90604078256760ab19632a80de1163ce815fec85c719692ba9cf17ac34eb3d9ba2937640264fdd0a3f281defaea31d4c9e4916bec2e10bcb288b4a8ea25ba369cb38c9cfaaac309345b5b26a6df38aaaac9cb1800a48281a50d9fb1489beb99ad9e272b7dbf732443ca53aeea9760cd9ad94776c40fc245276fc623b169f34755cf0c5faabed190423bc379050a85efa0e1b4f294712830c90ba2a9299ae48789938da5776612ad40824bb6fc27ed467837157e3e41a9695c32c3e5514d84246ae0dc92a34e9e1cbc1f1b653870f793f49c22767403ef660a6fc53c48fc9024e5a7f278232f070e2246b254f0429a2cc327dd2ad103cb87bc814333f6bfea4064ab058fb060bb7af30f7beb1c884c885496fdfbd1b463e745c4990c5da1fda74210a78af7b06ccc55a97191f80b8f1f2469a6e1a8f6e958d0b070dc26d58452eb503233e470c13cfd13a09787c64b1e244225ada8df986d32416964dee33c1308c723b0ce1df4c70095e258ceff830dfeebb957c62987e963b59e6a06f9f30f8206dd82007f7d60d11da6b2c1d07e89e04b8546d9957082028e5a15cb67ca6b036530a291e7e57804f2ca4189cb2ab96d7895e19d962cb3f1a8db7e9d6d2e4bc4d2515e51a230a88c2adac3954fb53287f45e0c80219738933466f95cbf9d75ae420dce6e0a3b6ec84ce26e5ff0e391f7649d044cbec9f48ba7111291e5c7ca1dcadec7e35aff03ea7562ff7fae86f75ac9c431eaabfe69172ca3973ec2bc7fa85c013af8b107f2004a3f92ecb8650a029a7617cf1037d890130dbf1d5a5f06975e98e84833191988d9b3325b766011e61c72493d5c4b03eeced593da9105299805115dc00dc55a950426037241c5181f73b11e43ad74f916a29a4dccd9dc8e2c3e60e92d33a63caa2d20cb85a32d223d7d83dc33f83380284d904005ce1290d510f2bb0b594787ebbebf58b246ec488cce4f5606c760ff5339f2c7bf2827973a995379ff47cf3871912fec4d20779b306e2d695fa8b90178842e807642c01e954c397ee7eaaeda73b6b87c605cffe8e08c7ee8dc04be38c759c16967cacbf880e4aa6d0fa13a9270d64169e2d54e12494aa2e0a4cb1119e0fd498775019742dd55ac9c0e559d0e9a0c5acd46536d5ad44142c5d19c191af92f37d22137bfebb4b34573a377d95de417f010e0f26e5d6a9a4ce049fefab7bb512f65da190f226ec02d74c444111a55bc1dd739a395955dbc51702ff7dd7a329ece1d5c832f5d3f988c9a129da3f3040e783eec51114b3e6c49d961acd38a103b55791ff96f278489538aefc281001bf0c907de724c48330ed9717d022f76a192fc59816a262453523ebf591fbc6e7fcfba56ddd9f58bae5337ffc62abfe572cd5fa8c7fbfb0a5fd1b4b6b7ce69f5f6dd1fe8ca55b3ef1ef57b6357f62a9adcff8f3ab6dfa1fb154d367fef9c5b6ee6f2ca5f129ff7e65cb4ecaca8f9a9fe8ff57b5367fb39436b6264939a7f5e9b958d3245f5ff3cf966503af263f099f0ba83bdfccf2763ffe77c918a166b5940d0e09fc42763f12b8d978a468f2e5583190f96fbedd7c582434d58567271b83fcf28b34670e1c62274b5e72215289ccc450801e541cfa60967a825a95449004a6977b1ed4fbf27de466a92ac3ac88e8c09f040532f0a64fb72cc5daf2fd13c1e6e0de45cf0952f4a5673b56313ccd617744c30663db3a2bcb95ed81fa2ddb47443b00213794202d5ceede7453204661b7faedbc0101a8df3250eb308854d5c77337aa0245cbbea2644c78f8528df4a0872cbc6f4f81dbf55d8645cdef457d320fea7e951f7d5e84498368ffc422078f3c429e863aed87ad1bf7d9d8adbbb70b88e19495bc177b1cbccb5b527ab39d19e30c854574c57187627407f43dcdff3927b077e680aca1ce574c7ec16f5bf806e5cc3aa6f525c62d0659c7bc526d7d38e93965d40da10aae5c4eef219807675400908d295854a01d97a602bb81175e192cb8f6cfaba22a030491f6494f8a9f2abeaf06fc24b813f725626e7df5c1c9d8abf131263be834106299c6e5d9f7ed0ae44d3a7580954ce3c2e8a5e5d297ca0169e9a934029aa4501c2c148a05b32d1c1054c4f2762aac528153800436b630f5d01bd6a87d5edc6529eb9be36c5af6d8f507a4435bed064cbe5fb2adb6d31b9c670f056311ca3ca7ac847630c1eccca559230535eb08c97d3fa5fad80409c37c201e6c1fa1052e0a0b872246bbe017a6140f4daa8969c2d140d93a26f0a01785d2304182a63946947f7b4c85382235bf16b3f1d5d05f4c2bce61a41a3c4e42114bbfd9efe3051640c725624c4cc4d64f8681dec21f23307527884ab3245a62b311766d2ec0cf3bc114dd9a58e72ef03ca4c7dfc8eb55e50166dd5052d1ce3d9e2e5d12546aeb4c895d36eff1078a94752796e1be419ea7fe96dbc21bf3cf92634a3213f58a83baae7746173bd2bfded5f9076c4a570a477e3648b7bde21df28ebdf9b92667304459f129662118533f31b93e693c7b4f7ef232217298c504f0aea8a96fdfec143ed145d6321accea14a57642607acf74262df3c884fd4a4a3a5756037c67aa35a144b15da3d5db0c1a66acd7de2d836954493af14fce434bed4d92bcc2af2e642d958844ea603190d834acda38c59b22281574a3e461775ef8906b699aceeb5fb64af06af17363ad173e32b3f2cb80c2de2b6baa57f5bd90f2849cc2e3ab460a80b113945f004fe0d752694bdaa0fc7b836c4e4fadae50f1cc5b265a98219c6e6033bf77770747f481be82fbdf2b1f9fdd179ee6ec4981834febd37194815ba2566698c85e6f68e21b5e0f4a7e90a4aa35dc536c4f68daca47b2735787b20512d2acaba7743073d03f2bc70975b4a28fb8dae79314da72c826d39371ed8c31301802288845b7e17097822a5a736ead2dafff6cdeca6699bb0d792df046aa4bbf51c668ea633414cd3168e8cae09392698cec8ff3949df748064adecf8055600871558e1816a8ad2e476aaad8e2eef07c2357efab95783cea7a539b3147b1dfecfb16e900699f09adad72b672da73b14fdfcb862dea1f849afab529b6ec57e34f745fd0e72711087069e3843a92bcf5f28bfeac3670fdfecbaa198c2927053a3225edf1fce162fc8da24d7b02c8174fbc664461bb597fd086a13285d2d2279be597832d4d4845eff626f6051ffeda29420bd3542df462aacb13524d78333933dfffd176f5fde43657b064b9106ce7963d2024f4747740267a1ab924a501c3919e450ef6ffb67100f870c33f1077569a8d0ccbf69ff63dd1051c0a991483b3f832fd49db40426efa818f6496e1c0d9bedce9946a531e0a81052a1d9269f930993438f20082b47816f6e12e9775b1724d080240ccdb548f5699c082937298349a6d3e94f78c3ecd51614eef340e26be8042fa530b4d9a13227103f0da4ee0e12cd31a215af4dd1391bb4d008c5b54b07e71aa22301c9b6c0bb3ffb5e49b65aaac892affa0b738ff45940bd1af3052b2d0e529f4b87b2c8dabe4c0623580d02e58eccaa8d668da5f0ad9e4df6fa061f73688cef6290a4e7a036c2404de0284d70c5520da554d07da4bd8211d8c06e3dae2c78f98a7b359b9aaa0140bcf8f7ce442e054f166411ca51d40a53e40dfe1accc060b18d626dc426c0675abe6dea1bc7417f557a938ac0d76c834b26d6d6fb9f7de52ca94a40c120d9d0ce60cb107ceaf3ea43de1244338cba8f1e1dc02fe708291fde5c329052ee24b25f65ac1416cf587d328fb4f2ce26b25c85bed5af94104fbc3b924fbcf2aa26b05498347b1c74dec41f3feb328f6d0f1be42d423f600c0fb77f45180f79fd115f3fe5a74bd4be6fdbfe8daf1fea8e8caf1feaae8c2f1feace86abdff4717f8fe33d175df71388483e5fafed3a01bf9f96afb603732c48df75942d351229b32658a4e12aa3d11d74709394527090ebf84a613c4efa879225a86f97b9138424ec9364f44cbac2e29f7ab20b54beb51f922ba34255462fed27e5670105f9a9395207f69b01524edd28e567e105d5a172b1cde80367008fe0c0e5f5503872aac12c32ab170852877942ffc24f002f1369701dfe342e07ddc08e0dc073ccd75c0ebb80df8ec7abe7187863c8e21af0d695980019ff44adeea1f26809a60d4c50d08feab54df9008dc1504eeea014cfc38a001404d3002020202020202e2a6600cb8a926f20607d93799056eec1fe2aabcd5dfff63bcd247f9257f49e0fb6f8fbf84f87e5baf4d96c0bd6274ebe401c1c9d95b3b3bdac15c1b9d595abbadf33a99ab80ffebc3d7dc047c8e8b806f5d1e1ec7ede1c17b80b7b90678fac3d3dc05f8e8f10930c04dfe61013e28200108e88187031860e593e1ac589a96d5216ec7861ac95b4dc46d25af931a6cd68d1b2fa64ec7aaee64a71a0014e076bca91ff35793c9715111ac8fe3aa2258bf755911ac0fde8f36f58b60bd126079416e7e79fbe5c83131deceeaed0987c9a47dad7c3a6d2a165002f3f7713aee4be062e085b8453c055613b842be0237fcecd228ddd0a8f855515abd5840488881222e603d20594ec150107373fee56fae4b02f702fe3677f5e0ddf1382e0ddfba377c8e5bc3d7dc9bdd1b77c5e3654e394526d3aa27e9c471df773a9d4ea793caad8186554c7ec12f4a3e306f19b9059062270f88edf96c186948a8771492a3901c85e428244721e5544ec9295f6cb086928d9b1c7fc3dba9792b3ff0a3b7d37abbeae8ad11c425e26d767196b9ad8488a897741168d3ad260deb1c385a35466dd45e787d74840387b713732750043bf2d6ea27da9ce0c311d35134d88fc36b245b20f9d4130f8897414606a7a0d4c85c1dfe6f90afb93c9fe302f9d6cde171dc9d07ef00dee6eae0dcfc377787a7b90478ed461e9d1deeea8700f76529c8d581e7a69eecdc540e37e5c54d21e9dc14141d3a6abe32dad4d7714375dc989cdd1816f6a736de8ea6eab20ba323bbacacddbc641c776888c7dde32d1c6f482e794b2e35d0cf4f0be1781d1444236b44bc8cdce10dc9246f75120d5ca7fd683faa5c331ab29baa21a6cb6e4b7e191e31aba5d5522c167b581b2f1f5700dfe3fe789bfbf2e0bd8fe3def0adbbe3735c1abee6aefe2f8f97b935fc046e115f818b81cf2ecbeac50a71c3bfc0953a14b8f268488657daf024520c29ca36e504718978ede2a7b7c6b3eeccc35c1b7f811b757230705749ab98b77e08200033de4e7df1a86175e405128c072443c1171bd4716d789aebfa9beb8f735fefe3e67c8f1b80b7b9f5c1bb7a1c77c7b7eefd1cf786afb92fffb78697b9347c7657f28d3b34c4e370872c30c46b2fd5023c92b20a66748414c316b82b246fe50c715746de82b9eecb52b451e278acacacacacd440c3cb0d3beeeaa6901a8482fd468d1aa08acb061816cd0410809c97cb061816cd6a641727cfccb4ba98fbe375dc9c003cce15c0cb65030c8bfe104000725e2e1b6058d9fd329df180d02c3f1c7f83b793e36ff07866ae791b7574415c223ebb279b1b10fc57a9be0f46fb0a00bcca3256c6a2f1c9ca08670b23a51bbb31ed869a6ff537bc9d97bfe1f1ccfa3647177305f03aeeeb69aeffcdcd799c1b8097c0bdc00b712df014b843d4ef715ffec6bd36577bf0def0386e0ddfba347c8ecbe36bee8e9fc0c5c057e016f1a6bc430b02e90ba027e393aed1ddc265030c8bde18d2cb08e0e7a75de16a0cab3104e0ae8abeb84839af27c3852f900df802c1e00bc4c21788e20b94e10bc4e3a69ad470534634dc705347ae5d2d0e05f148d92565e42dd8cb4d35c1401117b0c010373c2034fbe8e4e7e37d783bdafbf07866bee1651cee10114484ab2524887c997efdc8c26165f328a73e5c2da598449bfe7a5358c49b7eeda69af8b829a31e444ca0023715f3569253e0a696bcd5efc30342f30d9c822df175f9c61d22e271b84343bc8fbbea71575e34d88f7357b068d344bc46045e1979ab3f88fba3e90c815748de6a69f927475e20e17083573f27f86283d4dedcd54fb4e9a7b92f4b2b2c2cdccacacacaca0a0a8ad14dc19a3c39f20209003ab2bb65992b9510112d292a6a12004fc2b2abc55c1985003c89044976b32c73e591eeff2b9d088ab9120a4f0ad56c3314c4b740991c170f0df119c79006737f60c8086ff5f707d19f3dd993bd1d3c030000d9eee8e4577f87b7e39f5d9c6c6be862aebf8ecbe369ae0d7f73efe35cd7e37057efe3bebec7cd799bbbe3c14bc3d7dc1bfe6f7d99fbf241dca8935d9a6fdca1209edea11f4d2788d782b861c76b3dedba46ad4474dd2d22d87f63deea2b83d8ea0be4adfea406fbbb10c1aee1c39b1064693f3f396ec01729f75fa47685f7e7fee4dcd59206fb5f7755d4607f107745e4ad7ed75d21d9a2ff1a6ddf6fc37d89459b7e1ef70529daf4dfd89581fdfe0b64bfffbbd07dff2775dcd780c31bee61700872cfc2e1734f71a8d26e2cc337e67db85acafd34dc146cc74d35b9a92cfbd58b96551c3e804e7eff03f07662deaebaecce8c735745d1a61fe67640cb35cfba1dd0b2cd6b4a987a4cdf7f73573dd1a65fc77d498a36fddacfe9fb352730eefbb52e3c7fdfaf1db52b46f0bbb901c17f95eafb62a8e550fbc90d94553ed49072bfcd4d79910347eba69e803775149369f08b52b4e96f1fff1bd9df549301d4abe349dbd09f8307c4738653b032ecdc5883f7e5dfa476c17c7d6d08fc35be3eaa5d433faf33819799afffedb2f1f567dab5fa8ac32160ceee4d6ab0c9f0651fded88d35d8ab3bd3204fe73704a7fba50fc4dbc99ede2b06cc476f87f5567e353e7a3bf8ad7b3b6fe3d6800df6cce58153e30e4de0e51613c038e4c0dca12186b8a9262c9c822d7df5fd77c0c915e7f0e3164087aef176b4cfe1c6ae1837e9d6e02160ce56da673803e0cc3bde0e119635ec430f5bd45b93591f4e19419807e205a199f5f6864ebb295876534f1aec97c04d09715348deeae7f180b472c529a3317cb1c17a716409dc54936ef5eb9005f1514dad0cf3fe91f5d9bfc0047185f0567f0e0de6e00191ddde01f237d5a4c17e999b326ab09f2706a7604a7cf2c3940e36353e72f8c031303e5c522d3e502c3e7c640f7363660571a38e76635ee1b0487e79ffac76dece8bd3b831ab6e984acafd2e374c2de5fed40d5d7a727fcb0d5758e47ed40d53b1dccf72c31732e4fe951bae5290fb556e9842cafddf0d5fb690fb4f375c9520f79b6eb8aa22f77bb7bbe18b14c21730c29732c2550fb2759f1f37429d83ed10c160b244c6c1788858c847c8294dc068825741e4949ce130469bec334cc17802c69d2c03c38beeb2cfd2ab4f329fee29a3dc2958b79aa660b9a560af971aecef251b4a39d620c1a908045a0a3d616d9294dd493bee01c982d4dc3836022340e470043f93d62c0c5a2b1431621f18a348d362496244f9a1b41991631262e4d8607c4588720c9388714a3696e3dbae935ff7f57bde4e52c663e4f8328ccf9444528e7f9292e39f3c1e565efa54569280b2c2a2f2b1b0b0b0b09862b4099340caf1e3d5c65089a4d0510f2a111438a4dc2fa51f459bf6a241297969297735ca5ee43027420e69e418df8f6c76a58e8c3f5a87288759cf52d6c311f517db916d07836a1f8940ed7ede6acd5badc95e7224db11180803411808031d08f62ad5d19442658bf293fd49a1af2ae94ad454a90ac51ef5fb69947e6d3e95c8852a910b552217aa442e54895ca812b9d0d623444499f491ffc41ef3fddb8b7e69deeaffa0a8c4f83140c7691c61b9a5e62f2ac6911c2338a0948f42c7c80d74a4c106f258838d57f2635e01c932cb2007d2925af0b9c7d926e957461bfaeded646f69508d5f8372d7a01ad460d7a0a0966daa33da505a85eec8954ca2067b7a912bf1dae34e8fe490155fdac71f2459bb9b17ddda8e1aec0fb70d6883c51ed9f76f47fad541b11d55d8765461db51856d4715b61d6d47b91d7742db11ea6bb02b8c6803c215d61d551510e57edbdf37dfbd1d29a594524eac6ab0510df6ec5883fd1e4d6a57d0979b5229517ca814233e39d6234672ac4ee4feb01ec9d1a3c434c3516ed12e14a992d48250ee2782d938136e421f8d3146f718dde3ff6830471ac6c7329259394a7f711f3d88bb158a2af4e48b5bf4d3a41a147b6cdf4fc7e89716a55bfd50a08821c6186374942839f4a096d25272c59a52831d56a1dc55c3b1ba130df6cbeb4240b00735d86f85fe4d486bca026b6518bed84252e9de1bf6510b29c124508cc9307cf1334d33ad82741836ce84b507a6d443e4312058183edbb36adcca3ba9b0b45cd50b2be6c6ad61030788c3e6066747075343d7428da489baa8616da46474841473a29e3eeae9e9e9e969a45892d2126bf542434544444444e4d2d3d3d3d3d393fb53333c8e282d754fff489866f41da990021f7243c8ad6a253e49eb898836213232328a3d62bc7efc69147b04c51ef4e38e24e4287bb4985df0c30d8cdc1feec8fd2f2125da623e44b9896677916c9fb466dac6d9ce339d3e951516544bca4545e365c5828909f54c22d6ea8586ca254606c68184e8512cd5826259519179969003a97c27d3df9504aa4a0df33a5b2f7e9140194c89db325c8386fcf82ff23150ee6f0da8c68c2a6bb11c6e44b1dc9f6d441b914b5629fa628c36536ca42651ec1123b99e961fdba91a444921a45c6c1b0e8750a2ec9e217d2e45d63ea45c64b9e2d73e9b948812d91e272349f6f1b78cf361d26ddb36997138c656b8a96840c5bd9d1502ec73ff83c5d15bdcff103fbb31ab08e13b222e691f9372119d223a41e81f21a7f86cfff970ef572508df117129ebd80f3fe93f7f78bda12a67bf6193207b0d327a260dffe88cce39fd83744fd699d32459d32511c972614550448282955c6faecdf8598cd5e9cd590bfed762c0e681d6963dd75aeb95c0b5d95ace9ae85cc2c6192b539e4ab5c80f71c0d65f158d30277798b309807b89c3a805fb61b442f7618c42f63e8c4dc8fd6174921b6b1efe3aacb21883361b116d7a68fd54a22b7b01e4441ff15ba28ffaf543971c1f1bf1616442b3110daae0bb467440cbfe1b882ec73c1aec2db2cc0b32b3f656e3a8b753630f9690468ef443951c69fc1b44d8d9d67dfcabca2a2edaf89a9683d3ba3436d41054d7caf3439cccfdc7df382dab74bacded99baf838e0a5a1b2bda4900b91fdb390bf34ed536552480ad1e4302ad1e4500a5d23fc75436cf56391841e2ea21472c7980c723f8773649b6c8eedf2cd74eae6a98bb147ca7226fa9216d11af5858cd10fbf170e38c468a483b7a20b8806a3eb0111ecd7c15f4200d12e231e105d1b901f6a38e4ceb1071fae66fadcf64b683adc0be1af0fb811ed923f1b882ec984c4a1d643b1d5bf5d2945dcd1ff017fc99f7649a10699882ea98308f62f5d1f9f255e27ca1a42a924f72f81a34345ee97446d838c426cb514f184246b6985efc341647f99495890cf15897379faab636b7eafe49981ec5fae42fee2beb90e70b7a77752089c4fbd2033d7b7b3e35e4a115f43f1f5deea2115ad26fa4d02196de65bc9dd1f4d67c39a0fb5093e29639b249dd2250e39f0c091b1dad919d6dbb22ff6b0178706fbbbcb52a972b6cdf886ff5bb339bb28efe391b7cbe5aeb39532a75ddcf7f3c081bb1dcdb0e623e868439f7a3bdadb5a7fabee652bbbd92fefe3fbed32e82f0ff3903c220f31b49761db340aaa766d4d726bdbbf72d8b457a970408975c8a15dfe1507c73924f022b4bb0636ced4bbe588148fb275198f22d28c474884b29d2d84a40721b92495b2a52e95e492d01352a98d1a966d9d0d6b23a9d4b020a06c330a14d430204ff258b65af598270135e1b1593489b2ddb249348b3c36897e724fb65c57ef6afe96b56c5f548a3edae3fe93896610728d31301cc89b685863a124cb10924ff4c0456d42ce301232f7471ca34dff14daa345d93e69cdb6cd547fc6a3d490d3ee1a9c2f1f4d737777d768f5966eaa4e0690c6932c2801bd986f4fb35f3efe4bbc4e92fe98647e7ff6b21f5f15a2af3fba57802252277a9304b2a510bacf5f3eda2b719a3265ca149ded637c95bf387a69f28d6cbba3d7c60c773595f735286f8d8cb3ad1dbd37dbaca3f7b3d53a7a65b2dd3a7a63b2e53a7a61b2b55d47ef2a5bafa3f7255b53472f8d6c4f1dbdaa6cbf8e5e976c553a7a53b9256b570923361312dbadb135bfc50ba2e5fa96a5a317952daaa39725db968ede95acf265abeae83d654ba3a3d794ed4b47af97bb6c5916a6a397cb36a6a377cb5a5633eee8a5d9d6e8e89dd9ce74f47ab636ec8d0e470b34d1d7a921c897469b2982ecd3c16e79f7d3a6524eb629bdaaff277ca1d6f54b8562853c3210deea377df89d3e547d1fbeca832af7bba71bbdc5bde9467f15e1ad7e96aac1ee0622fbfe22fcf5eee150cb31e93f158763d21693b6ac611dbe3e41b58b95cd9cec39199567d7140b5776cff6e93e73e30d4c6f47a28ee091b93f08971b6f807a3b8dbf3a6bf5965533ad826cb95f4a1ccbb85d83120c6be5d7de0ef8e564f9d28c4ffe0fefcf3faf6dea1a8c5dabac543e0372b7c046d93ee9a9c2e0cb3c1e89a7a699e2512765b350eeeec9da265a6bb633356ddbb828727c0e89ed3a6faa509fc9343b8d0ae5489dc8f1834e9dfc82768eccfc7dde4ebf8ab723cbf8ecca0a0b458242b5b47c2e2d2e2e2e289615171795cfc5c5e5e462f25c5c5c2aa5316565b0dd6c9f34a7d698699dfc62839ab7c36a3082d937cf7a3b51766d9ad6769d67eabed3e9fb54703454444d16166f47fb3a333e161614aaa505f5a158aa2f95f276663783fa502cd5e7a232e3a36fe90db5eceda695e78a430fe4fa699f573cadea697cfe2fde8e6ab5f276be06bdb2585f76181809862f0463626464fe3dccc9f5a5195f0d4137e3bb1e902dc7c718cbc4c0b05618bfd050b9e0540b0a63cc825754f08731c6d98d29461bef1b33952b3e36ce84740675ab3f53fab4cff00c9a4ecc235449b45de7f1cc23352eea6ddc965f5dfa2f57fbe9c4cfa45c5630312f322a2bef0fc6174e7c81ef9f135f34efffe373882efcfe3ac4578ef7ef21be6a66d074a204f3c83c329d5855d4bfd0687915d613d132fd15d513d1b2f6d676120c9f2b2d792be6860d0e1c3638fede21f0f1b5adeb93a46bbdd4b4168eabf2560f7de0d31f7f81dad329a5c75f34349716b55c1bdfe22a33bed35bad43dde4189baf322aedc650ebadcdf549e262d83cca03c2e5d4a362311b544b5661aeccadeb4a439ee449b307e5f9922fb5c0c0b0b85c87824242d250de4ec6753f733bdeac7ceace08aebccbd522b8f230f78be0cac75c5404575ee6b222b8f2acfbd166a58be08a2a822b2b2aefdfe205b9a81b73ea5754563ee5edb0bc75f170787174e4a232b59e1819a9689cc0263058eed7aa46e38caf43dd1a9f5d9a2852e80f05a24154884231977a7c1a5ce24545b95fabdacb0d2429fcf7fbf17525ab8b9d88752791aa0866b49a42d9b561e4ad7b2712be13caacb933c95bac29b45203e68bf9186f07e6adfc581fbd1d199cdd88fff88f1f691088a58a324e78500c8d1b03e35008b9e74890c8c8b4c0dc2904c58c621621215222e59349b98f8ce73ddea3bd07c4cb905d19a2a20b832712964ebbd1e50ee9f8aae3ad8eeb93a4a53448f3357a6989e6cab823fb1a335b86bd9d8a82a9c19a79b119b2c17d34d4461d436ab0652369e5728768686870c3ba8886e6a5cbaeaa953411110d9a14d832957074d28c6f63c95869490af5a1b954c85b51680ffda146ee95b9e6b6f4861aa891784ba841a17b55aa7f10c4c1c1617446765732cda540f4c75bfd382eedf128504441b42445e501f1cea0695348f55b9e45526a4c6fa58ea8c3c626bb2a467e7eb41a1befadbc89373a7464f76b9feee91e1b1ddd5b8913716e6ee27d81b953294a834f33aaa5c4a0e3c6be953be20e1c1caac494715c5ad42d29312d34684f8a88a85d2195824a418bdae5af8a3db497a2c2726949bbc1e9a4195ff636bbdc5b4943a4c1fd3d90fde5eff0766694063bcba494eb782a35d8abf772ea4e973ba348a13d4b324aa481a592526e9692bfa650b73ae27840bc3c85ce40bbec72a7d08db9338aa964c2bc45d4602ff1806c9985679194f2b95c39060d292c9392b2bb797174040509490c198bb5683975e51369644463838b0d291b5e3ebb35ab865a0f73876ebc4ceb5177e807d4697dcc0d3c91b868e02924a7fcb97165d090046a5d8924e6f276f0fcf5abcbdbc95e2f69c6174ea5ecd21cf32db7035aa68127920e6899f59a0acfa50883a71013be902ac9fd5449bb424a4489628f28ed627dff546a97ccf7cf25d6953e3258f6c81efafa5c3ec7db49bd199fff0f77c9818ab9496c19067fc00c9ffc302ed1c8261448523651dc30857a50252abaa4c585468506b8f2b262d1250d36554295f0c0c1072d7269a1a182d360af6e0e3f68dc21105471b943340f450b9e4253c88786001048ad1ba8125a4497a85a3d282044ecc6a5c5e57db4bcc5e9b43b85261493e64ef0ce226ff5e3e0016909eda0b9130a000480866a5a71c97ec5e5c635e2066fa7e586588eee51237dd8b8dc094583fd283c91a4f014128350eeb700688134d02043834baa8506140b0d34b464d40a8bca0ae7eda8d09fdc6ff23acb29d1208f9b4766d074427644ca960b2b64905d8b2690320072d402a88acc034652cc7eddf488d4793b443162b12425e9ed4449cab22d16539a48724f2131c688a224468cf378c088419942624c23fe337fe85664a61d60031b67421b657cda4bec3fda7523eed3a0d0d675b1e7e53fdd6af7699006b671617ee6b2bec6a58faff644dc20de8d7497749455bea046b23f4d4174a92051a3f8a2c0fb53587c09f1feb428be24f0fe9428be2af0fe14497c4de0fda9507c11f1fed489e8eaf1fe3428ba7cbc3f058aaf21de9ffe041eeba7c74397b9ffecd7e4cce0b04054b66f710883439c5cff0b2cb9233b9a5737e69a5720c8dd5befe617bcaf1fc308856c5ff5617c02ce101e79fb1027db0fa318d9e270088fdcd90d0be9de7bfbe1dca17bef51ddcc2bef63bb58acb5af62e518f2c8c9d64658663f1b9f646bed4f9c7699defe02620fd5db8ff30b3f481f2679d36fbfa792520e6b4f8ec3ab1dfcb9e7f1e7be48de6e38e5f53e7af67f340a8733577be717e44da5f1f2beb068a824f57f425c947dee3b286f9f94eda9b3d67e7c96db537c599647fefa34d551288f8e7208e6aaba2ad1a61fd5b57476bb1bc7ddaffe76b577b9a1cc1df01c7e2013f1ccf2dd0d87a832cbd7ce2c2e2cb8d2eb99e5b2581957dd76f18078dfedd4b6ffa36b72e5b8ee65cc290f88fced5db4b7efdd0ccc6421f2371cbabc3693ed5b1a1dcdc04ce67e2673ef225fe6759f9a843eae6c5ba7f2db0ab6261c7eb7ac87c3afcbf6a5d7c3bdf63ffc475b0d0f9909bf0ccce4213319d520954824142c570a9de10be5913cf2a25df6fb2552bba0b42b1c9293b7b7aceff3acc5e167bbcdeec32e6fbfbd954719c95f32df2f63f2c85f5acb5c6b5f7a3b9cf7db3dfd7cef3d6fe784e36731916957ba89a1a4ee910e52e5c3f3ceacdd9394eb6fadc7bdf7b15ddedbfbdd6bfec2df610e87f23b793cdfd3ffeccf9867cc76be7d93b763adc5e1e4baaedb4e96dbbe56ee7f38c772e2417bfb424ecfa97cf7917b151c763ebd4ccadbb3e0ed6bd87db709393df7dd8744a6ecbaeea367006e7b4b64e6d36f78a57df7d9f6168741b6b7bf7d679fc3d586a8cfba93c7c3bd35711d0ab3745cd7b1785cf75d673be8a459fbd786d33b890f701cce517298fd9c39fbee654cfad8bec33fdcde508ec16121767a3c6838dc3aedc3f91c0e6552cefef49c8689f409731f4eccd9afcf7d98a968feaaf1dc477fcd3cf7b6bbdb9df974ed4b8f079aed6b156f32266fb25f31fdccbd5fe3e2ffe1df8d79c392a8c1cc6adb879bdd36adfbad627b05e92353623fb41d16b2e15066dfb66f6f07ee3bfbdb0d89e055fdd367f6b37fd95efb502ac9a799b7eeb3f71e9f4ef6b3375dfb1a0ea5929c7de7f16c2fa4c3da5b8f872e6f9b7def2511e7ed781ccdf556ee8620c8dcdbd9b9b703f7dadb1b12e1b8b777e6aac9bcf5b72f89da15b37d7905e943e67ffbd4dbb1387e324926719f75f7b6c3ab1502641eff0ffff71310757c4e20f3189fe0ff7e916c2f77b71b1a71b5ecb95b246f97c8cc1a96579037d9fff08ce21bbde5adae45603a87249c9c7ef869dd94d74a58967249965249969228cb4f29033129874582b210d37b1f3d20614ccaf2bb8e49d9f45e4eb62d1f4ed487da1192059525ab0310f3e1af3e9cc992c6876096aa0f6bb2fc3ee491a5c4218dd5ed29bed5bffffb4be69dc6b3defff33f5dd695bfbab1c1bfb15b3257bedc9ee20b55ef2f9f9fd789f9255e07e6fd55fef249f2f24bbc4e0c8dd3df981bbb057363db40e3c6066f6cd0e5ca4fddd860cb95cf72a5ca7763599eb0e9a7a9bbe190989435eee22139597be9edb00245125c30f3763b9c97ae52ac8d49393e527c32a5900bcc8a176c5698c00737a8951c61449812cdf082154408424f0c8660050d52180107388041136460a2027b051f5801064cc6c8c2193b6e3c498109c68042d00982c222207851104e4d64763ea104f62bfa014e912b98b0c40a5a3c3185338250a4054a625cc8c00927c820869b1a3ce103280c01053a98428b28250c317c50852d6071462c07072803c90b8410fbc2c7880e56136674810a5eb8c2126c10da3869e20cce890b7e540220a50c5ee00292a2293c515385a121644189123e55a47274d24452ee7274d2041421d4ce66939129751733d09882a4af65aa2f3a944ca9acf56adbd70d7f4d977024534a29a594563abf1cc32f87385370c9fe857ffc50dd922e39fc32256aaa90422b8b232594810b9850165f7060490ca258c1040b67b8c197a30a1afc60754a41ac091956e06305d82f61093e5230e1841363c01145a58a13b468a0e789164cf801195b7072842e9cf8e00b315041ac082d5811164e4c9e3071e9421541545801186c308589cecce20c56a8c20966d8c21267d8c8115604cb2d39360143690bd99e3a9b524a29b3cf9b5359a526250eb797c13559bec623cbaf7426b6e4cfedb3b7dbbd5a83bdf5f6b3c1fe6fc3db5737dc61edfb1c432dfb37679e52b07186caaf3f46dc9f4f121af6cfd93fbf9bae7e6d4ef798678ed1854477e739ecd7d779f48184cc443a776719630f229dfbe96cd77c7fcda740b748d2c41313acc00b59009700841b3491c5139a88c217f2431c64cd6c54010693294cf244e9cc39333ab43ddd302a8c9e744e947bd454393299f283cc92239329413389e909366420864ccb518b2540f1ed9a2ad68cdc3829b539974cfa1cfd0d47aa6a9026cf573de8af08c389f3b599e167a9e69c4428ca734eacea57844dbc032944300218497070062874c2cfc9111f9aec51a8410ca268d1041c204189af393a79c119f5056764c949da450194944005d8154cec200537a08002217ca106495394f164882674214990112a9a28b211b53881135e00431342445ad0891f85cc8861d36209506824e8e20c5280e2064a5228237e014a0bc460a4892864f4a0092c06a62aa888c064f5d520c20a58882054838c212cc290c489255160d2440c7e40f4c491a415941171154860a1220c2a0e343922842db4200c5d888218b0e0240667082189122e155e9ca80863c505880a4cb6281ab241147466132db0d0450b9e00460b7040859314e0d04a851559534a67a6bb3baea918ac5139931bd0a0b25e6555feb278c64911601354cdcccc80302a7440c50a723883b335dd8111be29884c53e040e594236c0a20248deac0a85082fb3c856c162b408297d163848232ce1045153b4bb8800b24252f60c0834f460c9e131434318720a50c54942049132bce20f20413445378a2053e41d1639840615374e1452ff8a00b477e008511a8008519402d48c29432c8a083152c94108439e7fc3e542a96c3af9e91d19a851329b69926582409a369e4c8644a14b297236c8a2e66e031c618636ce92598d2bb9dc8b949ad33af9d6b9d74c237e52a08a765eeee3ea34dfc495128966ffa7477197cf265dcdee413c31863d464d4a8bbf7449b48372dab747ae3186d681676ba778c6df21b286539454f0c87d851969d12a56c9471b07126c471818af533ab1eb68f999b77c8629f257274b6b7b837ee66bfcd3b64c4ca3f8908d30141f620d0be86ec9ad3fbdf7f15710fda3b4e40d4d1300eedb985cf9bc4e7f4e95385e89b3fdfe791f7c41e5ef4abc590f2939ffce427f1c41dbb82d32c0633898c9c3492a3f6316b57faf4c81e6944fe78d62e11239492f8c0edac5d0a08111b52040480a0de324e2aab6c9f2ba0b6767e6dd6f9b55ae7d76e27c896ebfc5adb755d76639e573ae1c9a020cfb3993c2281643c71a6fab44e26542091b4f4a1876d4b418ecfdd1f5b4e4e8eb528c8f1a7d6a186a078e0e074d775da1239fe877a95bb773520d8f237e0793bfea61956e7b42a91adec4c9087b60d4b24dd8a317ad4144a28963e948422f7775b782de39c26fa55f3598124cafac3c2c699d0e5e9a3f76df1855a46f2767864fe3c0214c94b786afe9e87e6efe3995a3735cde3f1fcbddd3aeae910b3ca15dfcca10721fb6f1e4fe7ef2d1716c93cdc7f1fbd20dc7fde0a01a867791f501896fd5970741fa2b7422fca3c59e65ee5edc761eea507e42d777962e69ec32befbdeeb9efb8edade4817bdbddddddeeeeee73ce3929a5b4d69a651cfe8c3e23ce7b8fa7eb3cbcd27297793c2befad789eb701efadec3e02c9b20724cb2b6fba595eb9d153c13c59fe62b439e1d089bc20a6ff625e7d2fe4f4a6ffb0ca15df2ac8e94d7fc2317f28b98687474ec9dbdb25a3a4a4a218ad5ccaee2fa59452b65176ffeeee9e1e4f751a94dddfdd9d7a3c742665f79f73568f67d2a2ecfe94661e8f57afde11724a3661cde3e96cbadf12beecb5df3c1eaecbbc1db27c7a6b0a8be40f7fafe5affbd36bf9c47d7b3ca73f612424d961e061201d8e0d5a5c9164d091b2e3b0d63089a33cc489b2fb159fec71a02ea2d22d3a70a29642c90b9c28c32127e767a95d39f52877fda256a43a863a25eee8af46feaa316f21b5ab2a35f84574553044d0a88ec19de476587426f1951d79a19c1dd922f77b7684c787d991dcef38994fb644eecf7a6acc5f5ea7d425af31f75997aad25795aa5256eb943a066dcb4c348355a01664444936ce8451f6e4818383434e4ebbcffcd780a04b54831f4ba5a294d2e932c21c0955a962d4e2cb1e3983905b6295a26f4ea2a62ee3b24d94f6b411078b60304101077b6261dc1167c421715f7046fee262de426a17a7d4e017d1c5818133ca9d655ccc5fdc92b794da657f38304497e5386bb9257f59fbd32e6b99882e6b396ba9c8fd96a86de8b740fee2c15a1ba3607372acb5d6daa1f80271fe559f9643613329da740a2c8c0827a29faf023267d3eef676e4ed4c352bafe490cc39efccb676d2a358de997f38244064f276d429f8fc432ad432d669ca689e9c141c92f883f8d25ec32a0f5fbb7cb8408c0e864509587a3082197ea220c6145328d17991e20493d8135a808509605de8626e52ab950a55c3435cadffc1b8c8b556ed519ac6bdc6e1984d8a8231c9b5d6fa53ab9ffcecabb556d8d6e5888514b690698e584c810aada991256c50b03d5046607c11041cc0800c483df209944044c613622485610b53dc009bc106cbc1ad6144032bf460090a7c5640a3045d9c000a1433308104a0adc296e0baf0c4146aa821fb6b5c6411454cfbceb0e51ce10ade11c8305dc18513a4c8e206403698c2006650c60b963c21258a2a747294d470042f8ea04526ab5cc2363328d8feb2a00118957ef2cb310b1af08006e1d5c407420e3b0251cb03c620a38a2f6c7044060b74a813c6f0040941485fb001195039c28ee044b63962d185284ce1afd689aff9eb868d9ff9f9f1df5ffef1417f71351ebfeec7d7c15ffff17bf097ccc707c25f31301fbf087fb13ebe11fe017ff5f8cbfa6bf5f2f16590bf687c547d7c89c45f2e1f5f12f92bf5f16591bf685a1f5f1ac9a3eee3cb98bf583eaea87c7cb9e4afefe3774ffff8cbf4f11bc83bc85f1b124700b17df740f467bf33a49dde032289ef4ddfffa35b5a5ee5d4fa687e47478b46071e4ad9fccae9d3f1998eefbe888ecded81c5d2eaa27251d17061a9607ec78605638387625e90a841b9a86c9edabc5d7dcd45423e124720f143bf3f4fcc43f39100220999f77e7b2092f8372121bfa5e56ffe7e111d2b2f1235bf019991380288d50fe0a31e854720f3e0479d990762f503ea713c0e3c021d1bbf83f3567a3dccbcf47ab0f1d1dbc1c14337646eb9ab9bc75f44c7d6dc04441d1ff0516fa5f783cc835f03c43feaa30784f7e0470f08d3a3f0aae6fd8be8fce81f0dde55cd735f44e7e6f650e36deba29ee6b6bc955dea4a1d9abbfa01fc1ec4ab1fb2071fc423003f6bdd5397e33bdb5d4afb1f9d7adbba2cd6b3f0085cac8551511ab333549f755b0f73693ee6469d98ffd1b67567f0ea87d6cffc0c1e81ccb7f0ea072ec77334d7065efd40f3ad6fe111fcd3e0d50ffe344f834700be7fd4893a37aed4b1b2bb71a34ef486e6f770e37f34d8df9fe32691e407f9852994d0a383e35b9f0409c0a7791c2d4c0210c7b621ec28b2fc11908006f738942e1ce9d1d97e4372e3dab833b7c6c5f1967c7c73bc25ffde1fde92ff57871ebc253fe602e12df93057086fc967dd225657be5c0944e34ad59542de92ef7225126fc94f5d49e42df92d5716794b3eea4a98b7e4b3c85fb932c95bf255ae54f296fcefca256fc93fdd36ddfef1967cef36d05de9e8b044b2c1b26755f3ab1fb6e77e7b0e83de92bfe116ba2b1db8070d4b232c8f6c700f151bf181550dee616295b7e4af7ee8c7ef2df98d3bc85bf28b5012e068d31336ce843396e52331821339c29648c93639c2ae20233751ecf1451b9980d6d1bce5842f6ca23c91fc45cbb024d4d3d3d353025891bfa415384802d3913f899020c5b27c1722f257111df95ee4307f653ae8c10e7e8cdc8f96261091bfa2d191bf5ab6600632827a746491234c89f94beac8ef257ff9e8c111918e7cef310a9a3d51c77f8e84e64f96ad34631e05d5aa18e8748c527d4dbecc978ce179ce4f9b9963154af539494111ec0cc5db122c64dbb6e48acd6572842d414266c9910917964a60a5945a025c27de200b246c415b52c5ac91236c490c96a460c6da84732dd1c2e0476a30842b6e608630a080021d2f8110ae200524d8200833a8828e3b79c150ae393a39f2c513aa471b9694402b421856f0e00b1a2cc10929bc20ca11ca30c50c945c318331e8e428e111c5912651cc000856cce0670a4fc880890760c1075ac0785004304c5043164351ea912fa64a0d9ec084703045922e74661958e08213604e68e2c48fceec72c4428a0da0d8b07328a5e6ad788574c0f31008fcb71c3d1f664f8f0fb2a747c77d88301dc7d15b5176cb25aa176169a68917669a68a1ce4431831c7ed38709bd856741032a60450823bee8abbeb2d7b4ccaf165bfdf452124c29011b675c85070c230dc63cbf76a9f0c492ac8cdd268f11942a5a835f838d87e6c7ff1cc76e45159ed8528331b3e4082bc2518e1f67a29c827ffca6d67deedaa440b7bc22def89810a5b568c252fea476ebd3ca9f9a4b2cc45f737a433a2dbd9d7be79ab70d87f2e7dbffe1f28824727d7b43fa99fc0d08992fa716dfb67941a8cf972fc47766d7a0ac19adb30611e2f4a590ae5f7a38350c1b67bac917fe87fae6ab7c62ff7c92c88e808dfe6a5ff9d0146bde92ef77e583531cbdb59a2f7b88dec208681d0834c9604558a2c1e488051198c833c726453f5feb56eb566bddb48ca5925feba5b82342352572728cd106d6ca4ff6cf6db3b6da6d031b9c59965d4ae7dbd973ca484d33d166fe371b9c0ec5379355edad9c0d36b6d3556bddda47d7efda2d65adf5395c6bddb4acd65aabc43eb3c96ac456ec98da395dd3dbc7f673ce891d55c15cdfe3a99966eb5d4fdacdda512053f3ca6ab04656ae5115e79c9347b4a938c61a4377777a3bdb858d38ccb12d37f72e894c3fdbb66d23e2ed6cdb74d3f468576dc669dba67199ad1df5a6c94ffdc98e27538c36b4ca6ee9e40333d9ddc9edeb7f0d6659d6992abb32a3da35599a263111b9f1b0bd10f919ceb26dcbb26dcbb6ad1271bb6d59779d655b966ddb46b7fbd186fbd92047b32ccb62262595cf7df576e4e37057caee867dfd514a29a3669a8936f18dc8d9b79d0d6e52d20fa5942fa594f2e54729239552e2503ead1f524a29a594524a29a594524a29a594524a29a594524ab78dc8ccf2b3fe7e2b6383dbb66ddb365d516edb6f588b526edbb6454d4a4aa9c41abd4ebef84372b2fc88e30cf4c77d4e7fedc647bbff669aa850e1cc5af36d72d476de8ea993dece8f7e6febed78395f371b9c382442ad54751587f29b534567b23ec217e2e489eb6b5b1be1939fb9bb4b275dadb3fe1432432215d78a9d72df400d524e03ca210fcd0279437fbe5f23f2c6bfe2fe6916c81bff19b35fedfd3610d5b449bf5eff79351f1a94bfe13e7a62e475a8eeb74cd3b44a6936b96f907b2239ebf2a494524a35faae793bf52bebf3af5fcde6fedaf6fedbd7e7bc20fe1b0e79a8d6a3536d4897e95beab5ddabf50ed5ae76779799feacb5d65a3955831ca735d8cd06bbef549e7f07bb2c1ce9649b5fadb7e7e99ade3e654afbd03ea4b433454266a71a91ceeeb3662b40b4d9debae3b839ddb64eb3eeee9bd3edb71c1adc866ca8ed036548a963e944abb341a733feee5e93e5c726d951145fe15d7422298a524a9ffe44754bbeb0cb8d9a9f7d3827fd2964d2ac0e894d76bc089fa93defa6a55cddb20ed5aef0e5bb287f4a31cac917762ec73f51fde5b09bb99b19458568f043fde8b80a12ca4c6f48c433c5a1fd90fb8d66cff12a08fd99290e43faf58b64d39b86c4a36c7ab7a7d3db13cedeedaec96e26d36f26ecdd30c2ec0d5196b3f6398b759059cb726850d3dcce59699e3eafcc35537add677a2241dff12a887ffdea3f2436c9f58be422b948b6f3ae9ee6d91ace4462e61597b71cbd20b2a727d7e80589b05cb1ac79de503524a77dd2fa81bcd2c1ff94c3059461bed53acbb2c745644a294855f33bef7d6bd10ddba7bfe25ec8f6da73db6bbfe122321da20a7b5071ed42d2dd5d95e53b8e27f8000a4354b9fba743c1cefadddddb8cb9290d6514509cd2afdfbbbf67bbe4b7b7fcbef49bd2eff69f410d1671ffe84d7c44b6a3e16f5056a135dadd46e4cec9a10e5988e9edf70d631297934d3f93b753f8e546b584ff427de3707b0d3b8e0d865afe6e4ff1752f3f87769dde3fc75f28d7f7fe3ab44be5fd0bd0ae9516dc7d5fa8caaef2c913ee2cfc1caab8bb5d3c648655544618b97ea675c7a32946f7e4a642997ba56cbbee54862ffc80f4f65f277371648d1d0e7354b08f388c466087c378c4e1180b71da65a37dd9bdecec6f1b92980f27cbe2507a1e0f3673f63b8fe7fb9767b52b7ea4f1730c1aaf526a178db76fbd1dcb72595fafa6c2d29272f9ce3aa50d875fbd93d83829dc4af6730cfcc3b7d5732b5848f65d9d5f903e569e436dd9779b8a87ee5538ec9cfd54ca9c0b0e4128291cbe172d38543d61c1429b0adeb60d874378acdc50e6ae7eb8fd86439ccc3d16926ddcea2b5ed5cf5ff228e5e25193ecba96d73e9c4a597656c2e01556b9e014b6afa55af0c6e23c1eaee5b76d7bd3f6747b6ffbd3969a2d9af651a12ccb32ef24b89f634c2939d4ba9f63cc28da4a86c3ce2bbf4da5f9056d2ad5ccb0b88f2dd465ee27f7d96fdac4443a675888fd15d91941817951f4849338642ee491b9c7c99c7d6de5b78ab5acae68730c96cb7a951bf3a82bfffb4c8f0a41d61be12f79e420f8281cbeca8443958795366ff3386e0b67def06af5f2ebab549fb67d1dc223731f0ee191bd87f910273feac309a29e75a9c7c3bd90a467a8446b182bab9a648acd8800020000e315003028140e8804e3e13c4e23c90f14000f7ba45a58489b48c3718ea32008528a18638801841802c60cd0949068ba1bb76da839b02e56b6c293e7c056f05fb18c243b5a4d9ef0bfcd39f806e4bfd3b3502183e4c767771d57d53eeb869115ff2de7ce0fd62469172883643ea3ed9913a8415cf0332f505e7aa62d2e01b9396d7b7fc33be62ed835b649bbd7c3be616967de901f62d57ece2b5a9bce7eb16ccca013675ff48a10cd0834ac9d067f23f3f32ad0cd262470f5b076d5566cbddc5bc0402d3a8d587a6a71cf0a8410b022d3ea0365b9e9c8caf707a5b548887c04582e31a2f51595ddbbca46cb081673e2430b89b98adcd1a35eaced9bec4b4e6ed719990fc1e56947d2e9457b13a7f4e87122988a33c1b5b01a236b6147f92712f4183f720785891436125c5dc017e456c025c94a5d328dd4210972a3d2f9c57136cc1a3c32ec063d5b448a26283bcc55d1325d2dbdde1d53a04e29d0812cae21fbf6a0c4bab3b9a7187060d860c4cdec58bafd6d1d487ce691ddcf6fdbf606a951a08dd8bc7a6d9cea32c6ac5834efb48c1117eb2bb80d72fc981d0d11755a2c2e7d56c14915cc859e2a601ffbb9b2b29602ad0e5f38125f50d79f5c2e2f7cda76ee775b9526e7966de8d96ef6790fafb641c6e46a55ef47c9a57cc3dcf2d31feb7181c3ed5af2c4b3b38c1668ebb0e396b281ee3af89648a71c199f0a40dac018c7e78c65d94fd84fea42731b4b11796e5c755387f8427af14884f552f9c8076f04fb3d0411380a58da12d7f7cbf5f69fee6d1611430ea18e5f080e80336ae5bdefadf885523794e51828adb05133611bb9474a6698670820047609b6523fe14a218f2931189ce726fc013f6d75301a4086ec283e5f19e7bcae099821000ec279c6cd58de8789eb5f08abfc013098af4f31dbc388e047b7abbd623bb5fc9e55a140ff70062c0a3da258f25e355d21aed15c9194df566e6b351b428fa900a0b1e7cf588a4db0ea456d840002ac8d03623dc1e60e2f077d48fafd4adc96566bad96ae1cfcf7f3ca8ccbdf7f55a1d2d66d59102afc0af5041c789f550370baec1b1087293cc64ecfdbfe8537d91b0251a1e62460c2a3ada1abd4270ecf2bb876bfc72ec1998c1c9077659121f055d8298dfbe6489b60b714a48b65df920531ab6ecfa38a046578aa9d947190f492834f8bc6610f0706ef7dba4c15e5c70db1f6ad95c460d4ab61817ef2e9451310ecbd9f0a16305a0885bb4a37d2127a51d12ff583cf04982be48db946b7d8d979987fd936d647355409dc70b76c9be6bf3b5c2e37883ddd33d0b33dda09fc439cb4744b6b0db15c44a7827261ef17445e299dc02cbd8e5911ff5169160f27556b8a29437b3b283420672d9579f6efee499f6443db7b0267ab71372bc4eb6eff658ef648cfafc9e3a70ffcf0842d5b5752fa131167172d72124398d785e1df1cb3454d00239bafd9466612570d3c55d9c4facb1ead83b5101dcb525929f45f9c2623cebfb5ee84e852db5088f2af7bf94342a9a3642c5eae3b7a9105bfaa6a05a551157c354f5be681e304a8eae8079962d560ac860f8e2d0a15cc430b9c55ab0719d123d8869cf597705175e24712e879380999f537dbe2cbcd23b45d4b42f33be3d9c8bb0889e6229605bfe024908826589560af583dfd5eaf6002088a5b2c5f548c684e4c782b662b8cb64b7bc6b4fca7a81775552f52256694af211e293a80341f6ea89cc6b3e0c4694da1b93921cac7a790b3435df567d5df0b4f0f3c4e809738d784a8555fd0728653460d9f9087f14541767c3413a4d82db0d2402835260f85a459f687adf8a5b00ea8745a4d10260fad5499ba17d9f79c3b8ec9497a6e2b977bf868ab48437d961813e59ad635770e12504ed2d8161a076404cb2384069d757aa47aff330331cc424aed2468ea6a3cd6a10a03ecd37185d4fefe538367026c5a80f7ac03bf7ef1996368e19fd579614db62830856105bf6a03d566e4365a9a17aa7d28a3b4e8cf37371fe17f62eee3eb0fc4c158ba7136f761a45458ffb13791d3b61fe40c7325b236f70718cc459115a9e6cae6b00a4c13f8b545eb32ca99ee906e4df418303e273c6c56576baad460dac9dd2cb3eaa3ab182ebf0cab354e7f797552756c9f94323d8f81a243f436757864b871d554a46d5ecd83e59e193723119c09d1b1d0cce6309fc95016d9ee614a1e9ef5db9f63627a4e2606544a76ce6ac6723e0c9c69a45f999567dbf0b9c49a5c245a50327638b180b25218665f6a85bc0780cabd87bfcf9cb6915b9efab3fa61f0fa399ecb5eccb060a75b4c2794cd8eb8024fb8264b97b63e19fe8f1778b7624a33783214c3391b17a3df7e7bfbfa7d4dc2a3a2e87c5325ff023faabf2134a63fe33574e4a3ee4ce8c2aa16e815f22663c5c1f33ab659eefebd306aabdc93167a48626b45e6ffe2af492be2868e9cad040aa4dd8389ba23ea4d7ed0a9458f217e622a625fe1dc8a18d403bc2c38523c423af0feb7b122f9cc2215b648e084932b1d7023cc074abb62a3a6fcfa29ab115c04a8acdb5105908c4426c1b628bfb2feb92f792e9f0c2735dbeb5ee518b24c1f90e5e046bf5cf97e033425c8e4cfc8e3a3dc252814f95fac13c91a7ea5519a62630369236659120cd5d8d4d4731dd56700e7e50412d090386964ce8e87c13c999ca246eaac0f33674bb1fb332bd507db41fe6c50e434299e812cb76866079daa98826137040318c363284f3c8b7211aa4ffcb5fc6dc3f135473897350b7ba34265ce32d19b549adfbcfe034b44c2423fea7c7b9fb1fa8589ae3efb4cc1bf442da0f6d22b5f284ad38ccfe9d39a8fc25ceabd48634046837dfdea54287ac0fdfb9b41a413ef476c853a2379d6a1314f838c3c45abd7a5199a44115dedb299257375f49b560b4cf95dfd67a1b04c4e935358409aea418c72576b8d1c5cd1ccabeb402fe819913ae7417678a864706f6137469a0339f2f9a4c01eeddb2cd385bf9602faaaa48e41442c53b287cd201db70a5088ea264a055c24508f5f3f215cd83dc1e3a5a0ae6522153f002125029628f04f92e4331791661a73e2115c1e372cfcba908bab803c0701d664bbda573c83b6819e9ff62dc33c7240b284defee0aa6676cc1c62ead3dcb45a8577a1350a8b92b115aff4c92f0d1662fd04fed1815e185a02f168590909225b9af52c02898bab1500e1045564d4153c6ab017789d96fe13d79029493f4c6263ee79e673c58c497bdb3871e51544c8b182d332922a50e004a7278cf04b6f70124631b8bd4842964e59bdf167dccad351768d92c80418800b647812f59b876a1e1350ab978509cc5f9b9c01ad40edf63637a491c09fa064f9a16872000c28851564f2c729c6e21caa14f9dc12c48c8f9900a7cb64533869303faeb02f8d158c8682fb414a2b86c92b030d990e303780eba93e991e84c5b47fab1f9e34c3f37ccb209a58d586450ccd8d035125b69a8bfb44760d69fadce1ed8ba418b125953a9034809d0638ef8318e61481563e5f330eedfb117e0e6ffb0d2e8edbf8711c0ebff53b1e1cdbe537dc1cb4efd7f81cb231fce41cb4f4621fd7cea65fce17b2f4d9b0da65f3e98d08a88f0538e9fd50770f71a94f4071aa28e98ea144cf92c9764818fee4c68f57e41b0b997e444637a303385c266dce5b1807dc6139aaf74b51f73c35946d99479074c090b7655e088a8660f769697c3c4d6dc5f0bea569fc4751e4682148005a6930385aa6ed168736cf9b10dde8cb8e9e86691df83ec63aeb1f6cc71903bae0dbd689e78213bb91d07123cf560c27919c1b5f6c3546b3b5a7430d8062700c07505c787c024011444e6554d81a21d0730b213f8096f01d0296b5b3c4eef096767ac09bd5c086f95e17e6cb63824a4375d2f999aae2cfdace36e6933da4d432d5035ec9a78d8246de9731f179324d81e90ed16d6cc879664db7385ab40e4474873c3f8c4cf4c3a47586bdde80821a5577538c3753fbeddccb8c4ced309eafafc6aaf4c799f195a0002082b3f35f31fbfe78c324eca185f61cb37e5f397ce4afc369cd42fab53dba793dfe60d25d5c778500d4d97aee5c102091f8b28deaa456bb490ae1ae5aabc310d41e16dcb0f8367ac11906d53c274066734fe68cd70979ee27be2fcec5a0fbc4980adee92c0158445e3fa3322696e0c29780d05b2bd4ea62b6d864f23ad3e176381ef607f7af64ff19eae38e89dfac33aa8b97b037cca40ab205b3459d5eb02d10a0890f2f1a1b0eaef245472b3aaf90cca0cbd5e77f13495cdb9da4d9ccf2dadc96c29538f4b8f4f61fa0f1696c2178e56a825dc009e2be8b5d6d7f8fab514b6a3288e209f3aaa8f1c9fcd262432806a174cb77cb3a5fa695939f9dd22b850a37f62ba81e66490c0682f42995773970ba1660ec27a3f7585eedff2e247c86c13150f790d95e77132ed4ba226c40542d3a05e106019f8d2a124b739dc6471ed3a2a8e3845f97d00940adc71e309c7e545f4006f81ab21e81af62333f1181aeb3cf3cbec3b5a61be3b0f6380c6e096702285145dd92191274c7ee1556482060e438564491ee628923c0473e2b48849385ccca3d273edb596146229835415a6d24d268c9bd6b3f10ec3f6190ce8ec807c8bbcf91324bab178cdda1b4a48b17daa74a3be129a176cb9661b0db3083d8c6ca1cf7fd52636758825cb04e98b097d8533677498c5d697e2c0eac667fca46d34a09e64efff1f249abef5e6ba768aa7b68a1883b5e3bd536f9cfb3b08633df6b18cff62ecc906c2faced6eb592841de3984d74b0038e02d1aacdc682fd88d51eb4d9b07cd96110417c697994702490172783548a8e4e11eeff0fd8e9e418e893d635c3e66922e7aa4a4f67ec5d2d047afd6305e8bf7e6cfa27cf18e6ca58557e23be8f57b204656b03a576247cc62bf0d053dffb42942ff8bc5eb8a18606b294660b35f6b0df61d855ea88c2d6a5f6d703e1da11f087e8e74df5937906830b3b13e1e7e3aee0b0e2d0c7449aa1dc48ad80cd4b2efb9f7c1dd0d3277ff2afcc744dcef58bbc958ed505b1fb031713c3e85b4abd9f32d4142bf7aef20a9b2013816c370d68ac51daba45945209c9c001bd1f82458c08de785d967246ac1ae02a16bea2c6d2653081475d0869bb0109c5a158e3f81fb8572c581e74c784300c94ada112d2592974b392e9e4468f5e54c567982507822650b7bdbfa334a52eeb67bcb0651d70676a44894ba5711f2427c585d37259df5f881623b71657824b4ef89cdb6be1f464741c7a72d8dabcc2b9cc401930055d0a87b93584ef78ec03d8614d8a7024a2eea6a1b1958b9c2d34aef16e1efe748aef3d0067c4bdd71c9cd2833fb83c550a91341ae27bf8bbad6d59ee156678074916992a54ad80a3d89f4a1fa68dec50399cd38e72307ab551d74da3bf639cf581e474143bd0d78d64ca99373567fde4da5b22364a14baec7d4eea6db1a20cdcef8f260393dfeb6408dedcb7db4309adb63bcba3d5b24c987ddbc5ed36157c8a9098a6ee6d6014f65978446871abaad7e40a4906d99e17e506b081763404f27b05383f7d19b2e45e9e1a7df4106d45dac56ce7c5440aff4762fba6dc8acb346b057bf52d6f6b5a78fd23723ae9d79c54f92d9dbf9af10cbbd0f833467413547d41ad82b254d7a5ff7051082607c48ec9fac868a84fc1557cfda5411542fa7a3a18a8c6470ff2f150c125148c5e3f3087a6f10f7d575dc0cdc452ec2faddc04c80932be01a621a92f5dbd1e5815828beaa15b90435cdd3348e2b07678a4a7c280bd8aab84f609d5ecffc1086c05c368c6a78f82f5d8307ab10c274e1ada43d8cb1ee740c92dd9dc485d2e507dec1f89dcb4bfad7d7035ebd576e1be842c61e981bcdf3d5bfb1e9df4fa23867c15f680ca19e0c6894830f10e39da436d379da764bf76dff528708cbd868033143feebada75a8a08f1bdcb2bb0b2c800c4d09b6b00570816884c697549e9e34e515004aa697313d544796bfe22410c55b66375ee56cea7c9efae1ba56912e43dd4daa32161e5c481bbabdeee6e84bbae0d00c106921cf50bf0fe2fe88da7b08dbb589ebc611b1c83728312168feee212ad8395e509281e215fbc1eb083323a512f7229262b50389de9492dc9d88d4b19da7cc681fa6cd91e094f30be1f6fd32002c536ea20cf5a9ba1a43b33369ac1a67978176524e4d64ff3cca3e25db2c0c0320fc704921d89caac6e2a90c8accde9791e0843f05193a0770452098e9df04a817da75d368cc188868ce58c5ff07c15f76318ea68070c24590cc42d1196cf8439e305925494b7b57cf7af17acf051b430bdc0f1215d0669230ea01a3803545d533fe321d98309b5b2abdee82cb1964150a6cf6c8d75c2cadacf296bbe9aabaf506d2a332dd29f66e7f26bab3a8cc5fee7de5725ee45062b75710392db4395513366bd4cc88084d53133e36ad799296aea5b7c0e0482b3f402b71faebcff685507121c203d39a1d1e050b10c057580a5535fabebf0ba31692b921b8a7e2524edd7b00eb316700895687da8d0916f0d8ef5bd6e2344f45b7235d164a88f2bbf5affb32a66428db9ba32d2a87e78a234bfaae2759e59b1a991ded006ea99ffcd75b6b7aea3fcddf3907ae0987934eb2103f691127d56be99a7cfc64258ff6178cd1a1f19dcbaf24d36903d0d3bf95192c3a2dbd8b5333817be7c465ec46bdace21c2254f823f794e6189adcbaa0976db1c502e807fa5ceedd756984a5e83c5a09388a08b3e717ac9251b6ed6936c30b689872699897e722757d2a6b270ce82d9b9f85fbf5bb59e9741bd97f491cd8ee25846a060a7aea1441885a6b1bd85e572828552eb4180055431903dbd3bd0ed6b3a6c783748e525249a8bfc987ccd6fa22e1c780995166996a210f380233d90142e4279eeb22f0ed4e3ef0be04fe5d4061740dbe5612a13dfda7a4f00a3384d952441d596a3867c92fcbbed8d22ebfec9ff329a5dd61aabb6c8dcd1925d57576c5cf87b9b20c5ee3a57570233f4864857e80cc869a006b3d9bb8d2f32c00b302eba365dbe7950991449863a09496cfd51d5d405ad5e1e40963fcdd24a32d819005e12c71b55bbaee5dd679afc612288e157997bb8f270c71a56065ed818aea1cc638e44780786544a869c9178a9bb53a0b0fd52a933c3179b6544d2e445c534a32e8a8b2c3f5ee80279441876f1400a1b94e84101769d6ce953634a6b04d9c91107dbd1590ba551ada27ba782378be3a49206b780e528528d2bd1502d2f58c3fc72ed702c54da5ca743ca4bfac212e0d368f9912da93731788cc6a72a07201117347aea3824cb92e0257c6599ad4b944cfc689c796afcb69b2b5730ea5c413364b67f39e620d3730acb3f6331424bf46cdf06f3b105fb8be5643bab92ccf550ec7e73870941fb12b3e90675c39f97ee371923ab8746e818056c4bbf5b926a32ce0ebf043467907f9355b07ac07848faf9907ef9dbdf7a1f577c034f86652b121586ca517f542ac5bb25590a38130538e59098ae9561458cb4d6ea3865e60933025fb232490149b5c7d946d27782fa6320aea49debc538f09740e3421b03b10c2e0f4296e287602e866631dfc7e23ae0c18572c6b62c5be9ee2e95fcb39c1518c764c8565fd0603e8888c8d56f81bbfb5c38fad0eae88ad990283eef4f7b8daacd5298f3502bab0745986b141c905a016e7290a22cacaf9f7e4af9ffd1fa93de3973f12709338d35cd7162733f93a1719dbee42e852f43443229da31e4c6174dd9c2e210626416b9f920fc0867c75c4fff2edc88aefb91efe79e6b20b5904482f12304fc5dcfd6af007d40eb5173f7b2cec98ad90507c39a2a37b20d2c583ffd08604e5ebac542b2c57192e355c78d4594fa03bf7abecd07d50f90a0935007b0c952dc1e372135de69358a8b06b5aa26191752bda698f7861a3acaf8d85fc32519e541c98ff3991a314a7d009d59d3a8ba6b3ac7bd2931d4400e483e08242699cbdde88dbfa9cf24c67600e168da87ebccec1229eae963c21f79b2238779f7aa6c580f9a9d69e81eba2dd557d7ccd49b03e13c84500b472e1728d580a7a4e90167a17e267cbca1acdb8aa1fdc23aa1b7523f9bab2cf3b446f94c4accefee86ac508472d8ed0352c7d43f04c60c9d40e470e442d2c9b4170dab9af59baad6fd559003b09007ada0c72536178dbbd8045801d5fccaed87c12f3ebc3b25732bd4514217e55fd209cae918474550595dc7fab9e21626f3d3db0b5a25aa0059ba4a934557e6d8707177bc742101ce8755482aaa30650bd4eaa90521b75f4f8e6494b3df4ef0275a4444bf36aa02d75885ada1f81f3c5b293f0d3186ffb4d5a984a4bbc07a8913b065ebd9dc008e6b197d1d890ba8155154fbed80aeb0a76179c75f8d6fc7d661d76b805bc015982d4a90aea724a0d46833406ee902ce73e90b8540cd9ba95fbc31416cfcdcbe4c486ae36038e0eaa947975269edb04701342bc0409194cda9b37c3cc55810a385422cd2ee3128da202228657756d3124e09fbf90eca063fff1903f0e237c43fed9115075fad6b6a3f01b97df9db55420058fe40a14d8b66b4cb8ccd090e00dfe0bce9709560a2b0b54e6d7148f95f203790f6746c128e5f333715cc6f656194ee1bf2feafe347808c2913e822ebb9e23a00e88197cf551765c31f37969160737dbfac5869c1797887e6c0023ecd36a1466581ee9d289a85737aef8eddce39ad75f5c78cf6bb262dcc78c366ae4fda44a75ed00753fbe0b9c1ccb43db7b2cf46294398f6530d5a2a3d2efbee20a589382ea3422dc56b73bbb9b3eaf0a073ced86acab02955b74949d7a6104211c3c6a4552901cd647a17bc5bb64fec2f8e34f7299580dd18244b8d98a96cb32e11a1f97cbed72925de3f09e35e55aa8d2b9964e23c05ba4b84c031b95a532c5d48d154a9ea2a8bd88125832f1a2be74ac5ebe4e2d8b283b7fdad8cb7cc4e9259c8249cf836b5c8649855554ca4684ceb6a80ace23c4a00eb805791db427e549be3b407ace938b28def3a5a272128defac82ab4f2c6c6e21732b036a0d896a1ded1fa7b46b4086c20290f0162157767b5ed33b7aca860e214a8bca418c8b2ce12cd42520e680dc877a20f9d3e641fde2043e5e8f355e6819a0136b18f90745366ef6ec94721fe20d13632dc04eb79874efe109842d037e61cd72af54b56f748d827c59f9faa4c6a806b94d5028e83d2a71e1e87e03827800099937712082a421bfd8661f45c33744d05590f5848881374171139c17c1e9f0eb18466a002665e8e43951b85e5fee717c5a3d4f74986a24b1d7e593c42696368d9b392831ae306f08b12463ef09edfeb71777c90d76c7724796cb00c4158ebd8b8318e9a30574757cacf40e47bccc9956f54ab4ae59e5098d3473319d5f3c11cbe967f71f6bab9e2b5b6d8b6b5531ab9dc10eac29b0188d32370e19ed510b553731a999485e5feb5c27eb7b4791b70d1619b222d37598a4df2358b5451664270a74d9c681dee21c82e4b5d21476244994a1034e9991c9f59e727a65034235d705282649f2e9c0df41ebb062761e73736db24ca816b4de3ab5cc10dca82831e47bd492bc43f36dd2feda7241f558a3ec29f6c309db0365269adf862464e024709bb3b3e858222d0ad95feee07a7360fbc6a105e6ed7ba3dd3a74a265adcac2e98c5c57b572ee4120e8a7dd23072bba74ccea16463e524572d49dee502332221e2202c7db48f134430249aa92c804c626d6fa67fe0ab2255f103b41b5390de3943ae377832f81a15aba94c73ce146ed0068603e03b4bfb2a51dcea44a5e1ae821836317ab65f487312135b63c68a5014b63393dc65b9975c891ff2a1f4b2ae0805bde238bf201e652cbc80509e811b39dde7ec77a6c65f39cebfbc015760529968b7b7bfa85f4f1a68f697dd9d64959561fe0b2d9d5113252002daeb2e6e76c480df9bd59179386c78137deb8b5e2593cd86337119ff796ad1891ecbe39ce77c345da847be7ce9abe6487ae155388edc218e3f7b7c6ce2071184b35056f56d288163a7732b0540ea3a6669b2c179120202bb70c81f7b9947e610d0cf73d8651d12410a3d23835378a3154508c4843ae657d9b28cfd4b27d813821c68095db5bf4150b0151b05e8c69e447b4c461603fa940b474b688714c1c568181f862506db2d37f85b94b5831f9d9b9d81875f0a744a975686b6a038d996b9b7724704ccf421be86d05f14e6c0744cdf26ffdaca2d39e45894e6c39e2789eeae3d594f8d2ca97f5fb888a3268e72ccf5ae28a0f41bdcbd9965042d8ed9aac2d31ec2fd75f25922821f0ce26d4c4b7fa5ed7c18e2d45112ea30dd869c7d314268e0037ede3cd707694f6affefc29d340792f0dc4258aa9e66c709a0837bfd6ed9a79eca59f12a87daa4fc7b1b6c8d0c9e921727862b4a5fcf31913d25f1299d4251c680b57cd1406803d0f08462a8eebdfa9cefc88862ae83058f3d63ec8a8eba8906dda103f99b357c866764e054737000cf98a8878487a1686890af7288f0c394b8d2473b1f35f15b05c2b6048615757ded6ba33bbf514d719aba099cd228d72d191a28c92d77e317784f430c8c8e3a9f34ba2153682c540d341da2a9fd1e2d7ed1f3fe55c9392fbbe8292b1aaac7e751994ca305a72a6c42a9a4c0b274f4446528e94c53055a5c711fe0c5bbe1c1891f422f2288308e49b00b454eb1d5b2492883fb1d9609466cb3ed3aba5cb158683a31c1103483053d02de6d6e90e6ac46c88c5551854c42129eed735c7fe04bbef8eb8c1c6e80cf022780cd5c6a9b79d572e3e4f83a386fae4bb97c163afeb230fd714779149540dc620f1d698c4d355d5d222186a83b389660e5ab61e6dcb89c90149a3a627aa7933df1ecf28d3a8dc45a88fcd3f278fdd7bfb96ba5d3330b2355b37d26832efe8b63b728bc28e10f49c5ccecbcb0717125e793881513acd50fcf92424ed774cd44d90e0768fbd44a7435bc5a89738ff5cc02841062aec9bb3f5dc19cdf29e2b636be12f0ecbea59a0e45fb519e143e8d705b80db258c142083ab183771fbf9cf018f892e2bd0f9ffd7083b84bd0cfb1eb2cd97919ae057bcb7c380761b6835582be03add630de21129cc7fa3c08d722843919df5840b78a713fb80de1232c54890e149ae6d886a86701270cc293f8389e3a8743aca4967e069f7ff446b12ff57f28160be70f67b1327907f8d29806717f742b4635e118f25411eaf8080edec40e5893e02980aef131535b9791e1516f9389a53b6260f6e82edcc5d6a3a05003b75bf942da69256d18bec8498146c27906448f71d63c4fd56efaaa3b43233a70f3d78cf6f8980e780fe407b9a61b43ab99f12156ee4a83262d99ccd8a83920c19cb5b5a6b848781c8860c0ec865ba6809142229e49f4d1e37091eb0cf2af2cecdd6da1a13a2e70090502f538a84c01cec75614f41f0f044f45db02ce30bfc307e43fac0a79aff2d7169b2ac3bf3f0e26685a945245db24b8ebc8aea78392a36ecccc677bba0eb512159cfec9a11d71421bd691fba08c7e41e23e70adbc8be0b0657858702ed5eb0bfae1c543695dd4bae4d09deace84b6d44a688358be6225da463c466d2a504fda5d526f7fac00bd5bfd123d2153e15e3797ab90acb78e31428f8019117ab3fb2fd010089fe9bf0614381897e0cea58e3e6ca229a96327ac9a1b711305e4bcbcbc90515b1803e7abb8498ad0f15c565ee05e6120dfa65008a376e5ee4a1d3643485f0b6690f8a198d613d181c08b1ecf641fdf4bd16802b5055e2423ec2304d1be1b618d15941dbb335e5f647807c58029b5b240e17346647d0999d8ca0a3b898d2800ae07d82a64faeae884f665c48c11fd0bf0840086582338a0fd28699fb4b412b23218fdf9c9eec8844453d4a8f240cec00568760fc89555fba1c7c800cc827ea9df0a30082d3d37fd6aa30328d823021623f887ae4a4792f14f9bed468aa3e9bf10713456ef6925f3d3298e60ffaef19d3c06086fa8e21136b00c223613cc1eddca2ed384fde362bad10696aba053763c79ee88affe5c8e62423a5ff9780a1b9e40220245ac703f02055014a4c26fc89d4b2deab5a1f0d09b7fb636b83c0e55e7a15c51ffe88140a501fb4a27e4f24ab0b2881f29aa8562832e9e26b6e2cc0a70340f286b0cf107834b3e8f6e4b9d6805cc58823541dda542f892018a452ba049a140812e07ae44b89c61973f399c3c3675e82fd33fc6c01c30ae3e2850306b39d3edd1491df90bcb9c6f275c834b2f0564422b18cc0d50e9707d7736197a4f693d6cc0174f8423fbd9878070f4367fbbc7bdf7dc234d03a854b0fa2ebf6592df74dd9b2cb507550e88a8257f7c71532ec9420717fb128235e3754ad0062a57d023a90d403d0f356af21aaa0d4c3a56bfadf3555d9e10014e4013d856880d61ef6e7df83dc8c7aeeff68e04d063afd5bee8e497f7cab5263711e06affd1a0b2de6be4229d4c6c9fac68343108d9666ded0a61b6fae5cfb663dec49b89994f0836aa695082761a544200701a7f2153e4cacd7f38b7e0761dd2cddf04d20982e8a85262aa2948b56f56481306a5dc3dee7cb9f75896d4519f871b137349efd6ea80ee6a54086caa4f5f28f847e76f26f41a6cd46bf9595d4c3b4861869ddc417fc637b7b26cead80cf83f6f84e65b5b5b7390d28f4bb6e28fee3f44e62c4bc9d1eec351fa7ddbb756d55cf786ec84d5dba5010f1c8cfb1003345e7701eff32e50779a321f1d13122bff0c40c42f6129a82fd24dec5428398bce0225bf26e00ca8b6034d496bbf457d297ca0018b5fe2ad3b0478b20188a0581bc10ca3ed9eeca680ffb537c9c3ac131e858feb35d31aafdb67a74cf21bc7881173a3009e1eb07ffcf7a8603f6e18ed6f1a9711767cd598f21f031c4c1b171c2c222abb455413d1e37b9ec00ca380c70a96ee06830b50a918f563c5b001999cdc406d9b797d2a07486ca8763a2c5e9a2b87153c6c44a2055ebebde3ff4ad06509476ecd3621039126b95cd9357b5524d2eb2db64e769540bcd8c1c713ac42702b580c52db8805bb9461d5164c829384187e1e0d6dbc6d06b24c802c1fd9c3dbe5960d0c960522ad3150c05c20130b51b9cf292b7d98a4059cd28c4ab6bc459a6d2b3ea65d008c017ae62dcaba4a08fb0f002b4fd33638c06b86ad129f2ff9197e6638d966835c51fad115b0dcb51ed2949ea8bc2565f53849272cb850179d195443026ce55ef04827bdf626b63f9dc31abdd62abcf4f9613ed1e8ed4a2e8119de3a55713c673ddd1927407e9971ca27c6e1645a4a5cbfb0874dc0e453c5a0f0900669ac2ba22894e303a8be69b3999ab666034acba62517733d0c765ae6deea2ac82394d5fb51812603c20cd3d4f85360345ddba8e9a8e72162e1d936d523f894cd0e5a477a6b692270fcbfdf354ca276a6d2a15057b244c95d724e7133fde3401e2c8d7a6b66edad98b577eb7a72d008ccbc96d199b04f258a0a9ae4ebf36920cfbc35c8fe6aa00f330dc29431263016aaf3cbd250d7f66427257ec99be40533854972228f13bb02b31a93b9f1c54d94d008666fc283cc0a36af3f737427fc834122cc069f3d198b454a176678ce1d5841a7e36fae14b6b72644601022c309e0a24336db0978eadcd51152aaca9d0e7ac45371fd9d1c5b1fab7550130957c7a10a7bc06498426e7684a2ee1d6b7991b7632a0984a78019d9f83a5b92e7584e8d81e47f8e85a5a68928e69f5839481358e326df1bb33634a3e558e59833a6cc0446c2e5347405c77c011666be6edf18c57959b1d1c65c13430acd01fbeb543e3200c5db74b35c6b6d1233cfca28b4055a92804f108215449249789817b67289699777b21276f23b3f0a4bc94a15e9d0529397a822012a4863c853c8a77d4e93fa9a0dd23ae1905111657c7c70247dcc3ace63fcf101043c3033900f80e53c36423e809af3586ece033fe7f1b401a32793a2cbebd19b784a5ccbfd7c26e3c3abea2ad03dfa3843e26aa937a7eec8cd52fc46eb225ddc036a1e1e098db9c88fda5ab3e6f685acb8332f1024566b77e435fc44d2375747fc4db4ef7a9e46095cf216c4907df14d7ac1dae5ece981b333d83f25a30017e0c195fe813660301e20a3dcebaae66019873464899a4064bdc8b74a2eaa74ccda118efdf0dd7309ad505d29773d3a6588a019ac1d8263eb0046501739c6592c5dd517159b0ac949741df2d48dcda96c03d060d4736f93abf86becb6cf2bd5e0c96d432b188b3bb6eea5d393614946c0beac555644f7dba642f0819cc00dcc8dc490ec26faca1f9388ff145f177804bc0a102d0e1f82f113f310569744c54218d8de977281c8fb7a575dda89fffe190dfaceab7e5a36ad7d13b15955cd12d056daf3fc23a0eab3473faaa4d1f4129200fb85b506e1a575dba148a1ed2746f8ba9eb94d029198ef3605b2523f9ed2719470e0210578b4fcad5491486c37a8ac5e85d36c702cd139133a7a8a1683a269531e240e184fd2989f89fa59ba2c8df4e74da30b9845efd717da12eb95b546fdab1ef889448f3e6da76d652f2946b146dc183c28b0685179a36428cce24c1c8f2d095f37bccbfe1e0f25920f56ee1708249b2162d32e2d81102ebb9ec539fa752851e2752707871b4295d3fa1a313de3ce51158720caa149a47145846a17e54899dafb3da523a07dfefd25418945d63de1dfdf9730a84c78b1900c5029d4c2e2e67008fd259b9a624e443ccd7c0d286de921d28c8190adeba961ebd8f8987c9300ee26a1c8f5c4e4cbcfb8d2d435d44e16027a5c4b76dfa0d565c63197ca98e3d27ecb5340408da8b542fe2b6afd5010647ca4150f384973709ccbdd1cd44e4fa799a16128d0748d75478b15d2ca4c8030245f0e0b6d3e531ee7e8504981f419195dfcfdc78f7fca8330e04650b62b3ffcfa490dbc21e8d7995cf9f5932ae043d05233b9f643131022ed7d562eb19ac04e02a5d4cdb26a94175e56b146c669aa00309e9735b0fde28063e04aef720670471d2e20af5cec8ac88c28a6647c2907706252ae878fa4c533c7ed2042f9f086024f32f66dae4887558a5bdf6b0a9c415cd40b972acc9e5075f80c90d81e254d95eca02e030451f9f073e7f8184b66d16170429abd41101d4502808ea3018f04d280a882729f2b3f7c81497f21124ac65c3c9ea0f3d55cb9e7a21903e538dcf386922bfb264706352a72a376416917db4ddff2d04af3042629ada8899b3e8f8ad8defa432c2dc630aa338345d0ccc037c25448dd3247aa4e2a7b9afae354cf0d6a9a63a6ae2263d6dd6225f66b9ceef637740376fe0deca6cd858267437513449fe19b4e532a27b6e53e1830a846103c63e244753ce62aeb6e65d5639d3e5fbec21884bfef887c06dfc2ed1ab12449425479ef01baf8d6ba2f81b2666d6920f901ee8d0447b714ee8cac5cd41c019fabd6bc696aecba24266adba506026df2d3f66ee33202e261a8ffbf27e2fc0de9d33b34f7491c3cdbd51193736fcea50904eed055c8e449d014157d2937e71a0e5d789b23151905278e6dcc0457864f143c0f1ef5be0e483fe9f29df7f56de4ba85d95d31858b7c425f1ef521812b4aa17f60570e5e76575c642d5e79d37e3742d413db2e5623f6cc7fb77748004bf4fbfc2f449a18da9a6601c3e73ba88fb4f3fa5df3558c41e2c26c81a24d217fc6dcf385a304f74b83cbd366296c827a010db606f3f9cb8c3f9b23cc448cbb75570fe8e8171ee3c45035a5476d03b64b8813ccbec4a2a8866073ca3fddf2a2d8397506b1bba7ab4e810dd9eedd6c389fd0380711b73d38670953021b38017fa57488d30ad0d1a39b0010b02de2a19741da60dcc79ea9e83bd537dfe7101532a924e8e4ea3008968c106de5e4023e705d6cb8a111876fc7bdf984998832a4044fa73e5c003a62f74dc2da9a80c440c43c3f64f2f810707c0fb136f9ad7d75156f48ed27d27531e80fa1d95e3f9ef6f41ee1c5df1d12a05e64ce695ad44987f00f026bd4e0643b24bce521706880ab4f8961966701e99687507a48a1f41037d1a6ab43dc7e588b860b9e6525ce180dce889a5e5bdf786a1ec9983e0ffc5566157022e78a2a985ceacaae1277a5950d46659a877c36c4fb9b41ce507974a39746a1f757337c4b103e1ef8aa6d920e287fe394669126a37ca71e05c335c54d12e9c7a06347cbcd2e12ae4caabf46dd8c5e8356ccdd610996caad7fc61ba4b0d8a7a7b678ad7daba0f560b46f6751954ca541ae849e4205bc428b9e832f278d53f6da1b2c58128c060a2f8fe752c6c31b9b40291b3912de4391d1d18c1b47e23ee85a0385de6fece1c5cd3265e3d3d0330ba4019184d0143d9d5f9f3463faaf5be6d381268a5a47e0ed17dd928e921a207afbeedcd0e966e83540ac7c378fe95237552e329bf76294bfc01051a4263c6ab83c878f6612516a193125b878455fde74e0ce1b3f1c53c1352ff877a704579c30faad1d0d258e62550dc6fbe7fa9c8fd9bada0bbeab63e1516fbe92027fa002bb03c51628cb4a9aebb96aa3768493f9a7af238a6d5aab4fe9033bf01f58ce818b4d991d31a36d0afa3d6a1debcdb99d965b9d47d9784a0ab4071accc05b4bebafcec8dff026f6daa11f878d254b93107670f22909e7bb5721be03306b15a6c48cec61394e5d7a77326be2d1d9fbc1d3136d564a3a5ecb196a36fe325a07ae35e34a4695eede75fdf1aa96f8d3e91ab7e003d63791837d599419531edef5c8b1360c4196c9297b0ed2d8b1a843dceb6f1507e87fb6a65f0d318c3c0a4d4c22bef9660fb4abc18e0fb2d89acbf699fae7fa25b11048b18123d7b4d2276502d2633e8e2e61067485dec889d5ae356ef5e2dd75dd3c116a53b04a8eaad23492e844be1a18f38c815c401e848791a1a409f4c40c8c6af24fc69a44f087ec464c8dec34f7324396df2d64981667808abdb611364c0976aefc40644a6ce4361ffdd468b9fa620747cb46f45273070f7a64d80cf085044edf540fee6c1af7da1b03a04fb825baf4362b4338782b76a7bfb95d01e4c3579c4bb7c8c21a70a90c525d7ae903af558185afdee8c08e23e9cf1d4cbf2bbb93c4fa48d4d00b0f5d848474d0d0a73040943d71e4d3b32577a6118075f3aacfb0c1b088732ac255fd0ed79ca57d29ba0b5c1d0db8f760baa446b11de1a1982d76e4ec20f26ff036502b618aff2033e19deb1cc16ace039266f21737830114181a03cc2bfaddb3fbca2c11e3054bd8d4caaaa631672380407dd65fd16063ef6c993d2a05a4554ec7a32ac7256a81db9973a9211aade576d4ab9066c6422d3d8f4b2a5cbdfcdde57623c252a838355b978fd71131b961caedc356baf57eea5e7c832367bff0c59f0fa23c39c599253143538924644eb244f5db87d17b937421a88dc39484ef6dbd2ed51d8476c5834b81bb317eca2358fb426ab8100e94397f945543ebb2ef61cb4aa3a6559f44d52a3e3ab8ec077881ebc6a571a2a168a036e0ef9e973786426e61974239f2dcb2d8b526b4146f67181d497057f89cfe0be9c78c6e02a5d313c9019c6fd536a5712963c18045462eae57655257168b4d0f42f9e5d013099394a597702ac9421e97247d1e9d80cc936378d53438bc9c255a32300800464f71b6984ea28be40d44528a38b265969a0678f3028c56e807da5de25a8bb0703965e6518789d87399341a4909e4ceea1e1a9a6fcca44e8af31de81bab8d66a59d6f0a34d8559a3867fc5fd3f18b70818019eb99c8d391c35f13aec0b4ce5c64cf7d7e64334dbed2ab7d8916c25daf676f4f965f86f3db3683a6c191261aceb43eb8f727531737a03022e80bf297a9664f0b8690add13138a6e90555e4b78acdc65b6746e8baa8882a0a10e7ebc130b70072cc76a298df4d488e2e60667aaab0bc8296f55455f10a6a2458f6e62b030778059e67b4105525ee669048bf22036d699b109e3f081f35943d53f1f578fba2f7e5e5d295dafe73e74cac410f35156cd7bf81024a080e67fd09664af3c97892eb538b196e427353db2078bfd8c96f3f4fc4e574e09e82497856731d903e2764e6579f48cd65abe3a656e3062451bf2368c626e9c69475e9e3ba744df881cc8ee5cc3740525a54cab0d9a5aaf458539bd2ac594fdfdcfcd7bf0a16b25b7e7dfd7ec8d7df3e51274a8e70079b8abf5d58339c2cf381cdda1e40da554a5a958eeeac09dfc059b59be4e2c9bc65b35c0a6d9013ab9d3de0bc9bd2ce9ec409530466d0ef9cce75a9d7bc8731115156c39720e0bbfabbd2ee4d738fe3987b2c8c267d63fd279383f3c3b6df58e58072c1b91b3001aff767f8cefc75004b6208844660961f4b0e6609bc7cba5617867dd7cd55bada1cd69e63e3809fad4280e4d4bb58be6a6f57748cc52a34398725ceb293e7eced880648e7439af2107c371144801b3c2d7edcf82173140e3a772d42a5a7d4b57212f62341220bde45aa2b923c480774bd3415faccda7fb8820d70ee06d0c23888669d384b4c34499c5f5cff5b06cc42626be3281753c5ee7495341c49e487f7684327e43a6c6950f939fab60180b2cf9e85e5b42d2864705ff4e42c184349e85d9959f0a220329980bfc11d353a4bc13b1055a1b9e838a8bd3989d52ce006043de07b1c8c21666beabf98766105bc5990e73806bc19dfef82d2a4e76e6de281395e87c637e27ea30f6b443b37272a5a5873aef7e2d601cc6a886d562bb431e0da62cd7da61c5e65ddf35ccdb1d3cf49951204908aaff6b5fa59e8d71581af0643364eb98603a43c229b5f519a172ca61522096df91c0636ab6064d141badc290fcefd6929b51825d19fd51417bea3dd0d254ac5ef72e388bab74a51a96fc63f7e2499e47e938070152f22145069d708168e387299beb510e5ce2a19cfd2cff146f97858e312ce9254c3f950a94fa967cb37396e597cd87070763d0f5ac3b3877f214e8f0f8ea3ff18de031b881b287da9e11161379ba4e9a66d734910b259d585886534dc406bd67e612966071fa9ad77135454ef86641bc7e0bf40190b4c8fe27e33d3335cb5cd2e09c32cbdb88459460cc77ff6ffa833890907f777d728bb01925028e3d2c184174100e866137b6d1158d5ef0ae4f34c015696f8617f625004e869d028d6632c5f13aee47ecc633f31f8a1143e68df385b269ad5c32006543c1b855c79d247e0559972758129dbe0678a37dd1f563431e711736edf0dea14a4f9d7b27d46bffc1702b568bb9350f32465f9fd58179215b038f7a5b85899d144ee3c9ddcc5031550a70ce12b417610a6ced1c62bce574620a2630b20d02450c584e0b38c11ad45cd156aa017bedbf77933a96e1fb2afd28a27156bce1b5e8c1f90ebb1dd8e7d9bc299146115e81f5c9dc54f918ab081d81f39d0444d4388c89a86fe5adb8718462edfac0a7ba7f91a5b107a9c1449af53e35e8314e95acc6e3246cd1744803943c6b3178b9e1637cecf998724ba014588f17902b919130eb18284b9cba53a5312bcf5bab2806f91fb40ead7b33eec62163e65335b5224411e8b71b087f7143baa4e872eedbc465a80488cf7a80e74fc591819b8efbb2275d669923a382656051a4e0936bafbea3b43866b687b6a1147af39121d31a3bd221200e08e716f0f47102ff81207d03071506ee003b1ba7995839d1b118db8787278c0f42311d568976435b1328ceda526b6e3d79a0f330b809ee683af7dad098e425169227af6ea46f45241a32a5727209a4605ef934460deea6d61e021e3030684ba32fec1be29b190bc118bd420d49883824a140a92ac41d58053591b691aa5592987c030df2b33dcd5f6a6c0f1c26a48c5286c1336249bad11fdd79aa0e047b5cf486c4ad59627d2326721777a55bbd4e3270c3eab52b12ca2aab7d751259fd7ddd7284fa40535cd249cd3886ae7f943320fd7bb820db584eb6df7a18ae468043de7436d4b81e37727402086e1d110eba0a89a85873b43e2da91e8a9f0adeb61e823de62a2c6e6492ac606e4b46cf9a0831c3aa9078316bc017a5b39b91e3fe9daac8428bba097f89c3d5d7d8a0da31176cbebc9f98895d88be37ebd01d5d699b4f9d0fe3663e4df1b8b29300ae974f01aff8a72621e80dcd68029baaaca3b02dc4fcadd20a06f93a714cd109bcfd093f8066815f50ddbb60ae03925bf8dd38285e4525f63fe9b4386a8a8d2c769cdb7df3e695f86499e991b43a98ed4a94eb02eb402bc38d44955e211e80867751330dd06e16850daf2fa5c987ee565904c4d7a0a498124432750a29f4fb2e57118f486f0c65a63b75e50bb1ceea823eeb44f056ce14fcee7818c4c30e837c9f13eb6d23d11a914135f0a7db0dc0188d8ac7228bb056761616fec95731684305e182511726f6b0e783d6c8bbd7905eb61fa8323543d51305241b19e3a20399382121b6d67d1b7d18808cefb49bdc5aabfaa6cb7c5f4a2266215f750b65d280b244a99c14fd81d36af1e1392e91fd4f80600ba80ced98c8494ec335bb071bed2292cef1c87db86cf21870c10d7ef630e1856205a7c2e10a8c37508a617a461162b06eb57443476107b87002e5d0af9fe911a630cddb0ff51906fe1890eb614a914eb0e4d723d3017d14fa7bb8c67ad94343efe01091f33d4d33db7f631903ba836bdbe0f55d7f539e33de5f2de81905e14e555d5dada3ae3fefca9d269a4b618639e3736d86365db5a61dbcb044e08142c9962d6f9950f8d803d53111ecad59c36ef112e56b150bc47489da852b67d8c94cd0c9f8b7022751955e7b81c0e102152c6667c14384695f3f630e362a126208f102877d0cde9879d078414b84868b63e3e9fd79dec09a31116dc117dd9a03e9e9d93c0409246ea40438d79d6eaedf3dc375499924535cb8a0b6969f89feac312a2d1be0d50f026d8c6ee4a472f34ac0f33e1f8e578f3c7a9d67de147f079d388c2e3eb4abeee2b30662470bcc5eb9d38a8f2af7707548716813254d3c82f395e7f033923617e23db40517dcd97e9fe86390dad44782faa8bb2edfed90426f6c45443a33e9db9342c185ae6f5c9343d2d747bee07413d159c33072cfe53b96dd52f94b3af457c543f0ed2d8c14af2f6fb1e6de620b732af7e631c2fa86751369151427ae0191159f7c7a1f35313907c6fa5e082061fa2f6e967d09afac08cb96c683337067a3e17ebe5382351d923957135d54f86582a6a42b9e0fb86688cfe411b007ccaca682d3c740d5d8d76dc788f1ecd8e2a583cb1427a6d125706c0996f5ed60effca0d618935dd128a8cc5323d95fc7d13284c08422f206f8a2ac7b72d20ebd1e7c6d059c2161b4257e9396f70ae418dc085b0232bdcffe596799a3f00bc1456d2c5509f77482d4f5f794e9dcf60da627f47ed91794a9c2c8d3a9df46cba1973674062678735f722e17c42dce130a0fde13507060f3630a6b29544d8206d86370afb217975238818489c476d96feb29e8643be73d9624746de06b67ac6f39bd0e6383bad0f7fca649671904d61493afbce1e29cfd350b1c6d715db7b6060e9e2c10b1791d362c7d40dad9db00d0dc7f2a230c2af4325cd2feea11e0f61e77d59ac1e04cf13b26f63931b50daae90b141acf860c25873cd6f929fa0f6d8e8129daf05de0e6ef2c3e072d0062fe8c08c1528ac222b204d90c3e321a8ed6874e0214ec131189919f2c5afc007e192ea09380119e278dfc644516cd8d93001abf0da611a2bf9001699d4208af3dff804f90cd88c61241bddb2626f5d571e53f220217bc2d430d13579899a91f4981075c7645d6f2e983532a64b326969136482af8be553de4bbc711619309e3bcb033dbd634a337e77df628cd838704ec301e091e307ab4bf91aab3c0c74a020bae59872f99bef14b43b6c602724c58d87043b6172691809e2052801e58817601612619e85b29ed9ea1f35d96c771115d010a82275e5b2824ea8bbb0b47441d520edf9a21431fdefe547b320fc9db922f9a29b4d2ff7d9e7b9381101d8a3dc06e5ea865946b74e5f1caff2dfd1238e27f1314e23d89c1e7223b1968427910c02a13431002eee61cae8d23c9015e593ea1d73838ea59b7116c90f59a5a007da9882c85ac711311b32e9519302c0fd20749fe12cb39b97b4820c2c00934f0d1980cf4955b386f7e1aa913594ba4dc15cb65380820858489863701173b442da822e03fc2084933a71f7e2d001dde561b33aa001a21310e47a93333f92ae14ba65ac8be05617e903aff8c10a08f2b4f6ede7c8de504b68b8e3523fba114039ab503b5f7059b0f9389a62ba7bc61d5b81c3e33f428b94be3d9ef93a726e0142612b2d1e839d17890dea6ab7e913d3fdd8a900d61d6dc8d0b48e3d4fd98fd16bce554bbae9b65fbf8efc89bb6645e0b8209ff27f151b15715f223f8720158c675e44e9554b69aba54e1caec9b167aa2b86b7ef3377c81ed883227e4ea043c0588aa9ba27b59d49058edf21200074cc928bb0da279ddb948439534cac70037a2079c374ff34aca23e493847a200d64a714c8ab23147366e13b6185cba7647a096ec1ebb7a0b6eb96983c5b94115c5dee164b8636781d335211a699d1f4b396b6a960bc9146198cc94e29b3aba16d7d74038fc02d32864388fd158f42af3a24606e1e3af318d09ffc37f96c372069b4692efa9e00c6826b43f6546e5f5528db4a7daa22198412df00663f1f30891539589f08ea70f97e57042d7ec3a49d61c914d78df3127a6ebc0030f1ad918c3794b570a627760c045cf88585e9ac7f5e51cfbee18bc9a50c8c3dc8a392ccd425bc27c83a8fbfa9175aed1f10686301a8af789ff66498396c27963f79056820e32e2f8aa150fdbc9c007f5259988a438e4ed82c59aed8b637401c17b04cb1614b1e329698126932a01d0d0785e3621bd655d8708b9402d60f7cdefc1add6c68807406977c99c99c11c1ff01cf5ff375dc18000083c7da03a4b833285834cdf427c05a34d4809595de38942ab6990b198413248aff4a6dab2cf758fadc3fa4bb0383d1c52c6f30752bf448eeaecff93f6a3580a22826ac7ef50ff9f96614a5614de7a7d6ccfc58eaac8e2c65256a8950c2a6a567d4dfa96daff3fc089b286d7676dce01aabbc01f0fe1a87fa0c7781c5583b4e6888d656340c3bf169c128c74f30eff64f9fa55f00dcac8672b02e68281c500ea1a7b8e8bf963f65bedc61634d1033f10a348b5a7ef8aa82008cfbe131cfbe6b3d0c87f8974d85352f16c3e055d08d0215becd700758cdb523adf2c2701d72e40ffbb1b054afb45cd19de6866584403c121cd59cd2ede6393e486b8327624d340099295aa02977318cc1247408036b9cc04ea06d76353f5aa624d4aa6f43e86d09e0ec514299ecb3b154d63970774502d32085891310987c5a8b54091ad4aed345ab4f5e1b211e7705f351dc9c93fdd8ebf4b266d834bdd0eb6b97af2ad61047e834941a8d8e93969885ac1e8bbcb057d3e20060d389e94b03964c1975a8eca07fb8330307e7939854ccb46b46f878382fa066e348c5ba77e1d3c9059473668d09945585a94126f5378b94c2607feff8aad81fb0b732c8f566dcb097d3bed70f74e7b7e93e62e00caf5a2f63918b607a9124055056ad3719227613442aae6c1ac09917c5845e411d0ff296c98e7b4ff8a817820de9dc36b299e812df0456bce7f09dc08884ac94baab0bb88da3033f8d6a1d57566ae5ed9e8d6241189414c1f0a0fb947683abddd7530e0331b71d6808b86d4836fbabd23ab7a6a26c89eef4e9feafb5b76df8f11f27b4ea6fd1e95d6df9921ff7d359560249ba65aeb377d40e1505dd816320b927cf7818a5544b0f173eea9052ad097afdcb467a3a4940fce35073291ad1dc07aedace641530091870211026f1769fbda296cc162d2844007dcf8f66a56a490f058cb654005ecd3f08d4a542ce85556ddfc15622ed7111b263e3791dff7e8106e8998f47e09a75e7503fe01a83c71a8ae7bf07c4def77982f441e5d6987e4581bc50cd6f9cdb0906da3edfbac348c9c31e3c063ec0077fa823ca1fa3d328238040b2a7f49ed28a0fdf07f29e40f8b2c8289f87f252ba43c5fb2b82b703699948d862b4cbad2d94ccf792a194bf831039a4368831b6283fca9c8f328605f53f3149326504d88b7397a0eb719cb464d2030309a0f371c7a1f972196444908c06d6414d44e3567f4c52136fb43b833db917c6894b3f7709b8d29e4fc4f84c41957320b79d880c657225decb2616df20b5d17446f0004e78cdab5e04ce886c1d16339f17d268f3479d2436560274dae73aed87dad1db40dd5a89913b1d9e10de492dff7c627aa7e50ac0b828244dfdbd71e6cc5634dd49c7f6bd137e7e6c5425d4678f0dd165e38e0800bae3595cc40a4e79c0d2ba1907231ec2d0d4e7208e408cfc2e227988b4b81cd023cbecc8676ea7afb7a582c40b9d8115a7a0dd66dbed74503381170a52e85373cd7e06e134397f8245b0307759b62302a8dc03629ee437e18e00ce462806890f803dccef9b4e15ea1315bdcb32f1a2f76c63987078cb845e8632cc79d890ca5a004514fa70fa0b60c1ac56944e0d4c0f47aba1c5d983a1490111b80644dfe4e54694fa8e698173f2b8fb8e90f15137c46323bf4fec17a3bcec20a77560b9c9dcccf3773c72959c32a55ba89804f9256a4130be08d0947af520b3cdf209058831766695257e61842d25ef906843a5e005052e0630e9b4cd46257fa12bc01c3cdef0e1438f3d4cf7949adb2921b153af828e6dea08ca7d0721dd13a6e1e8380e2479994c22f4efb911f2426275089455a0115fe4e7bcb6c300b6d225d83bc9a09181e421dd4ab267fa196b13348d9b239088a73389a0283c8fcdb7cbacb62bde9ee5addb53eeaeebb87a4e1b783cbc8c91b648a300f4334782c8464052a82a7a924cc2416095e8060a9e684118e05670b2b027a7c2b813806c9aaaeec7073b54a8686a7dfe5128a1211dccf65fab620c07a082ccf9068253d1ca7e61261ba57de135134367b0dc2563f8798906846e9fb676d57538fedac06932058cfd4c70735e5b7c1265935bdd34ae1d111211c07900393a10c577652c84f4449c3726a8ae0139692e28ec7a03c3601bf182ce47df9d24afb98ac1f50ff6f4e077c6407aaba826e9cc034c8c0deeba7eb6650b4eb39715caab1f02aa11a0c116b2b26b1bd120d6b85393f697bf57cea3bf7a6747bffa038c377496eef0afe847f158be8677c8614f9e860f834153fd051843e9aeea04ec84e4a9c63ac190a0ef0e000c4be65214639f73d3fd42b6ae967551ff73b0754e2b86b7cd6079e354cb4922b1a1763efd2a103845512a567f47931e1c201d7e0cd654b987bafcf8a5d403c6c7998ff8682986db7b8efd1d609d4960aa5527a98d870e00d1f90fb3a478961d6b5f6221338ab676794c20bcdc3b9ec847c7547e4250aa248757578457cbc36762b22172f6dad56bedade47298df92ba5c0793dab70cee9c33468f218ae1cc1090bb75a4cda17689b922b5922e29323a091385e072a9cd9f7462483d4cad701e74a015b59cebbf5c1ac30797ebab63dda15bc74cb6a76048a3727f7d4482cb7f2aa13d8dea084d5f0758ab881ad7051607878e9d4e6340a00407f52f0ba147a00689abaf2f54d8117ee5cc5032730f69b70c947270366e7fcb8b0f8372aa611594e44b4e1c1e8dc8b83d1da200d264af0304857ce2cf8e524a3a01c4448700b59647caab894b16d8a41faf3d944507d55aae001e1677222e27a8d219d7940206ffe0c93dc69220efe7929f4ce30857375710f826a4a9a5e109a0316c39dc4acf35dc897d9dbbc3315ad4dfc62d686b6f8863eec3928479b2945d8f427eae172fb5074d30692b6c8d081ed80dd77c3e81695c67b6f8ebbe2ffae14fd3a474597eb4eded7de3869a3f62d5b0c849ebe9f16da41e806e989262d4bfc1195563aab319c4023100d2b0f0572be55304d9adf39f512cb33e4b7d9266f6fe2edcdf98b34314948a182dc1ca7d4bb30e63ccb40072e7efc40b5af910fa114c2a4ac717b3f9252b537cfbb4b1c7e43a330446e8988bc01a26423fcc7ed78caad0af2ec6f79517734a286c31136468ca82305d6918785706cfc0675182f798566561ff9663a97d0a503acc0816f559cecc28271354a7a0cb6f8968b9deed4987b178c52ecd3b69cc14951faf9c733a6f0e4237934e65faa558e15c843a76561ecc7ad3c9310bbd3d78549eaa9b5fcfc1bce204887195fb4420065310e7d2cad364f4a42615c3df3153726c2288504b86ac698e26088f940a0d6386bfcb8ed799f1a9badf90434ab70c678a9ecc895dc1a74d32433b73484a47e5361b1cc5959231d1a1f9d8860a923b66c6300bc93dd9ce22a070c3c216d5130fbdf771614b233ec22888abe5f7502375e88dc3e61758bdce8988d91d382ef6028b34a3ff7636e65d18abdb220f87af86b6c1dd34ec828c42ed164c8bf6c18e15f707996b01c5cb437c37650788f35a759dc69834893675a40f5406946c33949690b9b51576ce5fd2be442be78ec3113dce693fde7d0a121a1f75b4a74b7ef4c84277ccc0cde7efdbda6da556ca43363b6be8bb055c493e325d6319ef7c5b34417ffababa376001957e0706d2907d56671ac817cb863dcea0681d092642b28895cc48ae18ff44d34ac9844fd55a7bce1d519284b5937c59a5a85a4815c3b67d4a36f7c3ee74fd25e36bbc7257bc141bd3020fa43fe9df975bf5c6dbd4640e71648615bb10558dd4c9f2f074ea6a743eeb560d54c0fbd7b805ec7287866851c89d6bc46cae61e717674b5a309a6e54563a41027215cbcdb2d745ef33f6602960bac95d43614e9d25a78e1d0821fe7aa8a90e1696f3a40e4cc3d6c19b471ef3aabe59be403b4f842aad2cc31350159eddd30aa0ad9587da706a59b902797585127890a89a787abf54c2ae8f584a93bc70a1cd692a24d959c1d192cdcbd2cbaa4be406a2f956f140522164852b0640c494b28a8ae1409e4f9a594bb46128888c52e9024e2106beed0d2ba001f9ac43c8e41df30978528abe1f8917591eed0f68eb3719e7f6fc59c020458ffd9189320bb30196486061102a27602017893cded05cc0be201bcd91202730873d152f8fbfd805faee450f20392c7e54a43a3c86114d3ee0310c44322790f004f5104f9ee2217fbe0fa7462ea9bbefeda479879cd831ed4c7413aab914c52ff743c333f48dbd6f4d8e631b9051a535cc7f62973e17b25533219c1009374cedb8d0b303c779beaf8d1a06345ba14d48c5d1318c04006cdc4bfd86e29d4a2fce9d62d66921e4bad233fab4bd8a1962015f612c3872c048dc7e47cc8803f1e4504a6ee197d6ee16509020ef9978f276f4dffca10731219b04a0654fd8fbfeeceadbdd282a404715b76cb7a0a01e2e8f395b9bb07f3da27bfe42fb086f9abd4d7249b2f3f619b55efe2b768b42fadb2ca260ba3c41ab1f3b1204540ff222260e75ea295a1bb097ac604332a7516f5a5d0c883f201cfa7f1c55387a30a08ced64ae1048b1abc79e57ab27685c33bb1b249536501f8257e4ca1783d9bf0136615b4463bc6dcefc95ca9572bd4faf2d02969d0e54bd098060607a9964e403894ffdeed03b8b5bbc2776aa9636c89a899030c2b8e661241ce65c30e8c12c780c69d6740725b08d2ce86d4bbf7d70df94124180a7ab63de061562bae93b3f08c86bf8004f760c0d712b0bd348c421c193f65a02eea423db46bd845281e1126eb40ee93bb6c0c21ba2137d9dc9bd8ca06c46c191d9ac1ccfb36e601dc564a08167fbac8f01168c176017c41d9d5504eb3261f9701ec8b11b9763240a5afcf3ed24ac7830c264791747a662dd40a149d25ead66aa1868d08f76c1fd2f9fd230235cbc0c6280e4a6f085b24a18140744a73e6c784a91de293390ffc857b0fe416ac0d97bfa67e0ce224ccb2ffe41025f23bd4d7091465a4bb2ce3848be3ec80a4f029276ae21b2ce384e385be85e0bd781908643a1d0495f05591da41f6382210a9e59cdc29fd0ecb9324d27fb1591b95a74326df2c979fd019b841ab00a6373b790a70a2d3cfb6c9f9c39fe92ac0560cf76c31d698bbbecd930a8de942201c803fc4b947e18f0791618b8688cd5fa7c486c815a8fc63ef684fb0e65e40fec10cc0a93c25ecf6b25aac286dc7e9d225c3a610df1085303c0bdf488dfae1beacefb3b8572a2af86decfdd14de69017edac3eb58d3e56b2e0968242a29f34c5c1054d9c86e0b3a05a4a745ab871dc65eec30548c29f37d3a9eded723eab5c14b83c1994b748ffe82b4cd24994f7e4d088ac134c40eb5db92dfd7d9b30c806397e22a0b00c648ce220f426cc53838dc0140955f9ad949cfe7e8a564060e4f5101b2f33565e323c649526e53e0e7f33e111e98cc811524a7f31001d89977b2f9702e454170d60221bb11aafa4b478e3fc1b1f20d63012521f1b9a46084ed4b6869174c4254673f0f3ce19fabf5cac71866f88c1f0cd838ed77df9a7688f1aa2825d08aecbb88a305fc1356fba7ea413c16a88d69bfe2d8da2d8b49e227fa7f58ea8593e2d8d7abca2cd4ac57a75a863e931e80b6e27f2e45f6e36e031b43fc96591fc03e274a2ca60cf1e18d8bc84b35e8f4c05c715fe1b7e1e4ea4c9bf4ab28bd19957e3774b44cdbdbcfaaafa706a280c39247fa074b2231fd0b1c7bec82e0d7a4f2dfd137c023b78b9af05bfdc289267433488a767579d920f307c8af71388ea289e394dd84038c55c4d35df6cbcbb6320b90c4c01a99fd8ca2eae3812cd12eeb349e38141fa10fa5bfcb966353590ac58e617d830c2ff33df2a335714678c68c0a934cdc90fb114faa332d2b1b2069b94add29c204a622402aad2872ffe2f082a0b277d7255b9f46ed2c4876c7a3cc8a55419ddcb79bbddd4982d6fc27e524ee7849dcede6c9fee74c1cb949659659c3a2492958baff6f7afd404bd4c5b9684481041ce9b3c5b64d4bc7cf3bd7c9baaa0893db63bd5389f89d320478426c1c7c867830708a6024713a6f0effea910135bab0cfee24f849cafd53a3609cfa54505eae5c367395be5efc789abac8c43f97501b7f047c66a01444693613f7cfaab7ddbf4c74eec7a5573304b915f632f4e3edfdbdae12045f6757cd1be30d420bf00af52f7297754bc4903cee36748d8e29036f7f6c6535048bb51a37deba223adf786fb836df54c1fd7a1a6a445b1bf13aea4afc4e3f29ab48a228aa2b0a85f47f915991ace66e675926a71dc3e917b673ab781c04f647a4984e3ed0f7694960be5f618aa76eb2b65f6dc2a5dd441af9b7886062489023af57d695a30ccc9d31caa9eb24aea076078e4190033e3a32358824546ad8e147fde6218cba89a4b07436655cd4843f48ac79a0f3d793f5d27bd44c3f3952be6b7799b32413529d2504fff7cc666c805226e31cb5f719a888808913249990243073c06a8065135aa2cea46459545455127516551516551519f5f8e3b6b5967b97b39dbb9579d057c5e2a7a8fd423fb5eb6b7c83d72a92e955417dd7ae416a965bd549f3dd3cc912707b25faa7a54e41ea947cd75fd06e66a04fce72a0bc6f0fd6cad20e79dc95dd77ddd64baf73aefc57ac56aebbaae7b5c4bdafded4befdea8bbf73aee22b595d864be72909989f2c1a48a0ff3c4d94fa326cbfe6f267b192f175e5e6cb4b24c4122861393e9dbee8811f7791aa1ac2731a1787bd202864f5d1fe879f714a5f661afbb634f3b7c12c0050457169413d0e0a4469bb32a58503db0825c6f1e40cf7a6d860e0f0951da94f16a2284469a6979e801458c0f2a3661fcde33b7e3cae4176ec02e37f0c00afbb245c6138e206a8c95d52913a373bb608ec455c2cbfd0de37f62cbff259ce37717cb2f7c84388695294e8c7ccd30ad0c5a9e9cc140474c49d982904fa8fcb7d66ebd2092adb597bbf7dea772e64db642f85f08ccbd356348aee5f38d7cde784657e4c2eeeb408fc80db3ba2bccc1b176c2fb769872c48bdb124266c703358264dd90c3142a191840523646cc99202da26e57da1fa0bd617ceb72e2439d6fedc4ed46b224856a59522a5035215b96f950e78bd36e5f6d378c6f5c528e1de99d6af14085caff52cc7b47ea6aadb55a3af4968f2d2a322f8071f143ad8716925455b14a339583697d4c81f3a6872d75d440b1dd30aefdad918f87b815bad6bef7423a3eac3b46b660d851b5b27c5946b4b297db4aab4b087ba089dc61dc57bdaf592e8020498a35f0e9653a55871a4949ab481dea7c7ad97b8ab5aa3267a5858378ad15ce36d27ca8b37b6855c6c90698c5c1915da77a0483e77aded3ee69f5aae727b0a8e5b5e3d2b994bd3fa19617ac96974baed9ff6c372858d4f2be7fe57983ef8b592cb338a11e757f7fc9769d521dc55a5e7be27c3f02f5a8f30de1be05ee8b70bf03f755dc138b591c4fe2020b82802a1871a3404408db8f4f0fe6d9a98921f8791d77ad57ea2684fe51cb7de3077588be3f6111b9afb640c936f7950f2fbcdbe1083130a19494e45ee77eafdbac1a9f10d1b5d6fa759b1583038009ae544a4abad65abf61c109c920f26fb79b23956f46a29b51595650d1de44a9949434e6d6c4871f80b0ea614e999e2daeaf165aea54a1c18c841839555a3af870f143ea4d171c4f6d68b871440b9a0bc24c39f3a2c5579498171944382383903367c0b0e9a18c0544494665a94314106b884c0141a3028d10d04ea08317b0155890414c10183332a8c440752959334308ae242fa0c112c3058f2f406122be7aa8b171444c8e18657094a1b961b382142b2d159828959292be14593227cc981fd0d09860c6922d506470e3820b06af115e34f0c6852b5b9294a1816556283262c0aef0d8d284ebd6a5c7d820e6450bb31c60d0a109c7949cb42b5571bca26051c0a527089d333ab42922d602069b3935b499e3c5cb1b2922b6987842e34a122a41f860e3c214b31a6e643d9192e14908a224a3b2d442e483143a436ef4c022864d1d34176780c09042112c26d766a2544a4acaa2448c863a51969c917246d6a4ce8b3126694a66f8019be3421b395f6c2853a40502e41042a4073a34b0cc30e2f315021b1a35c470c38c5610176ec0bed010030d2e565ee8214a322a4b2c5d597ac821090e5a375c71597ca8392b0344abc714f6ea3857309e5ec4a113f6038e8da733aa205f6af4e0214a322acb2b36a8dec091c2440dd89916a81770e8414b132c2c1d77c744a99494644549888e2f1739a88499a10e14b33144be14f902e546adca0792aca0a32a05ae272c0a88dd90c4853545c46450e18a5d4d3a5820f3416656e6ea0b080d0e283fd850c78a1aac1937e4e280ea48122263338ce9baa02b86098e80f992a40aeb0568a2544a4adaea322be400a2c8d6101f2f5cc0480c302dd6b4b00155e7a352638b152b6572567842246b8516e29049d361ab481c4f6b034fb48a9c29e13293d66056cce878fdc801860c101d519251596655b025063651d2bcc28c7480ca0d5064f00202c48b0f9c8952292909ab005a68b2a26a4c4d416256a92a5d42a2f4d8c1c50d9b4b94645496574372e832fb7ad2468e0f1064052163ca151c196166d644a994943445ab0c12382d6099515364850e2338f4e011862386328d131995a5150a6578b0194283485958120c5d6cc8a0a225cc97d29192c6aa09a5a4a405749a1b407cd8603386c895a0363dbca8b9d2029419404872244fac3b5091acd56b402de92b20d75a8d904c51d2c5863233aa164c25a92b2f64710ac2070fb382f001080da8b5d60ffafa1f3420024abeef03adb5d6033dfa719476d477ec2b55fa75118aced6eba2be3184b9a70afb0b099555fc760b7ada4173b5a867f0296611db68074da5c5194ce9d7f768079dd522d7b7b54b3676a0149ffd3f3b2936d75d446b55f3e5eacbfbc97d6555b6c38004e4bbc38545c10716168c6059018d19f3c6890336a48b94b0196ac0dc5747bc6c49a1f12b2bf68acbaf8e30c95dee2b24308a707f7756574e32f6aee47e7101360603386c39134c3e1c237a0b1718313652c8fc70a4b7605892a686b3ae2e361f577e7c9937ec072e4d60b051432b8d0b2ae430f794264bf26971b521a81eb1b02cec9430a467d77ab3cd5eb33739d21c5aea3ae8d7327d2fa37042a48bdaeb23144e8674d9b906f1e447922635729071316b2d77ad928d6b94049e580e5c3b17b34efc3928b1b2b25cfdfd562b9742cbfe6e295ae5f2773a859696e6156cca6d55f6da09da619614bb9a07dee7d1f7c44428361bf703e83ebc1485cd52afd5a9fda8573be7ecbdb47a3d99622b37c85c65ffebcf8d5e03b61fba73f9cb61a55d7d87fb2e9f25c81c89bb88dedc5d14763626f8b489b5a4b72ea2b6ff20b19192aabc22cfd3f56800f936805cffc6fd09804c4fa0f327d30fb9a7289ea480e2c98b1e1a40be9745ee2ee2be769faba1b0d96c3714446c680d3aa320b2a4cbcedcdf8e044ad156997b2f779923bf2d224b726dcab622617146d89636118ff6787f8e081bb4baf627fb601eabd102652a2a92f7f54950e1435ce77d6028d6c4aee600145c0e39d1d66c2379a047640fb4f79d3d99ac989a963c47e4b3cb28eebeab9db84f82772b4850e14e9240aae8b2237a86668f315d763e3b24b387971e7222de87be22cc9dcf2e7b0098ed93d08935109ab28a1515899af5e4c99424f2f4a688599cb862810cd4a1fa544b586651cbda616b727daa058bf9ec3011ea51d74e78ed43649b4ff6b12753ef57d423db573daae44aaea843b5bebd2aae8400424552e1bee4ec321edce3f3630b01922a94e0b3c344c8403deaf1117f445b881a084dd9690d84a6dafd80ec77be1fde7befbdf7fa8849f9fef97119f5d0fdb176c2c19d9329771f7a0d057dc0974b3859d45050ff30840abf2afc92277572b2491a5a7cc8f46df3d44e505b432166af8b68d36fc7fe97475015f5c8ff866b2dfb00456af3ecb20e3a9f54069d5cbfe90f4e3200480b5db625190004486bd09972b98be8532b0a5a84d4a8966dc24922b6442d9f2c77ed3ff79f9f9b56f0b195159642132c30cc058ce1e2c1061216a68499fd458e9227334ae698b1616610e548970d4daaf090c6ec6f2b339adb96806227d34f8133e521f7081ea15a9bf654a15a624f4bc854a696d2205aec7b41fededfae39afd239932c0e87cec9e501080f9e223804676642cc6680f202356e99499b4185365f6518c76d1370b8860391715b8dd68f3add950f2fecd79b1862c8582187206239e498a992d63596868d99a4f5432c8bb9afb8c0904f2c96c1dd4e9fa822b5d9a78912b9bee5c66e9039cbfe5df34ba95968bffc2423a32633dbb4f5657466ad00f597d199fe4d26ad9d08ab0522f0819295053b8104152288652440299a2cd36fb24c49b1968dd6b4fa08f2bd611f8126d0a6e743f69bcc6fd3df7ecf12dc264776e5c074aad5bf84b9adbca66c0678fcc36b733ff5ebefb51429ea8f70496cc991e6ae3502da76519d81d4f4ed15a95cff24caf56b50ae6d65e548ae65f914adfdd37a3677cddaf7b6f9fe08f753dcf7ef5aeb2ecffbb6f60014f27d3b8e70dfffdeafb51436772f829aa2520dea739576307697742a6cf319942dad98c4dc8cb029e0cf59794165ee2dae47dc736f53d41fc19298aa083d10737751d8b5eb8e45416b0e69757bbb1e6fe8be5ca781c2c3dbe251e4d31295a6050b51467278317d4ddad49a265a358228a1b0d0ed70aa5b2fbcb00525052e0e5aaf8be791622db1f584fc12ddb67e18f120cebb09a1d9829242e6b8a6292d244c989c80c80e551d9cc9418a0a071826782222ba09195d2718046170bf2cf7257b05d95da8fcb7cd3996adda3f4b77ff33b94a0f3c28f4e8cae2e6cc881b30a6ff94d51597ac312241986e8f5060b3d6ddadaae4c84e417677eb5fe4e410b9adaa387137bac4babac2b3c1b2f3f0be285cbfe2f0c4ce5aff2771c76c39a9ebe523ae5aae56ce66fb49a2b7f38eeec0f56f77d1bddd30e69efb36ca9572ffdde5aab516bce449bfe98aa64b4534eec37bd0ae90b4b5eca6dc65e8795dc771f75aeb5e6b0b983ecdb4967dddbd2eba5942e7e152bec379f80ee7e152bee3a439a46e80fa9b72932118ad5315cdad2c85ba64fdda3402a5a0dfdfe489cbe0d3a829879d48475c06f787deb743494a9e1ce0b0845dd442f6efd7fb22d68147b8efdd6a89c3ed5bd2849a573458ee4ba2e8fc06dfbf5e9f8a38a94f61b4481a7d831bf4467b2fc7759de77d1f087a0e1c544371c9a05a56d1dbb9b45ef2e440b65c97aa7a386c54545994e5eaa2a2caa2b837afc0e2945954d246fa0d8c5b0cc1dabde41293599659d42c94bbdb20879f48c79eb1e7e6b07677ae75dfd9a9b4bfcfe7462b8beb59a49713ebb0ecee26bca3e308136893bb4f02ee7b7cb4b973e6c8f6a1ce1d228f37d371cca1f54a6ddf1df740f13e98c19bc1fb74f40c5ed2f3a130146b39dc396de60913336dca2bc42c8ab49eb6495f218e26d8bce276392f87dee77d5fbfff4ef64a8e6366aa4db66e40a3caa0a4861e6ab021869b64099df1054b147389c968c993b49a830c25971482903297983af0526265d667a26764fc306b092c93c9f6c30094c60f132819e382c0d09202bb2264ce902b2ff040c75c620a9f94796322a11cf430fb3b83ea899e2574309c42b57f76da2d57cfa9ade48a5bb675ecfc1fe8b43c027da756aad4130d2326d3253342b74c8579612e315d20314cfb4c3e47050e3038001da2c34b0793e9de10c7ac4c4766a5b40cdb9196da4bc60c31fb4bfe4c7587134031ed33d53565ac4cffa50d56309798ba18a62591d467ea62984e22a10f81d06b6b4733ac1ed40020c9a2f265522b59bc4c95c032bdbdb67465692207acafda7c716282231019255f38aa4c701ce9181812a80b66cac90447201c0cc0e30854176523052f6f4793291d1f581c2822a0f88d54871cb22d263896c032c3104aea0b6a4b1c2a1db5a7336066b833e4ecca0c79c46f6cab1a649e9821b6d2224d494fd8921d467cc46fa44e3ef484053759b6e5933a65800312303d981f4942092cf3234ff0fac6de9ac18319131cc72f330c21c2df279f53b492fc30c1d17665869672c1c28a4274e5dd365f4e38196fa4ace9a88e31404e4074e56d05a105cec77506c70670cb6a0859d8464b05918b4c151b21335f5bc2d0607edf2464c604bfc99cea22fa97831e265d6a2b737e0831992c1d3a3873d0c3887e0f66614559633259375ce667058b0c9ac97453e0627e6dd5d9f321aa140111c0f60f802a6001153e74c5ad607ffb5e053be95df81be914b9d457345e38994c0ec644e25d987e93e9589892362b3269b9483d3a69945ceb515b69a1aa47941eb1f7643a9bb22539518918195c37b63c3792a50a7f9607aab02e3db212d0460e98f97d93098eb4089dc2c222a65327fcc31bce2ab23fe5baff9ac8a0612e7dcf44a988b93191dc6f324370fc46f25c71cbf6b99a2d4882df18c2d7df6436994a0e8e6dd291fb12984ab063671426d891b408a5e2c2e78a4ea31ad057aa1d5008e0871f924bd40898265c26d803ca8db220030a98f98db60714d30b3d14a44c706cb01b605c2638028d99619541438c76a9810233c111e8abea007b7232c1d182a70ad64217ab0d9caa801940ca0b272638b619c2f7e083e49275414d95f97d93197e5ee771d7bbdf4e083533fc9d7cd24c242497984ccf87280c37824099e0083483197e5401506862e6378a3ccc90de5a8e6d02d1a74e6a823899ddc6861e626653728969411033fcc0f6b67093e50aa64b470f8d05881beab8088e4649547093e59f7c1ae53ad21a33627831bf718315ccf08ae0f8a5166eb27c3e38621ff22cdc64b9c9f2893f2a93e9274e091f6c7899948d0c2be6477afd1540c7982a51ecccb3a38632131cc3316653893125cd5ceac8984c36194cf0bf71c9a3da010582cfd4c5b0c58809b6960d3560666f4973a5cc6c2c6fe8849921277e2385e2ca226682a3111333ec3c2e52333899e01844c30c6ba2930f28b38bd98f6907b5a711d08e249a31fbb1231dc00534b12e33dba4d9cbb5cfa60cf4c149a55cf161e6002ea089993c22382e5531b22993a906c4ec11bf71a9bd4ca6a6b254617c552d31856fd0acccef991a2ccc0ce6472201a2df942979521f1b5e4ea51434e647fe88df12ad81c3ca5c62d2e0cb9593f93d13d2971acc8ff42b5342c29c98df285e31439b088e4b74460e6226531533bb7270daa8880e77cea6ac54cf72d020667e63e865861dd2f64af10e500a9cedef64eb5618e008ca1da2d64395524a29a594e2fe23f436c2fb84aeb5d6babb9bfa5ead42bad24a510843b7c26ee55284506c939a6b5c3b1154cb10ac9de80ec51aae9507dbdaf6d3de3f36211bb605dd70081bb605ddb0900ddb826ef8d6c6d2da098f760540b513d86fb805616b41147c961790a0ffb5d2cad3fd531576a5d52dfdb2145c3f5ac9930399be68c33c8e033e6dad76c2b61171aed53cf8b2ad9651701b8cfd71edc40db8be92d73188b6c1fd618ff59e9e9e9e4a5bc4ced9946f3cb992e7063225ad932eeaefc0d0349e5016f6d263b31a8be75918cbf3b48238093def0712ff724f992335664dbe54c4d4e0f9800e2e7c80c2a5c7992ce68d63058790335341b402909b4a18b2cce5a65266cc2cdf2950bcf2d57261c8063b00990396e3484fbf1b014136a0101e1e61c3b7eeae604405dd1dd4371f1217f43c89fe2e0abaf19063298a6e260a757777061f75f7526c77771ff2a4dc86bd2eb2e1b74a322abfa86a40006aa441ed447f5320022885913fd532492a2d0d830c02500e49e1a8020288eebe21c0dcccc378180f635f786ee6666ee63f789cee16bdbf954698448fcf053f3e16d8f06dcc7fb02eee75e1666e665db899d3d233bbf7de0e1232332bb22dacf8998ff9999ff91b8fe37038ee72ddedb8eb631c77ef757791babb5b27efc47ee6633ee6673ee66fbc0ec7dd3a67f7fa99d7f1b1b1338ebb7e76efbd7e76af9ff9199d0324f1311ff33147f3317737ee3e070dcde7389acf713447f331511445511445477334eb632ee73a7e2ca1856161581816465555d61b3187e3701c0e9caeb5d64aebfb06a44287e3701c0e93189d0a824ea591800382c3e18724fbe656f992bb710a25f4a16df536d473f71edcdd71083d7b761dcdd66aeba5b656a7b992fe1586dd24fd5aab19b5d5e22e6a4ba2da4aad7dda45f59dacb5d3e129775afd5ed1691208ebad95a42f4ec0dddbd76fad50a108d97e8f94d27bbffd669a4571c54fc9efaef676cbf5bbc277bfd62bcd344be83be0ca35554a9fc229d9a7e4fed37d4a5be511dcbab5d652cff330beddfecbf2343a9346b05faf75afeef54a85613702b86bbdfa73ef35527dceedbbfb2579dcdd89f45b186cb86eae4ec9096362bba4eda76ad99ad545146a4d73d9532857ea6f2f295aafffcb11629bedc752bff7de7befbdd7bbadb5e479ef6d8e2a73dd9fdc7ba2e77df7f761d82355c13b9972672fd7cfbd1dfb397ba2ad7dee769d0a2574f95eaebf1bed73635b7724cf71d408db8e3c39eab56ddc43fdb6b39772df715c0e2190cd5c0e794cb05dd45f3399151052e7396b2673045a2aacf5051716d894a9cfd4637e90999544429f08bbfd6caded635d3d0cfdaed7d9b8a4eb79180f833d8ce89dd65afb1ed7751cbdd6432c7e7dcf917ca88a22e46b3f7793c823b8c7e2ee7cd65a6bbd7ae4edeeeed65a7b3debf56ccade05de0d7fe12bd5126bc2f733a72eb25fdf49225f2364538345302c4350ac7db59df6a11244b5ec2fbd9d8eb3f5dc1e9b19a65d647978ffa941b554e369bc0cd3b7a5c1b42686a028924b4c664892f8acb5d65fbc4fadfdb3bb6d5fd2c7b2dcd0d160ea3b60eeaff40ca68fb9329fd65a1b44864513be63e4b9992c13b58ef99867c1f4cdd432987e8f25ad1daa46e2c7e3e1cec530fd92dba21a9c9cf51055c40e22194cff26001ca2c746b5e0ee9f1f1f1f63448dc41e0763b18812b504c3b3531b3142aca036692b193ecbd0c10405bd2866c803839becab9e83b11d09ee450f73de846a1e706fc953285fcf92e14b9edffd4f62857d00d44eb4e80989ae03763019d802e4d35a6badb5d65e1436b4d1ae342d8721444a42beef23d7f608ecb616fcd35a6bc16ef0aded26fd3d1636b752bdf5c8ba513e57881dd775cd74a2a9937c8e9fd3265483664235b07f6fdb2654037b0275f25127e3d9544297c7ef8ef69d8bedaf2464cedeeecf7baf5d723f3d16365b0fc3f4fd8badc7e7c75a6b6d182244adf645d44e78b5fc7c7ef5a3e0569f6af19b8dab40ecdaedee6e6b4f4fbce478dedadded1d57dcda027950ad4fb5d0a75bdde0e7597bb9cefbc4aeedf0e09ef6918090500294e69eacd4015acb62a660a6d81dbba5a5538a6f7eb90ec803cffda45117f53756eeab4cf37bb5bc896028d676bcd29da7348862b1b6c383bd525cdbe1c13d5e69cf0e0feef1f14a7d78708fcf8f57fa837b3a2bd311a8667591cd2172f8630b814550e09552d077c77691cdd671d7fef8f460e7b155da3ef9a4d5edf54a6f757b3917ed2dc1755e69675dac65752f087739e46ea6ef0179c0e5afd2066d358100b9496a029741a6a4092c2e903fcd9f974de0b2092c6e06ca9fcdba9314cc8b77cd4d3a58775abf52b5277da7f40654bf96bf1cfa97bb96a2d60c662ed36bbfc935256a59ab77c144b5ac4db95a5bd545961413eab8901ed71705e482abdc8d88c41b18285f13b82df8c4942ab3a8e463a99e7efa4daa9059d4dce20dec63429828a8f48db71435ca0cdd0c00002000531640002010108a058351928579ac7c14800d649a3c5a52341106e4c0480cc3200c62280681100481180431481167a4922a390028ea8532c05d4fa850b34c30611db9c5916f4d189850ecdd3d1866430c61d957a541306180a5d82ca4314facf5be2f8f78efe3cd5cd64b7869a3b370a13c154f2a5f4a605fac4581c6b5305544568c58edd163d13ef53bf5ccb01a7dbc97388befd6c0a193911726cb26b2f64cf2b2385ac06d5ff9aecbf9678c63a4b432dbd5171f6dd2792fe3fca5679016269e6fc9ba54aaa0aeb946598b108f7bb3a17a178687373a0153398b9a191eba498b4372617cc5498f1059409116bc034e358c2a5e8df23db25f13e9c07b9c7dcc064f461ae07b42df2a46c725abc8a22154b61b3bc5e0c9bf2f393db01f3e44823479c4cff741068ec4c2396f48573bebfeccbef408c1302e052c89b00f91023e2bd01f6e4811a3d8f30ac323660dd49e853132f859c74bf5025484ae5060654c136889165621b6aa3d687a69121695baf228ead74b2e7577eedd34546da7903799cdad7e847123ad7e163fee7d5701aac00d33c040f7a12f82cb3f06fe27e40da7f259a23f14cd3e5c2f0cd2496dfb28f4fcf4904e255131b5e7c620551d28fcf8f3c4193e99de82a8648e2688bd36d2b3f8ff63fe57d317e31ab7d1d73d4a46bfd126eaefaaef9f63c3cd730ae8933424c01b9a8e7fa4e65b0228d02f8f5023982210c2b323d193a5f4e2c9f7011ed7c7f37a69e3cb24279ee9c4613ab8cf2346c48845081163b76038d797df5b508c1046c90f7dbf1cd811aec77679fbd5d416cdff1725c37ad5d6c1657a2cf8157c4fedc34d361f57d2d420b019b04144bc2cf26a5b194799ea0dac2178e36285ac0f1ed32b8178d929cc0fcbf30a0078f57a03a9cc7c6320212fdf872c8c4fd8185405be47a6a073653b67aaf729bd1374504ee9c3716f62e2394e8d60fd8f8b786db9ee7894fff3391601a87f143031bf14a099886bbe6759641e834f464c6b6398db8e64e6ca46c957d3571144312e080e9a94f561d24803e9f685f41db3e2cd58b3cac4130e50faaab380a6cd2a43bb74dd5202eeb2443854ab3bcd87a1a2a69cd7a904f47e7415310557c94d6e74201066797bae4c4e07b942e7a5c8eb1d9ab03eb400f0094d2ba30fcc411e1c8cc284567b2823d1a6dcfa24f0da093db0b77e458623f0f35fadf8b3cd422d053d4c186d5f8b12b8e40a409f135565f3ab8c126a1efc663092dfc80cda7140b2b50d5d6c949642de28db179169e45e01461fb0d28d1c1a070682b347ac148b5d14d4cbf55a34d520f05da088c2990435038575f9d6bb2f1ee08a3550a1aaa999ff06c72ca15edf1103682d841ee8d17129def38c0c20487f57178e2fee051195375768c4e3664300ff34343346bc7da6465ce2ae8c5840647339717967d1b6b9fb0e630d04671a70d52c00d7a16b62150c01f39823c63e00795b23763f6195fa3b9a4f984c42b4aa4b6785902ac20d51700720e55a2082e233071e39109de23d7b2792c55ac411c4a76d4f3992c65874c69be32f58c48cd480027188f055c902bd53c8090fb4ef83429de006a8591a6eba3aa5306f03a76639e1e6f710b8909cdb34a00af2e571540b9ec3754985c89a8343c8265454d92752a2007a3bc34e0e952054476fdd8875be9b36f262137ca4a82b7166e90c3045b194564e38a3efa333b4680d6ef588469433e0f68a524cc7ff125a9fb1dde21f720235f2f583d8adf5dcb13ea10734fca7fac782a7ed2d40c573bb21f5d40cbc804bf4ead8a203adbc878b31c2c684205eac8a36f9062b05fe3ab829855770417f6c4fb78c126585061c4868a2c6847cbd746944e3e5f706592c2d6d123e9dec223b9b5c90d12f3bcbad4948fbdab0ed3099015d97b9137fa133881d53311c1ea257da6886f47b747a7ef4cbf00e19def5cbe50a49b97eb9b64288e9979f9d900120f6c21e96127ab3e0429b858410e2ff5af3c8a1697d0b0c9795b4fa21d4623e9336b809172b002d76b03462f5c20467accb1027ec1003854ef6491743f4a79e4f16bba1358d62cd28572677d31537ba6929a9790eef36ac85ddc6dbe6e203e737fd7228b9b283e6f7d653012824662702a6db58200309407e17f8a14fc323d88da9c4fd628466166b40c09ea7cd06daa21357c0d91f85073ed9646d224e2dd72284f5fda6d3a0e057faadeb65657d89e62091907200e9267bc3a227923de742615e77836dc8f2d98211dcb275d035d006d7755b980c1969d5a8e303f9d343e732a35fccbbd8fad8993645c0bacd18f9a03b404c674833307afb2e9a204ddfdd48e9162c1464b266f7b4218e7b88d53cd80474966fb8dfe45b2e484e288512e2f674be9f517277c927d086d0b827f395c412f88ca82f4671710ef4c0140261fc067870a9bd243de664ce5ccefd88a7bcbe37d8aff886c6c14007849eae95a0f80ef8c216dc35190b6f8ca28342b3b831d2502f89600e1d9200cbb148f33085a3eda5432c0ec2e98df07ce976c6c73129c059a4533731d94c73e870f9d0050368ffc0ecc05eb4d461c595c8fbb507dd96317aed4caf90921e5b3bcb10805b41bf9fd85f74d13205314e26077b0bdc069bd8ad855ed2d25cf8732f2f888694b4fa31ccca798103321539b44c9c1a16222fa4fd3db5239f660168cca4a2f54bd3f31ed5f4a98420916c2b53e64c31d17f45c840fc09605c37e7cd9f4a82c1ba9d7b436bf7afd96e4fe1e3587fa1bc8861f35a0918e4bcd005b502f207c5fc9312a6b207bcd4c4442a6b90bb3bccb66bd9fe0f34e1ae3a582364ba09c7e33d3dea89508b6287a6994dec1a8abc6b2210b2ff914909024281833b1b6a00966fb94c79f970a5a1df7338486165c2d14959cf453087da71ff5104cd78c28ff7c180be24bcc920782f09f6d736d1471494a0f383809fb5fda0e752df0c538627daf0ea926da37c6e147d01ae28b0dd248f431053a6175982d8cc8348966b2f0ea653beda46fad4c5b32e8a306d346c704bb1b47bc3c4042b69ef54efdc83911ebd8ca45215b76eabbe535e04fcc5ee2d48504e6bc07a76fe62d68139fc9a6873fb387644dd88836d0c728dfa3fefa75487c7b8cf28fe1e3ea599149905cff39b28791e50afeaa51b941f1ceabb08ff8f39a1ed00e979c28c46fccd4d0f5acce34854b08e01a96bb6a85225202bf6e7dae8ac08b6a81390f9b8ad63bbbf76d00f210e49d4034f9bb7a462dc46908133a332e595e5439dffe16ec9b260d0328e29420e2876562341715f3acfde37321e259b8ff79d30b89daae347066e1841888b23d71de0e3d419b1e1223407ae9bf0830ffee1bf7e9ff9af0eac81e02292e32b29caf6d950edc2f0cd1545696abecda6b6658da06e2f44968c529b2086320c144e55a111ac08643464814a573acac98eeff5603346fc97cf854bd707df66593c3895d5d70ed1416f6045075fcdd6e7ede0e474264955a070ee56dc5aaba06355abaaab528d365e3470bd85538f3e287a7d5a129a81b8e59bcb5cdad454848567a2f2e6869143846010398d58f08e9455cc54b8401a896a2817201c63c1f83e5d1835eb5752090ad19b7a8634ec17dc574a0906d185de992c524be20dfd151f27782ea84960cc32182445bf3a38d525b9a70537156028d7c32c5bb4f6d8acf5653ac1236f91892938125cca09628d9a438702a90c0b0c5237c8fde00cc148dcd475a87d213fecde64b5b9501e841f70b01b77f6246116ea323e54203c4ca88fea60256464d4792ec5ae9035bb1a7f0baf817b48c5158122bfee6e2a4dfaf55a4fbf4c386148469944ad08aacda1caeecaa36b9f27644a346f26f11d99f0c79b8534060333496f1ffb25b8e48112c4592c650a4731eb81145c5a4b49ef6586f8609344145ca63b13a3edb8b97ea6ddc416b9d005a35ebcf42ec60978097ca14afa8fb1e8f36f611e146041c1f2ca70f0353a201f6e133ff265c2ac09a69fc0d86b636b583ef626093fbff09038c9cf2f13552f21fa21a926e58de5b3172a7d06d0fef7084cf53730f2f7d7cc2a8129b567220c9883b9074a9062f8685b2f07faf5deb1b7845e0816f7d770ca221d20ef623f7fa0d15377b0b857c3e0119d72b9858e5ffdc0bc4e9c239ac3ae4945cb63298450e289e4cb1fa7162f42bca9a0e8d29f40d4511b96cf59114489e194ddc836b044bc07541a6b381e731743cbcd3512408871d0d48b3466201ec0ea615fe9e884c52e9fd20f81a92e41891b00955940d5e8e705fac415a9a662dd59b3c01bc85e3c96ec92b9ff0f601f26fc860619ebc0b36e822087c38f8d3690a0317ff986f5ce4338f30ad9f6fb469fc35ce6b075f293c54162ab379c486561ec7d13c5272dbb1faab67fd2b4a09d46f37b99f4583de366b8c09098d4a4ad6ea211d6dfdab4759a75398f158b4ae286d2824d8b377e0447a1bdd4e683a4a956ddc807d2341cae7a6b782c95d72a20c77e857f666755f88e72314f679100e39c529370419f63808ef59d583f423080a1228c2a376e07c41528c38f8cbe4a5cc5ab8a34d37fa122bafb890556623b6628d26bff9ae6c74cadced557cb5b3d291e7b1a0fd5cc2e61dc4eb6b2183d66b713d76780daa1d9b13ea7d6562321114642c23b69cb35de37cf97869f1443d844ff42f01f250dc09f0a39a7437446169eb3b6ba6d8401388d546cce6aa75a48db15b24bb015eea639078bf6938eb4b9954be7e8fb88d988cb2163f93c58b26c279a04033f20434c007529ee8eafd4919cfa2b0500a249b47c4f1d552036534ff67af803c6fed9c3cec7ebb070c552b4f69cbf9605e5c3e02c61b97cb95959e0a9964d777a502d2e3543cb3d10d51b805ddaca9dd0a338eb9ac3f014d05499fcde3dfb47126ba0ad9a055c5a1c6f9e1ee164ba6e2bed2844895869d71acc40f6b1c54c3e136d91693e86f641430e9cfd28ced6352587009c6649072db0baf5d8a013a3235a6ea0db185b952a614fb02050790d61d93cb215419a88822bdd6e89f55b42fd50aa5fd3e86fe40522de2ee08e231c80d635ce7effe8fdaeb5984facd651a46a820bcedead7013fa8221cd95326dbe5971e2e472c0ed0173feddfe3d9646460b54bc7b12c3d50013391c27c6bf2e0da493a2a151d4ce8d82bce07b88ad97ebe5427a2b77a4b787ba9712894818dfe680af0c433018c9a8b468a2a1417560c6fd382338585224a93c630cd8652447206655d4880719ce7e9b6dad31c1559fe15383869161e32f408d1ef0cfea1bed74adb29b4d1e84f34d5b00e87259b0e2e514e03c137848c4cf48ac9c067a71c4d73b35b9fadd4b30d6d46af7fa884a33e1c9a5481a08e581a7927842b6ccf9dcc17b5b9f6a499d08b1acb596b45f8a31416e8be3e6c031fce5558381e1b8d34c00dcbeb7f0f01d7b2224cd9c42d0f426530e560656a2a5398f2f5d4e2c7b2493fa3ec2a1e04ce0a5debd8c7500be3548117b0892a2d974e496b705d01c630f0b0c708af1a7ab4e2db95df092dc0a345046cd630dd2dbbb9654e29db5979ea22f2f36ccd44c1f5d43005b357e6473c3e417c8bdd60052b9647c3614c1b25bc20cf85b0217ae295a3766a85a777f3f24f2b046d88fe1e72b882d84a1a801d131866517927cfd5c4e0b6b2dd17672abb3b5811eb68df6d81e86ec453dd18344b55ce04fe9f231ecd80c10b9ae4812dc17186dc04ab4cc0990b5f3d47afb93c286ee94ef0287f93ca1453a8395c0e3069840078748e3e9522b05e7a8e821ddcdfb997004efd97f36248de03791a2aba8f366545841e2ff3100c0a6b2addc71fa2c8b6758032e5b1604612a0831b026bfdc829eb32f66f178cf7483bb4277edcd6b3395c740efb6355ca909be276829f4f32610725929ef4c60d5483d9d0887b32e48c1775a11cdde50f62ed1b0a48de38cba989c72d58af820cb42af6260dfb992730859346cff0e28686fb7a3a81b039689a6edb9fa7877e5e746865065970eb4f795503c1c8425e376c938a9ac8b213e0e236edd22d2379243f66a0bda71a82b0217eaa214337291e51765e57a8c17da9517efc99e7decffb13cca98630e459ae537eab2e13cabd6d551a3b11251d280051de88bee4ec469b05a050b36c3f3d393df6e86053bb675328ecde7b70d787ec625acfed66e356dd53e5e381f04060c5638a7ab652d3c9655a19d4809e6d74d7e35b21ec7192566bbf7367328e99ad0b0ef6c5580760bd614c659b8c53015b46a8fbe955671f56de4522f0c58d001fa0bd44a407acd8217d65a4861f1fda6e2489f00ffb594048980f3080b07260c04d46cb5c2212e8de180f972a3cc3401c1bb05eb776a0808f80e7d9df4c666c541bddee717dd7b77756bda09775fc1e1b780868544ecd4803101634e28dc7bc6dc6b602c749be51ade7ec2d4a5584d9429b7bc2bf053bc1b0272cbf3263d6877f2cf3a6705db8dee98aa6546e7dc1840cf1fe673efcb4637063399c105a097dcad36a67b6d00faf009e582dd4ca4465555ca5975960315d6a932e86df5d1b936c1c8671c460f7329855d4df4a242b3a29ce85124c754ac5a59a9047a337910f71cdaa7000ae08e55d9871c38040121eb5c8fc27ce0f5c16d547d2433feaea77018f57565e003870f144527706fe4e49daafd2d77643585a679c345cf8ed6e6b100198543345cf001ed7d445269abac9199b5662a7a465ce23f018c5933d9543300a747c30b447496294f3e48cd7f293a6641c2cd9ce36f18153f7df8d20af2419dde439bdd0d5709542b977abb45eabb15f1ef0de0bee28a72c179c8e0e828833a0189cb34f537d2029a49eb0635df2f34c9162b664bc7f2924599bfda3b06e2d7fc8f48cdfa649a029142bbebb772967da18cd28c2abf8a13349fe3c5515c7ccce48ef0b5e014011437f91525d7fc7cf6396c2854b1615efdc654382d7fcb8f0eeaad97ee5c8dfa7406d88408643d6d09d4002ad339ae16de7cb28a9f14c1a078291b43b325f8af5e28eb0908cc81b0e08fda1e207f1245cf82ba5caf010f3d213e648a511ab829448e68fb7c734b615a63990c3fdd017ae77ce6fe151c837b056b70d2c96bc9be1341a75d638513f254e8200dbbfeeb81bc105eedf54e2105af51c1182a13b2a731431696d8913ad77cb8797e0715adfa56b337f703e0aae23132590adf69d7406b8438d1077c428d5e7e86d9409356d004733706d12be3a36b9c3f9a2dfeccd2c8c383367be78956071835c2fb3242b36ea750921a8a44def6392bdbf82661324bca014030a475865a7e549e398a29773cb43f12187d5191dce48e266f471899a9085c21fbfa13e0397d2e8a3956cdb870c4cf0c5693b454148186051b9cc588d2777150d92923821e18700e97c9620b32fcef0a59cd73b9b5bc890488d7134f912908b32a5cd3903eca18ac4dd034016fb0364e81c149b96db152541c5f3b32e541b5c4c44628cc82f9fbc9780251ba2c5e9a828d235a845fa1c3fb214544fa8a0783c7a3463bd30254fa53b695ea88a1f78ce4897480755e09b60469ac93796a97c18cc9612d2a4e2fb7301588c3731f2ef3355ca22d0ce10cb99733d5903a16254008a0dbcaaed869bcc592dc6d9f25dab008862be944558e0279d440b494b3ec72301d1e8b8b445aa13e3a524f0d1da3b1d5783f12d7f0609951278de50132ead4c86fcddd3be63e0f0139388d8c6b467036e333b0385a985e138804a1f468b6f4b38cd92eaed811387add98f6c86940c9879fde10840382c01a864158a8e54333ab50b44e968e26e7264a5af6036b34d7b4446d630a1337fd7d4b221169d7d16a8d32cebd752b800afcda5118abe3a0eb2786d028e9dcb8979d6a7c00a5b5e6be430442849e60afa50ed16e7dd3663422e274f6b34dfb15ef5f017be4cab6baa048605a97a218c1e9d4566c7e8bd8fdd6daa0dbd563b05cb8a3b53161566dab16907cf3b5a79e55e281a7661899bcc03c1c9dc4ae56d8a6ff5c8e0342c51216f182b7f41fc7482670db158a43fbf52c26a28c92245e6210ead75152b28f0f5f5ae5a424b1cc1035ebe91d7c880378b40c992b353b9d0a8f20dbfaf0476cca946a091a59a6689b0d6e7109e25fdb477f45e0f5b62d2051836d6f8f728d91229be3452462cc43e8cabce52c28d0bbd0bf8dc0ec2b408308d3f3742be9415f9bd9338ab152457d8273e1549f7a70ee46d9143d7afd8ad1925c303660bf371b47fd6cf48d6d94689e79dab13317c6c915457faf9a270440665128e3c274ae25b75f0b137aa66c223834014d053bf47882a88c9938307763d1db357201a10d2b36321a77335af03373da3ec8027112c5f8d927f4972f0bd4557a837f4dcee4a4a56db1a93397b4dc8c60dbda0fc5760ddb53c90f19ac3036e7daf855b6f0e05e83ac24471fef5358e98b4a025ac967bbc4a5ffd9cf229abed2b51b99bf82a97e1d1895453440f974583031e0c0d80790e2567c07b00772e4b5c2496881901783f048c8f45a9176e0c3306dc9a2c462f306db1cc0b9b7584f93cd167b193a04a44b86d35066b1ffadc5defcd8ea2e08e5473da74b00bc2e32f8d102bc553ee983be828180ed8b98aea1cf8c6b02befd43fe9074f005cf1574da98c3bea01783ca894d632e1a750e8e766008d7b8a38808458c08bbc577e1966b209f7534ffcb7c4c73a9adeb2d572252333642f7f31c7e8a31a100a92587be760380690e542f67bba3da9fe2b18696cc407be0de84fc01d98290a4542f037345e751da60f1bac10c467508f7f3e15b066218fd08b42ed381e70ce6de490693fe6f1bdad371e6fa9e38c570e2c77cf9225eb96d368040a725235b2b1524077b1e9acbf5195e788cd4b7049c22b59320433b59bf906698a8057b8eeba2df002f065d195440ace16133eff84d3a6d2036ea7dbfd549ecf08e3cac1e866f3b3f053005c34dbd522b5599cfbd71c8a1b47ae25dd17333b9679ba3e466c026ec2122021768eae0cf34a69b775de5ef1347524e8077f62797a41abb3c2e1868a9fcc766dbb2fa850b6cc8af007e380a7e34ec4665169156e1743d43191bcef72928ead90c5a1f44a8127f27d604f1e0208063587e89c04474406b685ba3da22f8fe65b323785de17fef87a2998b30c735b410447bc953a340d1b9676c2dbd93188e45598c4208f36a3b7652ec445b220397921d0883523db77322075542bee2625580e407b00426e1634e00dfd066e24d72a09df2734271ec6819f02a5e96599906bba3c0d1e4c83dec6c7d7008091a1cd767490474f914a520ae1dde9ca587f95551583400b103eb59c25a808bf2c49ca74ee24432969009bdb246b98f8c8e2572898116d5c37856087581de8e20ea474098dc6fdc7eb0c1d5089c0dbe7dfa3890311ac14f4bb4fa4e1db61d09fe35df1374163c375ae5a0714ca5e04221f3999a69400fa26cbaefb011208ef0f8e167e156ad525c6f5b7df4f45ba6a42e4b1c620ae771040a7b1de6c966c170665517c8ad0698fcf4d8bc066486658bff39659611e781da95c8e7c55d3fe29dccfba7063650686042fb6f475689060d15286c3bcd081e08130da92d57122f2e86fdaedbe8623469244555ce57523feaa237e630f46a292cf44ce0d793ef737e896e74f5adbfb58e1caf7a97073a0e74c697c151fe9ff7f75908e83c0b629d135f8df848cae888800bf0bb6a9b08c46b4d29c088377985d274630fcba80caa94034242a908d9aa50aae33290c19914e0f8cfc327548216db21b2b74055f4eaf5f8429bdb97b7a011a94fda8ae68f3446ace604567530e8d5badd7967318b492135cf2857aaca6b60c2ebcc4d8553f467d0ef7289a574d1a378efae34d672ca43c3e095ee03e446f061e85f26c2033b1419e95734fb0fa010dd0e060c97cd76c1bf6de449e9686f26e2dc22e47c5d3c33f86c2e9e749f1dff87d4af5eb52041077877d7fd0345caee75d46c185433df353ee94d3e8bb2e2b16248e177bf2cf58514c1c97c984e3b9670e420158344a0366f926a1328335a84404e45022a54676cfcf80c35f64d20c621da6f65eb891c5320e1ea9da415d937562971bdcace516e40d38de9dccb0dd7dcdc70266a481e5b660305a84c95413e3a0364cbe209723bae6584b209134a23d7a32286747e8d47351e03393bfef9cb4d09888d9810b17f2c0b24c87fe87a74073254e49c4a9f097dbbe3d997d7f422c5b18eba1cd51d298c366f921ac8fc2a4dd209ba55361eb5141cd064161d032e707738466de8300a68b9b90a096cf028e089966c92b2f07eb818b7da9d39c27140a5bd68b77e68194b758b739a477a6e28846b9e0073443be7abbc371e705758e671f552250e8c39bf9ac39becc199c4118dd483c5aa630f1b2393081e01dd8d204a81eaa3fa217254bfea26ff53a7adae912e8ac7a6036a730624c1a08b92cfb14a7d717bd01415f38898f50be4b76ea7a3513322487f5795d955c714ba90027cc166e0dfe3bee239e734835ae9209ac005ecad23fd276428e0232b86e00788aabb899d08847850783c3e56fb972b3124cf5c819f920b9c42ab1aed7075d010f42b2d9893216957fff5ded9389db88ab4d66a2354a55dfad086475b670517e55b244b857f8b8b11b98b7ef4f0a4948ab140d01073fa34be33a74a9ef0e9778596bc086348a0705606125c84864b479e880418efafa0ea37e9f5166c8f1ce64d6b4900535e868e955c9354963c71581ea8799582f82f036321d4b9144ec99840c70c7661681f7aae31caa7ca91d787595e217f22c5f9cd2a5cf2e574fbe2998832d02dacb40fb603c6b09ef76a02c62c9aa3df43c12802fbf45efac5c895791c909231683163100d3eaa7a9ec0b0718735e53a26d65ca4739de5bd49fc324a8b71fcf9db746f5c59e4a865c2aae26bd2c2af45805785e3ea1e68944dc8a06de6aec1075036def07c2e82d68d312adf4802c8033a7412a23dc49f71b1a8022b218c3956fa45df44ccb7694c3441b11d70f954680629141b58aae04180335ce4bd1038c77e03de40be03a58d9bc0139470014d2b87c4dc86409de4ca2085bf8be55d63cbad3dbdee4f6976dd0f9388a7c1e101f5f80837dd67b9fc36d4006aebf724eabdc0ff1af799a70669022996725c9c678bd1286129ee4c898ba4e0a8df250a2fc0531bf07512ed915e36279db9a64f87a240f6f8304c040d0f666f6291c66c3ef5b365583d2c47140a3cebea5c38a91e2e56351c65d5b43c0a2b69a18c710dda2a6208986e247f067c80aab794743375a5063cf7003919e4f570b1fbc674a98ce0a5def71d9622689d6781fb81d6200c2f89e23f0eedb88e587c936fafa881240fb219289b33e956ea46acc26f5e6b33b60c2c7d4787a09f0a314815fc36978db40e37b3b310066e94d2d1a3d72fe9ad613d4e793808d16201fc2901fedffe8379f31f15d5efd3c50ffc727fed558ca2f463bd145f08aba2f4eae5943401724cabc179cbef0e9f3b76e8789d9aea41bdd9f079200a43136dad26a39a0b66c900ba4fe0a4336dd3aab01214fd314477a526dbaefff498069c399bfb1ec2db73edf558713c73e482b9f64be7c0da479810cd5f8bb005a54edef36a5d642927545e24e287d049822e8ab4e4bc7272f4250af2afa93778b9c99350e4cddbbd20f7f5f7ebf0f4fd372344662b3d012efcfdc7ad1a0c3cfe46f316ac458c22d7df19e261893b0c74b87c9186245325e8ca64e2a03907045445673f7f2f0869014e7f60c4d547c16f5dcffff29f81649e5fb75c71f4cc97864db1399b4e40cf64db6edf0e80dcc5522742492ea64f84e21388854a1836b0851cc21fa814e0a808b44fc40c4ad82402c7d6ceb431ae525df19704bb9f58bca434baae40c2c06004e9147c4ccc59307c9c9a215163dbcbbdd1c332e3c9e1c921f36cc015a0710ed7b4dd32cec80226196c7d910b9a0a592ba492c837f3389b4403555e182808769cce2cf6e0dc3d65f284e190b6844e926cebf3ed7fc256c68c37aa8efd4b1031f80ef08fe76ca91f122ebd47a9f04e05fdbedf249304f4a73f0848ba8a37edfdee892d0933282bf419f300a79640a97812323ad2515c2273c8e93ecb87be24cd769afab497e07415308bd8ebaa135c91e6f4f9169a695a63305e7dd309a5c683542cde0dd11ea0f5a693e09cb2cf326b291c718e04b01edaaa998e44e08593e134141066e19000b88dfb3e4e269b70d41c87b4606f3c019c0d6f87e46655482372c31b89ba55ccfa70a3abca7e51a567970e47f6ee7532d1fd8aa2b2e5a584edaa70d55e0dc13cdd9c8c5bd1618ed6351d6256c3d2f3017970b3fad5f27be2ac6303dbaf6b2f08c149984ea3a96931e0647d1dd81e59441f1eb5baf1061169197cbd990d217e90190f5829e00edac7ea89ea56750d2f8336ce5231550b788110eef513007c187a0813d57d329504dad60aa093c4583052f6cab65fdcc46f9bbefcfecdafdf7f097eca176cbea7aa04e56b5fe218e9b28c33a4a5bb3166f78d72619f5d73cf26d6ea6e86b53264c191ee8bbc43543e9338c056642ce28ee1e95c97ea17cbed6e2964f3660c5fd44836d091da8fe9aed57a1661f087a75791967aaef46d4598fd60824f07a88c759120f868dcee3b5808d3580655465f77edb9aa434d26c3526dde2d28d8f22e4f147ba8bf54fb66e2b85053c82c4c551c80aefd986ff8957eaeecc9eec28a234b9b700c3c3cc6735f8a7e468c0880209c4c69895d881042c8f3ae98090bca8b8a40005ea79568afbb330b8dde557ef97df842aa6c008c5e4bb43a4861c603f1943c0048f781fa8cfb47958a13e768b9b26a828db07abe6d43b4867d7a238f0bb367eedea2b356c89615a42011598428228810f145518905b87a7991e848ce93081bd09b3d7e1fdc4e4bf324307feaf4d05eb80ffcb63c6d8ec188704598d06469cf2951797ebb12f4b3e2364bca2442eae3d48db8d3179be211df8e30407dc9d85e6ca8fc4c5ad76236b35d910f0d2ab48699c48fdff72141d1c8b62e477c8029d845e17eb14b031af9d875430cae5326fdef1824dfbe843afcae4f9c6d18cce985d6ee5fa909ea97fd3c008aaf041f3a08c95032655fd0d1c5dfcdfeb2ad17a564f883c6885938c23d822e0c63e3bc4ce4788470ec5c53571116b58636e8db8ca3bf9b4dcaedb960cc22b94472a2717d8b82a5c5ae7546839be87556b705883168517b7c3f2ec60ba7eee7b06ee69bd2a4e0ca913837b21247fc21e4a29e709cb991acc38f288af5c2dd581957e8b7b1d5b23609b1262aba0563701bb6f114f78a122e93873171ce75a04b65f9b32366eb62bbe45473df5b2982328fe87b6b5597408355bf2bdf5b995559a5a997e898391ba1da6edd006ddd9a9c88f7e17ae8bea35ecaace9edfac62f8c3d2fabb516817fa0a1fe69cd7a3f104c446ce5c547cdfdc3cd5aac1e10a00c3dc08260b3d2e21c7936cb5adc26095eacef43df29861860d86dc12d75e9658d18bc5bb7b4a15768c4e974159fda47787648eda39d30fff232a0351a878565bc309d019181aa2ec4c31e2e1f7d601312a75399129ba41728b80266bd33982d326424c40e441d84306f4158b9af4d26ea3d80c8c3fcbfd7f6e06edbc453307aac720acd1be9d227bb5f57cb03aa7fd9ee1391872b77facfe0d427181786300bb5702a9b60d0178faa3d4e3356c85edee2a847c02f40766fdf38544523e9d20e063f46894751007eb39614b8cd4e9f0c8fa9612ec7f3d114a7336778a5aa8b8238bd8f20b8a49bed91f527f0639a972ddcc91917aaaf13b96fc46e8093d3ce3ce875ccb0fe6e5718c142d19b24261e48b191092d391631efe49b053b23d9ae0f628c1ed72b5c30996acfa322dcc61ab40301d4ba3b13480ca12a0464051ce9e4310e7922a6b4becec0fa7865a7bf8ace70e1771b9319f610efaf1cb000650f45a31fb43697cfb3afea59f1084e017c67ebeb981e0b46c95abe6ec3aef4b126dcd35eb4a70beb04d76b112f479f59fb5939e8a32d1618ded2dd6fa370be2420021d27aad74e15465f1b3b161c3bb80482dad8b858625de1b56a32201cbb7cb0709260661a7f923389a921d1f92d804221dbc39f1e685800c21cc83a2991ad4d62c4e50560410c94bc8e9543e1e768e9408cea55ba5efd8d9845a0e93bfd406d5d9eabbc3ccf4a364b0866747370df753221788495deb4c8e3ddc60b6721922f37b887821e87d7f7b0782a468b4ccd4f49a63d8da8ebbeac6c7085ee7f5c8f0136e9c99b9b9066cea2d790cd31c134c3fdc6e005331178223372f81ebd3953b8f174d4094511ab1f7c568fbd5c8281632b70407c0d6eca3f2e4ea60524c78eeab7e78e7923641f9542829d01ec28bddff2bf4cfc6950ef728eec599a0189c94cbcb302ff422f02a28492e805c43319967f42819981a42a1eaa593d8a874244b08b7d7a9d15e5a9507a637ac7083adea04eb02e1abaf0882cceef7f883b02322885c16f4aeb81dcfb41bac2292e8a6bae920cce8b7bffe4e6b217ab09d180c9f18b6005f5b504dcd1ec2a80cfe2ee88fe018fbb96c162f093035e9e6c3402d9d880ece72df2fdcae47875646daaf0ec48226c42dc3f669d02683d886f7a0d4f85ba6be9943b518422cba6ec821b7efa50f3315e3dbbb4d4f0048c44ac53daa88f097bb84b547bafebcc938f59ca28055dafeeef0cf13b488f01031c1bff207a446257ee56206e58197619daa316b4cd0396c0c2b18149927c35304749e03d298427d7d9911f032c0451a7354d63f4976c05928b13be2baea031cc88ec96678c2fa6f5638f599d53086f74b780a7bb957a28098700fb0fed48569d93fd357ba56dc6796054feffae06baf35efebd0a3b390b253f3401bec85783d58445bc935b4396207407f9c145621af8725235fa219a28c856a3df798d91ed831dfd6fc0b5d60aaecf280b729bee7e708f4262e554faf1880221906ddb4ac4bbdd0251f403ee75635f9961ff224163723f3811b077f73aef2f121470d77a1b0275a78d207837061ba847cb65871c7656c9708d4c5ce00b0b5db5a47d5815f561e95a50fb695e460810d909702730900b9302b3ea5a1c69b301230627ebd232928573014f15ca60825c80788fda2d6529299cf4b202ad39aa86328e895f0188158a7c5947df3b2b00cfeb9d1ff98309ed00f8e23ecef00fc4897a5e13f549ddd5e278b26ee0d6d94d160c145a9510c16007f6a01482782e4e0659d2cf667da577dd650d5364aa41ff1a77128d28557b02ec684e779342d61742f446bdce3d387cd0a96cd29e9735c397896bf359292278546f99bc40074cff54073f81ab695a1ba3d13821270c70216d2a3c2ecf62020d594b3b11170ac366e4ede16ff1860c6ab123b158d9e96eeb35bc5277e408d85d6640bd9e07b265e1064304069fa92221e30ed538d793e93b4837d4878645b997867c8d2c3dbf2c9334edac108bc3bc11b805bdae0d85a8b2b071ca1d1527d60c58d491f7718fd32f1f66fd9495fae07afb112b9b3343630f19069cdacb1bc35df753e164cced7f3bdb40e5fb8b871cb75d5f5a78b03a1ef4e2a3a358be01bef0f10981042b81155caac084fec68fee4f8ebbfdf4c9a0f3c49c5b7287e388341d55d401e9be156c9ecba989bbe0947c874dd6a9bbf6ad1da8f6edd752df8aad07a36b15aedacf1a7623c302ad57c86015bd05407f3f433d38393f1582abbb61ff13a419f279872573bf6fa918950b108bb699388e4afcc762448820023cf13125d2839c4df1a96525431d20c23c9582131ed29eb68f116a603e2fc610377d31be015fb06797fc7f3fd38ef64c30cf3996156d4c6773cf3fabc4e3eeb854989b252b44c46185157e5c13a2d7ff9e95a236cf81220baaf2a9efed2e376d73d5398a1d440aaea9e583c8d0e9b1232e0d3b10866b6eb610d8b52397f7c497278ba1393544fa38e2a3435eb3852433323d41405d465b1271dfd8f7118132c81ae71d7dbf65ea637ec86829bcb9dce17fffc3c905cd8308aed6b29dc160fb8550e2f88b7c100e23e7af8c7c95bb284a6f072e86a928d8c68471b80d9cd56ce0d9544485909a08f50015712a11852a01368bea14fda010a582a3a424caa494aa18c740248f82a6e0583908e61242aacb621f015a128449c45c9c8af83a77bfec83a3c82487042c076c7cc4567f80e25da8fa53d6d8921a6920705198cf9faecda829a0143f23d6801a88795dac461cb010b8435a0870c1e23a7b52b8d2195656fef943eaae64e05a76c055d376b5e2a7e9fc885f21cc4fa25495a6394a3a018019bf5176ae3fbc3f70b2a002fe1bb104954f9c4ba04a3204ff3cf9c568a6c73e8e3424e88e4922e4591577a8485afb9ce02dfb46a5cdb900c421bca6b67ea2f9214a22a4d11808a68832c1501641792c7f2d0e37e7fb3081d9fd4d02d1a6a86a8c430407e7f5d039ae65e97ee63d2f4b59c36d92750383a0082c39f73bbac8b336f5bfb2c7ca6dae42718e15eb57a48597943c3fb409bb82e1e5adead5114f99103e098ff78d2e3dc400dc76ad7655f6ef87403ee34394b2ea2acba9d932926440f2bb997e74fb68780b0111a67e4577e41b58619dd36ca9fa9cb36f42a244508f07aa4bb02972ac4cb9d96228b3e89b6949ac95485dccca3631c9052fe136c9d9067ef226a9d84ca222669bbc5f4f90ce8210794c8b31909910772bcdb5621ba5edbcaaccda3d500403e70ffe6f10188c682c6d02db84f05653dae2611e268dcbffdb392ba623873b93cada68e497eadda00ab354a0c84b6d32d64d1de3683bc1dac909f2128ad5b95fff963d0495236db17332e4cd65192fd56dbce4e194789fa3c39b8be24057674e3bfd53a7b9180eecbcab53f5e70ccfe66f19001c3e1860726880453c8d3a93b3422bce32d44c80c1c9f476c86af0012995ae33915e8db0fc853e61aee6af3e66058fd6e56a5e64a49d242f8e283d108139291d32eea6084566fe916157b0b421bac04ccdc54028e4c6025fc32d3e586d7fb66086074da2064e8f4804aa70587a3f7de439ef76af6fa5d82b61b9e018898d1dd28341af7ace2c3651630870ce5344d4ad7b806320f1478a846e74f886eebf54bf4a8066790acffc6311b37d2410a4302ecc64c40fb4f13675b2670252c54fd7858846872bee82aab921b9a7c6f02c019cfb40aab06fdd017554d2c10a89d0d8facfecffdbed5ce3ddd12ae058ce9804b8ee2ab88c71ad5b9c26f5f2d7f5ccd907062b05fb6e44d55f3299afed0cb6606fd2d1b5e059d762b46a07a72bf26059538cbbc66d70bac198ae22cdb8a31723e9ff2bbb6575efa486cc7a5de4899acc0571dc168f8f8d8cf55e3b86e35d43be602538fd41ae902b540c90f0c48cfa3e5058ed6f6fac70b457d5ca2659d339abd00afcff48054f797a665328fb23633ee7024f30333d3cfae7a89c9261aac119bd326a7a309cc683eb3c0ea95b0bd3d2060254d57e9ebdc0501c755d4d1a6f2d91425a3a33c9306248e53d1c4d470eafa1f47c50d590a3b0dd73c54e42de0eca97f2b95405211710cae9416ed1fd8d911128d351c9706cede09c7b126d6425e8d46491f802135fd0e8283336c9caf1f83b17e7267ef320c653ed860d94c9eac9b90fd927642445b85b7481e10768de517f69a89a22719fb154b32912356f0b69ce5f728d1856dc67186ca38612cf11881fa62e4c0ebfe5033a9a2526970c2fad9181264c8c8da7d958ae11e669f90111ddbfe3875a779ce28008de586492a860ee4d931c76a0d0d13948a804ee27614834597eee0f31fbf6c0b464b2a11e9b39c37e51a1309c64cb54b62674a16776f6aa88f6e5bf6e92dbbd43bad33330af169170981bc381a8a13179d28353105cf78ccff32db03076e02748cc88e60fde485127369b3dff5152a24db9e9c39337bc509602425b0e499a161b120090cf0cbb6486e6aafc18357c3f260ebb7a1c16801722bad0aa2a0a45273f98eee370cc764946c5679cbf6615130c8754f0ca5e4987fee8129653c9452557ce82e2558dff03ae6a91c437a79cfb21ebfb23596bdcad7e2df8969143f2352b6fa5eb97e7d06ed09de128cc9c0305ff4db6b591ec31e641b2d6236e974a10dde6ef0eff569380f7ea12260e19325d209f13d6732b7166a148a1bff601766c3a16293e44583629957613f126fddafe4172fe2c56496e2ee52f88088c345532ad8022acbf680ea713fd5124854522ea15cec810a07a9555c11fd214b92d2cdb9a80ecd1e2f07c3fbeefd7f37d7f3c9fe7ebfd793e9feffbf37c3d9ff7c7f37d3edfdfe7e3f9bebfcfe7f3797f3e9fe7e3fd7dbe9ecffbf37c3cf4d52ec4a0d6f082b533a08c0cbf4b9a9bf6d9b304027d756b769a6696efec048292a21bb0164bff769c7c1fff84625712382c3688b30f64d13940673077a897dd1067deba3b4c0db5c906aa73bddb3e6654e4e00f57d6f998b9db1d846d4ab1994b480046ce897064577ec8fb43fc2a24638e39593e3085c56de3c23910e91618b7e8a185b58755d6f638402c408177c0d19026c605840eb6123f100e7627040f3fd3c9caae713dc95e62f49726518060ad3ebc199d3e85372862e9e63387ef269f5bd928e2561ffc4174a8137d80f3a07b7444a3b4a5586519dcdc051a943bc0b9100fcdce4fa2a17a56f412964679ac20ece00a7c9529fddcbd1a319d7e0a3428ec00eb295fb09b05ab241496b8c936f9ba77acd1c683ab94451355266155ed958e88879dd0079d0f3a7347324a2286552c94a54bf199982eae4568662cfd50ea9c5246d1aad0489ed8c1e022bd825520ba542588d2079ddc419c46fb61471a4b23849bd5e076271b2ac2dc76f097e6c0688cab082c06c35f30df5b76b9887ba31c6a806275f010b1fa6b26008ecaea22d5d45ca427272a5a7133ac2e474e3a04dd1ede5b78514e4cf0964b37eda003dc079c0bfa033a926a5486401f461683ef4e6843bf438d38a297c9e52e3528ccad1ce561377a61e7f0c6e818462588280f9b3e1cc55085e08993f800b344444aaf6fcca10f4731ae246ce308e11bc14c69105aad943c00653045f41a5bfe65c48474adea960ea133107a20ba2555ac61c787357513610e3b06de95508cd4a22d04e271611483d70e42f0de6330d78683757697e38c69c3cc7d6a6a1114e1c7ae5d4801b53d0d1ae7b5b56912f5f7bd17666116f9598c6e5ac81b5acd8d4b90aa5152092849289d037d8db793dc675fb9beef5b03d01e32f3884b2fbd79a6cf084eae2d1052eb388dc3bf274ae334352806c17eab4f0dc410581159f0396814416a66fec8fb371b348dbef590fdb3f2adc635385a657198de9f5504e06f7d50add5d2db6a21c636cfaa6d69173c1a3284ef52f4e57d3324572dcf0be8a044828aaba40ce8c9ffba09a859952841479093ebb641a4faba840b337a5bb1abda94dd7e4a9247fd1bb10b1510437f1cfdc13a7a850ff2cbcd7aaf7dac868b20b26162b24265aa4921b4807decc6912db779c4e565f9570ea856a908b3b8279a9dec00c15c6c65e82fe23513fecd01d22b657c60587193f1a29270b8e5a3f8fa02232aae7a6ec2987e74f20868e6664efa4a9be1b0e672d16f8e31c5430017ffb0a6ef21744a828daab32dd9366d6cfa17901c3b6582f0abc6642a25a9ef649facb846544257ef7701791f2650216cb3269851b6a349483302759456ca58688259cc065ebb4084cd896535cacee0bb079c69edd25c0f43d4409f9cd15dc7ca2f359296547503b6efb50706ccea038a168b9d5a301616a9037e87e918d3f541a347e65e2497b0eec0740a861cce4967a5a4de044271f3afcb560f97144689a6023b57bd722773621086802734060ea7adabfc226dc5c9fb605c2bc6db4bbc78114198a50449b7dd52ee2d534a32c509de09da095ca7c867a522617cbcca74f930aba755b2a53494fb44642731881c30ba3cf015baf7ae5b4901425b77a7cb9cdcf69884717777f7184276fb18443cfc6310f5e8cb5e0142fc4951f324b1f2faa0644cc61c43a636098afea40ab79bdcfe1af7f1e5f611ff4ccb5cc55324aaff09322ee37613b9fdb2b984f5988471e2b20eddbb9f696f59d7322a9d12db8705f9d33eaeeabebf7f1ac8ffe964ed8f0c3a33c07a64ad3486d0c62149123d492859b14caf98dc9e91618f4aacaa8ceac761eb7cc2ca2554d4722ca182765baeb8dfbc8df6d0e18aae3c20250c1a10e105152680f800117aaa208425ce00c214265c71440824ce20c3678b1c302042840c14d4400941acfa73b88a03591209b415fff6344162f05971cf24c7e68a724c49263935b7bf01b24514902b2e0452a2f841233d84c05538e0409b0018b3242cd1b999e206437c70860c5e4280c28a25353d68557cb88a044f28e14491571249f860d58f0157c925c0707c74808429a8b082d513c428220a3368208315f8acfa1fe0aa060421d3c14b0a539620c6aabf45d3092bd62d048d027d42207d64b6efdab64ffd8e0a3b646fafe6dcb4bef403c8d0176f5c06cc38e87f6ccf3d0364ca939061a7fcd5de9cde9ca04fbacf48294758ff8078f033587223190949097300992c6e9bc1a37fb6493f0d74f880cf471232d54c64d8a91e99c89494dd291b66fac73f398eb2c75136fb676329b151ceccc806c81a954e89fef297d4e13f8ece9b44f18b2e3f7f0b979fca27117072476666eee9b0fb676c55e8abb5a7d3f71802694f6a50baa57420fbcbff58c681900959d567306a7aa1ed4518521534d90efb7deae89f36c91401fae42a1128e3a8fe368363b66d4eb075a0846787abb8dbc966dce69fdbccaef3fc6281ed5146833981d2a923b77b629d7a3293176c9d9ed1ddbd5b1d027b8c2261685fcf7e5cd55e304aecb1b99032aeea98b78f0311c6edfee971e6c08a721cc7b19d78f78caef297bfc6dbaf9918061ac5ff23cad107a7d692c63bad8a40a37a68950c8d9a61865aad3d9dfee5c8727400d0c07bf9f1b36d39b39c53ca29196420977b4987b48be37ea629f7f2e7b365c9fc93b9b9fbfef6f1cfafe5c6028f7bd0723a457b754a3af7a0e54cf935c8f7972f1909dcfb9c3ee7e6f59472c52db743305cf921ab460c727515cb5cc6fdc986376ae89327991c3278a0ff4e312775807ef4f33d19f6a364aa76d87fa36bc894e8e58fed7ff8d3ef57a770e8300999e2800cfbbd5abd5a99ef94a1af57fc8dae689158c6619c928957f2452bfa268fa36616b6adb0dbc74310160f7e064b6e24cfb7cf48e8bb4f4a18ae756aad9db85c84713a6cff3aee6b25cdd3f36b0ec8148b21c3feae752846efdcfe6e2764d836f44a04f6112b324ebf36eee7e4266f1514fae4eabfafbb9d88070e38481a0eeaf217a026c0e29c687c74b875a845f3f9eb6c3af4994dd87e7133a92301b77f3261693aecfe3e42aad80889eaef3a12a9c615190767092b720d070707c725e35acd070e19645fe867ba0133dc9c5c7765a7a6ec90c463df13f170fee405f195a2c9436e92927ad0a874282f0e77820f6800f3d84e3ab5cd8c2412a984230c914434f8adcf835fa7a00c3cb883394a3232322c9c68fbeed20849518fed1914652ef39df16dfbd3f5daa1dfcdc11b2c221e1b18766805cde786be5e793442dc27ad885233e7275da89c3c16b64f16895d3e723b87a9887870ad8f9030dd4830aabffb094689cdc4d4195d06a711cb62bf1a0756e42a35afd56ab55aad5ffdaae1b82a64ede9f41fca88323b3473d7e0c0610369ff9da40ec95fdfb6c2d674286fc7bc85eab6754f87fdad73fb0b4957b5b4c2ca8dd483e6a384ad5db90409415c29190756ec8dd4230ad7f88ccb5c85b7b9310edf8e754a9438f4ab567b7a1742dd6d4124013ee36e2ff611091a09754e875ceb10d8af8d6b1db6c8b5dbbfe108250c3fa81f80e3e9e4f4ab6b9a65060dca4c09cf8eab8acf0e12463a79c08deef1d84af9325bb6011e5b76421326152b2553018d44441c8be6b1952f5c5983411a3cb62b7029ec8c27a57407a5d481943204ce0ebb2573196cc32c68cb36507ae6f89633bb2492282181c4cb1147dc78bd6046bf81d8e314f5df80fd99c199eb85c32b043005d8c06e332cc00676d3a183529a00956bfb9cdcccbe31333333d32ddb383f2e08400002109834343434b2cbb3810d6c60033a6febc9e690430e39c064b191e747e8c70f110f29ea41bbb93f443d68380caa466717cd9d65ce3176b948a0aa412a470d6490e10005680f48018ac818a0480c31c01080a5c8273274f53f397166661c322520000d0680830661288000f8d0644e629599e5304100667003861980e0f742e370abd67a6957ac3227185f30c28537c2860d5b5f6a28197958498f3176b98b5d17e605a981736201a7a58586a95dccc2a16bcfae388584a60cacd830da0ded865684fb6b93a807ad48a7440ee5d5e1ef41cbf96611b607ed0596f86b251db2883a0656be4e87b2c88dbde941bbe941cb895d2fd2aa1e71b617c771cf71dcd683a643cba1e1d06e56443d683734578fd7693822b1955cef41bbe9505e6f259d121bd6b0e6a9fdfe32aefa3f9dc41cdc320ec83c79c393ccdd2c3634e73cb1588e52296570f4e01b4ad9753dface789e277baebb3310d18d9536c4a3f65891d64e6badf5661accdd2dc3c343118f69b76de3388e562929b7cdaef3e68ead8d0e2537473e89b01b1782811543b565b769635986b01b37048e0ea78db536d6822fb0e287e61076c4325d568232c8b8c0e268c11cc2deb0b1b24390ed2ae5ec3647930bf5e05b29a5b6eb3a1008e4e5e0d1a3af27254b8fbe52c2d0d014c2ce197074c87f8305963b64c33dd4ecee21cfeb3e4d2b128d462b5692489423310804da40d31b0462b922732272977451bb72e4a2c89541b8725cc291cbd2a939b1f8b96ec51070ae833df41dc1e9f6705ab95224dd7ed174e5680749c6f48ba22bdf07ebc3e96e3fddbfd2af258c3ff7f598d741911d663950047ef9cadb97ef4ccfaf75e03baf0e7cb95e6eda7e057f6f06619b5fac2dcb9bec062543e1345760b92bfe952c1d5ee1fe6009d3cf2c29c866d615e7b77c16d5c0ac56c99956357de1ea57d33dfd5a75455f7ee20fdd07448e15f561deed5f68e0d7dd40075bf4c2813ee8cb4b635795fb171a4097038d5467d6ad1ffd2cff6cc2bbf02fdcc7c5703166b8b914a6f004004300babb1b00e0f72fb8d0828d17166a9c5ce44b29bbbb594c25925d1989421ea8ab94dba6374b29c391a9b6c536679d93859b13dc219c3f7b4ef739a77333dc4cb045619bdb9cf302958a990237829473ce1a7df2b9558ed60ee48544a3154b2a995868b4b89c6af83b8a932ce5b6712c70ee552cfff49e73ce39e704450f5c07414bbc0a5d54e18b2a7c5105f63814c333868691128724c036000e45c31c95c572a74d66c3215f08955c30955a603179b0ae27d1f7cf2668acca2aecd6136d4679a88b47adeb7f43715c58588a436f36d9e6e32821d8cd55d3629dffef3994c681e3c60d1b365858aec8b1da67a12b722c191ce18db77112a94ba42e2ec64d2776f4f5456e7cce87fbe1685c8d858e971b1dd57ffa5a25879beb5d657a7e4f871e2370aeec31a245802b7b70bab81ccd559b8bb25c657a178da3d196cafad7307790b993e309c2cecefc5e42efff520377e5e869a20cb7d3613b2de77aed88cf0e5512d29eb9c48e6e207de9069637819c9221a01f3d3fe963f9b8911b417107990bfaca8d1200fde83d534814c190d07b2e3d529072433fdfc351ddebb1674beccafde1fd0ae841ef7d2fddf3f5dee3be97109801fbf33330f986483f987e7fccfa21fbf90e327744e536a784e3d9b9fdde8d8782230c9b76851537d8e692304e48d5763a914872738d5e6c283de9694a20cd4ccf26967eb3d6617397ce6feb408ab3b9369cedb5e938e9eed36927e64a64dee34e3e3949df1c1d35a34998f6d31d43579c3c5e6c6079d2d3b0fcc673fb69485f02c7d0157b2495baa7c395ac51fd8d2a7d1b6c83f9ac057315c955a55a4b24178e256138160bfe498e88547122c7e2a2e36a1714b9314697419f49187a459fe00b04640874faf4b76fdbe9708349806dc85cc5d1402f8eba619d4486fd654898fee9ea243225a5538151b04ef913e46c8daec8d1260a36d7f55c08cdd51177798bf4f9cc513e3f12c667ee2375942155db9c446e7b1bcc551cd7e4360f27bb3dc5ed07b971c23adc2e289280e9869eba28ad81756008c8dbbdfffcb82b451de8c51eb6eb03dff95ee839f49d8847089c3cdfdc895971c26e3fe81367ed34ebaee83fd761cccc8ddcc88d3c0e6e3bdc488515b98dc8942b75cc8d8553c60bee7c02c7e2589daaf1669fce7394b12bf6d8e3a96b05f0f95175d3c5446ca597d3d5a92642a6b624d2d5a90dd66109e4588e02593d1cd337220af48af43ea330aa23619e60543fc5713a6271690fe88bfffbebf9d7975d703fea8484e1c60e93c814c744862c57f18a63428fdcfe145d42861f84577084142d58fd309b40c50ac94b0df3fddd550570c14aa43a52871352d2286eff948dd70acb778e9cd3e16bdb649d129bb53d39c23acdea9adb3f65739cb18dba28ac86796715762e91a8fe26ae2c6e4f2e5aa7dba2394a98fe39e208cdaf932bfffef2d77736ce2596af3869b73f00221aa4940b02f9a643578b5d2d9a0d88a371b42b7234fa0289ea3722468f90d12566d4c5eedd4f9fdd9ce31c137000038842ef1d202473e9d7ef5e069103e6871ef4331a14205891ba6e1496f4a517a9ab566b4fa712d8511708dc41e6ceef74981f7a908886f9a1f7e6e7bd8feb2ff36203e94b9f01d297c00cb0bc7414ef20f3b7e35a1d72353d964506110fef6510bdd8407a96cf40e94def7d1de8d0c36146133916941d10e0e5c0b1381657e3aad2f7bbe733976262a1f133cde250e4ca67aee2583438d68c63891ceb0e59020545d476661086145b6c54fcfcc0078c294d86287d1ccd51fda46f3683c2d16e3fe9fbb99aab4a25920e77770578ab03634cf142ca0c9690042b786802135020c29427531499ee5e8ed975206f865037e74c40682eb1db157bcc2172c0c73ae5a058bbd0d3097231ae6732b1ee7a10f821503c5d91baa84bea88491d0ab8edbd58412fda8ece90ecabe1853b8d949ede94409fcd661dce42e036a9b0a2b75aee8162adb6035b4e5db4c8edf726ff74c8205719b9580d2cd7df5340682eb17dc51e2730ef10a9171a36061fd0917a44616d57f41975cda0dc7efa729594820b86c0c384cd0e9c40b2eaa73aae92478002095f88310512a4b86225c708c30640f4c00b276c62b0eaa738ae1a52d3821d540982144f7e5eb002b9d5b18ade5c06a96bb4e21c5d97baa88bba681112bda12e57798be42deaf296b76a9d9aa3ab6ab5f674f2a95de8b5d29c032478f2865899a32151c9336dcf9c3b0f3fb02e3f73fcfd18dd1eea65fe7ef4504f2f211fbd86f083422f02830811fde8431f440892ee87e4c821bf533fb8ffb1bd2fa07b11c73dc0b3e8e5aa417f43e845a1078142462ffad007092204f4de23a119bd28f43dc0513c2ffc34a21f3d8b5e18b401347a4fb68c51fd35f36b80b02b1b3f1b5916abd97820ecaa051a3fd3ad0efdc68bcc29ac586f6e77cff2a2cf56dec792e945977595c77d9ac75572d52307bacba6c3d66dd0733ae44427eef4f9cbb9d007faee137d6de193ab95e7fe5da5516c8691ae0609f71d580384f59a96ccaa7b20ec8ad529fe8ea263dd0346f577154dc5edf742a2d9cd2385257d2f6f3f16def4d5f8d277fa95cfe559be969f22fef91919bd8fbe85af6557ded3f854c02b1a6fe3ab014266e57dcbae462f453c6ccfe00bf7bd70a01f2161609f7b22eea5c8c7e8abbf1ce5546e7ffd81155b36baa2bf10203a139703fda5c48a2d13cdbf115ac9481df30f70e51740eed854ae04a3fa81f08e0df41b8e7125580502d06fbaab021025fcc5a87e7e10b0cf0defe032644c73188cea377911b77f24cce83ac8350933c507b5d9032bb62c0acbc333399f4d587fd199d4b1e3f6bb0e8f1d7d8b5ec65e5628e38c24b6706d3184a5040ea63cb1f303204899a2171b44effd0da30f3d7fde957d52a2a48346eccfb4f7a465ae6a1ecbe32f22cc78e1a035050d665064d5ef3caeb2001038b8c21763e4f8008955bfbf5c3544052e60421456c06242a062d531393892832a88a08322e0acfa3def65f7a3bf01f41e2844f4a01f814290d0881ef44246dfbd5cbdf08f7ec84af4bd30f86243f7a2a7e95ef4fc223008120669403f0283881ef441462dfada67f44d1e1baae197b7a40ef71ffff11fffc9d1ddadeb443ca688c67bf9e4aac69f9e854fae3cff78fb5e7c809e027205fa1b1c8a18445c61257aaf5b3eb9aaf1c9d5e9932b978f453c7cd4a860086be5599e4d5ffa4daef8e5233d0b9ffd1a9fe94f5fe95dbe956ff9589ec6c72bfac96b835cd590defe4cd7805ef433ed23042b9966b7e5caf4c955e9932bd22757f6932bd0ca3784c52c4c28acd8b21ca66ffdc5f4e48face5100298aed30006dcdd3b77e7af064742441657b846402c24f57f10d5509fc57f9950587ffe17ee875c4e031d561cb68e431b03913f4080700d105771ad56f399bffce518987dddb33c8d107fcc4dea237fe73e97f1f08c356cb00ee7f0ab48872c20356ad4b031457f79139e841be12349f8087fbd7c7d41dfcbecbed1777f83e841a010d08bbe038520a101812f3eba7fa1805c75ff72c383c097f9decb95e88574e0cb045f6c007de86fe8de0385784290d078dfbd90d0835eae462f57cdf3f988c763d765a34fae449f5c853eb9f23eb9e2e1c35f8ee281edb195743877604f8e9a3b565ee947f812ee844751f397fcf117bf388775fce52f7ff911cff1d78b7bb8866ad7e9d438fd6a9d86bd107a00fc3f00668330840430802a3e5404405f00221edb0b40d4a32501dc37fac3356fc200e8e65d70dfdf5ac8de42a6aa4c6c19d7b2ad03bf7fe5dcda6d03c51eb6ab03f7fc1d334b8e821d0f1edcab22dfeb7588ab2db99138a4835dae7a3bb77fc43352e28dcef5963eb98272e78f8e7438d658ede97053c28a944669aef29ad4b2f0f1b8f8b9fd9fc8f3c67ba3d63ad6b15616776a3eabe5f25021af546aad4aa9b151c2841e4ac4837b147db7cd83fefc9c080a38a6e6f3964d0c213932610924ab1f2617545625162ae4d8b3f22375c82a6e8db71a014f69b50d0722a57932570d31420b981188788215ceb8c1aadf9bb98a87911f7c814385093b3fab21434831c20d98200519476062d5efc55c5582170a64708320924005d9aabbaf9d384bc284aee8ac1c57e6b2ffcbe5fa22c82457646a7bfe2a774819539f570c8a3d70eda4c3ae6959c792b0f3c58e4db063750ab82161c58eb5887b0f46c2b08fe88f616b4dc250f1466ff446cf49c9ebf1465739abc4f246673979b90a48a3f87146174f0b365f2199cf994fdaacdd7e161a2d2ea71a2cbcd868c18517fe035912b175886d27e284276f885e1006c22b055fac64175114e187be020f56485806262bf17499c511a941dce68cf84e915cfc53c0a540a62ad0291f1590291e43fae81453e990a320c39692d371108fd421ad28b9caf415e62e2fda9617ffb2a9a5e55bbf32bd148db6d968a565b3276f7f83c28a1ceb722d57b57c3fe7ead40d8753a4b9959577118ff923aea651fd2d9fcd0fef7ff4502f4744c6f4f770ba5c0a248cc7f2a69617c2f2269617d2c2f2feded3b0bce9a5e8c5036d207dcbdf40fa164b95180106bf683fee86c3e18a74d8cf4262f9e46af29520e71a811b0d4a87dbecf2b7786c27c7e25a5c4d876ea4f42e5feb572e4ffa6a80f895cbb77e55faf87ad58cdb2f7d6edbdfcc00b79f5ff9b62a3d56dcaa5c333a256feaa753f6fb2d28edca8a3802c5172961c4fa84c65d017fb0dc1eb65be5f60fb92f3fddb166da5271f9e475f96a779b759d3bb9fdbec56eac1d6ffb08dc9474784bdfe6f241913a56be7f438254714424aa9f0b6209b757408e2584f42e2fa4e54b2ca7297dcb0b7179d20b297d0b8f9795a769f9d24bd1cb0a7803092cfd0d2d6097c020b4075204f15a91401952122b57dc10af955c21d974ac05598911cb603b8975e8dd735d1a07bdc3b7d1cb9597ef6d5c6c47e01828f6db56beadd66117eb708322e5f6f36ccbb1dc15b7d98dedde635b7da874d8ad5f95e84ccf28ec0bbfcb0f5991dee56948ef020641c21f84e54960102434a46ff92034dee519a46979d39bc020a66f0183b43ce987acb617a5bf5c79f558c443f4cfdf7cb90a1204098dcbbb802ff6e52a88cbbf580cac802f13b48157d25122101e7eb8a1177d3cf075af3e1db65c911cac555a3e1a5f0b87eb3d7bf2849d71feeafbd7c376bd2a5f4be95acb1ce55dd3275720b069db0eacf3c6c46e2c6c3ab60345ce75fbab8fab4a543ac5bf55297dd5c7eb4f876674d862dc1f7c458ec5b1a6032a152376829b193f1d6e54d80d143ba78a8f614539338363712c8ec5d990b81a8e4562c530c02cef59cf7a565b2da23c171db2d29f10e415a594db01a98377b88115341f328820230c026c11859233aa1003270aaf65520cb3219362150c8ce26cc07ac549189692a9a1ca2c6ed9e01dd286ac912209f03bc82c6e31ab03524a077c9300ffec40879d03b7d51178e2981eb10a06c92c6e714d877c042b720e0e28497a40841648386108ab072831038c23a2ecc8c06635c4892b4c61848c28a048a9c2aac500e289154f3c810553ae58e5b4aa038d6a2a7ce4c43b70e08781553eb0a49d8ab80f3590d20b1b1bfe1c3a6c0777e0c28a528a0c0636906f3f9f777020b3386632cb871038b37847e5987e7eb90fac62259c6972c87011256e6e730db80537b0196266fb8a6cc3636e61d9866d54bcc33023585106068329e11d98abd886da308c6d5c25bb655aa6655a267cc29337443fb9e04f9ef816fec405469d4275743da7947de37aec2a38908563ba0a56b9b0b1b40bfe9a355142c6858ce12bbaa03d3ac7b4b0f38a1cf3cddd5d4a87b11fbc74728a60c566754da738219a8411e5f6e5072275ccef2f815435cbbb45e4ba826819d46a5daed81bb344f1090a12734ea3341ae8507c460b5152e54e840e0b1d1656b004f20736f20b804898fe1e691886230beff0221ce36030ca8bb0dce6b68de3b62d02fc33058c221c0657c106b77f72ada751fd4fda09c76e2fe9f18995300973917342530bbb912ebff0fbffe62e1f3df2c03acf4e871c9333d4ef6f2252c54de88b278e358b63602f915cc47a0c430a84fe00913e3a85a351fc4e6e8e4ad3aa50a3580c439f538806068c7780c0cdc53160b08a0362832581314773e72a1d36fb74dee2182058458bf05637ba1d2d8255927947672163a86054bf162c689984e9718984a912c686beb6f44e79453ae55f7fce38e8f3e710e8b9ccfad79f44b0fc6d97061af7e3c6d2933e4889540291ccff81aa6045029178df634bf268342fe99dbf7bd1671ceba3ef81b81df60de6713b73738eb5c1b88de378380f14653641aa4d264e9f29cd8a3265e6b329e1f66784f4fe33890cb739dd672170141047b5287db61e4b5f6196f2cc89d3e1cd74f5a04918da1cb92894af27758cae9c3dcee9fd7c51e6ce99ae417e71bde9ea7af41efd7a522423ceb807768b59b3c9a45dd1a3840942aa7a8944b5b7ba39dba3e1628ee68dc54d57d13279ba8c90fcf3aeab0c7314f338caabe8194707d9492cc64f64dc38723d0c85671b6cdb61e90a7d1326758c3a55abebc01f7a7ff1af879e6be0cdcbc2f20d3dcc67b378936d4998db93cd082c6c446c2eae0a6ef45e20bb1a21e911922e71db9b324bdfeb8220c5942dcac001148ab00241c1480ca44882104d98b0c13c1bec1d881bb92a3617ef0081d3c5315c15acda8cd04dd7c6b9240c47c408adcb3bb817c8987e147044dc7e71c2c0051d9f9bcb05973f9ebcda1894468801152a58fd309168b1229db8abb355d84c667bd20898ceddb106fd7cb1c74db63de956a740d4a9535af21ce0efbdf75de3bdd82cd6cb6b1b9c3a1c14dc0efb9c3a9de2680d05b7d3a97ef5e6e29c00e2a41ce1c010d9c0b16851b609e54e2f2617dc38639b0f2b0cd694dd96326b51e48ec6e1989e3eb77b717e71fb4987dbac5138bc63cb42c6f46fb4c9735b0b09d333b8fdde269330cdea1074c54d260129e5829ebabcebde9d85a5f4d251a28fcb9f8b787832a983b3902a4a65d6012321582148684c5f7a212c4f7a21a62f7d14560892ee85909ee58594def4a2cf483480fe85067f1e82f51f72e7126bf96f203dcbdf507ad3cfb4243dcbd3909ee53b90a6f4a656a73c10c8f4bda3f859badb7f827e2eb1f376ef9fc8d7673f7fc6652ea8bba603e02de7d92f18bac9648e0ca2ae299b3599c854d3a0bb05351ce3364030aa4536804aaf53023be60d9bf578ba39ac5c7206cf1d3de83d0f916852471429a75c232496aba6ab59f3c5d1159b35753aa4814ccd266438618eea284d3494ab335d13d63157f16a4e97cff2abab7826790897635ac854a74086dd2da6c231ec8441b1529d4e81ab289126681932ac28a03557f1ca3562418505915a1421c419ab1fb61560b142c2ff0d61b5dd6a39d068dce99099bd1d6fecf06e3cb0287e5180416fa753dcf2f3adab4c3fb79f73dbb6a7ef6da3dd5ef48e5cef88a80653e8d61abaf70abed0d0bd7fdd7e7e1b77917eb5ce3899b0e311ac8c41ef86fb463c232530578d1374c5caf2ae58597794eefe3c812e828415bdd1065ef5cb51b3b2ea743263ecd3994aa7ba48954e39699d2ed22967bd44f187b59662b3af03362479874fb9922bb9125fb812a43a0ece507697e7f4da7a3f3f6f89176b54bf470587fd9de3c96ebf37ba3095db2fc2c035e6956986d28ba71a7201adba2a29a015ae4a2fb630432bc7aaf4e20bd6dba630bdb807d5a4b0bcfdc0529a922e64fa5eead3f821abd2f752bd1eeec586d29b5abe04064142537a960fe2f2a6679086c6b3804158bef4dd37e21929198d266afa4c26f0a57bb90a62fa97ae5210c8f4c9550964a4f41e87a4085462f9eae88da40eff1f7cc53a6e3e90d1f09edcee811529cdeb7c329bd4f738c9b18f3c369d4c59873eebf457374bc7799cc24ace301ecc581cc30356b11358cde21dcdea7e31add26177bfbc9efa1b14b607f5e9f0a3749c9ba5b525e41abd18123da5997ec8aa9ffe748ae6f4359ebf067802e58a411750320aa401b6801d63540f5b15fad3519f2d0a9d10ebc7f36a20086ea0378edd4de7ea6cba67518f97e88afde22bd2514aa1344ab3f27ab26d079603db65535f399d027baa3ac6a87eeb453a9c9bd3c8a8eeda31efda5aa486d0b1da5dd429b1fa75379dabb3a1e243a555e166b3d54c336695f99aaff99aaf122582bafa554dfd6a25a8abc631b48a5ad32a6a2387c1515871bef83b36a1cc27b7413184737b32b9fd528262688825b55aebb1570ddd845c211bcff33c291d7a316fecbedb633d3dfea234cee7cce9908ac1cdee1b14bd2a1ea5d56e1e2151fd4b4c276614f3e5d5240c159f904dc815ba99aff99a4766ce7cbd2a109b9aab667764ccc951e4f6cb16bb1b19cf6163bc514753b3b0f36c063ba29d4022091fe125615e52478f384ec483c29ce52dafd928e722af3ca1378a3ee79cf5996b37e7775f6be72eaace7215a5352b94b9a23b8b86404a773a5659aea2a3a34e39405126accc4fac5cb15fb19a940ea58e26316f8cd1240c8f15ebab09eeaf4954233235eb2bc96d50ac535eafd9d56ef4c6988cd9a75798d322a80e13276f74c56abd5887dc4b67e6bcf71b1432ef49a7669dd2a17b289d0ab5fcacfb7195b324aa3d9a57f37c4e2edb0ab1aee581952b13f8e2a3e55f684aef1ea55eadb55650871e3611e907ddc7974edebe4eda136fe641f1467714c7e2ccb9ada24aa42703812ddbb1a2b3288b8807a184dbdce5e92c96b3660f6eec9cf0c75d508ce562b90bba5b123b5dfcdb7d7ba0e872c5f9f2a760071a29d19e0efb557af58bf26c4f50d89cafd73856599dd110a356c5d84d5a7cd66eaca2d6e2185a05abaa128cea5993dab216ef682eaee82e58d0b1eec58e759bf15305746b5ecfd7974ee7786323f180e004a7534c3d2b4a57ec58e9d63a76d8dd57f698d4c1b7b956f999634828579c2ff6e9fcd329913a6bc25a459c654f1f3af1272decb3ab74e41d1dd82f8ee9c622467da26051bbbc833e41c6502fc840e24691309446dd3de4b1d85b4ddce5383fbaf9ed5e8f070419d33f3f2b2e4fb0ead49c97102c4f81af40a6aae3d42a4e449d52e7ac6377bb70173ca34b4e5c3b9fd4458b9860b31cfca8ac7e74098d5dde41b39031940aaa45a3807a5b8ef517e9b86d221e1d85ddb835c4b6f680443c38a0ef47eb11f5555f35575158a3fa7fb8a03e0cf3a93587eae8dcb8fd35a7bb71f9632aecd36133ad530ebed0008a1e04edfa0fb93446f5d73a3d2fc4d6dfebbae5581abe8028b8c8811557b492a064c554d8a75e66f6e7671f7ae9771232945abca4483ff6a1c2dc65e651698d7d181457ae8b3627ac48ebabc39c0e753aecaff5f5ea544ea7746afdbadae1dc0e47c2b4182cb146e10b9962824cd51f82d6b5c8b853f02254b71c7b9a3eaa5524cc8f3fccf277d52b7f07d29d0e772077f8502f4fa7984271fbe98ed4f1b9383fb779bbbae7ef5e07fe6e75d8dccead6e79eda2a20d7d49df6bab6d3ac52e8f433d9d8a758a73d2a94ec6640785714cd351ea58223d3a8e2e5e0545f7de3f0afa6acf0b0db47b0ad62157d646b7fb69eb843267f38984e99c0ee76beecc2374943adad2faaa3a399b0eac4869544aa76a9da2d283e58adee89f27ebd049875ecceb81f10e6f0913fac4ede74c57f4462fc685381e0c7a4ebc1e2fd6a19703db81ecc35490344dac4e2acfc945aee82c16908a83e3c6159d253a8be58acea2e2ee0480675c6b9a44861dba184a9211f6c2621400cf5a886ef9a4230b91e43685c9d004d21975bd6a8cc1507df5103a08b236b15948b1b5b0af9e58a7a677ef2207a5edfe5dc4a37bdf72accbadd5a34169264aeb2b584503f45aa078617a7204cf0911bcb109dbfd7cd17bd91a279137d6aed65a6bad94a3b5761d0ca179c5f99a4eb80d06a3fac15ba231f1a470cccbe72729134aa363c79c40aba5af57330923576ed3e4c68b74b5765ba9f64c9df9aa916359b862c5c2f29773b7266c2b79799ec73e9d639d82b9cf16e2768bc37ef1bba173ed545c6327748b777420d5e118ea6227b08a16d1ba4d757807cf38a695a854e7c2244c7db5123abca33a2163904832bbf52575b447697d45912a3a4a54ff0ab5a276fb2913a99a2f55acc98c06e1f66f4c58d11b474746b011cf48497d7134def746df6c1d892230e4d611cc51239e91920e29f883bd51c28c8e748cd2b83ac65ac483c2ea58c75a8ff0e5ba097cade3f81251ca4377460a8b759f0c67a5308a05487328d76a57a3549a84a9506e7fedaaacd2a48ebeded5dad5eab07b63b3e5587eb1d26a5c2f067e552675ecb0eb4b3a361399a24dc870ec14358114467b38a673e8e8aafaa2231d3bc533da844c711714e62ad981b03aab51aa178ceaa272517deaabd6521da5d43a45a553d55b2255942651fd360b5b9bdce6a27b8f2df5c6ce8b815e4f879ed41145aa5a46a7d027b85c29e28eb9ca1b1d35c6bc31e68db18e7aa3b78527dbfac8c6d4455d1cd8ae256cfdf93c8fcc23ad92f33573ea4f27f7347ba612f9b3d371473bcad1ce6dda6b6afb91f69cf622ed81a17963eb7b6c7978473ad092fa729547854704987745d5b9fd01f046212d6f7a21346830d07821a66f7921a5a7f122a5c14043e34bdff2a6bfa10534994e34c03a9ac093a3da08cbd73fd229d84e95ddd25350acf7f38e74584d5fecc6322856d9eddfe1be7ebf7f943e75ea9482a20e3d6c977be799a341a8748db357452e999a010000200083140000200c0c8643c251b158d4d3e40714000c7e984e74561fcac224875114659031c818428001408008c048c90c1500009dd3e353358d691599108a9510e8a4e0ffd360b20443fbb502a2fecc2b93e0f2981b5274c0a70531908af52711048e26e2e8a63ec9bdda596de5a6f66887a98f32f5a38f4084c4454b459d8e6dbdf134491cd695a64859f9092b448b48b870989c893e5a5f44661c369d1325a2515518085386130dfabba53a013b5294ade0b788bfc8cbfd1934ddb87fcf8b067216b81210131bd407d256cc502a9250c37eb377c2832e63350335b58193745d71650ab826cacf8dce36992837ffc3768c2846b7793f7845cd5239fc0db645efbee7fa65f15803bda15b738daea4ff4cce5a9f62d170963bc4ab5f9d416e2b21f729032fd1cc24465a1b65178ab94ee2f1f7ad88bfebf5f2ca81e89cdea9a2a362c44e671c979057a72d0e6e9d172445b1e9ff6b9b275b36744231be5daf15c63d99fce3e317f9d5932bd8be4ce6afb259150830515c2d299f562bb1484fc063fec56ab60f0491fa4b20462e607b512b84543e48f5495217c58c4d035bd0ebc1cfc93e12f33052f77ce4e9aaaf152e795da5bf5ed7fa5a9adfc20b9c2e5bdfdcbdeb736d3bc99f4b3269bcd2f461e5384db6850a7dcdd2dad318e963dcccdf4b796ffea8daf320cb6ef1848c229f8ddcb015f9e5cb1edbaede79864411ae6fa57009e5686deebe5e1a71aedf6e2c34ad48c232ae692dcc9e4d6fb428808a990b27caeea3f0127c4c116e8e531503e93c981c71e02ab2e5450af6995ff4b972f73c1bc248dc6dae312e3975c357d344ee19fb5e6b3128543e415007c61aa43f90149a4bc81a0a804d7b60be350b6441420a94c2135e0b82e2fc92540bc3aa16f27e86806cc0b447dcecd5ca78521f6ba7673ac112bc8400150c9367183f6c584acb9263343ab95616e824cd20b5ecd7a8f851f82fe605183438d36c9e21a70abc24cb64b81bca6e985dfb6a99017aca292698d810c1935a8c8dcf75821e87bad62ab67d4b9ba8365c91af3ff892838b5acc8ae556e2a55c43af9be149b4ca4218c93a2994a00c2d439bc03015f6f398fa279526492dcf4c62fe374994c57b8d88a5c6aaf123f3552bf0c9653f970ca4cc5e9bef0dd0a43c10da6a518e1f0a3b847eb07e431f650309239a9287b224f4fcc764ece6d4bddc9cb2d6259509ba6803bd0c5cdeba3c063f47c1f49ac9a5a21c7303448921c0780f90d688a7d78a87b9aaa0de01e52d5b3020a2fdbdb0c0b2a06c6e5acf0f9fddcfa201babbb177307f78ed6e7b9928d569dc6f5cce790426ad05f31e61bab69977a0763dde8bd58bbc041aaea3e672fa0b5e530cf30e20040c81d99e3b00216b767a1b3a69050b3dc8b89ea963b9c31bab107a9e9ee6d2b8786675f1e47f95980c77c90bdef2c59f93c5ab932f4ab6f26184db1dea23f7fe494ece9b5bd895c7c687a00813da36c62adc00f6793337699aec5cafea1de634d91f3a2a43ce485cc74a17509a2cb67d4d543412fc186994da3012c0342cef84771753013c051350a38cd350ea24b3dd2ab16eb64299f9f637619089254032d5f4165a1ef5fdbd2f0cca5623a6f274789ecdfe798701ceebda157c5f057088d3e87eb0b373aab7336b5981a93c2c30c0dc6aaeeb28e7f2a7f2ecfc56d4510d65372d24269eca9c70236e0b665482c82933562a196fef9d16a8fb5f8a656895a459de9d760b2f9be560e1c8b089339b845ffbcb5a168cf11820aa1ed42831e144c81bdb02ddd6784d48b07b543c4533cba69ab4a7b627d2c1a02b4f4e699c54eae4f083d1660815bd8ae31435863bd867954ffa065bc1f70b3fd562f9efa4c98aebe694f714ac7b6335ab74ecbfeb5d35bad65e171f030193b619afcaf8c5cd3feaccf83895d396b7f62c9edcc91f4eaf846f0aae371ce84386e8b575a279aa6af0d5df0c0351036a3c96f84a50333aff097c13967ec7ff92fec86829f562fc7b4997b673a4defcb1611dab289d3fe84a9e7a2a2e28d5d37364f6a8978a0652260adafcd93c52c0169f1981b4bf8f3ae604b8d2297f934a21ca4e67d235e116f6c310e64a3cd0bd35a336413e3f31b1638af11580c124e494fe8dc8375e0fd5a3acb6697cc4f8dfedc9418a02cd2b54677f25ba82bffb33635cdf157f9e4c83fefb28bf214ad43b60c7ce19e1ed18a465934e28994560908d40621f587a3a85502a233aed8c5e4e502876653da161f488d25bf7a648a766f9a7dc09f12eceedcf3a487e92d5e212c2774da6f10a37f75ee89a12495e6b37801cec9ff1ff6b27c5ae3350caa2a45697d6e091768f59eedc70648b128f25c79c5034426575cecf118fddd6d510cc870631e0b157f4f5eef5ae1621b7645e88bd8fc7ef62ff801e02f792004dde401393104f604be42db2b4fb4538f7ea20a7435f6bb2aae0d2ecf1196c527fa5ed76401eecec3370a36e3bc0ca2cadd212fcccd9eaccd4935f7073b965ac5f52772045716befb740aedad20ff080e23282b92efb464a39d821a5bc0c8ff8b1dbaa4e31a16740159d0837dae9708c64cc9929d0d608ccc4ba50873b93202a281bc6815c9ed65c5a2a0453d03289de39599e1d26576668cef824bf453c35cf60ed632b3d7642d072730eb9b3bc1b0108d9b525f8f42d3af337e0575ee2b07b2193f20f700214f183acf57e2d42797abe65212a7500f133b0f4c1cf8054fd0bca8abd6e06313234cee28577f0797e710c5b03fcc5bc87c8a8c080d8a0adf58c03821cf017c75af44b571e124c1337c46c1426332a88ed0053c90118909022b397c292415206620a2a367fc68d71ff6729dd95f81cec3fafd94b745ec287d1cfd02d68eedd33f6e527ef545329b9264c82e11b4d1480e2ed924a17d0fe51a54e4fb459dd9e9697e60c3fb0a312d5836bd7a846567b32ba49d37cbcc590208dbe687e701c358c8184d2104d4a1a46506a47e5c40de83d5bd8053beaa3f6fdf91c9f1480abc16a3d2128f427b98cc305896bc834343f9c15c011f4e2baf838556708e2c43ef9bb3c15e6dccb0833b4c825bf402aff4ba2d656ea2fde14467d58b68adc348e23d7e15d0a01106016305286759e42ca744357e0f09db3009a27ce992d1515bac10de9947b6f7bff475a82227549ebea0c0673738ec78590667c3bacf0ddc1fc5456fcd8dbed00e36f0dc94b5d93834d48f9f4a07ad2e139919375bc7573cd9a277c4416b8cf72ec1a609ce7384fc37dc631a8f77046c5260e4f27dc191f9b7451a78694be7b6eb7714be08d1d35f9f16d3bb90f31b0b26c2b8ee734defb30783d2881b49936959a1045b762c5841a907362e4c647e09a5dd6dcd4be3e202e9acdd43306aa160a47ed78f89718c408ab80b232a8a536c70fc3d2387ce6cc151394a87f6f5be15b14812b6e94e3dd784b0cfe2ccd3251bede50dc2286a11a1285d0591fa4bb4ffcc9948cf0fb279da44f090c6ba2e1f30c167b366882c8860e53f6c15a045746c4f712f0a1e102ce084a5200de8a1401b44e47d288b971756a84abaa8643db805e4f88abf8eed8cb9405e002c1df2807f290ddafa65d6c6aecc588d814c49e6d8e2e67ec831a85ecceb17df3fb6c093604c5e13711cdcfed5d7a1c5d72c680910e8dcb2fc326e5c647251b853d2086d453dabbdd294a0a2f4ae5dff94edb4f4837b4f5e696bef0c1436d17377a338be4088657ceb888b2d291e0d1659f1cec0ab733d0c4619e7b1bb10cefaa3ef73336de333908c614050e2be39fc0aa74e88c8ea88facdef280170d869a8927e7c3c03991bb44f63a54383203448f2738492a63ba8e4d15a5c4ec06c6208748052dab4fb1194c5f272fe2a3dbb89d0dfa94d93e31508da90c3087579d09b7b56d043422dd20738403f654660f80c12342d9034154f9117bc92cc0dae0c077a1a9c8573491ea81e4d847afeaf35ff6acbab85d9ec871e92f672fb95426495bce7cd8b8a5436117dd7c55148aa797f5744a59c0aa482f9abe1e8dfb9f2886ad2f9d305394c1b121d5855916c23de231755298f3d2fd4a47b80bdd1eace98fb82ac9e20861f2fcb2607538fece09f52d48ec07158d9092e8ef02ad622f4a72f4ccf9f9513edbc9dda9b939a8730fe4ecd566ec4cde07fd6985086b15e5a24c308889d803f5721398509cf42536c475578b7a90e54c13cec5fa050ce8737af115797c1a19be8130bb4e9bbffa3b6565b4dcb384f7a48e584456787e4790e0b23bd866d8c4d32c279d2b958d3d620c075758b269793cccedb4d49ed6e204f67c4ec2529f296adff2b41c427c47d35614281e45e6ba4c99f4eebd1e8b27aea3d413d122633b7ca31628a43ead4b4a7a988898ad7c134d14b3da4fb0d67d1d58dff17813d56164a430a4d13ecc403cfd1a9fae7710c41a5f8a1270540125371956fe43b040c62964eb84af7ab0d51e2f58c2e5e5d691d6cc319d22c029f5076e82f36620469cdec1f7e865cd709d0d623f49eb5ac82869d44b6c9d22d7606aa880c9d579ff2dbf0581735e425616773e413e566a7ded4f71f7605938dc54908e36f90cc1385b3c593d31ca8278fcab5bbdffd8bb0a4e3b894ce34d06fa6904f6f404f8941968ca26329250837a65e8f8a61763ef6ac58c09f8bfd9cdb741a7bd0457b0ab02d609b6593587a19b9207580bd408531ee081a8f27c6083f1744ebf478cc9a2f3825e540f817d237087c8033e7c094d8921e45ba3688069924ef37c1af8f21ff6c80ba61878b97978d02d347996e56b0d16bae353468b5fa0135366a6ae85f06c4c68417a0a3941ebccaa221e0fafd3032ae8b0b199ea938c7492e449d436c2796f9b0795147e18491c29a1c5b654f34d14e4862007f741a8ea32818943131146b3de20c8d3fd6e78c3cdf007c90b11b5e0f4789e61f1c941cd7e3c2705677eb0a0aee78b87f533077f564d1efb31509fc9e102905a4129100446f896de4170b05803ea02464b47ffcbbc0d5e73c1b8d72b7cf5bf533f38712e44e61afe6989290623919c409fd13d5487e21024f4554f5abe00e476f58042f28a87450939d6fb1d87ef2263d9c8f065c4c025541b7156ef5afa4101e693a5a8f2e5dfcd2c64358c49047bafc9970acf751241fcadf0781de1d3d0b47078e83b5a0a93b50b1fb288affcf3b6c84d6bc8786e07d8e0410affdf6e93daa83176175a63593392f8bbe690fcff1e87709a43eca93d88f19a11fd595c797d35f231c600090a65007448a4eac5a53b342947b03cdcaedf5bdc96be63aa2f42dce978ba35a9b6b5afd780517d43b44cb21427607c648ae2c5eec8216941557ee76631a5057c4d22e382cd045173e7265cf2d09cfb0b6ac5dc85b5d39fc909faf8b08aa1e0e4a041151e32a7933a4175f0df9547c45414b9cadedac240907c384671424a327a69a0204a8486e420957ccd570ce28bf9e3708c66b12e48293059c24f077eb0f04abd93d4defad66675f49bcc4c43a090b4aded2b23684cd767874c559a7e2c6fbcef3481485cb8bb780d6d4938b89014cb84aaff272f36675c7d0275048171112bd733888d38a69c6848dc7e4268c5c1c226a969c068a8714847ed4e03fbaeb12d94dcae13e1f563c83b6727f5b245c2613b9cc1aa67b2ad4aad58edd67a092c40fb84666796e60e56145a7cd66c6f02cf2b63c91b266d5d394d6aca847285f18f0cb79bbc791847010bfc3c09d854eb779dfc3d374d2b4fe257ada467bdf17fc0e0078796ba94f8f5eb1c9bc8e1834eae93f73dfa12ecc3092d255c68c9e780c3ad3d9c7536835ae00a88a5f1d5c6f10331195c46cb12cdf19572755c400a4a70c72dba377cdfb8560f47115592f12b3d893baee53baec02647f2602815f66af45070d3378e487441cd9782c210aeac304f57b59b76713fe930b0962895d9cff4d0eef74336096940bfd606cd050d07cbbaaf48841cb8f47ccaf20638cf900923585074163f505328a7a9ce6b4eba82e0f03fa7b797472bd29f692c6267c0470b5a323c8a36e557a902fa0ca5bd1b8b0a5d1d0ce3228e06dd314e4354bc0386c42d833eccfb1a80c867c13009df06337ae634973dc907b6ae33bde6af1a5af8e2b5e075e856e1ce8910ee05d379cfb8605245258930e705e9474e80dbb941fe32879447400a8108c9d4907d1c4c051ea6adf981926379dbfc1305ab68d8e6733b8c4b87f9b92212d1966ba73088765248e06a940d9e11a0454a540e831d8a06e25f6b20853da0c8d0758974482a92ba043a9ed3387d5e1b2f29ca34c590ae7a2be7f240b2ed01f143718264fd037d74e3073d5039bf75864098c7644ffcfe1455b7459b320edff6630531f021322e554284b3528abdb73248806dce3bd25a6b27f06a27231514e8c0326277b0ac09ed94c98b702c4ccb029c5863317c064e76eb58508dc7c8756697f3d401a65b8810f0f152ab2826c741351d4caf53919065ee6366f6d8dadda13f9c33f9ab2090628cb4bb7fc4492c741d3bca44fe4ab43f080c6aff4bc530886fa5b03b34977aa33a2640e8c7ce9fd046f47e1b105f11e5c01a7c8f126b1fe6727320c0b6f6f319dd9470bf091211d2943b187f53b50ada08146fdc02c9c3ddc6d7e3cc928bb176d4d8f19f5e702d991a3b8233249ae51b0deda181fe1c0d07d14069474310d1c0562593fe0408ca0edba2ef50521d70035909a41d7fc62d51b7f05c32895453f217cb4a7bf44cb16d322e4f0bd6ec707b2ced0a3980be8102e1f554653eb12121fa6f3cf3bc3d2d235a9a50b43742472372dab2fc51039095d977165b889d6cd4e9a9cdd26e33c3838eb2aa1c70b7016cd56b0525db9f0607975420ce21c6fec0e1be18e1169d5121f87ca33e015548688387404b4b89dfe17f5dc3fe019dc734fea34053243467a99ffcda89bf3ab6649a867c659226ca62578ac20b1703d162b2a9619c1252ce9f94aef55beada521834917cc621b728931d0ad0061c78fbeb7806560250743bb742766e961fcd7d80a1be9b54a63c0f5cf7c7da27c934c00a158501239d9bbbad8dc3fb78344b12a21b8b0546b6490a4b584db42ed4d9cbc4af8b7948428693c973d7bb2950597a0da274e5151baf0c9b6418622df4c9596ff2466311159118f8fb13bb44271f7c1d603ef2e72ccf0e36e9fbd27d45457c0d014c3e59c4c163a68612512eaf528db2ca80e1a52d908f9a3af2ef6aa4943a72589057f162ccd5abf125813b4bced6bb101e8692b6437409eac12cee236f688b3156c192beaf0edb56d7739390236925a71c62863b9817ecce680cc497495b2ef3c733642eebcfd19d03b9c04787c5e7c321e4589a2a8291e7443347c2cd46f067481d4b1febbea798f426f7a40541f0a49698c714acaa7acf0e8b5bb7bf2bfea7f58f4e17c4765e11e24479fecc851292e8d2447fac30b7b4651f1db10609b143a0cb29d642c75a35c4dbc2e7dcb7dbc0797d391621a7229fc063d699cb43351f83057a3f03c9302dafda7500b0b9433e68dedfaaf47e8c4dce7c2f18e46a9ad8cbea9a600dff16296c1a5691d825a96edcca602a2cdeebe3980f3f7029411de2e95960372d49bac47d5372c08b05367267ea15785b742a0f7ee07dab1489dac5193765724b1254c5b0b8a3ba80a039a22eb81bcff58b73123d3a8cc27f5b7390b0cce3a0600c16494f1b436547f0f1260032d331a0892af6008a561aac5158698a5699bac960119bf149cb656da44dadbbed9d254d125807198da15e820411f0d23241d03fd4b0d374c657c05f164d57d325e440db9d29f2b12547112682edc792a50d2ad08ae8dee0326b2dcccc720e31e6e68f2ce1b153519d6c0b7e012632256b5b2677742daf6a700731005d6380c37c6a6340cfcca6c4f38b243da6edf84c3b2ca8aa3b2d9e05ad89a7c9715ba44079a814b6338fdd4a7443e018849c8edb94c502be83c4112c774c551818d6ca1e86daa38cf01d581d13af00fdd8a219dc98b6858c0101f60b88be994914ac3e4abf9036e018e80509f040065af7e48e61606ce460cebd74e1147f313363f1a18769c758ad582f66f3f0569dafe719499de756a6f202a9a85eaeb89338974224f6e2569b50132c167e1a4aafe3274b8ba91f79279dd52112114a4a897a4deaa600aa138685c9548a4182361a053b7b6a574d84c003c6d7345f4defbd0328151306eca3f6b4ce3900b35b563ce8fa03463240423b208891b806503993a69179c93dc0793ca0d0b05b5c335124de359b3c60c23ad5139b7e5cc671595808521bbd6178529e4eef913640f50b5ca3036a905171abd667777be6c8ce499f101363f8f26c17f5b8c32929d9c3c035dd6646b45bd7867892798178139d3614ba15b98b0b3fbc128cce66849d47c02b00a75c7ece3f1f2b242c08e120f8e18d45a004005dcc50434906855cd32c9648fe3e782ba858af0ee3a25cef4eb3e81896c6555ee78fba889aeb8578100a6c81467d446f397018686f057e4bc448448bf2b488519705c30c5c5d3321b27cc227583d18a7289e38ee772da78740bae1dc56de3b58610c42888bcd9dc43c2cd20cd99682b07da0b6a1898102211864701969826fd903f877fe7dc183b542c7c2b862ae59adf36c427f80bfe6772f5825b6dc27c02f9a3fd78e697d29d5677e956f887a8dcb672d382c1890c38d059f802c103482d630f2f11a310ff48cc52eb945c0ae9b359cb53c126b7f2e8dc8de7cb3a859d7333df64516b11f3f9effe878aa512c0089b22cbc8da747ef4cc357099160d96b7fb8d43082529de13f41d77ab102fa86a8325f351aaef01b4fac77eebd40722da45cf14f06b132feb9f1c85b66f62ce6241d0767edc8a10d6bf42f9791c32b6727651c8b3612ff7b92c8e1f36ba4d31adc5b3115822372eb4e53e36b510368fed663048f55966382e2d66c17f4ea5a464eecb91a9a5d408f64d2c1037cdcd268a8f304ac230081803daacbb3a479fa5a5f63de1367938f610bb2ab4e3b25ed6ca8ba795b78eb9071f244b15c968d161b99b8913cc5e13a120de31d302ccf3442f3ede2917ce90f244c1c3afbafbd34383774c77b80754e00a54dcdcdb03649fb54e0a2a4cddaf282cbdf658547b6bbcd1ab1c18d76d8e9b29cdc2bc24d28136b6df60069eb10e9849ecda35962f617566adef995203805cb21ad4fe8c834159dfc0283256213864e37d8dea4aaf4c6892ae752e4079c8abe01695aa9698a543720ffc5656acdd7142c6c405e9cddbe1862d001046b98ec026bc645cb3a4cad044dc39e7311f65fbe555d8b43c0af2234cd5e1ba805d7d52554ebc4868e4fc6f8a6c4b38d997744be7a4c1308b5ffcbb8f4f44e828dca9b63c39ad4ab6c71e03a7057e47884d6f34eda496a305291c3cbbc24de0081257bd784c14890da10f2e8d34fd8be4657ab3f80668db8ad1593573a4c1886e6c5c8d0d763e0872ef3d073bd7576294410258ba5376651bc1d065fd6f859e6c019d66051b2b3bcbc25125e504e4a69565e0aae95cbf463486dbf8d7d08742b9a39f7fdf97a25446604e8a4dcbefc6723d40764409b6f6526dbd9eae9d351aef94fa8aa5a201b1043d80ea8861200186895ee4b84a1014bb4ccf568b8303ea84f1cedb921e8a5911b0a9c86259cc22e319c8b202dbeb7989046a1c7026859e93e32b7c29d50796fd06ca4f0ccca08fa0d66e84dfbe5f306d44ec878a79b34f71b01d91be5e97133953e9881c131a5ba63ae718c793d3e4efde2b86caf6dd221c9850140ed3d796b02587fb65e48e62213a04494d161fc96514e2cd1c5574aa43e024e1f800c915ecd82d02042d1f537a43397cd89f606b4d38a642d1a23fc28097745450229023919922bcba3f2de04346354798f0716a74d53f1dab9e2aa30153d3c188f1baa578b8be5695e105aba9506446394458631eac8965243ff8bc98406ddb2fe2b1342c84a0da91936db033061c704e2a7dd2b8a0de7c2e157488b9d1a2bdee8bef34fc4924af5fd858c25a3485b4f065f9028e3ab050d55e00245f5e4d47b334a376e01e22c910ab09502a52eabe7421a2e5ceb5e267c680ddeec3d171810d32af8658a5b29d1415a4ca8ebafbd6426a850c81dff642b0a29ca3a594884e9fcf3d6edf6e42589d98aa2f1163293290918a1b3c1b387878ac866c604047ad907f48619819fc9d8ff32a47f0cfcd0d3bea1ec3897d04e93bc9468f2af50892562ae6d7d14d6914e80b3c400853ec7f2827c1d3d2fc98cff07f08ffe0a1bce411e48dd7e4981fc28263f8e6aae150c87282981a589ef54d12e0d5e6b14c028e12de13692d7675aa9a9c8a61e71d85e9771c36b7d2b4891417df06e0b337d451694b7aecc1a63bbaaf1f5bb1680673d2ce951af7787a76d7555117bd0ce653247cd499cfd2df6721b9c61fe45cbcc116345072028abbb770ad114915eac429ff4942c6526617004fedb9e374022f466185a951e0559602d24ba3e73d19d3b3813399d12385e0bbbb7197da772e74e9698f2af84e2a0ce128028ef817892ef90be05828033f746ffaa20984ab2446de68b743f0c0db797c802082387851e02d5aab3cfbe77dd4ddb1d9f01481aae1d1c2e0b6294541ea8f80f1331fc1e374b1d8d929d28bd486312f4a5312cdf3b7bdfaffe37faa3c3b89444e94dd4fbadbca9f5e341984880b487eb6cb62f422d74982ffc6918956c5785038d90f76705adf6557cf3780c6c9ae56ec8387a11df4289021f052cd912945874586efd1ea4799922bc123a917a9b280d5a36b7f9462e8c097a87e7bb07ffa6109f14f17cab5a5e4eb5b6b27e1a66bf2e6c4ba1e943161111e9daffc107d206edbe668e78f7ea25dce9d598bc896e900f79d2a16d8892c7b5be1fc1da5fb725aa59c4779dcfdf4f00ab6d00818a7daaded59a9414976629d8781c7831e451ecf01e9580a404d97b7d9f9404140c97d79192c0009bbd22460e4ae4a15b0e37e205199792019436e9efea62b3a11be3c77214391a77ef59054c7914c5ea9848814247f5b6877bf44bb96ea6929016b0ea7a8d1861495782b8bbd959a8573b015c6ce40c4eb115647ffdd9a4a5666fc719a5c38044518c87bdd641d4a66a2a996c6765067726cfb0b24d07a651f8683252afdc9a72c169653b6ac6cf5225aae9afb4a1738de725b651d22a96d8dce92dba3ec9ed23ac16a80f8a549e5f30e4fe734427f5e89d85019d6c390db3f6e9bea922009d8d58f71e5c4fccebbf48108d211457927ad2a76a9c9eb42bfa90f43ca95c38c33b11cee8f6ea298f461b1de480f57a967806dad2f0e157424d2e4f736ee5d520a5f05513510027756ad10fdde169881e2404c94387a25f0f9ad1f7527e1b0f60fc14bf907fa0057c0ef7562100a5884051289913a275588ba6e35ab9634643ee503bf19051f53c28f6540393f1900505bb6700f87c48a78f962e08713d68ee9f86dcf4a63c451d333d3cbdc0c3a3426065ffe975601f760611360b7f25469a140f9880a65060e43bb746a8055956a2d348ccf4327156772ebe343f0b79a34766a921fb0e1fc821ae411ef75fa51ded2f53c5fab7e32181cbe53ec6b95cbe33b011314a7145c5de5aa9e9c53bcedf11dab6f277ea289601a9fa9678e51c41865732859a0f867cfc3d4b1f548895ab312b50a10c0f23217c0ab399885f6de7fe645363c71eaf169641ddb3930e7858e5c16a7c83ac5b59ebd464ece0007c38e04200caec6f428c5e957831db9876f40fe7311a0e90a77e10cf3700cf60f92d39e17d434b21227b2cab859bc529ffd8e1efe99572459d75b57e84925f06e2650940455c7d5f64d35dea5d65fc9b0d2265c26ba327d4976d82483fda5f52af8c752af05357a06a6c55293861afa8092fb94321ac220c15e5532624d004223189fe133419156dbf325419002b57a6e8ccd6b4b928dce6e006bfaa8ac8262c6c23f6820a37fac651455dff8dd291916de9877e19e1a06bcdd070284bfcb959722c35f5a288a5c284c75bbcd01cfd9a1195a38cd8d5d229d1daf362267cef3ad91ac2408890119492eec553e636a388e71e90d204721118a5935a57f8682568bdc518288c0227e673973aafd2c58907ff8b64fecae030e3c2776de107f67dc1dc281ce19362c4f482a3f6af0c3f4813dd964d51c46406164e44b461c65c44e8b44cd883452873018396b6004a9d26abd8c3b98dda7ef16b8bb34b14259ffd9199f81a845eb2002062eda61c994dd2d113fa424419ae77e55e5b082d33a14d50e67b57c5efe2f017d161a0cc0064352a20ec97303a6ab7f25cbba449a908a5c297d3cc016e3df24d25a7ccf21f2b446a57111e481cf26f7709b9a6dd31951ca2c1624958adcc3371ba3c53a6028b9f329c7430a3a49d74360006a2eb04e4d5744c551a18f3d29cf2d3244648dc7d33041df07368e702fb87bcdeb1fe4ebcbed1e62c7a40608d8626afe23b2d722c893b5722e0b996802b4426e44a484d9d0839639370ec2630e97c20b8049c8e47c577a2d62786ede61c3b3ecec4b13d38c3c09e6cc3520ca8a5e730d78baed804d501998b11d59223beca5be49834e309e01306712b1cdce95169aae78d24b6eca150325456de95d6059a5884e0ee821f5d15ad93a034bd208d6bac0102fddb69e1f6266657d084fff60b1188620652ca3ad85e16af1a382bb23fa1cf503d5ca9036fe01c46e826a3f92fc18bf328c9fb580467a6d5f18c0d9a239b9ca72f6afd55a06116a8032ab03eec853a4f679a366566620da4252bd7c96a55258b6673a28fa9fd913531b1f168ce487128b4dccfff5302e4a13890fec3ea4fc276eb90f06347a389cd8c9293e69db2e78228c924038b0c2e8422b0a818f01ef78b3c3560f1e269fc7ce2145d6fd6b4c1ac817e5e6f7ccddc4bac20d5db3ee80d0183179b63c4d9dd3568d66be94893d7b0a304cd13102fdee83455abf033421b01b2f19c92a208a41ae6346ade54a160494d991e9055c13765f0c018b183dc6987d8e9f48f2cc5a74636ced57e6e381d72027c82b8f4ec7df290efaf908d70485f99a7cd02a01f9f3c58d1aaf221e2916d36eaf60029c97aaccc01a65d4fb21aed5fe50634f2c3ee205b6da9f0b67026db8cdf3d6439d2a4ba628fac3b37b4ea3b2575f80aeb16284a9439fc95864d9caa32c0aa3f64f9c224ca79b65f5a6c1976d07b0b78570ced1f3210dfdfd8c0ea0dbb3d67abd4a00d128385595518d22a0d8836cfc93d2790078067cec836a153dd4cf9a8f8d6a8874ce95cbc3032a108148123d0e626c845dcded997406eb3c897f388c4f39adae1524feb58d0976babe9a2280876ff539e7ef7a5e0700b139556851b64b9442acfe053b9f8a398087ccdf2de5c859355abd036f99a658dede89231d62ca2910256613a331495fba1a5cd063d328432c23248ee8593dd77d4ecc49f519bb735b75c030b7940bda7096c3cebd3d721284e55d10a99502c24a9f7da2446850eb3c339dd10906dfa82a0bd3d2cfc21fc3fae5f9a8d280723d95efb72964c5706b8ae8129f487728370106b6fc26a791aae0da24699053a95428fedc2238925622833e0d1b90ab45fe0a7abbb1a85de82c9d1e208da374af9197200d59c3950f792eb8b39a086f3895487f68ca5f640c674eb0344667141142ee778579c1e45ff64204b85141a8e75400e792c9f7737a8fcb07aea3ace3dfee31c5ab3cf026dbe82fd770fc7c55925547fd575883a732f7e832b09398b5470817e12a9af33267e969fece22131bc517c7401228c282e49b017da4e65c1c5ed7d44da2f5816ab2ca899affe5dd04458c510c73ba030362db4dc21f68977882d44c9af52431ba77f3597979ae32fc62021dcb9c13f10f15a832eeb3756fe47ff038fb67615f6d073dcbe15be0f588c0b31e4442485e8d07343840b2087cc183dc8e7213cd1c726441e69449e3ec97f038ab0eb11b01efd30674d49d7960010ca6310cbd375916f117d15ed133a2cb32c09576c6cc68fb3f580af72ec39ccec088ff33775a1f52b392968cef801867cc9c07be08acb65b32b94e2174fc27f7eb0f648df3e55c7453fdf8c343049a2b82532ee4113dcfb1ff888bb07242870ad80f4dad80c28377233132eb8b5fdf792981620164312d1a7187b564bfc7a85255882b448f46f290e1998029cc23a771dd93f60a6a0117da3ad4ddf2f27d0c5c604ed6b442c5d491fabf0ad4e2d0b4e7174c443f466d95687242e1ff8119ce302fe62c5b7181e9f50f54b901de67f25295cfb4432ff745241a5b97caa471f872c9350f6f0760a9053d66efc92a48056970d18f8c98a9ffec8534e4525666e33197af06f88ac1d24963e87db70f44c951394219749eba34760c7d8489b10a9a42abf7cd13b9dad2e324be47e685da78caaa36f3544b3e58f0647dfcc9dfde17f621df4e80b64c1e3bb5901b6c36778dd6e742ad53380618ba852fdadf0f0774878ee635232ad0d80ba26f3ccb2f47a95c6187ca2f74137648c5c1d3a1901a7f976476d68a347467814fca723cbf42d90e1294a8b6323ffe3cfe61ec251916efe3eeb9d8d10effe670e982413b1de2031f3efec2294b3c377a47a6018dad9db079b2a58a34beb24b862d11af979716b44748f02b4352682538dcb3abd2fa74e8d803220ee05e2bb309b274cdfab03dae8993fd51722b6a7b40fc53360351dc5b7c99a5d36b855e5a3ff744ad5739eefc5ea4dcda29a4e3eb785bf696b46681380f83fda8a2d16a9c088aced08de1519dc3f601c51d8a31fe5253e8d426a8b04bee440427150785268e1a5500b4393a2ca1fa5062b7192958cd37c4761c619a9820d19a8c7aa0baa39e330152c48948fbcc73e72231ca5ead9aab3421781a46a27a5693e75e47bbe5c585553d2456bb176381065616de668b42caafec49699f4082243e4b0e6d51d4279f09b9dd3104ec9bf321f6bf05819a15b07b4b0d8e0e33df0f57cd544c497fef1c9acbea8a284ba5e12494c0f1f8447d1ce9e97210edaec571ff1ae354811489abcdc0abd23d26c03efcf31d4b72df7acadc8368787616ac208f8a7a64a4fbd00c826c449a1001e0b565de5b1267a86c4e5d88d5c1aa99cc989ad1a33e7d1e5eecad8e933873bb16accbc3fb1c136005997a71edc9d8e5b59f5a4c7e72817952b5e6be82ab093baaa0613d5aca15a7c6aea6f1cff3c4a509cefe3d3b853e064bdca8175787fbd199b993a3ee827899b0ec8e9c4e7c5643a9df99e1d9c923593df9cfd3a9764967171bc277e039e9e01eeb8a74eaaa0b24b005af363a818cc95ea8bb307d5b014b5386defc7f525cbc4d72e280ee48b3c54c902812e23f6a1a1c39c83babfafebb66110ecd6f9c8590381b60268eed2fa8f1108562d9befd23ace83129244f5c6634c6980a0effd7b4896d4392c348bd48489ae0fee7f61dd8e4adc745542fc5578b2d7be0dd301916d950de1a59415025cd18f683aec316b37e332975b3bc1710ddba80c1b06e4e8a95a1ee0f4d2337526127092bce254ec1b0340faebf56c1d0b3cbd00ab8ac6ffba328e1fec4a14aba1523c505dc4037db4e1208e7291c7398aa3a040d303298f778e25cc03c1a1256ef256ae235b37adb588e23ac92c444d994189279e0ed537137e74d46d4ac6496473c03baceabe5964dccb8c24ddd6d2c70c2cc8cfe5c4fa5200980df3d295f1f6f3813ca2f155b533377409bdb4e4f6a0a12f66151fa642ea92e9f764f23da0d0db1f12359df29da42f79e31aa754df874c345c87a116cfa05cc8acdec311dd50ae2e60f7aa1a814b2e10736c781eb5ab1f05218b31c84f06e82ce0a9d4d268ce60de6c3b696c26a908c1eaef1c6c0e072a1c5d6b9e74e8524028d11c0f9fc54f3bbb3c2a79b6e66eeaae2ca2eafa9dbc1d8a067e88ed6d8c4340c8f74449aa30978a9a2ae842c75a8cdef1159ccbf24c644ba0d8a7c839af38398d5a41a348a2e17fa8ff8ded8ed84e75db40b5b1ccba82959351206ad3c86dc954897bbe481003256a07ae99c4e5276b02892ebdfe79bb0d5e2317fd8a44533f73c1d3c3fdb322c0897c2c10606fe943377e56a5d01d37a23c2563da056ff59da803531b7b8ca99abd5df82c2549cb9d7de9efae464cc0c649f2724631e480ef97ed2535f50dc4805476fc02149eab9e1877255461d8627a36fcea409cbc1d65a88d9226e557b3a284f69ba33459519502751b0c5fa3d9e57d87a2fffc95695cec83be05d45ef97499c1f993b4c748d48e2389e18daf742e8cc1c47309f5fe28e035519e6b9a9e2ac983fac2d5b41e96657a87fa1d82f2a4a05c77b8728dc62106bbbe32aba014b8b34618495736fbebe18ba000bea0b883aaf69006b2a80542db98fc885c4713ae5efb4c7ead943bd5a795fcee5f3914d72cd69ed5e958f9e1d909848c32e8d717ce5d337c646e75c5fc5d957d50634afd3e8be4e844640dd10b1ba6f3530145597f8442a888423911ea28a940e0f560b6830bcf80de9668e092b0b5f84e460c9c37a2fe46f4961592c70eace5bad85f34500f0ea79e907dc1bb54d1d0e813082dd87c36cf2d5a810087654a204125791d0713b917e0b39e5ebe396b8d1e8d222759def046d654d618bfbe8b4428f2864f8780fc7ad18cc94d0eaad395a19fd1726120a0768b86f67ed85ef139fadea295548991dffecaa2938a7cb565fce5d8e29c7e8904893014a4890b2e75a3cafc5dde023f1c5d70928a535320884fe06f99c03127e15c857eee0ce4588e72488d65d79ac26dd0885a7285444b534423698f257b27857f1fdb18b3b5e97f15fe4ba0b4ef9efb92670865ed355c6ba543c22ff5fe3052b3e8a2af5eb1a57f957f2800708e9d0c6c296432f123be9fed6d530a95d4ea4cf69b2a7d28105d2ff7a708f98539321ad2b08503549bfc7659b8fe5307540421e8640acf052f1da0c47ee6880cd391e5d5e8d3e59ce47244f48728725feca7d822117ae155d3fd3b05ea4b943d1e84f5ab3ee25940c0c250ddd05eea9d32b3a466b95ac8a7fc45c1930e047f7826f07dfb1023b6114999aeaf19c92129eb4e2ee1861101a8eed3174894e33a44392b19bb2bfa587756e6b28938f03dd163cd63a119e6874c879c642f236f40caa67fe21ed1906731c96eda749dfed5f5120a345c4b80cdf76c5529f247e2308d0b9e19e133b74fec4d2771d8524cca8a0d279edc505feb462ad644622e53002bef130e3e5c9619268596aa0b86e30454511872bec973ad3bd1e79e3d2300195a4928d0a35b93278603a2f2da46f417dac57357aec91fdccf76ec446bf888c134dd23f12f83207fffa11180156784906f00207791cd22d38ed66bbc5444fb0fb12bc41f69b95591f63a70b12b6e446682b8910a998bbb6a515e7b290a31a4f3852cbf7c883cb792435b180227abc25071f4a0ea9a8d445859c37d75cc26dffef07f0264545c431a22d7266ec5b7ce2ad53801b460ef302c40b84c9ae16a28bacfa4b8cb4ff29358b163170dc540d5d40a8bc756c0f00b169958537dd6102226d10bb068b96dfa9ed6538b50d3d829e59622a491a5e8f57d69d24a695018b2fbd4e51ff69b5c4db9a5cf508ec852dedcf5c5d96ad573b6f0c36c18367dd5b5e74ada580b32c14887d98a29a1dcc6231346c786e2e1fe2baef9d1d6aaff75c115103e70b9e6708b0b93128667684d62c7fb17f4184ea1e65851fed622290f5673727573597289952067d0a07c24863850b2a140ce965d2e3604fe86d3fa93fe0e9b2286c06e7001b967b99bad11538154a0caa33d0154d4a2600df81625edd6ddcd1d7e37db86f06cca5d8fcddf4d6f1c82c30720b44630c77eee5e120c4bcd0fa21fc4589f0f631382b43148da7e64d936209ccb33419c68694b919abd8c0389eb004b2cba68a6546b452265d0fd8005ba068a594f20d81b887d8d0615a606428112e110e3a4b9e6ac918a80c1aa338986c965d11b74df84750f03aa5f29bb0e01ad78f2da37e43419be0da3b3c7383d146af8f35a8b48d220cac4685dcc01404b5686633327d2547baef8229c9784f85bb4a1878ccb888af770f787fb05bb832ca0f5c99d3a3a3c8aa74d3500413b4bf6a1d27f2407376b5961d312b9520c705b89e86fe1a0636d57088405deb2b5d1d0d60110465485c85b1be9635a13848096d7a9cd14dcb2ca5d1a0aae2ab78d77d7d0c429a2440923f53f91b7c9baed1a30f7101b0ffc3681214771ed8000ea74a5632f1835a35d2f1a1d3cb4fa88bec7a44a4905c15c44cb857c8b1a6acb5d6282f59f76817c15053fac1a90f2a96d3935cec77f02f45092dc9eec85a72d0a5b74704680608c9e3dcf1c7b6310d858916523b4e67b5c2eb4dc622ec400a179ab01b546cc99a4cd499e6a20d28a365e419b58fe83c6719d1cdeaddb7402166992a5ebd79f8e5fef3a348e7b45c5556153769d04d2578ec88ccada2937a6cbc7603a6e9a70c44f2061516f7f926fd02846f6715c71434f69744402c67a004e7559d470dee6b8126e47e2bf85583bea2ebe3236a08896392d363a1299d42da292582457e5ab95d6a3d074e5e1cdc09577ee3c48e47fc50da61ed55f0ad89b1ccd69a5f8e3204cd51b20330860c4740a8837e00f42512573a90c5d7918bd9311c628cbb3751eb6db683d72743bd336b1ca7b95caed18fc812990af5492852fabe5738aa9b3805fe8742b70a287e5b52549804fe9671c50d4cc6c02648d5a956330d56365a131c18163efad626e6c1c2a9080dec08673a775c3c8871301647f0b5a5634b91203b769e45011f8f828e4e9a96f100d4a52bb3f7ddbb4d5891e2be47dd48b2c64163780944cb15952e8a1d4eef2bdc18bc42aaf742e8e430d0edac1a288e5f6065695df0b3431006eeae6d5c567b2c33f7cc18a6953a08b7eb686b0fb94683b1cfeb7e7e00f11468a5f30b392a4cbf88871e8f3609bdeded331f57a782eeb89fff92795a62fd10d5e4c49b0e60266e52514335988d354c35182c015ae2524479d42a3edc121f18fb31f2a96a9a43da4ba38a57e3da64615587be1650688d1b589afb091a90b2fd5ea3866b154de19aa1a837f9f05f17afd88d448dabdc58cd36cfc7e9a18d51ce8651e29cd1203132cc6150e870dee8e5fbc789290c5ddcfd8f5da83bbe99e901ac663c8b322872f89da0f617dc1c97d3ba9b350d9f21ba845298c5ec8db2e715730a3b52a8f46f26ad9565a4b4addb24f2cfb0b032e64fac1fd907fa4880b55f2bb594b9f50b311bd0d42e662d436fd00cd9ea4acb15de8f1db53d6d59f7bd4a4a0672097503d16517dc6c61c062c2ee87a1bd3557383364f6b20e735794da3d6ca71b464a8b2cf031e45727079e6a178eac908ec1aa80e91307b8a477069898695f0389ad998801a0768d729fb8381f547d3b3594e9a56645f1c6a75ea2c419feef613a2a27754d8753e94f94dbf09959b6651dd9bcd4ac5fcc550e144021358119f50c3f0fb41732e1934632e088b4de5293c54ab23b8165caac58620dd05018b497a441612ba6390b6afbfe35045e363134bdc691dcb0564edc1acef2ced45e0803f5571b6e52439a288ec7990700be92befe20458dd580113ae2079304f08c4c58fe58788132d0b3ff182a12c234f17b8ad420ebb9e3550d6797b2c4dac356fa01419ed7d8d66f6abd206d509306226669dddab54d3b7dfd4dd9ab6833be42530cc88eb2a90520f19fac2589790be30863f25f1af2c568dc73a90984d69532503d087976c457b214d884c40b8c6e44bed09d8aa452a400ad836ee7127e57af22bd414561ecf7d301930e60d47b00fe5c00939adf00fe609ac61c295654e87ef70715f8536c3c586bba40983a48b4ba1ffcf8826cd6ecac5b845fb9114f187d6a2499572b818c4c35ee25d86c98328dbdbf20a8082ea3b34353c7180e0aa3cb1959c65347354125fd04fa54ed3ce302e2af4b361e10174ac49c23a23406a7248567beee081b6db314d5d0e83a4af0994d5a2180911f71e75b229b67b7464212b2f8eaafe3823e73a6ead7ce55d45eceae5913b2766d1669eb70190441435dff9f346d52aed095a9871d5471269e6486f34a77fe41204239d7b8a6f615f858fc35f4da78fe21526ec97a297003cfef55d8412248de13c75f327f330948a0696dc04243cfb5b459e8b9e57b52c8a5079aa3e21fca035628cd85ae5092c078528681f83fdbfc3003250c220b3079edbd5db734cc892dea286689128dc7d3b388ee9c97349a8a4cdd74e221f544c29c8885c15c8b3b68bcab488d354ce07a407458062c2914fa66b0a620d20f7277f4c97954e1fa2f54d4d69b25bfe8a5db07f5c09f208241df301d36a0d7459df7cf40d6927229c4ffcee04a73e1c76d89914d93622d657340e2c22d311fe0cd0084487fd98f790078a2f25c683a0faf1fe6fcaad493724ceb753e24b8552228556880f52649de99539c9dcbbf11030be6883e004bc0a4e6a2dde19ce6f723bd3f46419154777e0308c51f13068f428beacf86486b998086e947fde4c9f2c7724c599ccfb00fc0fa3c929cb88a0d1ba4e8c212cfe7ea18f1ca41c6aee057f64f45e7516a84bf3310b1e817b2363844a163aae3faabefcf2c8ab7236eea940d7a419780dc3b4c60161baa7d5cfb244914da2e4709849d0a6af45f0ba447370b485637f9c37b10590d42cd30c5c0336b7dc8770e917c5f0cd3c03f5930d56dbe3f4d76031002ba06fd5cd39dc91c6529ecafbcf2762887d8d10698421e18cc167dc3ee39bd19f999bc29640bf0b68033a6af457a7bed08dbc6c01a0eaedbc3b9a975f91e84b0e1276227d8c5565018f4be9b0256674adc1cb5902f0b43881bcd7b5e325f798de86a63508fe516421e0e420f4ab96393dcf5262f60b1ecf62acb3c425bb5f0359cd27145a0b10bf43fd5a84f4b45152f5400547d663bf6ffac22dbecfab3e300267a734fced26896e5b81e81b2ba73bd0e6478332e9f58ed9c6d63a2f60970752e67d4a6a33772cbf2701416217c8eec9d5222ceb81007d8ed10d27008020edde50fc0baf32bfe11f0648111d3aede594f8b57aa3ad4e4bcc5f06494b45f877d72a76a5f3b8804c060b20b8c6f13d9103d1ea8d0d2765c754af9c5413b840d9765e08d48e63934dd7d210c081a6701651f710826e556421932e7e0230aaa042458097a96564b1d8c8099aa3f944181a48697659c449e410903faa1f8434cb774480f25cc465d714ba3a3f426f6193cc0c9c1078be49457c953292084dc989404710664e509d02da46a791783a70f99e4e025c4c1130d2705ef59d42ea0d40a11cc54b22521e640341f15643eff935c1a71f6cb42e13b0fbbaad367c4794a9a4d8789f7368c0a9bc4d1438b72ffc8d1560f5fa813c696b29ca48a5198f41af86ca94004676e5aaa4fa46abb16c56253e23e436b0fc0719a22191869180409b23f96aeac996b7a40d88b23c2c896ca6c3df567f354fdd94f2cccd0fef3fcd79b6dc1a43ea87944baf237bc8b2c926a61b8c7c8fd323c454b1d12fd044e2f2a5dffa0d5f757caa9555be325a0caa4ecf7b92cb4fe8e5dc68cf6cc18249a8758a4bbd703bc48dba31f2dd1e3e071f4d7b350874442dba31b6d4b247e1a59a5c1267a1128ed3951aabf6195d17dcf6997655f5164506fce5dba111d830ab2979b64db689438eff09ccb8c7912afc840b760b765d119035c5f57e48ffce997b62370704047c70889571eb0f1c7a8283bab429d7f38cf27487e2be8e225c629000eab2d8e131ddd4d79545c42abd6aff304fb1bb051e602b8a4021c8e24111df635017a0f0ec100d53372f81814d7034c26453a8f76999dc9d9f7bf0ce1ed03e6bdc0c29bf4963fc635a3e38f603f4f7cf207e11455ceae8bf5ee82444ffd50060670fbe5afbb52bf65505dfc1cebd3ea69af2711ce09b0f0d181b82231e139c79da8cdbe0eacd3810d21422ccf6d029078dd22423af500e0db11876e1b9fc5e1114b177a8f2408e0e98b3756a0009bec0323ef01d45207ae16055555fafc7a733bdc1f8d5f4d21f2853645cd081b24d67cfcf623564983560a442f4ba38823a583532da2c7b1cfbe58fd791ed928c7d5d9a16fd1ab1e36a0c0626f2be24c10841298b7fa5da906209736bdec0c4ae9ee7f55a057b63caf9e5ada21653532f11fe2f9782a2dcccdf5a5660d1a5cc60fcfe728f250e159cee70ca12e6ff2db264a4e8b8d4776473ea4ae572a05ca2040929bd2919f0bf765e57818153de5076affc78145a79a3b7e4b1fd7a2e5f8691e125121cf65f7f05631e563a516a7f61d7d2db352e146102bbd6907018aef926be6e62e9471f3e91d497284a63e95d5a0c6cb0b7d7fe29a6b0d2909808c016280c76b8d7c102f0f67661c8b6dd650a7870f66b471227805a7c6865fa8bb177867dc7d5834208b66d2453db6106dad8e5c4aedd3a1aae8a85265606e2a9e45f51a5db1e70f8f5cb299ba74300ac85b6a53b3a0e5fbfc941df88dca0c33e2e834a64234229e5253395d73ae4e08ebc8d03a042d544b5366c6269c64100dd13de337861a3f17649ecdcd847121f2186fd5e7890d3694180fabd4201f84821624b5e7ac3f1207d17d3816aa2955d24b30a4f46c8133723a7cf9961a8377b6b755542223b459f91dfd4ff3ca04365786e3dace2d29c7da548054f2f1399261e8ccfbab79b0b87561860b0fe6a99da8b9edf444e9fe81a3308ecd2a100e802147af802922824c493103d2e141d66feb81ed9881a521f7dddcd89c7fee4806d8c2209d523096ba66ea4369e1cf217cdc58c529dcc8467c51da29e2c5ffc1b9d3a6963b169598a81c95deca736ffed8ac3252a46d7089dca502a501a05e759c5906e6e68b459f45985c478f77c18148484d68c276c068040e181adbbbe6cd248ab67dd2ba6bb3783d943df33715caf64a4f9404ff39c026bf50c30c979bb1557f02b8e3b4dd312ab808c5e603dd9843deff95df173d847fbd77d8919d49b5897374203ca1b41908a4585fc51d07961a000f3409d37580a235f843f0e638918fa60a8a41313b958d2ec720fd2cb6039e7eb65d3090c7580ba6f1029fae355f50f89d3c25c098f010c7843137f8754ae134c4f8ad4b3fd0b02da16b09dc5f32c32d0b0ad087bd7fbd0ed2ab5d957c5659d7f793776fb1319fc1cdd0c36d465ebc35c02b5b3b3abc4a4f84c705b5595a1dc0a53b798dd474f042744ada447f0d5c31e3c39dc663575c3ba0628a8fc548bf6290b2bd64079649da546f0546908208cdd136ad52f256430b3749a50ee4819d45ec952dbb7e3b23a908b23e469875176e7da321ee9a99578c371b7ef19387faeaea475ddd19b2955b80554f9f21930aec57a33d4393b37caed2dc808a36546890fd7efd485daf57605f5f8728fa809b4a93a83ebd5d05356d716a4045754b8d53d2eae0578a52d8798c1714649617032c214152439d761bfb3773089f5a4db271943390f96457dccda6f9e781a6cb797e514971f99dffddcd446ea09b22df087141bcfbe2f2bd8447b2aaaab7025d34546a5f4035986ba3b8f7c07e5de0d65d9ff55ea59308eae3f5ffee32243e8a4685009dc2881d4224ab8772bea804f3a676cd0c5fd0a7304ea0e097aa9b9bd0d49930655946b33a471899e8980afd3ce676b7e19c158c8e5284ea7e99a5226f1306cc770ce603c98d575f5a71bc4e93d4ed7dc4b4a5fb7c998503a4dc13f38901b4a621e1a995542789202bd13b28a508d0505d9ab7638658e1260a1480ce89331ffca6ca4d984984e5bf40c751b9ddc705c099003e9228f648c3d167982ea117662242af31e916cd89badbee635df09a61230090d671e898daf6d3ed0a25e3e9e12fd2875a752eb3c9e9b28bfe77e58c8b16d8917e93be63038f3f9a7621ba38ce55f12d5db7b5b85fddbc0c07770293244987387f97edaafc26aef9162470fbec20737e9eaa6aae880e48ca3844771b8ed82c659809dccdfc06894f513342d7d177386358285369c220bf1f493bb6447cb938b37d9fdb97f02d86bfff272de998b5bf7e1e05a80edda3cc79b93723f75bd4c17de01d5b540168ed667684cb35f335224868d3d34ccd1b914193e7ef3a06720148ce6c11cd695b9e1da0374f95674c82ee1f494f8a5ff85db3a36e8e725ff558ed061e8106fcbcb258dd873684b7b6a0b1b41876950650eb0e55c2847773738728095db1a9ad17898c93992a3ab6a264899d7b201fdc1722eabcf570aaa3567689e4d73868aeaee954ed59d029c6f60028b686c1ae65e7c98e5be8ec3c1630691bb3624a274a11bfc149974d47ca56802238bb02d748be355bb416e53ee30965964659221b8a841ee746dceddcb999489a8737f24b2a5c36e0927f0d23da09d27fb4b55c16fad8e725ef083784298703caf10499b80c9a857eb9023203d9ce020391b30b41e17801cad282563cb2b22b2377584b8306e55886c0d45f40ea0b06a2a61405f9d7ae7564456446d589be97fba4f6f246fe08f67782bba006f40d4743ba10ac84b845466e9971d1a0d0ec62449fac4432ee865fc3e7a1641308e9fdd989e3e93c4ff6890843c4708db80478d47e8bcc77e2c15799c743e3beae881c2cc37d116de7ea15ab4fbed7ce3f313223518dc55c6780483c3452e96efda3d7f70c6b80489b60edb86be084baf54465e11db2999231f6b9f5aa89759fa1b27c305d06feb33673720c290617446149cbf9f71ea00ed182e191fbe99f2175bc414a7505f00d4c0eb014172a034daa2224ad9712913c141e96351b9e408779d2d09df51c1a886793bbf6a8803faf5be5587fad527489f6c898b683bc2748a164665fa6d62ae431db89a4a1fdf9d9489f4633ceec91777c6af099440229f34e290ddb4fe9121f1bc5eb661e35644118a214eb85e0ab46b475138467bde372fee5192e78124f23ceb71b1ad76b941f2172d9fbcf9a0d2426939dcaf8393c90520d3928a3f014dd2d46f422fd590b9aa34b99825a98f976b5cbe9f624b261ca1fb37fbf9435decba71f39b9957987575027fa5a03120b715d2c2bac122439ca2d5e7c6dcbb892a15adf3955022d96959af81eb181c9323c88e1c9bf11f575b9c9842cb6bda4e71628b00bd2f6928ee35f27c7f6147ce747a756ff08757df350c1c59e6e13430cc46cdc3401cd0522026dbfd69d52963d75411a539eea95d22015f1ac2f3b9d9c7eba2db45c44755301747b9a512fc131fde7ab63e2654d5157c4e30012f2ae9f892c5f1cb07df7b5d81dbcbc95099c2c5ef30dc6f815b1d36284f417caecfa1c00c6a835e282dfa569636a2e9c238f5e2372437772ca18b66ddff06712efb0c5cc0d5a13c32df91050f44af6aef3dff65b38e6e7d428565eabdd93fea2fc61b9acfcf543fd7053a057e71c06aa1781f1b32d989ea2d341a90e9b6995e71118e15ed110a49ea4350fb6a3f9328904ab41b35597190e989ede18e1d15353fb21acb80f451045b03788136a4e3d0dc43fb762c4715299d3d6f0eb4756e4f13dcbd1ceaf18d7f72d7006ba7610a5c0e4a3166e49f041dc9c67adb4c150bfec54dc48ebce0d9b2f789e806fd7a8fd623ae6257169b4f4502cca703a58ef7d2b3d4c5862a02d40bcbf7b2141dd74a0a568a43ae21239b520a4ef9fd7b318024ed65a58d94d6470865e4d2019c9c9dd0915f45699a0cc4c59091549a71f5f2c344c20ca20d050a604f5bf586c3a03976ac561e6cbadccb45f98c4caafcf917c4de7943d26cbfc76fde591629c3a58c3b0b94b1c36ee0ce075510f793e4b1360d4dd9546f6985906d1e92be5d152d05c6aceb048cfccca512d699bd4eeff6c46f98ee898ac11b05c5b9d1d2cc9d470008be7858ec0f16ed33d8fe5cc885823f864ee937817a9ff66127deb82729a4530bc87e0c961b6efd109f35caa9c757a215aee3e73581c8a2d4083d004f9ac0a326a1aea5a633e30b975b79afaeada68436f8af7ffd6bc7eba65cbb0732e7624e1860dc2004fd821032401831075b9941306775e62e0d08d70b6be93d8f3b7163f072ab33024d6609be236787c549f1b52fb10136eea95258e4b6ad6d07ec600ac966e110af12e54221e94dc4403d82c01ee3bc1f7872f00d0ae9b2c0ab069893f22f1d330f21aebae20eab767d1ecc1a438b288241ae35372a6e1cde9bcefcd327b8fa826ef541c00eb8f05fda74b98079a8f2a86f4adcde3bbb022e0d2a688c7cf6e63b895fc60cddd57b1644b180265d40cdbbce588ed42e2104497349177ed9acdb08c7e1566876771b6e4d7ce29b73929dc343489e7fcac5d20061d33df65013d025044afa7a844bf935abc25da8d1fca8102be67e570b6f0674ae5952b463126a0aaab1a23057078dd8f8c3e698b0ef70fc19d8e4cf1d62c1a4db26319555e81c6b5a135bd4b4fef49d85e89c9365f66bd392f3f795de6ab5a06804bc4b51b23a3b05ea93e43b14461bf7af88a1c116eb5cb0566dc03dde46f9e78cff6dd9b9ca9e02217509fc4907a78f1c5a7c4be12e6597e1b5bc5edd6f8cda21e481d1554946feb21397643cb715bc400c163b2e60b23998e99a5b1abe535a8f6850c0188d1761e0d7d0bb83189047ed1e24e7906187fb4b9d002d52ac1191025aa892a314331a191498a5cd04440b082796b93c568bf4d434d53e0a4fb409eec6c78e7cd51f7511e08325231b4248ba9374d052c081db01e2e7ad6cdfa39bc464996c11c42e81dd51a8a06f8f10676b31dadce8e6b65a970fe5d9fec2795f05bebcbe8b8544adf5d505dc401e843c27f952f31f3c5ae31fb8375105125f81be44850ff8f47570b0ad9c8bd5527a75b7082e4e22d320cdd18563d22329d35eb5bcfdc5f225d8202ce7a03725e02f497e1348eaf9c7035697ec5df2e62bab7166d3a3126892adc7d125a097028560d44bbb08892e0a842f63f4b3a040b78fbb3aa896326bc40d1f212090a3a5db8e0c3ee88dccb8449cdef609c947c8cbdb88e166e554842bc3487ff37b421fa1b8219a69a6a0d833387b0b222efdcaa6b7991c05f443f496ee99a147e8ded2de997b84ee5db23753cf103d4aa037e35e270ac427a9e33618eb8b772d77769a33d88c8db1ee8b8da88d30b941dcccc2a9a118fd6f14c9d286316d232062a1a7c5550641bd96364280941e9cb4e141eace2013172599e317cf541e7498fbc8ead6df7ee407d18c7426d241c8a5c9df7fe4eb10752e70049095ba45f2efcd5b71cd6256e819e4ff6928e6f75f5b9289ed4b1fdcfe272fa8aadcbef21561b99299d6545305fc972adbbdda8a22b0d69cb4d01d5e0e5379fbbeb3c38f09fe16841cad71e1dbd09718b134744cd1afecb0088c15229963215f3651b9b520a74b7dbfc422315648a681eec5bdf78e51fb8e3e19f59d19906266b86bebc60afbc67ae358294418fa489851fadd17ceacddea352ed3aaed815205b7c24d92f451e086dad0ab7963a2902bd1f4059e3f753170b52b8b5533d02ad26b1a8611d7fcf8782ad4c2f526992139d60487fb06e404dc77a6be534243f9042f387bf992d2e2e67def5f334ea47a25df10529786ed974b8acaf6d8e5e8e55a7029d71b81afee759d1b8103b89d88cd46f76eb7a000d752b1380fde0b4d43af7d83695ef934cb3c7e358679884d76794fd69ad2df37b63dbffca5b6bb616bafae05b792de08ff074046e8a92e3b9ca7de77ca69af7809a80057b1eda51ec4d695627ae5fa7195e8dd81ab9feb4bcb6d2c3d1bc65050726674d294e3d86d3f481fa9ed6eb4f7feb586db20092564ee2dd11ff2c1e92934bb920c58e27bfa9738018b6e29496e840c95121ea307e612ebf99167d43b50ba3eaada85dfa7ab1a7e56b8d0446c59d96eafaf1d9752bd15c8ea5c57b023876d0977e56ea04b6850ce16f4acb6688caedfe3ec23abaf852cd508aef993b4a8d16b155f55acd7bab2d131db57ed842ff6510c3f40c2b4f7b848f7ead02ba24ae00ae626e3d4177a3fa0d3af100ea19a2cc55e9aa32b20903634e5e4b7957a071869456f5cbb573a8badd46cd13291a2a874d3ce30e3e68f53b3123b632c6715afd2ec2c735c99c013f26de959a8ba8889a2829b5ec1219e07ad89385c767c4c0bb833c01a88939573a074c84162ecaab1642dc464ca7fd318f69ee511f765802c1440aabca19eba365ecba3957c3696edec81e4b0395857338fbd92cdd8a4552f07e0b1cde66805960bdf8c73b91f75fe9e42eec83e5b027491c9d08fcd3e776ebefb6e7f0c76334c0c297ce4589afc16be0ba6fcc106f4f97f1baf5d32469f7dd78f080b12c320f67a5143040cf6bc4be2a57adc9dcaa34fe0a020556ca3370a0d11441931e7b732531aba03a303416e705586cf380dd4e9d4cdadf6ec947a1c5bd700f69b1262a7f419203e176418b8e48f7ae32e6603c6996438f4ad4050333458c33db223b498612982df25d5419e97a82d143e0f55ed5b33f3fd73efe8650ddaf60f3930175a651681a9d3aa177c23474fe76c779444e20d399bec53c77d9a6a870eafd811796c3f81db5ef66e084a65e49ea02abe279ae6160f4ca8ea2a83b379c7c3093f27f72d18aac463de19af05144af786a4a657683c9a00d869411075f4149be112b31d2dfb15e41259a765a22af29c954785691dc7692ccd784a58ae613daa6daddc7af840ff687aeda1d1016e50405bf35a629404199645580d6ef3ee1766c7bc9ba2d1e3eba26858a3b2d2b6cf40c6a6e248423aed8cc0ebc85066fd89c3d16bcc961faff9bee82cd2b78065ddd63c2a3f0216786bebf1d5e1d4583daf3527c427a00e8245f8132d7f12fc885fab02a6ff9e54d95151636af88611e12289aa72d5042a88f9349e957b5b4a5994fae2d499ad5df3e769dce12a64ce49e08c04f4785dad0320de0414386b54409cc89fa94f118524f33e469c7201d62e81d4e8ed71f9938698e941983ed37daa53bd7ed8679630b032a9ca4207c6c4e7db535cf029f1b6b1afab988d6fc64dfb72a8432fa32317d1155a20d8f8b1b905255fbc70317088df4f156342cecc5f9ec5fc6f9971e715895ccfc2c8858d1a01cd6c9f6a3f59199a9fe2144fc127b62e22e141e0a4adee51a19c336b4575ff2c3457d67a133a761c400b20126f385ac86c89470a0e92758d1df61d5dfea4478c906d49bb9720b4b0a14f6175192cd10af57cdeb71c53085d9c421770e7c69a67b4f07e406f1640f2418508ee84786648eb3f24f4acdbf7e562973e2fefabba6ae67af90c42d1e9460c0ee8c130bc2d236c64019696f6c48ea69554ff26d52947a237740280360398488b1be986a3ec164be5b204af5899742a16c1d2cbf8dc60c8d7e2943065537c691c83bc8f9e7b502a5efc1ab199b9610532122da9d0e45d5437cb4ca4ba1be32b714319609bb3d0c95de77340427895ca2d5eef8be9618e658192b3b3e0241429b0bfb6cbaa9985fb4d9e1e8e51d4cf66ff7780a2d0caab8fd59d3eaf93870090aeab00fb0f985a6780aa05ac574a2e8885d4c05985974266240c5c38e4c20206f4aacdcbb870ad58d36dd4e62355f4be190cf30f59ea86f2cb44a41a1dcacaa96b9b5135319b59827b1bc5f896fa6b516d09737789fd1fc871a67ef3af2a9bbd984b416705baa781af47be0dbd920fcd4dce6b644e78ad49f622904c285ce95290f6f8ab94dac91b7e29836bd1e44cc3cc2e567723fe414b3bc3a91b5e374080ecd7fcd8bd66e806570168747ed1a2e48cd9a7d816e1e4db77b5b60cd1f65d3fc1c32c8f32f0a2e24e0c4765901bca9f47ee105d1170e2111756a86bb66d3c4857d1a84ec077d6ae8bf3839574dbf3b90c401174329b7715f598c1f599abbeaac71a523b0308d90f2b17d163844048d9deb4c4ecdea10074bf67f3578ac143b574440f9c5841919fc7cc9b0ff61ff2565caf4c4533fea55741974c8d3fcd63a2bf0e05a630cc54a4b957b385660ead67511a872c735bffb187fc35aa67acbc35b7e6ad7b6b6bc559335666cdc06a047598cd30015a2b2483aca770830a915eb59690c462ae7eb4ea0260955bd9688ce7be05d46f7d6365568d756fd558796b6edd5b7bebd68ab36eaccdaab1e2ad0d5a5dec431633d99f29f45865593d92dc6f72d311ba416b5179dab16d059eef4fd446683225a28762a0d788a05b283c16b17cf6db01f2a5459f58da4bf9325db4c2db71bab61d925b821327d2f6b89dcac68c373e94bcafd9d4a59136086bfba21f7a49f5d800a0cec0800d9291d603a4952b50f0d96700ca2ab789ba16fabf2792e74cc27401b2023847305882a00b8e43a6771317bfc291a4638e696bf7418985ae8c6a855194dda64716d06a3ed89f6cab90835699a22d434f818eebce7e174de2579b7091c8cad43d63940a379ea687e9ef42cb351bc52fc139a3187e3a90ab3092a40b0ee767dc7d4cdee2134bcba18c8b6db185d1fe3049c24e40561b53edc2be8c763b52c2dcfafc559305352cd94b82f1bc7650925020042447901662f5f53a5e3e223b763944716019c477c0f21177f89211ebb825200e3fd2a23ea8c2b75dfc8eb52e0335458defaf26e0201569eb1763b53cba03494764f4fd261e9dbe4dead5815a7aa7d574ed13cf1a2eccee6f3ee9e69864fae519e364bca98d94797b490916732ebcb6765894496480e145cd273a6d3d36734a3c11f4d692a5cb1a8d618f2de221d362ca6764e093eb893b6565aee14532ed7c1617a3e08f3168d73aab575b0c89309d7f083f59f927390f70d11e8c1b039c9fd03265e4fe564547f4248bf4a53e110a8e9b2ee039fef023f369942994c48126944caf6ddd1d2a182d4be88157f69cf658dedf6d86dba5ed331c01c55dbc6a993bcdd186db7231d1e7ab41e9f11e5dd7d36b835775481a66254e6ee1d079058ad2d28c26e02aaa4ec7b7cdd7b67ffbb434458ce803b10000af3806b7188efefd873b74288e695c60bc6ab1d4bcfa6ec7f2ab1ee89a67a91c9ffff2242942298d898e8615d61c2990be115b0937f5e19baf90a250af953aa073c9f740f8127f485959b0186ee27bc0ab4c00f5696e83e87f2dad1a4fd7fc56e418215116589548327e5b1ee483bf69f07a601fff00e7c0e7cf47fb5f0c079c0d05de39c48f0d592018564d073d984996615fe9170ffd883d126c42dd3b057d3046d281623313a55b2f575917b6459bd9c809a1d341194710cc08820f7d4fee7086a685fee3ed358cdfb9e1d6ff90aa30d731d7c6dd95d89becbdb26d29659232760d830d8c0d2606d84083b71860030df6157d30005a207c81de7c0b6220821670d0df5b3395fd749c09ba8a860cd41a8f9684bf7ee48c96844f21417f5f1241efb2f34c1b7afb4e6cb233a4d539eb9c7e84efb486b8761a71211157368c298f359488afba3f03c622c55da299d03c13c8575a4e4cf94721e2906986757285b49c27f60b2b856b85b805ed4f7a1d9e693cdb7eb54236dcf5add090b559ad59080eb9aaeaca3279628a7bd29015aa4f2a7537a41c6fedaa0ded50b5d975b41e07b52450c81a6f6ab54356c8410f73aaa623932980a1ad8e4c82c042efc9b3bdc80e71278ed6b1e3411d1c3d0f171ae2f474b9aac69ac9136556f34918d127fa4c9e3d79527afb10d67bf260bd7d68f20c0d0dcda118683972b284717ae8a0d717dc9984c70577dbd6a4526f6f453923b33b71d0a7143c9e64c7da7b5958fe417047be669d44aeda60d19034835e23167050dad4187d6cbc34c749a9ce59e72cd91ffbba9a0d67aa081dfa8477ae2ca0f1b82a498fab2a0550e6509db3cea845685f99fda1800da7b561186af959751f7290d64a6bd5d16610997ea28c149488abb5662a95a3dd9497333e9188297f26ec92ebb1eacde471a298834f7c6867c777b6c6a37d6b720ebd7ce8e5432f1f7af9d0cb879a5c274fb4d69730a8f14c1e9a3995cee715d312483649f19f58e3a79f493ce53f9578ca6d26123309a7e2b573270caeacad4b5770b70de792bbb51c2d27d6c83bbfbee04aada4474f9eea821bdad05542aea25eeb1097eaed3fb60b1bc6cb56e155c6cb86b289a7fc81ac932bf4e3e3e0cbc1c9337926cf54d2cd240efa5037342473668ac85553e6c81c992373640e11ff249a451e218db82c2273f2ec71d5d6264f1288b4ff4c3295d49a41edd5801c7072ca22e416da9ffb915249cf8fe5beba48cf6941736e5ba80532c4b0535c2c244b133ce5af05592d28d630410b92f23b8156543f25029195f280949c6ff83292ad7f4829947069f9a7bcedcc540743b4d180e28cfff7dbae4ebf6fca4a4505d317cd417ef7f537a86bf73f405d7770bbefa27e1696c9c99bd5d9c99949c993f124418955e8f92363a98844f9d25757e9b9d9c9ed4587b88a3406f5028c18465459aa85dff40ada3f6e2a34450c8bad88eb5efecab3fcde7822edb8ed156b96bc5e33a44cdc1bd4fc0e35334b0e82e486945ff98c921f592b39c8c8085314018795925f4aa1842befd7a0def73519dc99c3fcba434ac983f4a497f91dd4503db697cf637ba949f93ca296197c1ea4d63afcfefdedbe0e0722a7175ef49fa137b2a6dfb3680eb978736d3b146f3a0ee220cee840e7a2e4924bf6606947e13634b23dd9cc4c32ea8dc9f6824228b1037938447575d87cba855b914d47ceff4dc74197abe675584ce1adc8eba87be0a0e57c57b6e9f8eacabc0d6d420e3a93bbb9b622dba6a3e3aad7fe5b1157c99f3f77a42393297c74d5f1891e14d17e454cf933c1bb90b1301cf67298c3dc8903394ca26caff923675e1b147ee6cf4e0d3628b8b61fd8c0882940cd79938af9b3bdb61ae854bd379dad0651ab299036d40b499d902bc9a2854bc69c62d8292e16b209550b72502bc2d1cca8aebbe9cb89164a5d5f25296d22065470b1f6b4f67e4cac995f3f46504b2c5ff2c7c74119d2d70c65d4e18cc99a5529a517a9667deed21e5097b6851674faeff7a6337fb0148a512d65cd13d6e4c7d382b42d5cd286669a84ba36d8b624ca6c3fda7fbb22ce6c4e64b144addb2bd37b7b551ddc2d430d28cac81f07258f9ce9e981ce0d74a0b319e1ee330c636118d61e5d89b86a6b405a0728d6ccfafeb2c755198e28673600b4fce945309f2640a69e23f06840f2e7087225abe0f00c9222ca44399910e714d30952c415a53b57681742d011748f9c521871377dd9a258139fd0fe150591a5061506b606b1bd58cab85598af30ac14f78a489950a24946af1f9f4d87d64d67db99abd3c6a3e3a0c6046d4808da9d08c2472b404727824881e62ca9ce59e71ce1ad88de5a9016e42a20925227bea25b93493831717a7d9ff214383d055254fef4651cbe6d87b5b9686872e47095ff883e5b110737570eeefc4dc7417f1a7ae6235f96a912dae3e0ab8a4b7136169ddbcab176f413656a95c19dda027a7eccfc016a94fcec75e8839299be74d5b973680a6de1b67d115551889b97b1699ab6bde68a2e91e2b5c15eaf79af17e578cb5d9ecaa6b3e9e4e0e06c3a9f9cd90f4d22ab902b5a84138e1281269155c81f1ea0ef193ddd72b432a2cc86a3b720a216b6160c412b8a32a56ddb7070b7547959e42a20735bb23189329a19beda7c7c88afb6269eda5e2adb8b522652527ecfb0a5f2298f82c0f7a7a700921b4eaff2141819610b467058a72c5d49dcc89a4488f16245f92a3987ecebfe214489ce5efe883e911b514a6ba594cae0d6971996435248c666ca6558e48ea80c6f70f70ce7fc22aaa21055d9240ac38ee62c4d9db99261481d39f424e6a00c6528c32a9f542924c3b00ae12a87457798c360405388fbb0b33c0b87d1579535a32f0a054cda64992691339442215734c9fc99295a845ccd2a648fb4d9c22a7edc88ab08276ff79c941453d86b49153f3da1562453fea156b4e9b8df3b6da00569453eaeda9bfcd114e6aaad05e926ffe32a5ac5f5af35b8f3f7f68a35b206b16627d6288935d90fa2cd16ca191bc8ad89b81de12b0ae4a3bce96c3a3b329d652a54e9166e61f65b0bfaa1680b5165cf88aaae68a768e2a0a8b3cfd968b52f3427685c4495a60569415a90463b3c8db88a44195a29a52f9f5893c5b22380b4247af244bb90132740a4aee351d25a9016a4bbae061aba9b6118669fed20495c3515a22b8fedebcbaec7f6357f57ebf3d0bee6982833aa193543d435873f4021ba7bd9bd86bb9b2e1ff97e2ba243371dbae9501d8ba9a638ae0aa5ce5cc5d7e6da76e62ab258742e29cb9754e260a5c1dd5ad116ced5f69229ff2c6f6b6b7ec95c6570addef367d38a362c79a8786d4ca22a8aa8cab6d796057dd5a2b9a2542bda72a856a4fdb58ebe60d20c1c0729d5a4ac599572d67aa2e227aee64f9dc1ddf455a4a90aa28de49137348eab86c41a229f55883634899cf1afef3fbd90abed3553b38b58235f9258618342a6fc3359278dabf933ab9036344b275ad0ac42aeb42da6931fcd0c2fca6acd6a75220f72981369a301c999a0b9d28a666a0bb9d2ba2053fe4e76942e9769401a108569405a177eb4229a8516dabfca204c226d64cf06c5f69a2bc9236d281871860279ca9f7e127d436ffaa2af51a64251c65fb01e6943af883350f82a914b7f6fa1ced683b8e9d4f7df6e10371d4495b6f10cd95bcddbcbd874b47f67e394b334dac2b99a5dc4947f18b60ab70ced5b38431c37a328cab8bbfb8bbe3a1ff4459b7c3e1f7d61d5a4a10cff5958ee0d3d678693e6478630198eac26e3c6995c06e108774acdaebcdf59431184d6162c1fe8118660cd2ce39c333261d35292b801fc2d47a9b434ef91cfb4f687c8a5cf594ba51ce2a87dcd231fdda13ba81b3cd0e341ddf0fde94f39488e99f24d7b98687f457026e1cedfa00e1a2c6ef79b463b10cc416b7d2a115a9ea3f232c853294152528a43107d740ef7494e8831a4a31362eccce8e884183dfaf5b297659264a7692f43ff4e3bfc09c7ac621962e94406c530d6b8704c4596eded6b4e9be597cd1f6536bc69689a37d785467ace84274e900c517e623a473cee0a8211d9a4081fbd6b490f6582e2cc9c210e4a4d4bb9419d4743b6a5899ebce8b62efa1acd3f81ca7bdbba46145079efa5ca7b3fb392e8d3d1e7426a437b2d40c273c88fe8a3ed9b9288318803e282b817f7a3fd63e92bbd2218dae699e37ad3979c720a3171fce7de9f51f893c35bfe44932fd70e5cb3887620d8966bbaec90d1d028dc4a34cad9f22114cf1d4c1ecc1a44d07ff24c20b828912bf1b61765e68060a6b8ef7ec721ff097fbcff3e2eb97bc4c393c455b7443a6d1ca78262ea50ded4751d0a3ee2fd649bba48a5238ac01c1017c4bd54a43e71b024935a3a47e1c4d9708cd8b14100238e11d2ba5ad6c810ab7d1fac34c5e5e874ed55ba2446cd731cf416780b3cc7e69f6d777c094da2c003960ff50536602121cd114b58ba28e028e4388ee39ecb4823ede09c7fe7ea344924d2ec48df753e3e4d7a8eaba4a798f4134bfa229d303853d9577cc4fb0f9770a9a7a4a4f4eaba1dddabea4d5fdf7b7fc397b3f7f28e767765a3df7a1c1cf1741c4c1ff171d673a6b49e334a62c4a3b95c4a418b2672c685f02abc7f4599efa91332f565ba33539f6b31c5c723add014d32551661483386a3938923150429988a04fe1841353b07c98322083854452191486a4aef4fd29c79b46268e87a96ba67aa8ab8712b9dbc27447daa4d5cefd0884686a676af4277cf12867dc53ccfdc432a8b461d7193ee23da993b574449076712423088dc1f2619eb104169229674b4ae94de6e8e52bc7c49929f7bc21574d1607e57fd8ced468288673356a713709465cc0f28102218899693fddba5c3fb026d4559ff2d01eeaa23ba39775b9ac6bf43b88323c9033feb25217ddf151a6d469de1c11a7921fb930b4cfd18f1c1af98c5eb4bb19693f7138ed498c2484abb61c6a327fce39e7908dd9220d47cb011580841d1861f930b5b0828544a24c4b3f7e4c8ebbe68f5ed9686447d65a6badb5d6dad76baec22551c6093933fa894b3a877de53c6a19b14b62ca5f0a7b858b09da5a6bed67bf1775c55cb5472dcd711cc785f83a28ef4f90c402cd20b516052333f468c8d2518cc7e2e86d7138fb4e7c71846699f2476621b10e73ea7c247b1d9ea5bd1e1d6b51467ec4d37dc6a8c595fcade96d8abf5bf4b635d1e608b918b359387bbaf29eacb4c9720c2880981869239bc4c4263220202641fb2740472b3819628d872be18a130751f2a546b911ede92d83e634929c592d65f808ca5794a79807cb43f7dd2c0b499b95980f3d983c9905492400507ea0003201c895d4a2e210e978cb6be02cf01be4041165fc29ad3fdcdab262859598e7b8c89a4dea39ee829598b4a17925286825b612246d5684568228a52fefbccef22f3cb4af52b5168a9048ceb88542aea41632e533682157514a9b1e71c66b221558d03407b8599671b475b56ddb342d57825684caa049a93fdcfa9e9361a95d7e0b59c802881e70d1a28285050fbc90820826f40c018225c4084f10e1ba42cb0b1d7cc1b20013b45802a70c22279cf42003a30d200b580262ea90eb60447921ac52a954fa4d43b5e26648928c16529665d9d7d7e1adabbd2483070dfb234a4774341a71a311371a7d42e8d8d00f973e4dac710e4b9a9a824bb370f74a0c8cebe94df382f6f2da9764b82b04735ee14a6cead57522da5fdea0e06e169cedb7bc12f34ad14d51396d1567eb467987a6b733ec6f4457786e1b4952b771ee7215b98a5c9e41778d46dce86b7d443e9dafc8e7fa8cb82a7b95140f46a39253728e99a2f9fb02517e72648f23e68525ab35ab59566b56ab07a381843b9fa341a265dc0dca1bf3d0bbf02af8907b610528680f69175684a48db54ed82c5684a8ded6711cd5635a40cbdc43e9b77d512e5cd73fd3bea819576af92c3f4450fa20aa5870f496476839847c99e32a397a2933e8750bd76a7f69aa85bb3d0c638d4923d9ae25cb0f51e560447004e290c9f2b6f9bbc29caf5a6b66b35acd701575cf818144cb00e36e0128ba9be6835870a25eadc4624f765cc26b0914895883136b465ce84d91d05408d683d12cd8e711a34799148b3258b87b4548862c431cf4e1dada58e3422c2a882a072364c109af40748558dea1692dd75f1172951c8a352e1486cd262a7de542ee0ddd6d5f34342e1a96076ddee0a47165360bc39086d658148b421a1a1a8e86868626005eacb10920451b455ca1bc83d35aa143af8b88923d985b05904a94e86efbd266ca71e6aa2473b5da88db685c45c13c6909bf025870e48c0b726c96d92cb3a10dc2913657ced0cc940be42a0195e54322ceb89c07eeba453d984ad3da7b3f1616d3ff4c7998e34c8561286598fdf627322bb950580a8570158e0f7115685fdbbe4879d3e8edc1babc73e8edc13698c3e288f91c244a29f53c2f0769000418807d51302ec9be624d495be1a24857550368d05f6ce8444f88b43f7121ed9f850e4e1c32ae949fd28a35f42ba7001d9a45490b60c0cd88b4a3e6b83952e24a18898f91ae4d624ce51e56d79287f2a97417f2b0be0b0dd5ea524af943ae92d9ad9531f5d97316fb90832eb3bfc9507c287b4b02b5ee66c16172e9bd3a3299c212cde9f8440f8ea0b77d813864a2cac170a12813d24a3d9857e485de9017d3b4d224405e3993803ae79436e035815e90f745ac71302ea7b70703e3a2768cb47c4d777a7b300f26b3adc27d491f22aa3c25d817ad74c6402ad139e99ca6eee625279dd20eb9aa075f954adc024a257967a5b452ea61093b4b2500d8a43db8ea2776b707931e6a5aa910945443e99084c1ddb38624b17dcdecc7c1166dea76805a7e099b1e057f2ff11194e73e7cdf84bd47c148b2e76c48d6c76d13d7c1071cfb9229b324ef7c0f7bb199725aed7d7f1bce950967157b405e90177a31046caf2928200119cf183a14d0dd5007e91307c01dd228d8bbd81b02b517ca19674966548f69019d65295c942f6d77c180620d0e254495cc04c500c500a5109ef2f79c302e90b9b23e37474f4dfb637da618775be9f37392af927f58d1b3b23e1a1dba2f1d34334529a52a94f7d731431c145cba014150da4898ecc1870a7a6194f160de1551c6eb22ce78587814ee8e29b34a236db22c6172a6c2688a984d5c4a2badb5567929a536cb6c96c91c692383883326905868ffdb4309a070b7072b8aac9c300c73841e7a98651edadffe24b3250fe6c13c982572d5f61c9dd998aba685d9a09b72439af4ef9c33ab35ab559368ebd2f049a8c1c22760dc4db3485ec743d3d9bb115fb90f92bc931a7185624d51acc9dadf06cdd54a50906de22b49e4294904a42513d60c7b8568c7d8160cedcf80ce5d510687ab55bb21d1d6bde9764c0fc88db82a13badb83791865beb8db7356629ce6aafad987b0e972d088833b42be72224ff9bfbcc4c4e0c011430cdbc350cbec311c8de3a011ae17e40139983d98835edcedc170c2b95a11f294b3e00c61c98935dcfb732b4fbaf75f89ad10ad14fd8841bafbd16865a88b2b75f77b45684528aff020cde0a41e93d4001f95444346aac101f56bf62b315769d409d71fc75543c2bb578284b43fb783879366e8d1001f19898611a9868e86fc66c895a01527b1c68558794254f910be92c3c50542750e17777b300fe61e90afdc88a7dcb5c5054273e6ca853cba9ca523a50fe7aa945dc61a0f28ca9411559e1222e82fb3077bc2ccb207a34eee760f261760193072d24db6a3f2a09534c3d43db80690465d0384e89a5f62a9e50bf96ac80a401692fa4390d85fc1b37e9067b0908c18d0edd0b48c5a0af90a898d5976d3659947d461a979f0e031c443a1a127b16614ebe20b1f23dad489d3751ca9eb485d97b7108fc80bd2dd8e20ed3af260f5e8bda34ef09c687f1ba3ccf6c228e30175405c6f8f76d8bb22caf893b2ef20cae4d27bb0d053fed6decbc2e21e4cfb4f20dceda1b419c2bd7515f7b7bbe17ab0d9c438b36520d288abe48e1f116b46afb9f64541126dea67b987281304c7c1215106450571c65a6b4b1e9642ef41fea43430d22c9572101f582c2d924b24107131664b39374dd3b49ff3ca2c73e4cf2c2b692467cb55a37c1df4e79ce6ab658e844194d1712224e8ae1968ff0ac49dbf65cbce929e735447958b3a5c878fe868345222b3d0fe94662c80412b88bb6590141a7a39a1c224491da4ae39d73399a4e4430fb3759dbc68385277437d5e5c121e9e8f9aeb78844968d66416b1462a71157d0d9c29ff9932bd96948ee8a88e280eaeda2c1ea0f1d57b8e185c953de8343f0e3ec8e2a07cb198ae4c39eac10711c819972f1fe44a42318a41116a6923c38833b20941918c212e28ca300188abcd956cb582642b68078a962d9e1e57d1979247e813f6843d0e46cd23ece9f199723e8ff035318fd0a7aee04e2533f3087db41eae932ab8f5631cf47f077b78463cae923caf1e5fc996a73c89124ae7f479250979429e231c8c3a09e5893532c7c1966bfa83bb73b45aad22441c0cd2825a419f0157adb43973bc4833c75ec8011763f62865f47ddfe8fbbe144a294dc1cee2827c4f2b57554e1afdbe6fe54f1afdbe4f659465a32cc341c6421953c1ce5ac192a51d49f90fe758568a8a4a2e9148f387f83d0e6164c98739a8f2f3b3b75305eb949494df34be77158b1d8dec68c400f0a3ccc447be4f4951c9f385b0504a37cb766c7feb97c9510146d9ca9969e516d266063923b7902b1b94f46167753c4a3acb5a51c66de4cc206d240ca24c410ca6c84834cb689645208e281d519a655946a794d92440ca5449f9cd82535252b22ccb94eb48a8d19f5e08ebc328fa529bb4a3a0e8aedb8929ffee632c69a5d2c72ebb2185e21bbecf92501e07ae43f1d6762380487df78f58544aa99364b98c8e68c6555436a27444e9ccb9d97393345fdecc81620d55425cf98e3f413b1184240a62ca838080b37098292fe90f3b8b06715fdad1c8524ab39ffefe3363a1948eec889eb815122dbda655469ed7dd947ea4614f19a960c95ac12bffe1212a7feab2151ce4b33fc35cb9042fcaa5414403f8abc4580093f71ce742925df71267d6592a2ba76ce5b4b2f22c2b2b7fc2a81b58fef42ca715fa1aa7695ca6c5277890a3e973a4ee46d33794eedfa92ddfe8edf617f810accd89701deddf8d48238d562929a5a511cc479594cfbe677d3958dfb338e8309619261159246333cc6c278eaccf7596d12cfb708e657d1fee41e244194f8104835620b154c1a893ca0b61712af83138532a2a7fca3f530e824fc1a81b4e9ff2a70cce94abe498cc1070d6f75fc66132b9337640902b87cd1d69e338dae590136111e4107876a28c9423eb20a54ff0c0a537496759f65d779349d9dd481c66ca9f8eeccb2b7198ab18a3166398fd0ec95c48e477318ce028e76d7f8cc0622aea1cd1267bf937124067389333feb0b9da404cf98761ab002b0307580c659c7367eeccbc5976e888ba8eb4c95e7e0e169733f2391812f742a6e9141c5913cf3063108ba674f21092a3ad7d89bb1fe1d2c79aab7177535f057f4f736e086291b6bfa3a346dcedb0205fe93d27d644263aaeec86ef555e250739a560d40d29aff2425825dc61ee8465d0e957b20ccaa8ec65d1ab60d40d2baff22b59861995fd293bce4ca550598680b3545e25cbd89ca920622bb8db7776b6c9e4ee1866449aa35194e56f0484e6a47078cbfc83be5f11653cc853584830d442fb5721ee7698128cd830f5c1ad2db8da23d182abe5cda26596d91ffd7627d9c88eb003398843c6e229f9f36b69144680092ec66cede6b83940a02591c37364930136d0304441f0c20058b34a73b4b209c6d2bb8f76d84c95b2f34cda13b90e3bcba5e043923525e5596248da64990639e34bc8d589c6263e4483b4f11c3993639ee44a255dad28038328e3afd2d9419c21a20794e4ad583389147118449b1983fb01007330c0411b22083e07035ce538393b5a8e96133fae4a89e1b70cf4517e93c2b82cffc2bf03e133719a5042fb9e486cf0eff983fc7b1a51a3f27b1e31a7ddb1ae17807c0f80e72ade2691d2abb852d5419e01c47bd37f3885fa505fd0f5f00e56eb20cfe0fca5a6fa07496f2f6408900e66e0832a8a90c40f718c254da09841ab0a2342af12f7df97ad11eb5ac2ddf6fbeffbcf4e97c734a0d24af618f6220dc683e5e16abb32634431200db6a262995ad0d58234200da6c17a7a7a7a7ae4fdf04a8daf4183869c355ed6a8f13a1cc78f0174f4d9a28acc2606b126ea95f7ba1bd557cc694e5e03bc0ebf9ed7dd18e0b7ee069577108d7a2f8af94d73fa3d80d4c67a7e0bd8f2ab9a9767a9f17e7e8d35377e7e266d4c3ff3fe2183a64fe33fbca9fe8a9c28e7d2dfde9aabadf54276c9fb9e4e1f93378d694dd882d81a59617b84a7fcb7d6ac7fca9b86de5b6bbae4f9429e30d9f54bb649a28ceb05377422ac150d5d17dada8751bee26d95d8c1f5a44123c75bb3fc43063d3feb7c98727c78a0e773292493a6631ad088e4b1a8576ab88a52cad3f3bae24787a34c03644d88bbb51d22073d7acc631e6bc554d4b12ed7153b26ce4bc1281f3672986fe3a38e01a37cc090037d183e6a2de6e0e7d5e93df5beeff3a256a4116931770d46916ca73b3c3daf38fae766ed4c2938c660ca3af0a05a8720daf43ea63655ea14879e3f31156136e8863115f50d0c8c38b48dcd9506b33158ccb5f23ae3a835bdb528441d6a415a83ade8adc14cefe556de2bf4319671667ec633cacc57993f5bf35f8e3c96a648bdc889b49846a4da1a4cabb6a623371c0db6e514d1602b1d9d2b6057045d115e31c4a582b28e3e5b1c510b803f82f50980c108d64f05e00110801c13c1fa03c02f11ac9f03b344b0fe0c4e89607d01e01bc1fa30605204ebdbc03682f565308d607d1cb4db016a530070d400d81193c2517bb7e35f58522ec9a44d5987209abe4f9d4c16d17346a1f2102146851610718521213e00224917703005d71928a076c71ab150b87bebd97adec375fba03ff961ea3dc5937a38eacfc3527f786aead5546bc5a285850e162e2c76a80bd55469fa1aed6fc2242346b365fafa55c7254e284273261c35f57cb628e2b3059123ab37e11d268f7ade6fde7b6f3b1a8468cf7b1deee51888e4d85aae32656b8488ab6a3eb27aff55763da1c7a930877c9e4003ef6bed76d82eee9eae7944eb8bbb271562cd354dece269d40ea9e7f7ae5db80fc72833699e3ab3aba69eadc5627e45110c0e0a0b8f561b2c318282d5d6e358e84db79eeff77df9f8c2d717f2a664c351c3e46d5157cfadc7554a5c45e744b96fedbd630c318345062c5fb0022870589cede26a41403030eed66041933eed6810b2c3b55512651c455fea4a497ae61f241d1df48182891ae06009557cf14310142431859e19fc50c4453eb2da7a7ab69eabf2b1bb59791daef232e09805133178b1c608d271898e3e6310d1f86ffcdb2e6e8de7a215bad167c98fded1fe1a6cee708f01693bb186e60d28caf8fbccf38928f32bac711a4c0372d50bae82d1424dc8f35ec0ae323d7d18d8bf600d48f3b00d1e36e52db5a95a60664dc894b530af82886005cf922c9005981f244f6d9aa613dcefb7c7605a45e4aa08db602b3c9a744e6dfa89e934ad8eac22ebc328d3479ddfabb57ade7b796b62faede7150421740e1d5f489c688e7392ec5c7ee21c288d0e9e7e8719394942991ef52fd8bb9b17ae66940fefebf3f0bebe10bd83e84931cc14a227dec1354c962c9033a8a77847271af53ae60b061f855bdec3d1c1d37c17bc8568978fdd4dcbebf00feb98b2eb31d2de7fdf534a5f877b2fe0a8bf177e3ee7a40fbf50eb4f4ce58c3659a0be0e37cdf9c2cff994bef03a9cbef03abc7e6fc2f32b7ee1053c8b6c3f5b934f876f3eaeca6112f171d055391c59fdf672d063cd2adbd84cd9f84d43c7b05c1df3315a1d53e3cb314f036f1a4de36d1797068dfea7dd8e1b8f6fe04da36fbc75ddf8d5df782fdf781b371e861b6fcad153377ee2942873e3c6d76c63379ee6d80dacf236f0a6a1b775c5e03d7da0fd6be08cf7d518eff92aff78cfa0599e86cad6e3e017f73f93e9b35e5cd37fd6b5824f3e5c14c5d047094c13719f2918d1353afa8c31a47d9e24f1797284898912424e98285184891244b42ce2abf8811ba35022a45f4320f21a821076c755a6a7d1a66ff9ef39aedbb1f2a7e76247a9edc28680467f4f710868740eded78ec7ca9f5adecb9b467beff22c384619d4ef186a607ea7ac687ec3e89adf3068ea2b9bdfd67b95b7c12fe01a18f47c1a3c7f85e7fc979779e63d59f6dcd953085abbe016bce77f6fc239acfce96d77a3f28346afe42db50d9e112988d0f3f42b359ba48aa6afed942f6a13fe41a34f38ea9553b63b0eba3542b50db5586bc65a3505a70c41a3e9574d3303746caf4d898e4f084a4111444378020d50c0721b461812820dae90040b94d0627335bfdfd6fb98e9378b5efd6ccd2f6febe5ec77f5a6bc59f4a45b8f9e3f3dd3aff01024d564fad9e2b926d3a3743408d1b58729d3e0a0ff0c7288fbe365d37bff4d1dffb0874d186faf8d8bbbadab47ef7984ab92b84aeec9c3e3aa9626d2febeb5669e77487c1d2023d95a4cdfc072622ab6ac4e4c45ddba81b9622a0ad930f57cef22b07a9ab7aeb95a65ff07cc94bf3f81890e807852851fb004106345d6ea77ec992b9a3c7566ca5dba07ccd61697c912437464a20491a6a12393248ed0b3156b60106be6afde3b1f235d57385a5db164510c64128932fe3b584d03ed3f6510679cc77c1d5f4150325b397ab6527077ccfbead66ccd199f70b92f7d6b7b9e1bbb1ed6c945c92070507e8763d861d3323388b48ca182c041c761b65aae9ad35574e6582308f45cc5bf71a34fe8a3e3aae8132a21225d7367b6a60e45e26ea1015c8aa1447599fe0e20d6c83f8076ebbe537a34678c314a1daec3c1cb525d7195e598cc69cffe39a2ffd6b2af5efdad1219f838e10c28b010420d560ce1079815662c910596fffb831f65fc62e152874d772c703166732e2d3f823134c6411c207813339a3eda6116e1d62e669ec5adb483e891a679f3d0a43ac5e55a7b8bc91b7f1b7295f5917bb60d65345e1de936e4a07cc75bd8ddc41cefeb98730b5b5a3ed77255cc1bcc41f95b132dbf5a71f7166e43b446ca187f138a781b927a6fe136e42aa975120765b8096d43913edda16e30540ffaf163fe18f11558c725314272824335c234378ad13934b771955229a3a914a1d01cf5a1e2fafbacb492e250a5e2ce1886e646a48863179ab3d4b5e7ad839e59b7a3a46b763da4a3c0824757ec325a6b3d2ba17a5420bae62b8a74c4d2355de5cbe894e65cd63036adb8bb0e69f9281fd28996a3dae4663d5cef095809c44d5a8178468afb47848541b6be3458ade2660f24d334ba49a64959fce81ddc4788d55ce98592854befe05afedef49e59dccd92c5cd1ed523be7fcc350937fb88816c11bf8e19d523525d3310aaf78f08fb1161baf63898428ab8365151a12ad3656429d5df34a76da488f1159a239122c603d05c8914b129e21a230652ab8f96cf79a3ac523a5dcab849bd44732414135abed458674135375dc61967d6915e3b15f22b155789964ec5dd954e77a7328e4ab527cac82fd1e99d8c28259491f6bc79682da6e563ac33bc6bcf15447870e62a8291c4121e8011dbc20f7058f2b99cb9aa80901327728c5841104a58f2b7d856b4137355fc296ede52ebbd99a1b37c44db886273b585f2e58731c88b32b2a0220b58e06141841531a2080b3f20110422bcac3b5ab774e464c7636afad64199a2eb73b576144fcdcd9ae39c3a76738b6d3107a5945f5f7375c222280b155c31861167b0e4d79fb9724962091b18a1080b8c100396fcca537baab89c0b46059ca4818b313b878c0e4a4f7389597bd4a28c3fad5256aac5959c52ba74e9f2373e92b93b2dc26749d07f0ce820756286a61fa378424bcf918d52d378b83cb0e8fa53c396fe88e62d6ff65c8637cd7bf47494d167d1fb669f72647b4fc5546a444de5c2ad1d30e208289ac0d1820e8c4c71c4132fc0b0412c4706d9b304e0de9a59f275300aafb2e6982b2144604117b680446c084cb0205ce2084a90820a9630d1c4f441f50f77ffb4810914392f6012450f5a0428a28822805084176061055d751965a89e5f733cb2bd0e8f1e802114c131a2c4185920430c3196e0a007346042c40953e7982b0f4c0109601ca1c290278058310a53480291a223f8f8e0072c8e05579461051344424fb0be2b9c48c21244c8099960f9733be0620c1077f2a0405cf9d3c69a520f0410a181e6ded4c445d1f1091d0069fa40ea6f1ff186e3f65e47bf618e521a07637070ded24b8e76a4a75d0faab7c781c3c149ca3b8826fd244dbd65ebe0de4173b18b80901bf0a0c00a3380028912b860454f917ec3a5a7dd8eed515ec7dc8eac3c0afe415ac9349e9ac1cae0aa2d6fa9b79fbf47dafeceb4e969acf9bcb7ae2abd7dfb32d6a8bc7d8f35296ff3fe41d2db77f33b4cb385bbfd8e21061b416b4b3fff8455b08c32f653b04719fb1fa651c69ab0fd8bb57d9491b65e7aef7a585dca395c65bb9f2fc3b66df90749dba79d8fa80420280108da52d2db2765520e0149e77010c7b677d0f6e773984670b33a04d136878393c65333869f9be2e0fc18f4c5617f7e8ee96f330e07e78f7c945f1c9c9fe51c2c15879ebf5966ccccc2d5f6eb14df82e0628c749fb40a3918f56bf9d68cbb73e81cae8ac1a5d3c4e0d9462146cf176744c18a1ac81411450a685044032d10b170d091c1138c54010a4045b048108519100103838996192cf92fd78203c223f2a8154738ced4a6d136b2323b53f407081ca454891b63eeb4081763767da9b4b4d9539ccd30b3076796d9e8ec59c21b9465318bd9c7b9ca5e70a5fe7d6fd602fa5767b166f4b5b44ffaca54f63bd3236d81d0dc94ddcd66f30ddc07197de9236b76a8076ca48f9dfd20f4b9b7f986ed4939086af42c33958df20322cbfa7b37c21708cd4dd2086f4068cfd15ce5b25169841d08cd593c7ad2737f01d27319a55da07b94965110e07efb1bb8df721024da0741d94abfbd101f526b1f81c8ba0fb86f71664759a8b3b70fe03e0291c565fadc964f307fd3f76fa07f739c37549d6979844719cb4c65cfe19942c11d46c19155eaee4c65b5c7c1ec47992ac18382007dee6f98bf7de571307bab4467cf6da391cd47489135ca7ec3915579e6aaba3c957d46e2aacbc1ecea2cfbcf1eccfe66cf927dec1e3084fefcfaa2cee1808b13b8f33dfa5ce1a5b7d53186aa38203c1c45c74cc5fb38481b5781f6af3a1c902b1d624832a416b4eb78d9d7fc2d6f163d726bb32cc3a3e734cadfb7a8ecbd17c24265197581fba6bf01257b94cff20df74d6fca414a52cc00091790308283c3ba2f8455faee33d767bfb323748ca9ec4bb8bb89d286a2a0c3251c59b2b3e1ea2d1f317d863323aeb9ca4c59e6ca6ad6d236aa20620b20a4800a4850c1129263031f2759084308232f60f9d7582dbaf58c1b59f20b218851840d70705871a6ee4c796421e161eb6248b42882115a38382cdad540fa2dc39b94fd0f92e678909a6678e7d87b6f190081ce3e66bf6578e3d0a3e72c89c4490debd0ddd82c038d0a6e36e4ee1ae3baee2623495de4233a38331ece371ff4f42c9164899e1e2649625a4647264950d143001d7db8f8415b97ab8000d9e16a13cb5fae62aba900a423908e3e54c0e1d11c4a8c41b92fd4fcea5739c8ea6b5e086b5f4df3366f9383a09a60d1bc10d666d1f2daa8c14110f032d0c85b88a661c35ae1aabce4a2074394844ccc700203a060228427bc50c10c624031c7cdf9f2f3853ec78d48b203f316a2c1d7ba1bfa26d34f93c9647ac1514ffa2f144f8a27a5efddcda4f4651299f5e575f8c42f2f2f37e067302e3f3d53deafbff796dff67b98e73ebcbd3625afbfefb79ebc6dded79bef7ded6ebcede5aaeffdbfdfdec3e44d89e7e5cd85b81ef457616afdef83f13eaf7adc24c264c2b3256766164e224c1e9149a456af46ede1f9268c727981c19b92ede520b881ef5fabac311a04b156e43385984ee9e833051fcd818fca5b068d6a4d14ea5b3ea2fe848a9d0e52a3ded472726939b97c9f8ffaa6e751dfe47926cf8389f90fdfb8613255134cad28fc82bd2e313764d02cff02cbdf98b225aaf9ef5192a4f708845039439fca191dbe83f6ea9b7e90f4b711f16a172eeabddf5b0f0f3a888212b2e8420da4c0850d442421064d9002892158d85a3aaef28fd44a1ba9e97bcfa170ddc245a1ec0e7ad327d1f7f0f683a45179d3c20ad750cfcb368613f036ef1d050ef035efdd0d346f93839094b068debb1b565f938320c0095fc458ab1b53b6440efad7609aef3d477d1eca4ae17aaeb94a5a619ba7c135ded5f03d6a07d52e8f42bd108d3af5b8a05ea7bc29a9ef4cb81448c0d37cec2870805fe520528a1670f162ad3e7637d43c4d0e826a8255f3b1bbc1e683c82796702164d9bc0e8fb475bd3c752691a168caf152ada34188a6f9474c6f3dfff2f234cfd66807776fad047c8d050ef03634b8e6637781d5dbe420538a2e42d6aa06d3fcec6e4ccf49efb7d42653b6f1307853bd6964d1d0f803e0790510163e38ac04e008c3c16171b2bb39b2fa5502f001f0cfd4d6b3f968969962e26e1ba3795362895c35b796dd94c0c412404682c0852ab480041034203a6245114ff0a2e5e7a330eafdc88df7222eea515fe329be0ea21e06a35c1ee6a556c128975779f0b9893f4b74f76cb562f2dea1de68c5b06e3c27bbef3bfd7f180618369f1f22df4b77c345d3f3f07274d07b13f64e1fbb7afa5c487f1aea3949da94b80af565cd0503e901a25ee56f605ec744611b0f83a38ec1dbde78ac01610de6e04cf23abc05ef1f295aac68ae341f58d4b42456b85bf3d1ae35d17cb49f39a45b748c6289269a9ba4ba438d4c9717d152d73c8938485bb2377ddd54e7afbf27911d527bb3f52edfcbd31b0f8302f1d6335b13e7cfdb82795f5476f9fa1ff8df9f7074f0dba7afbff5ccef61f83ed49b3ee625ef50f50b0c36f5dc1b7907d72fbf33d0f430f4a97ec9397cfff2fdcc19e6770b4cde2e54352ae7f0fd4b8f2fe740bfea17d329efe0da45d32fef4944d7fa3abc6252caeb70223e44b616add4a31fa5744b4db38ef97d4fc22f1fbb6fb6a48df77412f1565a8d98fad385bc5cb3e761a5b43ead986e21947e78e2979727fd6cbdbc90fee5e99d3e9af45cec6ce0f487b7d4dfa4791221675a73b59aab555efd97370bcd7b79dfaf79db9a5c236f4b93e34cd5f81898fc6fc2371ec7680df6f4eb7b29daf4e5d731b71e18de3b1ea877798ca5d6605eae99665484216fdbf23572cc6c994c0f9abec5f4a777c1a36ec78d373d6749b2c3ef82511acc822d274c7a9c9f03710bbe8133e92711d2266ad2c74944ff5b32aed4fff95bfac17fd293be65c2d0f22e35bec6e9f1df88f91ba6f7de64fa98cc84bfaf786740575335d5faaf6b46bdbc9737ca06d49bbc9f79eb0ce898156fd473303f5f6cf0de6403eabf37515a6b46bde41ea81c1d34fd977f3e35e1fa30f974b226fcbd349d62ece9141313a34f356274cce78fa9d1f220be71036c79978f5d0d2deff22d2e2e2e23971697077fe402ba3c0c2e1986071d86af1886160e04c1a79f6564985e6ad3cf5ce36546f5f89fff2d2d4f32c9ae86962791f03f89f42da8fff08ec980f6fe65bebc68eae2925fc097bc5934fd9da25dfe74ca30ef82a38330795f0a0313f3debfbcdcf82fbf87b98fc1fb478c36fd8d47611e7ab88fef617a52de2d6ff26c70eddd0e53de72e2ef29de313de67fae29de373e06ef4d3d6abcf6720e2dff35f0be917fc4e8964cfafc3a6686afae3a06bce38fcecfe19d019ddfeb6e401bf3ff196f44b6d6bf09ef186dfa4dc737cbd5a8df36889e799b3e3f97ab70a9571f26bfbcf672d5e765ed31d5356b2f07dd84413deae1fa7f6ba560aa37229bce8bcef9a393747eeaab2ddfe41caf6ce99eb9a231457fc768ba33a0e7fbbfe80d96b2fd9832cd9a12077d5c1577103d67d65e3886b85b53a229719596b5231c74576ddace5c693a3ada8e4e4c4747257c9182190c41460b8834c1c2a18226b250a4c9112b72c0f2b7315b6463576a1a6fe3635783d434dea5ffe56da1f1f9b9a86f8cc20833340e1da33002a68f1042e77731e2e5434abdc33c3d4c8ccbc3f0e05357dd78f05d4c3d3787fadefbf8b8e9839a4c26d457ece511488dfaa8bd9f39a0b20e3db4f73b5e1ef551dbf0f243cf4765ef51348c68e9fa378cc0890208b1287e20449fe364d7e3e5e76783f77504527f26d3d3e74c78beee1171dd81ea81cab5fe0bdea8b7f1b5a3c1e5bfafdd0c52bb7ccdf4ffb951ed1c2075fd3e760e90da659bfecba69e6bca3f52fe636783cbd79c83cb7f39871b5f7fa498f28f141df334ef1f29b3f341e346a60ec6e46ff99a370c393a083e75109c35ccbc65ec6a383dcc9ff0f641c33ca76130cccbae866d7a8a83f6e6d4b2ab61cf374d7dcafb041ae65bde7635b886f95ac37c53f6f26ef91da686f94d738dbc8568985ce35b66d7c3758dafb8469eeff2346fae05d397b7a56507a92be96beca27c487dfa7ce36546f5a0f1f369fccc7bd32e39b87cdef4e96367038dcfd1e5f34b80c66720843abfcb97b710fdbd8777cafea14d94d2b9fa9797bcc1373d0a9561de7b1dd3c336de84ed8378ff48d1a787f90ff320f5e9bdebe1faf4f963d7e3f4396f973f79d26443747067407bdcfed3e1a78cb7cb9f9e3be1edfa858b1d8f970c3ec5a6ffb0f727bca53efdc4dbbb1edf7ba6d883be29bfe0a84fd8f5c41be6b507710e2e8f1ff5a7ae4774f0c67f4f531cbcf1b2eb31f30d8dca39b83c8d1b78c3e41f29da25e7b77133a86dfc86378db6f116ef1fdac697ba9b961cafc4d19fe3fd91a279909ac6ebf0ae878aa6f125bcb5a67031de52e39f78a7e8b9a7c6afb71e4ff9db78ce06de8850e16ed4fcd15b36019a4966cf6b6fadadf53a5c2ab163dc3d5b34f0768d5334c64234b5f152dbb0d1f294bf0d1b3345d31a340103657d7e6c100f54e7609d58211a386a1b986a3b053bc6ddd63567e611352933421a45adc455231bf4f293339162e7637e7d13ce6166940faf66540fefa9ec76783f64d026d3bff0b462963761969f1cf7f544148efa433d6a892413d58342a1b84b22e1f914cb247286f413a5934bc819d2cff9a44822fdc4a311e905678f22b16424154c72b0b3566bf5c00522bc8ec04512c2d042035414d14451112d422a3cb9b155a72459295cd3476a04021ed504ab357bf4e79aa5928bda41b756cbc1d973379d8d88835d8f798619daa47dc553049abe1f992d6b8b08524d78cf24f627116d220007915f4ca183d8ea7d885a8cb14513ac5546625d2ebbb3b5b6223426de8838e804213c71041cd88048091894c088304220b06048870bab6722da6023c49aacb2016d497842e3d03326aa807caf833c4307e0092063030601fcfc94a89a51e5f8f92f1f550550e1f8f973bae68af4444e0c054b8478e209263f0ce5fcf43c19a2c52c72d323c6dd5bcff6caa6ce0f19b4106d79e6ea03599491843196b8a067aec02030f1c30d8660320414ec4eab58a8344df3864dcf32a568040000800013140000200c0a0744c231a15828aa6afc14000c859e54765a1b49b324c7610821838c31640400004040201a860444c283634949ae244cca9840156c592ff1a834c256f8bbd3fec5d995367cb48ecce8fb4bf3aaaf88f52e2014b98b4bbefa080af3094bf1a29dfc31802a05e295a8a3f3d21ff0a802fa1599a94dff421b8d2d4900968b62a1587bc490e17c9fdcab0fc03b6f8e574b278935be6747588e4db4e65bec8a8004ab3f33697feaeede70ef22cc85132c686446a767d44f14520893e612b321330dfbd0be4c5996b9a9a9f39b0475583e76032aa1c0b8dfc32e6a15015bb2a24384d27d79d89b6d385aef6555801f076098893bb12557245e03a6dc1a3ea3fd39550b4bc26fed213775aea6df07d175ccf120d8b91cc1670862a9389deadd52b4bed770ac5e11f99c9818935d2d1b63ae017131680c4ce2661c0bc7426a50e75039aa1fb04c9baca7dcaab8d16e25e8a8bed7497c2ecf5b3115c88ce090a965c375f452d9d60d3da5e48273bd88a434f6e0ed68713c65eadc12d596f1727bcd4ad109739e1cb687948394dc7690bd4677909be1d22fde41f2e1bee76116003f3901aa7435acd30f39677c671e7ff865421c90461a03c7c833f943b3f85e61edd886cf3648e455b6bd2f49337ad90604f20ef130f30e9902ed87e09e6e3f6447ea7834e9b80f3dc33a1b2c83bfd029b19e7c27818f24bd72bbf1b32bd43db6a097cf1e6b1de67065e21fab65845e924928344bb82ac706c97de2cfebd77bdba209ce664a3b1202f7dc7bbeca3cc0d1e23539a0b928887180453e19bf2863bbc84b7e6cb805bc2b999727cef7109738882e90e0c35e80e9321d5ae3d5303f25ce1226cb58a7f6c340f61c3504034b5d3164ee07cd80987972a63d2d85a2de03f35a4e64fb34d48a84d1379f307b58559d491b4181d5b236d8ae8c67ad2e8d0cc0e2d7e701641e68ee668a0e5a63e597985c47d2f3d9dd168586cec9261e830e652ef502566e7f8abfcc6844c8a9f0cc215b9245a1d3bffe2dc21bfe3dfe3b95b0d3682956ca06bd771e9feb3a9c7936aad0f447b455381d6d6b8cc61074410314329af10414e9468728c3a2378cc1e967d3f0b88bce9f2acfd7000c292cec06d985a5ab4ae87c9dcc5f5850fe4dbe8d4802ea1f23667508e8d0661474d29eefe1261ddc91decd556309aa55962c19fa6a42882f3511ecdb34fb71658620e26687fb92898e9ddd9fd2f93fce9f37e89c996bbdf4b5f767991b2e6d57701df9736020a062217f42939407f03747006acb1b2a315cda8a63fb353aa216304de21712e219142ff074c60756ec1d3e5de5c25cef19081de71f869444490b10946ba0ce911ee2ccf9b44ad26c046f8cedcfcb0e58366864182780cb9ecb650151c6cbc65d60221de9acd8f730d5167adb020b8f88bfd8b2da51f1f92d150e137d2bc9ee66cf4312a333f2d2cfd25c526a242a2da3e814916b15e3156a354eac378e01a4d978aa7e67054ebd1076226f9f1518a0a7029f858e34e18a851843a7b06f944cb8b4ba0863d071e7162fcd3b9acd4703c2e1b833d554931378ed2ed4faa68667b44438c7212b09d7a27e9d48ed4750c894e0147644130df915cd3cb3d631f690b2d6c41285ee705d77034e6a4364bd5ca436f70dbfa7823af03afa2cc6e75a1b6bf5d5cf6b79620fad2b907d61e7ab40beb2e5107cf8a56dc518fd5495c05578423cfa99d4d5f2508d6a7a656d72f6c00ff95a1879a4b7b784ad3a6c158ec37c2d7021dd79984a03762a2ced9d2b4efd62ae16f26a4655181bdf18f91df2320de4b7c30dc879afaa01022e7a3e5055488e8d8a337918fef9e648979cfedfe3379257d37d85afff2b9479fc781a02652657f09615e5e453d679d605cfdeeeb22abc98031c70fe475566539902933e59e3dcacce2b12220283e63e0ffe6d3b1a4cfdfb5b6aa7fe0b16a237998ef4d5633c6c284b84aa6a99fda97a42605ba2601b644eab31248ce5b9a1ea92c10f3dd35650fff88fd8e919d000dc34c93e0141e61c4818f12116f4d6575c207e185c2c232127102a10fb0b8fe5c16b868906606b98608a7176fa25f03c3777f201fd4a3d53ac042b50606044deac99379757e692358a84d5a5242d361c1ee32765c00e4aadd8ce701095d121b33c23d931e373febf215439f0bdbb9c7713bf4c216eeeddf02ddb02bac1bebcb472847dc038cc1e0ef3d8ccfbcc02394c42805998709d2200ae7472896be088fdc4431a9c2ab53c39c19dba9005578351d8d4a9b5009206131c944df53e8c4d41ff8e88427e215bf036aa40fb77eed925b1e68b9d5bb0146df214ce4ed58110bc4d5f389b217ebb3224d7d94f7d9f998041996879cb24bf1e066b67e8e95138675261a2348120c5947e1364e4836c6b93f176f98cf048d7d6106726801dce68c2d19b20a507ffe0e7da6ec818ec5dfdf11adf95895184f886dd8205cbb7744b44bfa82205a775ccc46e3cbe4f9d7c5787be5de80d7f65378821718d87a128d659fbbbb48048ac2b1c278a5d1cfedf2fc4692a1ec252f8d711e9ad160cc1874c614c6e1277cd2dcfea1839b15aac326ab79fc8ce26bfaa217da258a8d5f0575ef8d50c858f6f49a255d99947d120424fbcb330d0930bb6c5cb4ff3c363b1bcec4fa396e570ebf2bab51f33d14e470c31b10ec974e78a7619002e6b2d701ff51405501f91c76cc60f84c0e7a1931cea16b1ddecd56c2af4338f6450474fddb28febb967c091088ffb489761350d3dd42b1397fe9beea6dd67a77a4f2510ca8439bbda3d41a1e49d7021ef855eded06dd993a39ba9749c5e4d4717d055342dd2d402a26194482451eb03992f48f8c12bbe8c57e2004d73d8f0b65b2d094f96e8f3f0a920bfa4e07754b13aef270d58d4b70a8c7b9a1730225e21a6cdec75463d71db88044a457ea341b123e90c090e94e48f918cc5c34c890318523fc6aadd6bc5d91ae641887c373086922f2b94d4f16aee9510aaf1c0c102f33d1b3c0f6051abe032b87295673a86579fbcfae838e5d43d69cb5959c04c343eb9fa5a1faf20d4746c7d8ec01078ddd279783b28cb051c1cecb8fd559910b632e516d8ca7221178e3285e12c0aa1d4c6867c3581c9ad0c17bd789770d18398d7905706a82d90b5a012abd6e4ed5ec1bcc5edbb011dc7eced2fc24411a9c6bae3d32ab4a5647e12288d95533a1e1aa6146b20606fb1a7cc60b46c0c9237ecf70ba219d47c877d5af2fbf6eb52b4359df5453a8ed9b7aa967f7f4b923a9c50949eddfe25d0167b079a015b5e52c58c5d9f90293a677dea97f6bb5082021ffd24a1fe0365068f38d10c7a8326347843a9df55e937521f8acd5ea71eda2a7368b09356649829185bf883da2fa99fba1ca57b78a0a7cd7c88bdd58205d33acae00e66bfcc49a79b1fb3e013b136ae3a8a1404a6dd2e0ad1f9bd46cd408a4c2802abea8be8f422fc89861fc130cfec8a0fccd197544c542c5f694013feb9ca484aa83bf9fa564b775b93f4c0e9953fc4d3d04d95432c7acde03e67c69b8cbb4773a66b1c061bd619bb5ac04dd42367a602a4c10588c314a70f8795f90991ad5e80780442656155b4148098a9093cc088384989aba4c8d6d0adb890f00307506fa9ac29c05d3ec4b450546e6fe9188d0f32f1009917035c64e18a32f6ff0b2974c2fda896cc5b0a0231d851abe1a10a99acfb2363029f9568041052f377b27aaf23494f34f374be768a23a07a6959125470bc60639383884560fc7566ba8b15783f44775cb15396be85cc18e5ab72d576ed4e0e274465776df79fd975ecfed99e7c22b939f653a803b10c8e8d49ba87e63c0b6afd7cf9b814c819b0482c9bdc08cbc2a9e6adf8f1b035a01740d8999f1e40df0a9f59fd6215cdfe10744e05516c8ed45e9843e8a558b12df62019caeb3899fb043ddbcf6d2171a5fc2804fb2a4bc995930d820d2739902e9e1564e985b2e7d2d09e179e8c8006a1d6aa14585323ba655b8c8f3377661733d16bf0c206cd79fc8a581d3993b7e1ee004c7302dbbf2a836f506c0ba1791b9b5d0eb05aa892c5272a1d528bd40b1f171c7605db8c8f7293ec7bd733d05e5307f86bd2fcdd303b1ea83ad3e87fe63950a571433744cbda9d1813624c1867713f00732164da53d8d5f9f680f1e423a64667cfcf19530d20920c6d270c254d638d26c94a345075959621ae169567ea8ea26381eae4008f40de2438a32dab4e768861217b409f7f8cbfdd40132e5964f4782220aa35fb4089a36d0a117b420e8436a074f02086c930a24047e267e1bc85aa2109313ac3a81fd5ac7048e9baa761f2b9a5788d73d944be780ba02085a34c6df0cd0355a32a6225054841500d3eaa66cd0b92780725c608e403fe5a0dfbe29d9ab9aa92b60eaa258cd0e82cd0a7c02788532900be4835155114104848841c8a0a433011d1ebf55217c059a03b6d58ea49034b38b02edafab6971316279b18a2d9212f3f533d304209a280de1283dd7aa8a6ef239d16c978e1236a480d7434ac02f20a41f9b8af7c866f82730ea048f3e2b05c6c116b4ba0ea9dc214ebbbeccf29b9fcb19990fd6874d9553f99871d8c4eca7f8b550479d3c8020235047f34a7c908eff0e957ff8576287098e111d83309e4b2fabd2ab9df49ac36959bdc42d4f3fc34084e2b5df32863d3d480d83212c9934ffb7288207c9025cff0bb198e756ed266c12e5a0aa234e707045b2ac7329f734b613d9e26a0511a5189a6191fa7611cf13cf932949818955371e4a1517d70c5364920671f2a5933a72a1217cdd9f1c98ffedfdb710206f2c2a294d2a4f701b4090ae080dc49f68a574785b93c272e5c167af80e811224cdf3b424b2c14f484470f09010d579df8e033636f8786497400a6e01cce5e4d61d2cfebe065104f5194c416e4c2840fb85b45069173f3d99bb08e45cd32a81eb06c96dd1690ac5fd7b4f874eaeb3ce5e5db59a8f0cde043b85d0aee63a5f6aa9c79fc375b760c091141b20eaab915666e6c2a1af289cc42b522ba6128a3fb2bf1f334ee43360d07e724ca1d961ec6467f8f2e38e694f1c11966dd4e360f840eba38865be6c965b5e1ea6aa3fb63091a1048ee473353126cd4f1dfcb04c3083617307ed75912e9e487c85cf17e936960b07e0d444668deef5dc072f3e00a8dc51e4b5321490e5087120da8c99660cdaf000b2b7faad9cc67b29faadfdc735fd4c03a3e863fa02b4e31135926d620e1163d03b5e3f1f714d2af5cc8c607d1faeda1b520725f119ab1b917cc2042186a5c26540d91506025302bafe9fdd7c0652c3ffa39c6283b652dda8cae0d8bb88f37c050f3058eb92ee68c13d766aa432ba05959ab1d81493e6070a338740dadd96e0ca6f509541294ecfabcd90ad005c52588f2b6d1df5d4b8a0e45f7358c42913bf98cceec8267707db630d7ff4936e1406f9a645176ed375f0208ca4af25be96d8967dc1bd42e4a5146096a9c3a4695ae78512c20e51b927f7af8e58c854dbbb927a4ac35826a8c4f92b47a66cc21b3d1e18b8bfa7b9cf57e1cfa0cc4893ac6d764b268497ce5515b5a455df56d9c8286d36d433b8827a18380ab40efdac6adb2d97af354318d48ae2dcef865ce68f6871f12a175c89727fdc236e92a0a1a4a580343532476c9075d6a88bd00185e46b3e728692584b277f63f88121a0ca85dadec3d229fbb1779cac457b67de349ad58ca99d63a8a24ef859d3a827f9ed1589f473d06238d3bb796541428a1c3e01c96ae2bc1b08ec15b3528b5b5a5a87059f6a73609a7fca7b28671278699f75a99a0bb491447bdaaa99d2f7b17ad2c19d8e4602c07b63e967fe7f9265c182376a4ba409c0757b7d6896b043c00ca7865e737eab82ae2c47b1409ddf6c79ab7832e4f05a3018e430a8351626aa0718b25921cf01069ae943b45d376cf2beb38e826957240ab4346ba0bc666943dabac213342c1645fa15897263b57cc5e3f2ea506b3209ccf09c82c37547909d5ff74221172b4958ef82f6aa799760c656c750a4009a28834f9f602dee2e3d501c5308549f30376e118179909d132f35f29d36314bce7d30437b6c8fe0f76d233591067b78bcb7b779a875c74c35c5f22656dbfbd4e1d2b96f4e48c18470bd7109c8d6625c5e7558e33134b2598e8aceba49ff0498254c7a99d6ceef61bb4951dbd781e232fdf9e14b812ef338225927c7a71ed9f539ca9aa89c11caeb38279176241dcfe06f342f72d86f26d97f4fe23e25f57f86a57fef3dd064a874fb4e7957c87036be8721d62947fe154034f6905007bdf59a2c346ee798bdf7f10a150ce3da36c8e89545432d04888d07f0f5c672bc23f61ce464e3750abdb3741e0fd127ed8022774d15559421da3685c88bd5917dc5dd9471613c6bc04c5f25ca5aba1dbfe53152aec22fbb0b619c064881eec0bb093388763432c3b87608926300bce106776c6a0f2560d84a7c99fd7043d300e6022786789801bf663db0ea9e934783fb76046c876b18af3a46e13e5894fa8f2e00b13bb87d0b307b487218de1a7a88424e432092a9217d2b6104412cc34d8c18394041faa25c7bf5813b426100ae90627b71356d417697ac89a31c1dc04c9a9a4bbf3d4223cec09ee2ad7e9d91fec3bd9d8d064bf9ec73f329c80a222eff66899c35d8eb1fcd04096c664d86f135e5cd456d6c711761eb78e67c1c3c8840488896b2ad5a0ab397e58de5fc301e2f2e528374fb46fa4db91fe7533892ff4974a54048febfaa86c32e27f5e90123e21c1244632a4b06ce320a42453b11223959bd9e2358d6f6e7b75c29c0610b8286fc6a18d4b223aafd6502bd44b4e94bbe2603a00bfac294e3ff1316890a497408423c9634ca0a4785ae13e86658522da4154d575deb3cd250243594c85a0136566ffe38f5b48aa9c4871ebe0db43b0020a6b5a36eac109a039c74fa7f514d94e0840a8d809bdb011258560cd0df49d876c823a795e08733544c548cc893aa36e37a78e2853f300630cb3ddfb78a3c48bbe39b0a7bfb06cd31a8a099afab0e9507ab806dcf212116427c66f3576c249454f47c0a4072b73b3a75900b91aea2c0db64c40670812d9765db60e466e73c6202eb0839af412206c1b3e0ef925d803f093445d41c2717101fa4f74f90f31a56f04158ffbc03ef5874860125dd64efc92862d2ab21ad5b476fd0887a8f7b75564bd5e26e61459592565a14a944b59dd79dab4bf5fda73c2acdfc74132d97140c1850f113b1e062d5b7b4cc17892a4b0f0b33e58cf01c3820ed665ad4139e51cb969a118d2a43c6f6d49c6ab5879f6c4f32857409c4244444323d8e034a4ee0ee4749cff487e6d13b9095a75a15597e20a3a6236f0e5ab692c1f5588863816418dcd91e078e248a45716de01351cdd4f6a99bdb07a59795b931f421b49a3601796b7020783327ad4c9ab9ec8902b4eb64d1ecdf082664381776bf955bce56a81295b8ae9fd16991b21258660a28997d4a200a0ac4b42e4ae06a4d7164f30403295f2548cea833a8e8a4910e02a60fb6941395467b62422004318f827ccda4be5fe006238293dc600baeb94922c72bf40915fac3a92755ec8f586d09d5e4a9f99cd9742b5b31d5d92fa2c6019dc4aac2127fc88af3b869816520481896cc3c13f8dbff72f4486bad49db404bf7f47f6884d1f8e79cbf17f83d62081fa5a2ac26ab207099c101312d59a40271146d27d8ef638b3d5221768443ef17add28ba294cf7cc714a556908109bb9392c6bc081525b98722da0bc5f2f745ab3b322c08618a0803c080b1d5aee48cf1da869d40c782d14648782a761f197cd2df1ed06837512b3d9366dfd59aae6133908f92db474317eccc3bc0da47c09668e420edda2b3e3983eefbd84b10c207d1b43bd6de45953731454c65c96dc5c1846bc80f055fa4329583b3103d20cf0c5396d9cb80f5b973ddfd5a6a7ec8f3c61b0f29c62521bae0d6ca1e7f9b17ec47694f826d51a911628322e42602fa44a3cb3aace207f927342a4798fd2f521a89d32b50bb869afd7c4cb6c4d1696ea52b64d136b4a70cfa11c9961719e757eda6ac4e814631e8aa6e2f39ba1cae99532d20b523a6a8d055880f97c57b5bec347d73298b67019005ceb107d386ca14908e39f0eb84dcab5b31ea4891f87ff1748449fb2ca48cc21f0b6b4b0a2f031475ed59d9fadb8918ca1afe19794073db8710811c5c0b5be19bf934dee01784a1f30b5087d4a4af3cd8db245654c38ec5b66768cd4bdc4a77ffc675003fe94ac26dbffa04002a4bd710abcc846a5a4df689b3f46dded2cfbb4bebd4920560fc8450a87f7ab7ac36c6618e7c60a9c39fc94736fe2341272ae102595033fbc556d5ed0053f3d468e230ea1d4eb14f1a5818909c344009464204a170b36d937d170353af5c7bcd1676e68503b798252553afeff0704c9cb2d3a8bf7645cacabad47255968023c361576495f22186dc9927267fbf39ea9a1939aaacc797700151035aa9742ecd0c2eeb1bd1bb3264b1811e821074a938673c17b5b8869dc63b83cd31eec596eda881398485ec2622ad3680f4eaa24bbc31f3f5723c923874b93a1d74961b86b60e389dab254401af72d37ea1d0acb5e7e8745d8e68b6067361bfe97a18768edbd2a370e4bd55f61ead53c659c9a96537a713947871baf8ae6de72660ddea2a069c50976b0894f7e66ebe26e8bdf277d72d20fed783439177532aa0a95ed5224b93cc65f92f360b74e4ecb212024335c640ce07a384113eb0ee936beca749d9c5003cb8d7edd6f8eb783b189d6d86d8bc685a1b2675634fdd3d557c9cfb0ebcc34735d516a762e5292df77bec247f463869fb78f8e1bb878da038376d0a5dca1e5113ea8223d736c4ea742e425e9d6d28a80aa4a5611c019355c63aaa0bc9acc539548734b62450c98ca8d1a1157fee29f827aa93b04b6146bc86134b9d80946c553b2414b0565a20d08fdd8eca4b0439b6080d66ae43ee3b78eb62ccbb37806967943400802896c850a7f4cc4d2dec7de5a128d35ecd23dfc1a6fbe2104ab94a92da22cf866ead05cb4aaf731fdcbedab8248f19c724b7c2bd96f6704c25518cb1674e8f9a1225283a93cf51a45a09619786da3c2f67552391bd42610b0aa471f6f9950a807f4165bce7da4f1ca5c23d988be618dbe54bace2430074acf810a37f6a6a6d31608c9461518e4f67ce29ef3a6a19d2b5e47bd91162a632652bda214e105df671cf5d735088e04191990cfdafaef44b656992a514aea48bd168df3a3e54283d801a234cb25d049c530478b9ee2ee13d3a268f1a04a5572c78b5136122b1f7f8c4cc34afd6bcc9310726ec568488f85f556e335eab4994801d15907e8678ff0395bd33f72b8354b6611b05f4202fff1d2e26ab435ed9589bb16653e4c6da8223a79ae5d55b32e2e0c9a445725b8d6bc33ee03ce965c8452ce65b292c5e49539c86d1b1ea03315f53b0b6dade0ccd4e1cf4cbf8019fab92c6812898a464ce1f1ad3539b3092823dd833844551b2f21ee07f8fa2368d86fdf98f982c6a4057d61199a74ff9868dbbfc3e6de56e77ebf554afb7005d416f85686ec523fbd0d5332eb238260084ec7a41bd22103c6f56a4fc2e93c5b017721560fb48fda3eaf76c3371f5ddd274d726aaec64b2aaf46723e52cfb6c60b8aa74f0654fba1c213ba847bf2a87dc38ec8edc6ad9a6e687473e7a26f5259580fb20901d373ac541f05467c586bcf1b17e0e8522330422f5e215bc4983c88ec94fa0b508df86b3ede327b25d6cc7c0585ff34ec9a68071ab4ea6e4d60b878d8d856dd6039ccbb4d92005c06979c20d5014ccdc4757d62b00c3f630417be3745b751bbfaabefa3fe59535f2001d40b06f74f839478f125f718709abe005cd75cf8fa3afcf98b0f67a5650a81fe7545d1ea1f68da180f067a3b1d241f07b08d44fb20c8ceae95708bdd15d1a4a1996e5c99071cb4d3d1b03f242838772a0eedf863541171991e7f762796e387a11c9c0adf90cdc9fe71b130ba4b7106e9739b15b18130f8fdbf142167c3dc2de96b749dc1f5b599c6af1aece20ce87ca0d7dc8e044012393a58f9eb0e84567c23bd04ed9ccb9d15459c01cc52f4b308485ea7d490fe84b99bda60adeacf6e7cc14399039853445a5b22e6d4aef1c380acd5b46d9addb319972e88c29e48b76eacd3021c3135dfa304669bc802f737239bbbf08a2388d98b277127a372c19bb0c4acd03134b0e620617a54d408efde8f196083975035497820e21fea283f64120faf32d8136ce9d9d0c297491bc40fe2181678f94a0288c3a18d70390137f16ae237b10383f56deb507d6ec9e4d53b3c89453bfd6659a99ee9eca4f5c4f07e50f94eb812cab0a2ea39715cf1c31218952213740b3731ae78a1416f46035a6d3c0413cd23891448d26cec1bb865df57813a267cc0c97b14d59252b540117e5d72b89ae24c7b81a2d62d328e63b45f249ccd4842cb8a8c0c3e96cb0b24fdf8bd64c25f574aff91e0e139c17f8aede304da37679947aa4c1a58fc008cb1811c796b7d76e1265d45f0609fd89bd796ce7c1050cd9eeb3600e15ad5cbdde5a3f9a4418669bf0aa8f6a618b2a678c82df18b627ad1d0f175ad4ac4ed18915c13c16e4f2946b1eb72be68f118282952f42b58cfa33fa09147d06974c58aeaebb4b560f4ef194ffbab5d4faa1d4ded6494482014e018db86e26dc47904cd51a003b3a1df93de1ea1a1e1a131a9bb31102e2cfdc8e5e1ea2f8798345203aed829b9cf72fc6799ea3fd752030042879cf0b0212b698bef83f5739bb1fa5e1d3d13a6c7ba8685d471fc8b5a42efa8f0323c861071d257b6af84070ba07771bf88148a599f8afa9cb25a770c916ae6eb897bdc1de075b09f14b8a2b47309e4cdeeefe8e4c43e17c9b1c0c0fc7eb4746d4139f0b22b57e6c9080e2be5b264b14ba9165889fb7dabf8bd0cd9a55063f5eb6e03adc83078d66882d120b6320fd567973d652706be7cff3e0e80023d780003390fa890ed9d3834d12ec17142d7d87f77003d8db7a8cdbcb2b88d08e823966e53354451b6e854c374571553fd3143dc73d6fb857b01c543c335a98f13c2b3ef18b38a7970b5ad2893a4e96cfed1bd2f89431e23fcdd39db173d61893383e48dc7e4ccfb753538ee661e7fad0a224f8cd8258313b3f48d4fbc24b4facdf996e56703aff8b9fd7292eb8298dae736be883ff075a6d0ae2dc0b6ed25cedd4a6a6055b9cfa9d385cb66b2686b4095a3e4a9e3332284c3561b965dde5e7a499ac33c5ca4426465b91644eb22a5d849023a60f3b612d0b5905d66db276f7a20bee706f7084656155d58897f15e8b6a77a5d67ebb609495b29a5c16596e346d99d168a39a3cfce87020ad54568bddafae06babf4dc496844db4951292a000f4b0c0683df64591948b0a93d0b978f482b2188f049d75494892e04a58ef594783789ccc02627c79275674c40a880e6cca63a9c34a273d11ecde6c7a54c85c9119df0d429629ea1141e4eee8a6735052e7b94b1bc85d52a76e64472d1cd497724e555407dd1d49991790d552df44960caca20aa80b998371bb947a620f5144d28d15eee1a0540e0dba916f19babbd861e2f538f9d1b4846238951903f6c82373fa3c36666a327f54b51538b4da7670944938a86b2e863e983acfc84326dedd8c3c4184859289cc456685ee744dd13ec3a62cffe419b1cee833a8d387751f168863e1d8e0290ef92265890afb623ce4c8d315fe696b7d511eff06f2141f5d3ae1dbb20697729e516358f0169fa63529d459cba203c24d2e1bb5c3ad18004bb363276615336926c3db6492a5f5689686d32403656882b8a222f2556c62d4ada135ab609a6519312ebacd8a4238926eac4c504450ea002c0d746039310505b0a309945beabcf4046617e1f66b2542d5cee1743577c8b1652dc902ef29f4126138ba44cff6b516fd6d51a3f0f178aa7ca136588a439fecb05d3b00b57d50cf766827b2c2d86772f003c58216a4e3424216870cf7a621687a26bd4a8258fa54f431c2d13082ccd4ebaacbfda8675945084624cc83cde50c9bb41f2e7378f61624333d0218481a8e1216fe90cfd62243e8a218b603098ae55bb8e7e9414b4b566ad040e63ed9c4ccaebb721b3882fb8ec3f828152a78171b1365648f046f6b342ab8ce2e21141db3c167fba2e44929467dbe1ef6c3871d4bf60b7b00b55ec07a70ade6c11ec7b5bac2d3ef094d1003c1f9107471bdd788040edf5da6b1afbf649ab3cf3801b25b58980d282e713740f41b94254880c74fa4d0051c7da8cba6947ca60dec7e3c774131975c0d7ad530c2ecd7eb37f1cfac13538c0f607052336b16fcdf95337b08f51a5af8d36eb0b12eb1204e23596b033f759fbf96059275bed560f5c2a95f399a0e1c9bff35a2b286addadba54924071cc63c3f0e54afbf564797c19f0eb5e90e1880e23df55cdcf9c10a5145b83f40f7a1d4eb0abb776c7aa11313bcac5ce535336c4cedfaac17c3d811111a38a3b4a94aa4ac828de5ff5b36a1c9a0ffa2097e6f06c92992f556c72d768df6f5b73535f4d13fd019be31b46fd91d919775cc0425966c1b2b9c930f956cf805bd623232b1f6c55aefca0df5b819f4a4e4a3b62c52d40500e5530398a06c8334f8602e62eed2ddd276d1929499e341146eb9c21e88e34f8a70efff1cfc2de2522c55acd697ed839082348cba85fa7772ffdec9155e0f418916f1d45ad262c430b32c8a809d41fc27f50e31e93e8845696e5cb4b441eb88fd1a82a4601109958a88759c63602c58b1c96d369027f6469e9447e151399b8799f710bf69065023ba07cb5b8aa62e4ca6ffe8341c6a9b6199c5e6773d824ae40979a71b7576c927d6ccf7fe2fca17c0a937e0ae54e0420d4e6e20d2e533c49cb86faed80be18cd1de5e9a90bf15f2ec7bc6934b8ab4d74c9ad3c2b9862b09ca160bf4fffab1b1f0012d9ca10ac3b38003aa047f5855eca28370e76c8846478dfb5ce6e576c0b6b7eb41a2862637320c82db51b0066d75b4d6bb173b748dfd5527f3014bc2b5c3a75a1fa1fbfb3cc7a290e6481f8d5ab48f0b7779e947a2fc42c383c16de22dd2bf813480f41fd9a14b61a0c00d2cb33bb9a2dd7da7d5c6c3e4529b98ce5d03832b76aa9796948e417caa4813450629407c8e98bc9f5a9b28fe70cc9961f219a7cd652d2b4a98962ce7c6efbc0198dcf013c3c87f63547226f1c450d12ad841383865e7134a0c5b68fa2636b1a6fbdb1ce9503e7a1011164ff06a2ac9c07a6a76aa67b23fecf8ae5f03b8089492a3734eb6b8a809fe177560b72aa14691e8c36ea56d15d42c24713c11b0856439e7956b7c04fa6c13329d3d1fc58d91a27b5d3da78c2b976eb57df8a5d1868564404d65908020c8343559c8e5d968547fd52be9712a2ab6af35f3ad9638da0162033dfac190e13e5948b6d9315cb7ae65942c64653b10da2d4aa379b839d0f947a787859c033aa8963f020b0b9989ce38eb2c29223d13e1225bf789b3625083705640dda62e768ae3c4d5692d2c92a7eb0af6e1c40b1ea169e3451a3b462e385d48a63cbeb7f4869ba69c0197ddbfdda11561d7b75b9c072883941c1efdaf19ad334a2d1392146629fa5c8040d1ee818a48120faf0309f6906543af462aa44f8a245aa628a1a115531f379e7ee7ab0119f54a00f39351798b9fa0dde8c39942358ef13f6e8d59e89642a664e4ea17e158e418d8e3f00e5a7e2c395783d5dc4398cdb3e13a20491c3e7515938d0e61dbbf3a985633fb2e66b6ce5f3768fa8a10c0509250046eb1d385bcd9698adc30a8dbec908daa692a6341040acc43c8778f3a0cb7208fa968d5b3a7a28a260c0356499423aa6754574bb1103f12d117f5fe0c3aeb5d026e378639186c20671bacca5d394d9a6a7aff9d4267b03d549ca337dbc0349259eeb968d36c171f5b12229e5cad7b80801d7b528a9ea8e6c52a9e80c5bea2b57225861779f68f8ad200821eab11ebed7f408a6c73f7caeacdf0cbdbf79c2766e203baf1c3b60ad8c09048c0a415eaf8f79716a08577e8fcee702a03e043576c251135bc336417b9bd08a41ba7f21b6fe91f71ba6aec9e3332548094dea3d9bd373437414013e50d34948d505ae0648ee3039196cd1fd3d201cc406e454edd60a1e2fad707cadf9f13e22efabc2d4ecf3a8796f38b0036a699283b90623cb3a9cf1594c8f57044516b1cd384976e3ba6b89a80fd26abc5b76308854c4fb0489c0de6091a19c673ad4be050b2ba307c39ff43dc67a23a6533807544b74bd285916ab89d49501157e66efd786ceac99a20a75669707c1d801d448a99bafd847a4ef0e982aa50d7e64ec1c3651427538788e14444df65cce3a85045eee63d1ae97d82629e0cd638901995a2d248a17d445afb2945139be6b70b7d7e292c897c40b63748a469d85416d9d4f1891506953d95d63278a0c1adadf550dc83aaafc803f40eaf821199c8904e4e942940ffebc5ff8d9ed8834a68cf9359ffeb79dbe592bb546069ba7fb67da5d5847025aa054f631bbe9b665a7c0a1f383557ff796c08a06350701f617c460a1e825f661fdf49f1e73bfd663f1ec762cd33729f8fcafa1d7062c830804af99ac7c21aea602cb73ccf435c3bfb168e6a1dba8b36cea39e5c7b6da0c5a3e69d46d796e284925f0e340867232c6e73ce1efae9a0a1d87b0a05895a119075a6b28bc03228ead98da2c85c5da39f998aec1af22b5866e44705f4b63cb46a2215fbbce23ffa6e76a457c61e1f100bf44a04960aa2e8e53b55bc58d2546de5c9a4ff941ae633ebb0da558263b860f2bb2d771393ae39a43554a1459f162d70336a809bb40568d4a12eb0a8d032cd1a3bd534df823fa686c81fbd88e3ef2d5e63fa6615898a3aa7aafe149298cde2403f08069fd413f06b0729843ddfa63e4ec432c25c4c8f444bb7177c511b89ddd3b602b73e873f72ba219281c4d49f6899326f92d09bed58dff0bd58a6580663d3fcf0bb796e90110e94222d19330fb947484771d2284598bf717ca9287b30c13cc707b774e26e545926139cd953d295e6c4fcb8902d702531b0db52057f8cf0a9a2fa825db801be5724d67767b827c6fb2ebd3f68117c0f657be5970cfe16916ea8800363a6dfeaa3865f4e27df18d2865f3e8f1e83699c32c3aa29d8d68a09b1b04cb2efa6cb4149254d9ebc369aabdd6a9afc89d22ca4551562a3d9fb3280e4218ab4e3975bada54fc90fe190d0f858cca636353afe0efe201716a949a23e2aac976ff0f2217191b44b4d4b6fbc606cfa84f6ad44d966cb34d1ed08668217b0d13d48a8a52760b36e082effa00b87187eadd3470c551c301dd894412661389ebd2720c3da51f9f8385a349cb8a66ccfb9e1c856ca780fa057bbc7d91aa153017b4549b96ded4902861cd8f5534ff1c282f8636471fea35b1d5569701b4fa2f8bbac1197629ea5064cb71c3edca865633106d25a4f6a39edc56239b1552633b107572ef3942a9b6d1e6d4a26d20ac165cf1ccd2dbb951adb3d8c01eff292ebb05484329ab46526b61310ee56caca5b9bf322af462fc03bc3aedb4a1591f4071ba35b1bc2fc8584db16b46fa178fe17d6e03452c4a3297b6bdae0cc50489fda011b3ca9695815132a5d396b5a30cc9fcd847a798ce79c0f72c0a6b47d1b58baab2f3a5279ba5e660b64ea81fde826f891141a2259a4b4ea7c4489dfd2b028ba85fe4d1417840db3142dc55cbdd8c1fb219d6a9af14983811c28081a40b22c26515ebd61dc9f0dcab3a48a502330ac2b6ca419300ad1e34527ed72a3ce1f5354c9cc9e03fc4da8aa1178a2f5e18311f80e85b06ce92b320d3725be8c20e7af15ba382573e9322fd9a6b66525f96f7303b440c90a00f5be437a224917c4fc573e1a28ab0008a5237d1010308ce517e7ad0325dbe732025a028ffdc9a5ab32cde6579ab3b09d0eb384c0209cb5689a3d0bd9631dd709b96ebeee8e621b978ac8520d60f582643147631d2df67af17be0ed33181a81c49e5144bf834c60ec5dac858c799d1a1ad2aa3ae3dff8e75a8a0afdc5e832210edce2eb16b406c36d4f9b7a2aa89c2b0690f59aba89c6f40e94b1e5170138ad41d60f18ff4204c765cae86fb779145a699e2a600d303e1141d28abc2e949887c4ad5547c72c255e1cc8bb2553e7556bff53a880594b411c06b0735ef02f9b56e46937ccc3315d04d83bd0e18775eaa0bdca1bad3858a4f69e56af54b5f801b6bacfba83e143b82f0b6b0840cd855021046703239cb552b6708e466c032a104c065007b23277e69180901f0c462792aa3965d9147875030186a8c31508349b7244dd8d284bcf801c0afc16a1ef43ebe5c9baaffc010a5f4e0e9571edd8100aaabfa1241d3df6d21a8caf1fcedd4d6972a116af09e2c27dd30f088028665971e8d65bc7a59046cf7885bdb0d93b964ff1419f02d5a9b31d9ef66556fbe7acfe5430aff38613d82fbf037c03daff3eb95dadd58cfb589387a2ba005e2f35f3de5903edb64343297a41899a43c9a817258c25093645beb963b25000f712dadd8df9b261d2e2cf0854a2d16e5c04d4460093ef8e400fa86b3239cdf3fef888d1df278c4077882e902f798932a224ec48577ac21e196eb6726172c442c032c98d55e2df9708fe2a15bbb1de30ce968cfbc851abfcb0a5ca44e45254d59e8047d19f4f2d4357be0cdd4dc96b7b5eb6add2ccdc2f1503a79da104ed52afaed01376abd3d9a87140bfe654db95b700f5ad95015b7714a0e81ed921986b1d6fcb1dcdb847440c1de1a4964238144cc5caa3e4304fa3cede5fe69d72e0fd8d7269932b800f6d1151eb6db0f9e1d52e62e8d308622f40fd1823a04d546c11a606e06c18c5e53f0cb2c2548f8fa1c51bc65e5ce55ce5b123ef9f1d5863592092ce431367548418a47ccc968f99a7917f4a0916e5e69ea8654852994d8dfa1eb083d313b0a9f9ebf754f007946e74d9373924520d80378505aec9e61138303e9d54cc22559359f848b005f5ed7efbc05ab311a3f4222bbfb82582d1c8ace8345bf5627c3e5925fc72aec2b8786cb4faac27d08ca59aab07e4ec1831d448de15eae3401c14d0567a686c1d536b1b9b9b47498c5ee8ecfc16a42ee333b13f916d042a5ba99a488ca58c19d047bfd5539722b728ceb4953a019a846e19e58c70275c01d9e872739d09d158f7957e24158f43e3bfcddf1afe5077eade4fd8d64cc983124cd6f3e5919bfbe8cafe7342550084c6146bc6bba01c76915481b75e09441b51044a261a2654057952f3072770ae56f6a3c6f8c375fb537d011ea2ff87df239671fc00b5b58050c601d5ecf67a2f59c9ab7a8104680cec9f01439da259f91ece214a257a5cebaadc055212f2bc56d59235056cceca1a85d60e046d9419aa81105ea4ad7a3681470c279e062fbeed23f53f058e47f074a97a95fd43e09f53b3c6110edf02eb1b16c7d50ea69d5e52f70b1e7229262fcc8a7b89d31a2d6a1fca078ba0c18facd5bd9ee9ad7278c4ce341150dc36e50fb8801053ca017cf8cf4af4532c58adb8c88a2c38ce1dafb8b1ce815062062ea69d61e2329cdd86b4c1b08b5c68d724611928196e4abeb185b08bfb004dc18a3d943221cefa2da7bdf0b3a1a94aa53f0b9692782c1240faae634c28a955bad474da8b3f9bec748e421e13bac5842945ff608e7694a36f35c217d799abfe21bc89acf01f069f0d6edd4bd30afc6b96074758987b269120a6897f5c342029eec351036c3dfbff2d0e2bfef877fd0b2e8ef5d5ae2bd6436340b26517c7ef52af6936417360d7f247bcf7dd4be7369fa61ff82cd0a0a7d1d55f7035274d39aac6175774865a282ca8c8ad8de8e2be231503529d878aae3cb48de340a78004ed6221996f2b4628641d03b72611c01e08c558928f97a1d7543db9026e6b9d8a24ceea30fd5b1a068c467929fb3c621a0b816c0b843f1341b09c97dc5dc3e9e40bbc6603dd6baf4434b8a321422178194139f3ea44ae7d589315a49a28d6423cc3fa2d647707e7a3d982c5f5255dce7cc533d8807bc5d3af668906c9e955fc33d7ef75aba818715d02175cb85990a4ea9782896c288b172bf760364e80fd4ddf32dcec5686851d604f3478f656f21c11938d21b188326125b013fe3586afd924333bfe4a32c94456f4d5649e51bc8857e99a2874fa54e7594712993deba013b97b1050063b582fc1c146f7253888976570225590a91f890e89f65959f4ce0303d243110ff133919cfbbd7c6846c8d5b48d94a3226a5919aa9c29c0f5cdf0aca61a41040806b63aae49d0ec08f51c99a2286a3c73687d7f2b544a7d000c706f4095ce1bbd197c4096b67e075bd86befb2c5a4c5bd320fb29782715ce9f2985faaa64223352e2283a0b332fd965ce017f39b00b2be294b86ccd65387a5bdab43ef3e87558d4eea3fd4614ebab9c55947c959266c3a96a3be2b7a2780fe3662ddda744e93b39123b4553727091e9d622357a1e51c9c8cf6d7e270332146af488b4c57223ce77d67f52a92f5ae885d6837f1ea91f17c310a8e0f0046ca3183de006324a7fc434695abeaab3f04c756ffbbf9f6221540340ec22d9b238459c4f81ead514744e00bb9011ef8040f1a1157a27370d1c94fb3bb1164ebd000e73a11337855f3ef6c28acc88023edb9e5f3309e183dc24cb901029096d844cb2b8f032ac31c20a578c0ff07e25f60f99f309b8138305067326c348c621b46a0d4d0a28dbb45b98af9d46a5e042e6a32204e4770f88c082dd3e17a6216d5a2e1242e7ccb1810761bc3bc06cdb9065a60e1000c966d343ea13f5a1c19a423de9cef2c651561108c77b1fa028add8e8c5a6f653f88a2d144eb1c8c4dfc9a770c5aaa99d2199ce248f4e6051210152408fb6132bec5de09c601735723624667a48b63003c91a8d12eddfe6a3f3f10e885d806ded44efa503e5d32bf20c8181140202d3a4d09da89c00dc2169f7e6769d4af42ec57e48c85ca0dd77bfebc29838ed6d2d0ada9bd5e0247d0569018824a842eb5c197784a10cf3fa80b0de204075f41492bcc1485c061fd221ab2dc461ca6b5afee25eeb60b79f13c911ba5c2a7f47c444fe2526659031c9fa6dd9d1c90570f1fa2005efb5297031587f39bccecc836a929e73fc8059932e25caaabcdd259863b1ab40c851677c1b4f9169ffa63f8eae4b7d9f96ca77baadbc4f5f759aa12829e6304bec30f0038ad3354ef8d6e8fa9d95d5119943e5ae6c48f00bcb21a47be4b6a2a3c1898e6854d33ee99dfb69026f47c1813e10434d3933e898f7488f192822d2a45420218dd2745d5630ae79142f122f45883ccaf304b881090478a2c97c81f0657bc4a3d7552a9b8b788aadb5a40a1ab569ecd692b8996141ec2d86144eed9385c0b071cab1afd1479df207d1439b1d0b5f9f041d766b37350358297831f19502344669f2a88a45e2683d2b632f54eabcd512783ad37d945499d9eb638efeecf28a2f41043af42c5d26cbda0aea89777e83f2b4e0554e5d540270208cf18b0b32bfcd9b254423c09884c1f8c7f2ee3340a801b1b3806619c49bbf6115beac751450ac88aa41922be8d150bb11187c14683631fa17cd68cce100b0e11fc1c65670c4255a8a01055822d5751e6f9159f44b35ea30deb8c048a6e7c19153500148241cb4b84c8c0e4085502a582cfbf16ee6e0bad112517a8c99af4e90e44dd2d0e047b26295e47c3b634e48b06cea3e0c10bec0b34b60b104dced9052dbd1477bdf5f04bdb6f61e7a9dbf67d7ba81e8b2c19e6bb329d01c63f209e309b0961997e1d5b48d9631054d5a5595f3c93958384f1bb7755188d5e337ab224e49decbbde9a9b6152df0fea0572f8d855d386c89903886521e1291c91096fe11a1d8663ffaef481b968d69d506c5debbf61ec1c6c53f1a7b1d78e2a4ade125569f6f4a2c0fda652a18ee5adae2874a7a8590eb73c096975b92b8eb6674e266831c1082e05f103d1f225f340924881c116004ddcc5717023189c24e577c18e064e3181e43472812feb300902d02485aea1b1f8548a15ac0a12745d4003133ae828e039791f78e6b2a4dc59636ed44e7162e9e5f00e3218e0f87ecfd8050d1434c2cc653591501082a23fed2839d47954040058741acca1e6dbac225fb4075341f39a430f73ed1383f435cc01a5b25d0f083966824bf53a8f556af638daf7041d7a3933f6b1a4f96c5d289d62c4d6a84090c5a21dab9c1e4fa1e0f86eac485135a9b4a5c6e1812ee514120a246193eb2410198d41b3ce27f09e856244edb5eaae21c32b952d06cb6e8b206b84732d0ca276922838eb01c9b9f0ffa6808aef0e4248d8ab11dc900d06d347e339555db583d54f79c12d05b98e05197220d3ba06ed6436f1726dd67f5a496aec0e133f6671672a941086005e4b89d6a0404811ab15d57f9497066bb547ed71223c736bb70084b15bd6de74df85a16053f72cd0a30cf4754bca5bc5f2345c4acf8ca61a048c442a2f8219a1ae089a148a255893621ab42990fc7408540969b549fb1ac1fbef5b63a7cc2251d54bc1986adb20bb9f22ca0d9b471a56cd6f79eeea0d13f7b0a01b61a5a9dce96a86aa15bb351868651f0934256586d99c2f1afbd8275b048e586caa3e85326e041caad010d2d4a8288ccfdf11402abf00aaf0a0898616d2eeec8e4facdb531e15106a12d92de0d5d89e44a0e7f15866ecbad11cb57719e569af4ea9e1b8e8b86e4f187c88456e24fee568f9b33f0c499246da3a9c456ab0c92a0b4c3369c8400e96004eb3d3324a4a6aff27aa04c773a75af49180a04247283ae5c75295b9dfe28a22f12b1a9acc9e4636f6c0f2d3ed9c65557a5fa596bb9d0606960d6afc15aadaac05a99a52eb87d2bdf95749f8cd4e082ef72b36f78fa6c8595addb2c8b82bc7d5dfa20c3aa8b54523fa93b9c815890c248e16f2e5393a9816320ccea43f4001a696995a54036dce432bec56d891e10a9f05c6515c31f5b7093ae967eb8d014489e469847aef9cdf4af58cb5ba9f9fef8f9909c249f8f1a3482bd305b13b6343abc875c501ea59c02b57b151a532e6cbba340f042bba8cc2bee57a195bc9170a07d1ff741d3f04ccb292f5f3580dab5db5013d50a6b4d1d459d605174416e8c75c2fa342992c35947cb34c29191dff5a26889167ca9ea32b178e113b7abcc7b4ae4a02c8aed6836430e1295260462891fd72d8eedfd34020acc8b01b3eb866a15417805a4b35a3b8e1a7a9a31e06b8dc9970877db49d9c3a67ac7476dd54ebcb33dea3848611614cd236404985cfe9acaa792196f504ecf45dfa94a983fdace5720c37292d1bbd33df9f6e03c3944b0c9e13c569799d31e30afa3e9cd5c286a6c6a7255c261599a83b8f8a01d26b921616ee18dbccfb66d7c353e56650d1666feb7c018e022a484c1123a6f248650f29dba42de726b0acfe426c495741e220750e94932cf3a409d15d97b1057403411a72241f6dc46cd2a4dd2c5501e0d23229f71d020bc28a083c987c79b8522a4300fc3aa2be4b4fe25691914cf2141e53b48ced98734643c847f31d9bea4ecdd51d24ddc662028a23ca4e63f35d668380c08160bcc2ee047f0c35a321066e4c034fe0dfda8e19f8797ed2648943c2bb1d1ec0d77b3165365b67e91f0cd717cd2c7a10095d11001baf07a2ef08e36cb3e6230468f0ba851b094947c90813f3a881134ed3184e8309bfb8607608bbd045cf48e53d26126a120719f171fcb116448a39a941870943d46954360a876b6a8592b2043e8404fc0ffaa4562acfb22a221f90b8de3626182cdd46c04af84da11fc243d1c4fc78c5d85c6339f39640397738372f80a684250f2bd6e4a321e93698234c3726402448211029802a14c0b9fdef6f1ef13f328aec8fee89e6cb229a8116245e01a5a8ec7c9582be5036537d3f8df8425e3294db6fdb9ff88ed63830149bda66ef30896357a742b33b3c73e2e053812cc24fbda827bac8b372c5ef1113c4da6cc97c366bc074cf6b8506ef412672e966a731abd17df1786a1ee7614fc2d48ee12c5ac6e2b4adff5b6e0f64a7a39d004d68369747a30d62b8a22f4ade85c4ea90441c3a51244c2dad1e7fd2454f3040187b9df1db7fd4612853c4a863bc4a1c211e04796f8e375a03050b7d61a83ac21894cd72b79e8c23dd554a2a2dfb213efb73a350b6413d52b078d1aa4f0ffbd241553e8c7613183c76c2dee2e1c9ccddf0a8da008422133c0f7818f0430f4e200e7de02c8f1bcc5938d5261311877fbf341b485924a4808073c30f631c1176182aa2f6cf374afdfcc80da9304a0c8877b0496f34b3ffa889ad6f6745f631e2911640c61f54f5e5edbd83c0d1646fb825035b390c4755f2536a04c8894b26e5d5ab01d31674862e86f4dc88f26010a6e7d3a9ca9180859e63717b74eec189eb2baa794c50e109ec2c019b65d12db93ecef01dc62bdb31e9147a1789019e521c10ae1eb1a60812ca1775ffbf1aa5358e460b806df29e8238aea750e0a755f1bfd4e047479f84ef20218fb321d2190472ba9b6d90ff250e0abef7ed7f0977b0fc815e1d7d23555c6af2036be25b84bb4719bf8671dc40c5f92df08f143ce56defc623363b6fe7f2f0c654431ab9037575f16bb0272d1f3f41d3254fa06f256607ba212c8989e4778679100299a207b59238727032c47cb544d735849e3a8318cef5d4ef6c6a7da24d55cf7ca9e0c3752b6beaf9b35a4407bcded1566a1ea30317959c68882a3ae53c9cb908f2f106506c06504d02304d1857cec9bdb64c62cc22f7f399619a49bd03adaab7b60aadaaa85445bcf9c2d796ce5f4fb3c4940be30b0709a007077b31df0d559f1b1f1afefdf2f1fbe49465ef6c8e1211688ac35a053bb0405e88aec637e0072987e3a6e52b857fc1518c1228b773232bfc60cf0680ea6e5dc61fd9bfa0b322fae8a643907f4d48fa735508ead99647693fbdbc8174aa3f38686f15fb1e30825ccb8ee81bd6233240854ad69a768db70efcec9a831b35ffb65d3fd5b3e18fecaffb6f88f887ed66bbf1c1b693940cfb231352f8c351452cec11ca09ca72201a9c9b2bda9d2cc9c80d0dc9664fcc61cd2d60cdd68f7cf60e1bb143d1f74493be810d5e56a11c6761221894f9612abe08b85da0179cfbb4fe2e34e3bcd05467a33c901093e824b1671234d8dff93cdddc40b661f894ab8ac5c2b652bc76fc3646766ad9d04b04e9b8fa0cc8eb0dbc910ecd7518bff0b18b20b9879a7baf9e0169bfd22a6b61d49de7df810af9010c0aceebc144e602419d94f603919298182f6c615a0290e8c32d11820c7a004407b8a4b864c93d013f62841b9bb31ab1b05c157d7115b50a50360168330e786a8c1a5f86b5b602d40eeb8cc038f58feade76090034c24858c038c6f8091790440be92452125b39b586a3ef29fa3e44f22e09fbb2005b3d76eb1953a6903dcd1733748c3c01c291334ff6820b4dcf5b3f25fc80e1eeb7679800ef0455332a107cbbc97c8135799593915a92243e1470ffa6fd26680198549c82b63c621c50ea01243682f720b4116f883dc9f177763ddb99efa3dce8483b9e9a9ea15b033abf10a1ed4d48ee27735949c08a42ab6885231c3ff4bc5206b816fa88311f0e64fdc94d3727bfd03a5f918883f7282f7d67112107909cf14948606179c3ea9a6eead53f1a6f72126d9fba7a0d28bf66075bcf75709afdf1e0b5e9b8b51490c810b9dbbcf80939c4e360c57f29d0a55303a10b9c29ae06bafd1c3cbecf41fe57a8c8b6ee0904047099e2f6de7aafe094bf0cdc0d932f252b9e51c58af17f179e50bb1bccd7fc827d1c783c028d2caa9bd1b0f9f6c66cea7733892834fa6ea06e7e129800ab099bed6642a356275ef087c0a71db65c99186ff081bf1bd8be91625cc461b2900036f98baf312286c07c6332f160fcc6a95d093e1366873952435b1b7c761caf1f0e0db68e1875d4d5e9ae3c03f5aa43acfdb8c3da63f3f095cef4f915b98a3bd071e015dcf1bb2c5d6b20f58de1c0edc6d3c7fc65ec618189c1f4c176302af6af6e7bca7e6e2fa52403c149a6fe057982949b666ff26637d1aa102e824bb8538e413f25a6c1abc306073162bc56f8363f1bbe5d4a40d821e28f25e2af00e0abaf073a01683464024efe7391b27b2cc89645e0655fea2d68a2338ee8e39bf4dff5e69b5a771a5c921f4a08bb35dfd3bb85682994f010a51cd322241daa5dc667e9514fbfe12ba656ddad15a5d99458e76bdf28dd1f25ca11005a8c42344445ac8325f3b2adbfc5e469db68f4edde2a7480fb0419c13c06ebadba7eb2b66ef32bee8276b1841b1af338bda7b89591fab44f2a9a28fc69b7cef03cb1870d1570864e0e5a2d20342252a6c34296075ca0e421cb41b8a4bddbc74a020e80954d57d090abffac9ec79188d440bdacbcd082886da96a2e64c6e5dc933fa7a5ea6ee497c93b1812c912ec24948f9c9b3b74b1a23250354397ac1018d710f3571a64214464ea019135ad1b4887f5fa5813c2fc010fabd90d64651a1f74b22b91940b7100f0c3313e1feb073af529127399a6c5d68924f4c993acdfbc9918d0d62b54c9586e2d0055f3592600a66dae0f4ce9dc1f0daeb2d608642bb21f5b682ca2c0c7b7a193ef0c4fc5d70bb550caee3954e1549cbc6c45f3821c58887315801fc29a19e7f3b574644f4c0a7aab1ff8ff0d96e3bd9b5515e603ff5ac615818398bdee20307b2fd3f2b8f5f55ae8d5459c9185ddd6629e989ae2629ccef3ab03fd9559174043b45c8fe300a7c3749edfa036476c5c77e617120892bc662601ab41835b1fbc6a6300982dc18e5b31baa4805908f3c31df8160e55f29de82baaab9b4b41e0906604a7a723d61c900388f2fb1e83812372a35ff97aab5a1d3442437988a6b87df818b57ed55538c0eafc1f7580a3da43c09acc35eafc0cdbb0d1ba9e7db8780654b9ceb2c46fed8831cd60e8e9a43e149801c9eadbf3fbf419c02fa9094ebe9951f7b11733c6c0265ec181be5d329ae2961c59b6289c8da2a34d54d57df690417f1d15ded0b30f82d5d31426db51fc2402305772f89ae77528c16623e82a19fdfdbda8fed8e07e428962fc36c54d32d40f0c36b4e6cca8b243b10967915dbdfcd68d913463ac7ff1090985c34057089c1e7cbcf4238c938d805383cae3fcf3b31a1f92a5ae8d6e9d1e0af017deddd1e002d375fa7cb1ed50fb62849d6ef82c9197ec22314536e9c9a40a170e3226590a910e6e55660d16f6a745c2e92a294bac76ae7d3fa80c8426db416e804bb8d995647e83a805b672aa7d46d528f6f333241e386226bdb0f3b46a2be4e531a82c451478871b6a75c07e4d5f1b14a4668f33dba2a7a080696f37b07d9eff974da104164290f57c3c296d191cd7e7364dc061b3a0e3ef8f315b0a65dfed3a0f73f7f15df8850bef809f8679b7c83413ddb3b7c78ff13b52a5e60152146df8d00201ac43b3e43d09281d5e41c2b5041b39c63c11a887961a62cdba6aacb1a4b4aa35cf648e3e9ef717f24336567e134c99184792f282068169151357e782f6c73d8d1689054d3158f1a49cefdf9f3a072bde45885032d05e523a9aa783eae47b801eb890c48d66cbe56a181daba06bfe541525025effc8bb6ab478152cb5828940e269e07e056b58f22e3e277d7f4387a008db60c7e2edaf7617456ec018cf6d477df2dd708e8a354aa7cedc538ceeec62929a8a5fe5bda4f88697fe95385caeeccae84f700b37f0d0bf3cc2a848557f0f0ef17f88b11298bc3cb9020f6a7d16cdb7fb1328749c277c655e39db4ec2a72ed03ab455431dfe2440aab345ee910a79f6204bbc60523d53ca3619ed9ac6c4153fff4dfe966d0b531edf551288004c748841d524fcbcd634adb5c76ff5bd767ada6a1b3e39d94ead7ef5b32258aa30d5b01ce1da9adc66595bfad89255ee3899b47d35a37eb0679552a6835ebe663a4793b8210472fd95f48dba9e478ab8be44e3060e60f0909a722ef71347b1c965a4be776ff0ac236b5b00341f951ff14bf992170bc260c0e237a5a28ccec27ebf8963aab0b82d4e016f4a7270e29a78955bfd1d6049b36c366fec0248b29df5b6f5b39f70241a4890f872b2908756ab25b2bdfa11c0bc3f07ec592670c604c099fb1fbd8d3490a8db1e767cc9f58beac1c16c96ab39e3106cb9a0f5808c00fbaa69bad8e45559bb097445113c3f9dd9c16556a6bb35dede524cd8096228e654a29d7af18e536ceeb2f08cae05248c1d088bf62d401adb5864434e9d86189991a93f5ad173c212443659eae2c72b1e016810fa6f34165e53be1f976cbb29fd64243e0fb184a2db57d28763bbfe911b212724b299200bb70e64c4a0f5ab1d7848c21b86828107f679de1fb95d161ac70930d9a8f14b949d284d2fc1771947da06e710dfc8e738e73344ece44e5508648d5ca9e3d05d176776eb376844ccc2d50877faa9bb9e5913a71e60f5059550be5395dfee67442c86ff6fcd04a6e557a06ba44bbef7cfbe07d6c4fe7eea3218b5a27f2ccfeed42a7e1b0ce4a5bf405e96801f2fba0dbc0cb7b7be323639e04f86f46000e067a05482535c245ef0b8766e1a8162e0534810ce8e6bfb01b2ce85ee009b102b845cadffedcb821f7cd1519f20f34430d84880e01ff63360d0a66b9d7e666282d40941737165ab6d8223fe87de3d8a3ab577197300be8dd1a355a4f0f1d4f1b13b1c197b624e9db04f5f67a9bf425c26d1f259fc2332b967c5947e1808ea68456b3e05f5ed47bf3b71ba1adf73ad1ed0d1357efa188e73b42629b32807004d982ec136101b069621a043d6afa6386ab3c6d89c5497f8230e07426f5fa35cc42eb4b47cc0ca9b068a20cbd196024db3341ba254c461a56663fd949e80bf10c630e774b1bd853f21b64d8286f033e28e0b44c71080543dfef736f04243ad1b21b78f17142490466f795e3d38e961cf0b5d8ffa2774fb62e74f49bfb95f78c712e6f777d553dd305923a10504b0609b969c9da310183624ca8dfd18e85aa410490e1143f7b393dc5dae87eb0be2f7a194df3f2fa8663f2d371f7472b5184e9c0fa1b0deb404e05eb8155aea54171292a7cac67a9139a189c506a6db08b5ca69c65b09a0795e34cc93585b92bf9c37f3714e520fd769d891cb046a80aeab6a5a070eb6b55b45449ee523dd2a20b459982993973497e4a4ece3afa6476277d8dacfaa5311485f2086f7b101c6205162f8e0d4560e4188681272f1215cc25336af90dce3c33dc3158e60c76be83115ac101c468c9ddaed68bfc895abccaf623a3aba4d470a5d64ca3f8375eb5435cb500e9fbd4eab50a1d877c2d79386aa3d6017ce366cbe0cb9bc12e1f6d2a1842c97e9fda54995f70333c78b321511e4ea45675de7281807e83858cc4b9afbe35d128baf0e70b85c38b96292c4574824750a5fcafd83872b158de72df853e07f325e3f1f092a3b0082e1f30834401f69ced942226becdc73d36335188b9c55e64946d9cbc832889dfbf7d937df0f1152522981d8aa5890831400c14010118fa9ace7ea9da66fa0ab909452590b04a48914f27c2165ca1db1544bd401b3bd20d970a3ee1a70f08b48ab0836931d203f2bc8e3c7e1fdb034a4628844d611f67ea41af237c3259d65041d90df4211fd2679ea71868fa2b313d76c7d371ab245c44f2fb22bdec9d581d636107325b356a22bb645324e2c099f32f922b3227ee424e4e2e647413c4891c85a69c6464d3829a7fc0e95a7e851356ba89cf40b9824e009ced91851cb21b66f1cd5e327fc2d19cc5b2762c0ef28339e4e2e809a0ae062243fe8cb96dd0b15a584c611eeec26f30d5465eea06a614b54784950d870903a93edd550afaa1086fec5677af6b10adfa344fb1f6fcec6c3fa2625702a844ef9d4ab4c9dd2e5f06ffbbbfde4df5fc3880c7e28570ceda2477a232fe5182e08d491ac7a885061e76332e89b60b2d62bbb14aea467cebe357ab477fa4ea3a6a2d1fb814f8ffa672fb5daf8628e1d2e177cb826573adcab2710d9a9c0141eb98f9689edce019b3936dcb4934676c738705cbb211534e16b36e6df12455a1a889cd8f521db401d3367d35aba959591b80e226c72619da17c4ed66d7c33968e404fb9913310f29b72d4103ee83c666a310794ab3aa2a6692473f90d2e9426a7425c7dd72ad6ca32f8fa375eb370d18c2b33dbd5ea15fcf6df409a6fb118f49a0f224723407185c30f2a5272db3f68b30fde820963603b4fb245a2ecbcf5312002a50d04e431bb6d4615d428e3bd83904c4718d5aa31ab17ab03180ec01e8e81240ccda9454f504fd08b82daa9920388af11a47cca4eb0c9862309042a76cc6f4cb998acb1622293acdc749098e8f65953e26166683c0d24f751ea836f6a065539160a3c3e622f8e33e05d6677017df8b4d16f8513660081436e90c701b7a0f56e4b5c49d66fb93d19f55aef5ab5678d4a0508531f69c5ed59632eb116beaddc93b40876ca8eb3ffa5c6bd3e4639097e149adbdea668e8f872832662ffbb2683688767594ff5afdd41e594a8508ea4a3780bb292c039761bdd646204891102bf47a9a7aac66d58a9a7fa19bbd681ecfcb5b3c07a2f9a4f221ba1b1aa063faf4b1ed252158ca0be3aaca992f04b5faef26d2c9c0d086ff3a44e49337f9fc8e2b9325f385fcfd79590086e826d9c52bf9585e79237e7f08ade213f3869c4590b8944fd6f6cbc906f1d6ecbb12d4c67c581621560c8c77b71ef8c80fff9a74a136515b4035a2344131be6936c06998eef2270ab08d99135b877eece7d7bef25528a6794a5b78deb7904b7c0b9a8b49788d4f306e08cb0c1e7873d49a88c0839b835f0b2e0ef5bef4f469961a11fafbcf1c28b9469f18ccde0d0e92a7b475424026282b134259c0481ad1d9cd2416e336f5a8de6bbfc4f5df7325458f2024f1df61e6c77151ee4a7d512ab8ae2c2fcb3c1d96da5656b583d0363eaed3a40c87fdbb1321f0fb23c8542cdf91a3b9f596e89081c57b2f4182321f62b7585f7042b5929a6d34f8194727fe6b5dce4499a801ad49c7c10f214bc2b5505990a74faf1b7c2826a60b5c58898c28ebbfceae42b56a0cecb1cce2b318ca79be87c645175d5766184e1ad96dd5fc83300774817cd494b8fb0f6e2f05fe16ca0e21f36435d12f1f6f3e8dc4e704066b9c1661d266a293cf1e83e13c184cd84e46c618e5e6e07fdef8bd21946b100272d2f3f73e571627537e926a2c169dd949170c9095b0f64c8d2027313247bcac4d3d35b2947877e51192c1dd9466fc379d283db683bf2edb39476ddf74d9a01488defa4940ebc0ed3790acb387ce30ec5aaddd5002e91d089087b87708c262056f31f2e19d629321cecddb4e06054b006bd5370f85430f71b1220e27db6cbbd37b12c10e14010fa823e71782a01c131f4a188b5eb64f5cf08074f42f7f132c08b83e885dcabb8fa220f70ee173b22e93cc8e4135d0f17e95d41827110c60e38d861402fdcf8634637d5444ce79deb2639ce253fefd6b60d3014d8db2419982c6ff7128e4076df59f85729aa0a327f913163b09f3ac53021091245dffdda6bdfa88d3f896f73583bddf514c43058b6517489477d9ed8ed89c9c66afcc4e4b68aa15135ed2cbca0b626cd94418d39a4cc0bca1241e4ba8cad23c663881726b380b31419015f0d572183a519f0e0c859d69cdaa23c2d593dc4bc6c88029d55a5d781e47ea0f91b4bd523637cbd119693cca59b5e9e39b5e41e7963433ba220a6598d7a58ddf7417deb34daf9ca54501ecd32a46d70186fd68fe33143aa5e2f96edcc7b52a32bf34782746409ad6a3c8aaef66531314ed1bd10e10195b16d555d50310acc94bd43ae0dd1a88ee452dd26a7ad98b90d83bf495a52cc020b3dc63b4f7b2f99795c1c52d682410633df1de31d2bfe574f6901a4635584644998ee16433ffd8d9268032c023005be242cb59be9f76602f59c304e1d6fc6aa452df34703290aaa9a61d782c9182bb0015891896767581d6dd98ee5bb9b41864faf2e87125bc8ba10120d16193cbe8eb1eb60a7f473f6dc8bb1a72635c2f62533a3cf90a87210a8560fc3ca4bff250535deb1da6771292888da8b8a768a9d5a8340124a5073d4103ca79205ab035728a26d30b0361e92eb7d78a2fe42f16aa31dc1e554af5ca70e65ab42ea0bc9dc271f84e83203ea636090784e8f7644cf2c21dda2c8867447a2730608d8f96c7354c106c5a4750b1f77a7564830a203874e8546dababcec4d2829d48c79c41583763abf82bfd253b6bc06ccafa3a86f3f78bbad7e92dc9eed67684c8a361e1885c0579de7334fe4e5813fc0c6fa654b351bff8593a877cfa83fff609b5fdcd499a3b78d493e657930c262250c3433402679bc5662cdfdfd4b95236412481404b7a9e70d1213ab377b7361ce337407e503f0738c9370f064a7c0b36eb3fb08cd33aedf75af463060f1234aed0e5b930559f73168ce340fbaec209c481baa0cc8317854c64b2600f459e5a1044a4c09452fbd730113a8ab2b80fd9dd7f3b6c4430a5832e5ac8cf6c77073d58e8b54121a539a59d10135a0cdd2644d17ec89a9ac8f55e84b53e19bee1e09d943b5b8b5e8f705f3afcce59cb738f2bb6d7cf907700ce08637f6ab9287efc59ec24410ae522c3fec78b1ae9ef54d64b9e52f4f6f72b84cd82422eff23262fbb41647a2e6a8f17ddb81ffc8c0727eefc7e1f746a3b3027e58f490cb61d440808a504c315b13521880af15a1faf19dcf28d425266e5c25c29d65de2a04a01a7c0ac5c79b48dce3818c51d121f0d88838ea0550378e94d9351223d0ca518f7258025feb3e3ec11c1711a91c9b86c93bd9d5fea688a5c54df0bf974b65ece4f275a9d914e8fb04b76b5ce1a69ed41f08bfaf6f9217a64a4d28218ff1d196c9028c39734da60fcde709a3776608cfaf3f9db58c12f5d3b451958bd07058802160c0000dfefbb0ab1840ee0da13de95605ed60340e6cadb5e23b972567948d4a74f060ba1a7a4e004b2002367870fff7ab8e64d85a1a690c5e581db678ef4f59d489b3a72f8852fc31249ed680f371684c97fd83fac1826384553de835fa8dc0c313c167188cf0b7901dce72f3846bba8a113d1f845140db7bd9750223d3b2f4674d7f690ed972714106add36f68ecd42e4c879f523e6ccd296e0025c15b01882a365b0ad9e5534c351016f7f991dc26b3de869896026c75dd2df4dc10333a69c8fcf406118a318044462385c1c5182b36cb312292d1895bfe825b7da43438f0af8748581c201a7c94a2c981dace832f9d024eca9c515b376aa4d2d295f80ed89583446139f8445d7e868f8e02dea2946ed25ab305c29b7725542d2a26db73bd13291ece71754d4c4b8b7d695583bc3b8baaca14ba294baf17ad13c2f40d6b190c46522db0bd1d50176dfc7b5ad0654d86efa9e9ca5bda1c33ef385badab904274cafb546fb1d3ca739ffeab6e12e92713e8098f5adacaab70944cd6868c1f63f2844058c71dae8eded62b91cda00830144860320fb5789fb561f06c3195ea1b2e3bf6d63a00498ee31ed971ede1569261086d3b23ab9d6851cc88cda4a6b6f5e8df1dcf5f6aaa34d95168c0a986e9f35d1d8008f1a33a035a5c85d6a1225152dbc36160949e91067f768c74f732351446e60da19782fb6d4ad271f6e8470c317d50f4a5f277758a48365a1487a735a60cfbe53297da0bfe945b0222623cb14e3baff55212a6ffdb11d316144b6ec5baa28e01f41ef1431550d48d1a9fd32b613ba26673889df51b2c3c11a03a87d90ce5bb922b4239565718a19a610bc02458aa11388abfb83a76a6aa6c3ea2a82381559927f6b9a939222deace02ab1644dc11ad21568f3aacc6be99e85db3bb5f9aa564312001dcdf38130d69893ccdc04588ccfec6239720f2d20034303a5599d2625ca91a04bef37e8255ea015df1f18ae048a2e9aa48c5cdbbff098a437455e144a3c32116bc8323730caa8a18668cc309a1f6ee32b6734e487c4aa1ba8525fde5ae2e54c4c3654b6135dc6c24690bc16f64209c2c3cb4935246db0c6d3a4c63989bc7fe2cdb943e17a6fb0da95de20aed064ab1e15ae48001fd1f487ece7c2190c8cbaea43d9112e4f46a6984851085d52f17c7562c6bb1586b25171445e9b995af049a9ec25c387ebc37b0314e71d123adbbf5186253451a7069abd6cfdb540931fef9760836ab0b42a22f89b2e66a9b6fa3d4e09448e820a9cb88c2afa2323b70807dc51b919aa0bfca30769a9bda21a0d170e9d19d6f9438637aca569f1f3d1951afa00e1ebbf63ce42ddcba031acab51c6a90700d6d1165cbf2929b22699fbc170bc338254cefcdc42b143c218d7a0e9be2dc51fa7642055ea44bafd1bd9d689fdb8cda4e534dc2a1ceb456c9a532f221b6baed048328892096ee2b6024cc962e0069eca2ee4b02ba4b38f50d714b3ab57413834d82802a88ac2172e99ae4128c238dc215461ad38baf1af4ac7f41bdea9268b9c00440d1d958ebd39372a3a88e508fe84ca9c0796c7287edd50bc4cd693e5517ff8555755b1b28168c02b507623f2118af433a299c1fd6e0ee75c24f0254198cbf40a102aec5c9b5c108b7af8d2f6e7c08bcfdf7c259672c350adad3ad71203557fc0eda6336b7f99e61fccd62895a413ca281e21b3acab8f1f2632ba9bd76b29744a1085ced8d68993cfac4c4bed1518f1f88826401fc8bc824876d490738cf85d9248d82e93b8ef2f1d9a3d9b0387c1cf4c7e2420d3bd16aa9add601b96008df39f334bfb7c9ebb417377a7d74578c62d2a6f1a8b11a38248cc2018b4958223374f859bf59d1dc4224784b447b72e580acd920243b51bee435a7794b65b4bc833ab3831ed113b69948707a738261efbe999d3c7e0620637f59c923419c622fe8d459f90aa4423abe444def9ef02d2b4745d1b04a0c6d5e1441b54351796907dac5a8002aceb48c19ddb1c199c354d79030bd720ab4ba6ae1b85f40ab2d3ea10985f44a18cdbf3268260c8937d0a28d81287ae9283341c18610786c2dacc41e67d11e9a83950622b049c0d4e9b25a7353db74d9ee544fd9125c8d948cdf8f10960c25692ed6929c56f8d71e8f45f833895a8f27a26cb4d03804e8efbb7cc082f90cfe1662e16cc9cb67817e119d21ad296abd491f3c1acae0acf64196032f09ee4085c068914baababe0c8f224237e69f728d255ef4a7082f90dd372b6bf4aa64891327eec77456c2c3af6288116f2f5d625293e86b4f2030e5d3d6dc50e8711497526358e202e61611ff2114caed218be70de87a81509979db3a73f46abb6e28aa0c062086dee372308c3bde554b5150726b04f447d5ff4db13f9c2b6d665a1b5b2f75efd2d7d6ef406c3dbd18a71bbc2d326feaf3d02858fca8cd95d9440a88aa004dd12a1eae3fc673d46eb48ca93bcbba318453070e8704681a8964456c028299e1b278f13fd73cfb2b7fdd4c1ee56a1a39294ff71d826fbbbc760159d8018257c7e97972a5b075b678d4fd981f3eb8c2e092ba600a2ab7cfd5733214b330cb37ccf7f893958f449bdc81e1a7e57188b4794280a0b74a7379edbae1f8250e06f428b952a198a38b68c887ab2c72650675881215796155a0afd2552e2d834b73ed0c4f0a83472263d0129601e867fe054c835be8d404704aa1b8bf64df62b1734caa89f21ecd93c140301c8f40b44cc82328b3c68736bc71df834ccd1aae8aa61d1345b800f0e4617ea3ad46f45c8ac9b93cf0a3d26a20d226b171168a41de79c53d300e1c0919ecffc39b4e18eb086d7227295b40f86ffc9bc7e8f7149846d6eee02d7e66c2c230ffffc4fc243f6a868f88f03a762d980a518a910c72e190f6427ff3b86f260ead626839372d0899876a821ff0027093c645b29ee78221237a4ebc0e30262f0c8fcc038e3810c41e9cab8407d274a8612d2d9ce9cc0b74bbada1bba8677e14317c2dbf370f6a8b85d3c483ab4f1391489b13c3e89e826cff021d455e5778aa4e42f76c5ff8f8e08311ab581008783d46a68de7b4a252e88200c5c4d1c17dfd167143b86f3f41cfa8dc56997180cc91ba70ddaf7fe7db95b159bcd2bdf9d8792245b10d6e88f020b668c18a749f2facab035069598af47c1d0f4b94252982a068f435cad6df931c0c123aa2920bd0f06a884b597f9f7fe440c5787c25686a5f0c1ac6d10d88aa1d89a2de7d739a073d7fba035d358c62decda39197af9c68004b07c5416c97d4c592106313b6932919fe7552db2f580e856defe3dc2439e6a4dd9740e3739dc2c8b3f7cca2f3158541b7040586fb2624f24f4d88fd01096ee3ae0d1ccef98b349f4e7c2c9c5056122b69bff2cb318a1d01ec36b9aab3d4adde507c6f4084085ec7fe5c541527fc4d66a177c6dbc5cde9a6df919e74aa92832830acdc5f5d98a64aa101022a8a24b5350e10c27e1c6e54e55c852ee0db34bd9aa284aed843658f94f1105b52753fb65e96aa75c6d20aa9d6cbb28546bfd519af01bf0beaa1a2b54e75f4aaae5f01332f28a90ca6b47e8d5260210a48f6e0af687d68f1547eece2960934a1e322feec728a55673f6eb9af03422d2e39bed5224c3957af7b67b570920761ece442140a2ea1862cc695c06f9f1612f173bd257f140b236eafdfa60aa1dd3208c1e21112f235a25dc6fc5f30dcba4e9bf05677c2ec715d2f009a2643a3368457ba813c6cf8ec90f058e823f456a64a4a72eb865f1e7efdb7376f3a040c89aa88c5f57487f3cb4c249b484d2c13f6b66f621ceebc8a85ae15b24a7e28fa718200bc8d06af5b86f7cbb3aa11bf69d85643558ac9ac2116c484e99abee3d159ec10b3fe8e76a6ec28aba37351d4ae6857f3e52e1fa49700006a66bf247104a5125fb90661a003c6f410c1f013d7c44a89afaa524a64d82e5aa5c8eab4872e0509380900c3dd1c1f07ae32bbd87175da6795d46187409dfbde242349a44ab04cbbab7b9d9404f018434fa62217302c5ad53ec5e6c58a34cf16d08e8efcb95b503c1bffb905e65be4d678aea9ca241b427dce8b4f90ae7ac166d58fb51ef3ae9010f9d6963e5dbed4d2ab1e1c78c41cf271904bed0f9e69c15366dd3b09b9999f963712939a502531862184300ee61b8a0625c5c89d36337f96b1b1dc08e5c3470d8a3ca1d6f580068ddbab36be1ee37e71596fee84574cf7b5f3a9ee6ae72da208fb6667ec4b5da430fa1f9a7bba4d791844161a82ef83180c360f960067bd852dfa04822814a9a0b7f6ba6e9b3f1717017354023b1496410d98741800d0df75308b2da8f571705983c8a50ee8f900f21205d587881b8607d0219238264944074ec7c452d869456b637b200742f213c80b88e5c84ffc1a4f563cdb49453f1ed73fc6aa2d3c11a49017a1214d63764b35a9100691e522a0417b7499511258540ff5457f504e77a356207a9ef08b69d59cb33d8152146e9a573aadb72c8f69e0081695c0d7c4c642211a2c685bab113638d7a498e48b92f1940448346b6ee68993c01a1e8251391cc0bd5983638fead4c7380b062ccd19a1077dd6a7d62bc78c514827ac427c4fb2f1e9106fe20bb300d33d138c4c612b5a6ce0aaca1cd5cc26758f9e96e40b5eccc20477141657dcbe38d04f676131b6390723eebadeff19d7cbecb9b8da0419fa47476327d9feaea473276cf28b38333ab870ea19013bf3fca9cfae836919252a0cd9a81ac546c1dcd342449cc1c9c283293dab5cca2ea4acfcd0c499986d80f78c2975991107c452509a29ac9a904258dc91b59ca2af8d12e76297d8fdcedc21e62b2a804606911114a0d67bb2f178161bb4ecce3357170ea28f9a70542ac45e53e470400182a734119aaf97b6cb5bfc90c8cced4cc1680d42f152a5a7ecf33b0128d719b1521e9c4ef653d099e4f6dd868f29cc302a9251ecd3a12ab212bae6f3a45ef9b2319a642e9fc5b3b177a9b04bfd434de4c467da5c98e476156d54e41d0100fc082c9be29cc1d887137658d8dea84cee051d3ba79f6bef3897872c8431cb20a65cccf63018385121ed703445b581a3890afdd04621e7c299db10866d9842e47b7e0858050305ccd461826873cbb0241c97798d0a0345f461ff463465f831eb55414ce907967dd80d88597ca20d31a9648994e3955362aa4ddcce0d7b5da528bd4c710623cfc41d2fb98a4c34d551873e5a8300b4870e79834304d393a830ca818c8b39c0cd6aa199ba0f814033cffefa393d25f14f4a439167c50b15bbf56cf47f03fb34a1d9de38a32be625fb802fcdd50ef0f444a7320b1831b411ed2a598fa9f161d26305827d22ba2e54a425e319037904c0498a644fd5e127de79743d53084780e66c3ebaae48a3cec61dd5be52f90e037b83fbaecc3a9cd27610ec862611a0fba73ca3dbea08fede088c7d1fb8a0ed34d1470e87a95ddb0ecd965fe2c0d478bd7c65599107d163d4a5afdd8d940f47152898681f34a5e86b2a1163536bf0f45648f5146e83c946f1f020316fd2e6f5dcd4a99e9939b2710296ace56022558764015612d9f6c632267a9127329e1976766a12f3f4b369065a6685ce3c4530d01a0d0ae862626e6858bdfb6c0e4653b27798eebf71793f61429046a7837dfdb1f2b306ae33cc0a046d7c1e1100f118af77f8798e0ee3ae74454ba91842fe57014469851e4da8ede7fee56d022d1daae71d10990d7806b8af02b5d32ad3c91e5fc8aeb39556e088045f19c3590734399e0efa49fc19b9c1c3b1bdb0cd9897ca089995d0aaf272fbab417c0f8eed9d588c4683bfc7c698e371d9fa0b1e67209c09decf5a03e139596a9b99da84cd36a5ebac1b2bab01e83d08530d738378158db01fb106f19f2b7a890135e2ae78154211bca3bf5a954e353205220e3c159d117a8fd4583c5c2c39bccd0ad10e667bee33cc6c9dd56dc4faa9024d1227091afe8c11dd199091e9e6d71a4078b69a0f48e225bf2fd2bcd205f371d0bbf8784e20f92e02ecb6452822a4812d4f4a4254971b56cbe906a70dcc8b1b4379cc7af2ab605c06ee42eb49c220c18cfb62305ba6c0783211e675bd84a303ba7185c12324c128f9417488df58c26edec0c462582ebcaf65fcf8d949bffe473f8b3372dc7047863635fbe5d8a35dd4306a1c320187ae1f41651a78292cc321263fd7dd6b6eed032542c33fd41b608b9d5c4fcf799a8e376f7e4d864519360b8d3b6061c3d648677e0396fcf1532b58e6fa173e90a4f48a246acbd0047317b7bf1a931d5ac124dfa5f57433f1ee427f2f16975de08d0d9ede9137cef2772a24812b83c1d1affe64c524bc26e4c6448268a1e84ff9d1905f5d87f45439d2858122d9d0c9842ef396209d9535924c3592180795fe2d650536eb42e6d406d661e1004b872b235bc412a6738175d6f8b501aafc26ae58e9dfdc0524e473fb466a83e158c342b056fe7ec434101fc9fcdd9c7bf5def43d286b3a784b56ec5122e7d080cbce6b1e1fe2889e14344ab6c1b633e2c757450af22ab8598246e25b1ab827cfc6f58c7716d75ac310d00ce1b827807a88683a5a3bcf4c3504d528335b20fdca39ff096d2256870214526583a46253784ab522e0ed5bb27b6c6498bc72a13730cc089a2b911bb9b8bb3a4b3cd2f64e1d2e28a031c909a8e2284b463fa72b8828a8f2868388b17155207f3b3217d052e7aef76093c692b73720132846e1d7c39c97ad2f1e65b56850ee3cc2fe6dd2feb2db4911234507881e2d7ed62e87c6425ac4c82c24c03078ec1dd46be3970ce626e94b7256994577386684d7a1bc03469789c857fe78f61256ccb3ab15019027be3607dbe8f2572d89aaba35fcd2f95cb6b3a0a572ce04982962eff052cd382856f754d732da5913e0c65faa8304346ffc0a96175693eed12cab184568eb62e5c682681f627b2bca09c082697740a7d0fd74a85661f1629c073a84f9a9eb9a05346c1a7ca583307dad613d6f870e80c61f875a6e8136b322ddaaea35ed502d28598e40903a33780823e9a28bcb70a21bf93d7a283c8368801386bd5dae250e1fd0264a1dcd8ec65bb0dca6e1215bb108a7b5559d2f08330b53e8f0cdfdea11e71c8c9ed7423daf6a8c19ee83b16d495b73b2d3dabbe3b4be58425c451a845f863d425253eb8f11e359c0f0270ce78f95c4e4ebf313b7be8589992137dc6b4d0c8f8c113ea280841f60ac3ef94fd6a451b10c9b26ed24838902c5c4f689c9973c26709b04aa30cfbcc620bcec4cafe2a69702a605c14bb2274a591efaf8001e2169293de9f06369f0fc0c63bf85fa509111a485157d9976e874936bddb618eea05094bd5de09866dbf3d9c73d17bbbc2d0efab41f0666e8dff10a76c3133c04141dfc864c4ee9620302e4c801fe3290a305ea8602f440c1fbba9133d74d6063dcc05e392f6347955792eaeef0595698f3eebf799fc1fa1315fc1008dde3af0602374eee3fdf7a2a8bbe3bda641e0bd96db3fbedfc2b0d14997e2c470a0354c5678c81cda694a1ed5dcd012fd96b215c7a76c1b3d8326f9e38c58e3ec62362c5b949390d5e43f3feb420646c346faae39dc1dd357e036d9c44f0d69ab42adb0cf323dc3aeed4185a7edde5d2ddc62e5f3772a8aa0e4bd2d40065885f75b0f9322ede65fe11f6e95afeeb6405087c4d395ed71d3e9746cd817dd1404a57a621653e0d54f9dc560f4a334e1f135c02d442de82032e7bbad5b4357e0c7bea749e5a049337e92e8062f24bd31084b0abca2e29b55dacb65e35033b6edf8d099fbfed00104ab8f1a365e4e849e9445fe6a5dfb01af958b6b6a60842e1e6f4f877f3413eae315532ec0305bec804d90f581040e86cd301601ad9d7a9bd1383e182584f4be7311422665828b783005d058383ea73c0dfdb36b3a11ef93fe76c7159a7072909f50733d741f12dba0c12718bf7f9f9210f9c060bb2bc42d9111983debac9ac9b08d952eecc0ea1105f10b70f0502b7ef8008dcfe5113b74fa5a99b58a124a84f3f072ba404f5e9ef60851e20c554c50a1921c50a1d81648590a03e7d2656680bf5a1621d609d947e8658cb8fac93120d8a51a9e53ab4de838d42ded6a3d828b0db2a9d584be9b94a273ee24ae01023b1c50a31d55873124d1e1f71256cd217be52d6d06637e131aed1d94a39031519fea45441ac8898ea8c8b789fa8a9ce78e97da2a73a6322de2782a2b51ede279aa26551de278a6a99d1fb4454b40cca73f8494ba081db279282da72783f0815ade9f07e10295adbe13d9b9d3f97669a97f65f1a8d463b8dc9cfd73d81c94ff09e70263fa1c96b176aaa3346e27da1a53ae323de1762aa3336e27da1a73a632def8728885aac0f2fd6f210482c21280cea09ea826a70b579768282827482726604715050501095215fae11e8c7d58027611989f316cb469c91ac131ff123ebc44894558ea062443985974aa6cbefc1f279b094fa48b1b44d2d3b584a7d74e06e452c11d174f9512cdf08ca1497ffc4465dbe134bdbe4212cad311662eaf25b4d2c137b721e3839175cbe03ecd9ddce25f79ec3057a9cdd13971b502ab9b7c4d2abc4d27bdaf30c48a2e5e9f671b0e717704396a6dbb7c19e3005d8d34cc018b7f3480ef003d2ed1bc09eb002d8d3ac41084cb74f007b9e86011861ea84c9604f33862eaa6e1f067bfe8800ae966eff057bc25cb0a75944ab9e6ebf057b9e8515744075fb46ec0953c19eb0148a68f174fb446c1654b73fc49e3021f63c51901844dd7e00ec091bba37a6db17b2e701604f4e0a20bc05eaf683ec0943c19edc13369a02abdbafd9f3272705cd9e1c0a4e50061401a9dbff5193ba7d13ec6996a023eaf67dd813f6d3e367eaf679f8d8a6dbdf614f988e1c37a06e3f66eadcd059e27a806eb07bded81ba593764f1bd24f4e8a9d19241b1238c39e1c171ce61275fb307b9e938243c13d6909a4c01a1a91ea843d71cf2feae44670cf2feae4b8dcb391441bd2d26deb9d653d3af2b9a42575b9044b2e074a75b9b26427661c7110cd101013d29e33879454cf98e3ee59213ffbd615c7dd4322b90b55ae6c7911464f78e5f6bb9f47bf179d363bbcf273b9cfc7e5ca2351806c8d69b33582fbd996559d812018bb7d5a6b49ddd36604609b0d7a4835070fea2ae19a9608ae13bee79146e0e37279240a90e7771ee9f661fd7e5de2415d3eade590626289e009bbcdeffaae09d6c425eb467db06819d732ee1d1589447df8fca64b6bd0f0c560907c6be538d1f3447034f295b48ab05fdcb56be53a8ee33aafebbacefb98983ccff33c21b50b03b4bab53255a69eeaa93163f8899fc22085d4f3431665d77974fbb4438278393aab620242d0ec771e12121252d310788774fc8e990f63ee8204468b28303c7cdba4de366761843a75176a93523024bf7637f5dce8e9f90de69e1ee61e6ed87bca9a1b966cf3a7a7bee74bcf8d9ffc9e52a74d18ac7c096bf3c66dd8b0414715eaedf96b8f91a3dbd3f3be4e4f133460dd20ac0f4116792b8e5b4feb299f47e63c0f64cf4269b3cdda5c09a5cd6a9abf952b4f0e0664bd4cea41f088592b799a357c77f0a1d7755dc7ea78a9ce9070975b91d430439b958b0149a4de081290ce98d48fd6b82bdd6cb3feb895499d812049c2ee573ab576b459cd3ae3a5a5366b12aea9a5c50a26aeb4b86d9144860c48e67105befcefad90c56e6c216c1dbcb9cd8ccf080fc339cc75327459f02f3bf241f038a45843de65690eda13c905c7bf2ed42e97cb55e6a4707442e9c8274757a634a2715d2592fb3a79cabc7bd9b1e6aff26cf21b65c695f9eb3cb640de55ba3edaf320489227ec8e650e4d99c2d195295d7fdd65c1d7d853e6142cab0b749d2e57f90ae240e94e5709a59bf111e7b4084ec9b539a33cec5c9bb0d70aaff2e47bb3c2cd6d6eec59e5dabc3e3e1c2d7722686d5c1f3b9b83afbb3eded89c7b6773f07517599edca1d46bf3936b73fcaba46db6cad6b9566b1cc17104cf7d3c0b1c415006aef375fd558aefd7f9aff26cdd9692d6bf16f8dff9df777bb63ef2bf2fec44d29e482e59f3712c4f1a77fceb35aff2a4c1c3b3b3a3a393933363060e0e0c76732343868d4d4d0d0dcdcc8c8c0c49be5e2ed7388a6218b65a2c960c19e509da9ce07d7d779cd1ddd7cd8cf2f4ee78d8712ca53eb0f2f4eeeb36afd39bf2e4eeeb36976129f5b1294fee8eaf91d57c2ccf99937fbdc6526abeca33a4276df719d7c3cbd8287c5de7c6227d5de75105beeb5f79b6eeba508f291c51a176b9ca93afebe35f967c7d9d2ccfdf57df973dc37be35d44e8157ffe8a63a9a475862594eeb6caef9465c97bfe22b9b4c937c61863545d285c119bcb385c83d48741f7b7d9250c469226ff6db609a5eb31dbec779b95f97d589f823f2d063d8c524acf96b6e0f625081728024b0aae1c4131821778e0891794800a0643f4941e94621d700fb9ae3fc9bbce1d4992a2196cdeb3e355dab85c8fc1e6afc7e03a59be4a9bd3a12445331cdce1b2016d7adae45e6720a51c92244533b46cce379d24459dd20c7566738574e338226011379dccc44abcb4f3935685303ac43303e7dcb926f31c580aa1402b9ae1489b372f66cf5d4d66cf8e759d87fc0cfb0a2d5f9d9cdb9cceb84e12969f21d795c8a15947815d2e9d92b09043f56d49d7b9c35ad659fb53f20801ab3971c7e69cc7dabc8ee075c032a7755da03edc3b8be4058e710f419deb805d2ef7306c7aa3595cae88c5fa107abb7f80642739adb228c7e6df59b62829e9e6354f92f1190fabe862a033c7e54e0f0212ccb9ce67b0f9cec1229edb582a4d25e736418a6a8cfb8e8e1122dc73ec17d66d2c957a17786d5ef3235f6c0e96476a3ea39cd2afb950bb6e63c7d7589bcfb0352ed4bb7ea4de755679a43fda7a433af4428dcb458770c4d3cc78437c71ac7898a5f98d9db90c2b731b4bbec6bec8bf5c1fe90c35c6ddf5b224f719ee345c11cd11d8329c6a3d7790cec0ee66811cc7fd2bb9366bd7e792ae95bb4b7e6ebf4ff6117e6c2c10830b2cf90913f6d4a6f5d293ec4a272f489b3f1ddb61feb005f814ec481a06a94301c9bd3472242debd2a9e39b572e70b91074eb8b68edbb15c6835b6f702b580f0669b3b659ff9544daace7ae20c1848ca43e497d51fd0cf5331c2901099ef30009fe3506d6d3ea83c6ea6bfd3969dc0a963fd4a7fedc5a74bd83f6fcb9e0bf8f0f72ff96fcdcee669bb5a7abea9cc29c22b4e7a4374b2f47bbdba50882f4345a4312416f44a74d7a0a6b935e88fe879e467f7af35627e0835e12b3346324226df28bdae41b0993a4632d7292d1087f49cb4e708479debdf2ecfeb24c6a8c59a077ce869f5dd249b020bf9f548c0da7318e499dd1137625e4b709935bcf35b4d9b721492f6919bd6177dccfad25922ec536e91635f4cc08913aa3d1ce37f9241fb6c4eaee05dd503a180c4a57e448484825146e1788b0ebc060bf0e0ca673d86bc8f7d0ca4849b8728206538031626a0b28b4b0dac186e92b7365e62e2de37ebebca49ee9a0b1b6d5d003ad6d21c46dbb6dc2ed07e91848c1503035b08da90a74d683c6faaf4a6b302448831176a209e859d416847b34f3a53708db84b847fdd9dc85d8164448f98ddf901a2f2edfee0c1eca9224486c00bf8ff57dadef0bbf4ffcbef1fb5cdff7fabe33521dbdb395fe0e5390688dbff2e4a421f61c6f8ff4e72bcf9715a94f570292dfd462ba55b356224274f65363fc1ae31959633ca3958e55a8b9059599d65c376ccb97499b7587124a9bf5222093b4ecb0b06b42679432a135eed6774fb4764211acdc5a2d777b4969439b956f8531b7010fa96100e5a54d86829fe88914d5198c9c824dc12e6fb97c32d3d185d559518df14926796a0c578f90866026911ae3aecb9a926c5364284e8c54a5618868ac294fc15470c95148a8a8a89ad80b3f7d3f190a5efaa050e175bd924bda26122a2a2aaa3b0315e3c08a2f5261a608a3c4a45545c36c5176545d98cb4320d97c46b21d7701f252215aabb476020a5c300327d4b320ad3192a4e407336fd3846aac87380e905c2956d523aebb1470ddaf7d2a3aaf9dcece39eee7eef4ba93eb9c785d231d92b1395d9943c37899c7e0faeb31c89c2ca98c97f9ab9411afabfb4aa7d785da2563e910adb30eaa63dcb91794cc0f771af77337b932477cce111e8bec853ae4ce91e76e34ced5b4c99de30e96dd14efce0eaace78a83c3783cb396997e3e160383fe9cdd2a11a960e95960ef1583af49c56e5b8d718f7953a30ae7b9b9cd9b381303e99eeeaab61655edad7796ccd6f69acfdf2021d4aa271f274cc613d86faf131f45db73d76b40a92cf352c8d97963c8fe16d93b0cc11cb221ae4bf0bf52d959dbbce63a97c39b273d7a9e87c7cc88580e4d6e958c4d3e21e9e0a9289baeead5639845ef01f20f95c448306793a7e4d8a72589fa17efc0c7dd7499bd39d87e74743346c4e7752e6e48f9c2ca77ce9ca23aff3945376ca9cee3d45a7cce9ca1c56e942fdf8237dd7ebc7cbfc6828a443de0baef1052fa748e62fd02199d7c39ef11525fd30f39b0bb54787c22a82966f8e9df90c7b731c2be3306bf3d1d6dc6569eed59c46e6aff025435363c35d06f79b194e86cccc6b8ce3a4d7c72791779d8e4532b7668d717f8ddc390e9020773ad449f5ddc3dd1cb1bac64a487bb89f3efc4181f68f1efaa9b37b67ced22166920fe353062384e168a83bedf161456bb69aeb3245c1e5132e77cf49c79cf4e6fda4555c615c4b11e4928e7eda64da8f367f922ebfd6be91346cd99ca2306cb5b80f903c8e17ea3adafa9d75500074a8ebd082f6e3cef2bb9f1a635859d3269fdb00497f92ac23ae3f23d43aa322a5344a6375264463445a66a4e848cbbe933466ad484dbe6741ca51939a54eae7e4e5ca264cc4cb95b47402b996f5483deff959eb6fb6ccc6fb85f39346fdc973eb98f37347fc29eafcd4197f86b7e6b87eb6787eceb8ac4be327cead27eb7fdedcead99f326eed6eb5b9ddebcf7a6bfca4b9f54d6bde6f7ecadc7ace805f0df65a9e367ee3a10d7bc3f6fc3de68d9292d586a5b7de147b2cd860c893acfd0ad218971c99c42155b2d65aa3b4a7c1b3a3933303077623c3a6e68a042908c1ad9fa997a927eb5fb6ded5baf56378ebc596ebd6b36ced380b529f5a766412ada225f052c5b5c1601521ed39e9d5e5eabdd3a19c5ae6b810fe7b0cad7b2515efad7f25952f47bcb74ee5cb29fabee7c4e03de4b1890a7cc173733317813654cb9d8b92c2839fcda9cfe9ca1c17becf3b585201ef81f74e8565439b5c683dee5f7c738a704e11aebbdced5b7f3ab64a0e2c9dc8879ff7d1af5d6391ef9e552e4b64b552c744d2267d012ff3f0b317b44ee465ac0f4cc296385af08a96de16e9103712f1135ff1552bf2f3ae74eb508f5f49c9ee2e9738297d48e6327882a265f50cd53399926f3c65ebedaec8b3b728f11453cf92be7897e9ee672d960f7de9dee30b24f91efb3d442bf589501aa4651dce18193a4bd2415010b2427249ea8ca76afdd454831f4f55f0845d188c244f90ad6aacbe4bbee2b3f6fb4abe953cd566fd82e0fde32db7beb7b4ac3b6beef7fa021aa3b22b4616d4a4b32b460acaf3bba2e6d24a73fbb29bd7dd54cbaee8197779d2ee533dcda523d00209669527089627f99527aceeb894fa7ca747e4916f4b5ea867e4eb2bd74dddd1d8375dd4cacc5d6bad948a2aa421a521b956783eec6573fe656aceef99819d6fde1c0a78679cbfa3653ce7ffb4cc49131ee3ee1c0a78699c73fcb45d3e9f694dc6f9cd36226726cfaf69998b26e77c1aade99c8f42cb74fcc6f9415a86a3e87cfe09d496e35c9e4bee7996de1e97b44e02b8689d5eb80b2f842eb8f0501c5d2f526686c605172c1d12807da1c8656c0aa7b12afc658ddc452334924291872c58b0c6bcaf604485148af49897c7258a2f51244551461467449146146b44d14614c37a45ebc4c273ac48529fbe0e7bc3c27472f4a0b1c3020b0f5f35363272e4e8de8d176a16c4b1e458b07448c67640204f93b4248f1bbeba8eec3a99ae9be93a9aaeabe93a9bae93d1759dd8591fbb8388a5b4c7d994b4d43c6ba8cca98e9b63877ec30e19f21d1b80e3d820bfb144775921392e5190003ca411421424004397a6c646c60d0c67064bccb1b6dfb04242dfb1281cc706fdc602b9cb022056031284c2c31a00000942c156abb1917103c39991d31273ec8fdfb0279cf01d0b741c2bfb8d9ddd6569a6093319d0431b1937309c19393ae237a6409bc9807e98607303c39991a3b3138a39d6e7376c09a593ef4daa20dd12be63791cc7f6f88dfdb9cbfa780e1c7706c6c2699c5838b9c3859f1e3c1edee4c801cb910327478e193972e4e4c8a19323c74e8e1c3c3972882e58166ce8c352fad38387f5d9412343521faf459c2acee0c49c4ed4f1c41d9eaed3711d3ae5178a62676fbc66dce4e89ee3218c459c2ae670a24e27ee7822cf27d2c071a36c934667e7271c450beab0de6f58da260ecb43c346016f0edb09d77bcf0d5f357274767868dc96a43863693a5b5ef235325124cdbbcbd03c9c4143d373f2dd5dae929224ce68e4e8922eee421971b4adcfb0173653f6b4c21d16795aa451c573a2edc4d2136bf4e01ce7a6f48ef3eee243d84824ce6895dd8c485af3a235dfb2b177f637f630649163c719896225254d9dd1c8d13565a248f3ddf9c6ccce8e25d7e64e6775726e2843ecec8c2b5a90c4b930b1e7fb6c7cdf8defc3f17de6f7c5be2fc7f77da28ed1c8d1fd3ed875d5dcc8e8ac4dcd0d77441cf637352e637bdeb2364e83e6deb0422e9c868593d6c98592d658510b4e2c94b03fb4f19a9e1ae579421b96d29e1aa5798f75bddb9520f589e5d0b1c387478f1f1e91c64cd8e2b151c08b8333637b5e1626731675b4b8a38a3e9cc8a3137b78e28f8f9c9d1f1def393faef790868c8e1d3e3c7afcf8280166e90e51f411451ea2d843147f44d1872896208a2688a2153bfb82892e6a7bcc1d360a786fce55853c58ecd1e24f157d7062099d688227fe00baf9cd4c0fce8eebfdc6b4b9a415c9b0078b3f2dfaa862099c684227fef04420190da53e34dd0fc893bb9e58235ed18234560766a38077e6e18f8f164ba8a2099cf8a313813c51369b91b9b194fad8f0c162092d9a50c51f9c08d489324f9c7d226d34227a0f6f889d65e1103b0b86e668b936c59828635fafb1366514f0be3ee3dd77a779c8e355c2eb5532f5f12eda9675d99a36bd9336cc415a97e5a280f7558232e7aac89394b5483b81136b9d68f344143e3168342243a33323731d0f67b4164fa8628d136d9d888227068d4680749deb2eb2f4eef2deb29dedce320fcb45016fab04c590b44d1e3962a6cf8e1ee0e7755cd541a98f77dbba3c0a01ef9dedd79deb3c1034d205507282eb59d297252d59c7e492d3b108a5ba5cabb58405defb92f748b4a4a4dc9758100b2e9750aadb9dfb12eb796f2d69ddb342b65a39b4a4ee12abc43babfc127b52aabbe44a949cd25a03cec34fbe2c6ae3207eb6949f1cd24fb0ca4f71cb4f32899f302d3fafc44fd3cacf9fcbbaf2f307edc94f2ae5e42705b3048b899ff486648f6c484c4d6d7a79aae13784a574442c15712f5ebcd8a42f1ce6bba24e65699ad2d254845511b71b6eb8e1861b6eb8e186052c6001389cb3346579ca0295256a74bd4899199a1a1b19263cbc81e1c09a880004ca240874395bb1fcc3f98a652c070ad3b1a42f0c8412d00de8f6e432272557b1b6a436dba6c4a484b535d598eda94d28a0a2a858c2daa498b0b6a90adaacd87c1885c8b86069f39ec8936641450355a5a18a062b1aae9afc342f914ba4c94fd825d2e427798934f9095e22a74d4ee4610ecd8d15dbc359892f50983c81010618608082618a964589010c478edc7befbdf70e0d0dfd890dc08b988a9a8a9e3809272c6b394f208ba5729680e523a8b01367242c4fe0542c67391f6159029780041ee234353d94625be7269bf46549cecd104543142de9c06e4845484549e50c9e16ae5a08a3852b1b90d01458e16cd182550b4f2d2cd96c369bcd66b3a180020a414fc12a85ab14c6a4b04515cf8c5b0ab714c2d0c8a1290093029814a66c187d67248af29d7108777b7878e3c7c3f2882bc1c5d6aabcb80ac3ca8654b332e1361f6c392025290db1b485a9a9ce5888f76b5b5ca94dd56e35aa96b1952345564e403911e584d404ae264005040404040404042493c966e70848d5196bb9c14383876984c8cfd4140f1e3aa280a680947e5cf5e8d1a3478f1e3d7afcfcfcf8f8cfd4cfed87aa84eb88d221a5634ac7153a6e3ac2e8a0d2b1858e2a1d563a5470fb3a50406d39e0a0311249a952e5e310d6051fc6fe44c979c912254b943cb9504bb14cce854b590303544547214c8ab00a22f424167b629b7440e5b8ca419523478e1c3972e4c8a143878e1dbf017523ea8694cfad7daa330b65a7b051960a2b65c1d8297bb31ab87d2b85f9d892874b6ccf43ae416bf0ebe5f2d4e1824bec929723115098361b0497884b2c1015a8c4798b05bad518558d015535502b51d6c0744c4837031b3d36de039636249d25bb64997e7bd48d1b376edcb871e3060e1c38cceb2ce930e934d5196b8959b91d89a6dc2e3da4522ed42098ea58d76e0dd4bcc5267d79722c1faa8169a027654d8aea4b6c65690b5397262f4f5048dcbecd086acbe135301de36c208591588932e90b5fb90f34ae8a40e14649472927c75a6badb5b62ccb1abfb9b971801313f130479597e311120909a91c5fe0421d569c84ad59d558ad8aad4d6db1b52b3ad6574a599372aa495d1d2ea24acba6bc6f5bb231d9bad89a6c5e9ed8a06c5136266edfc6a5e645cf92be48b9162b29f6c7cf0cd2cf0d12f5d1973125036a6767676767676787878787c667666696ea8c9170c0971e9a226bb13257550999307a96f4053c6b2965ae40bbc3e412f554675c044720aace98082b08dc707070707070707066cc989173e61295436424dbf314948a5cf5e87165c8902143860c19373737b0134955a229a21b1148e53646a2274747544e47a2a30b7588a377c85425297d8893002f23a6679c44cb9e3c0c3f29816e36206d482d7b92d4322a2d3b3a6b2993be38a939b13a22158c3eb14e6c847885cc94cc4d86aace6494c82b1a1a1a1a1a1a1a9a9a9a1a9b8b54e215e2ad677c048f1b2391942a55c21c226fb1a254155b672da528d5e01765e383428c0ac7845524499224499232323233ffbeef83e283eae15d214fa0d00718e45993ba5528d0ad06a667495f18e9587ce031866a522d9372f147642d9691b81147b012d686546336e6626d4faccd89b5e51885f4b86ca5b429791520cf4fe913e20be253fa86685914a34379e2a465cf96d490d695f2061b898be0250fca631ac7711cc77174b95caf03c1c096439db1961ec2b42c0a55cb8c80aa80c40059511d74e008238c313b442d5a4a5bd228444a69439a810de94a096fe088f14dcbd3962724ae90a04a922449922449922461000318709eb53c6981d212a5450a070fe6202ce51e3f54dc88e21f90a2380b1268830d63cc608c2cc6d0628c2dc6a0c1183518c30663541dc5e0480647588c4175e482a3171cc1e028cc11d511d51855606c4829e0274b71d218ead3ef497a0a622a08a8031ce0000738c0010e700024489020e0fc03d20f4a3f2cfdc094801f551ddd8ea88eac8ebc38ba3a0ae368cc91182d738254673c84d2183db8fd231ef880a2e7c908534f4753a0010c200409086102427042085e844001215440084e427832828051048c9a1042931117a3258c9830ea62d464d42484a7296a4015e02743f120554ab93a5aaa3266000318c000063080010c80061a6820c07998e2e1c603150f5535dce8c988c9a8c908ca680aa328232a8ca48cc0184d19dd84a081db3792a2842e25d3d51293d11238c30c5df0a08b2ebae841175e74e1832e7ed00510bab83a7570eee0e4a20babf306270ece1c9c624eabd3aa8b2b2fb649869fdcc444e90e88824205454a00021080000420000108e0c89123309cc9121326264d4c9e62f87975569d56e798530c25484a929428291942c99212a62e8e70fb6711a82d873392e52158574ac94a3aa0aa624fdb930d8a9eb11275c649fc27788d6cb91126ea15b3309db328d5196f296b5635c6d4327662aab3304165ec840aa879da966e7329adb22869b14036a031202c9c50019501c1809a4e4cb50ce8d6a60d806a004403a02d80b400ca02680640544058d4aceaac26558164001403a0304030a035bef23ed00b688dadbc0fe402a01bad39a9d5acae18144ea01ddc3e50550309a58035a917ee0b3fc11daaa4a8ca409506aaa6a8da401507aa3a70fb475115c917245120c100d47562913c417d9058c08a457201ead3e72b160914d4e7c852eaf3e4e480246e14a574da41ca7590f21ea4944e9c448904caf35ca516221eb2580509548df5594b5554115b9e9c062fb9f027f6069e5108cfbde16c3a955658618515565861851558608185167e03d50d553758dd705567acc5012f3a92a83a43f284040a8914123048a6905c81e4d6b227ef2309d33227ef23a1aa331ee27d245575c6425491e0f6918c80da72386891fe33124979952a9e15463a1d89aa5ca879c621acfba4642425ebe40c847d72c662a19c7fb0466fc23211e708585e3a43c01671ee62a33c8993780ee71fac932655902efff090d65a9b69e8e2227e00ab03dc8a142952a44891224552482105154e802702401120ea4b0f0f65222b616d491d6b24ce5aac0da9ce92584bf9c5071a573e7618721aa46898a2e14603d200ac820409122448902041888888841c862818a4609882e1c65b8c78c853c24ebbce19ae131bf15067c784769d3adc5699e4e42d505c98690c335501010204081020408000000000103a6f81aa333e22aaced80829de32b5330ae1916259370c02120689552c279db558663a2b61f90167262c0b715ec2f210672e16284cc79cf870a05b9db1125bac0d8824ac4d4b927552820d2561f9d0971d0e05765b3934f9972a671fac13275048467a95120aec323914f04a79131ee356b94d0bad5179df5604ad1dbd6f2382d61cf0be6d085a83f2be4d085a337adf9685d6a2bc6f0bc2a6640382d65aefdbb0d87ea0b51cdeb725d15a93f76d3ed01a93f76d57688d91deb759a13529efdb9068ad4a90d2b7dce6247eda94b87ddb5203e124982c6b393fc0260941511f7d1faa200df1031eb20e5c6ebf87256e3f0a13b76fd425396a8c44460f75183d34b2381ef20d7a83ad18d993d6b4c3c64844f3d266d39ed88aa8e572169a17da53d3a08c8ccaa025a32b2d632ba6791c3c524a24a851a3460da4d22a168bc562b1582c478e1c3ace23c523c523a5c387f7f4707948b3285da88bb8cc84fd62748680cd5283b9f8e0a4f4a12a31565e5c851134062907b71f74036ab3414c5bda0c5ae2a41f38512410014f140f153b6376aa7a7a7a7a7a7a7a7a6cd8b071e3385120881345b523e9364622f036c621dc0d7da22e68a33cc91a9d88cb4c36684bc7ba34b5392e05dd96683ce8d6b22a20276dd1b2aa20ab202f82ae82c2e0010890a01edc7e100f82a8e859d29728465151ec0eb3c6c481828d8155fdffff5b6bcbd740d540d540d54041f98758828b92f54108db23022e4f503db1c513554f583dc1c44f20e9fcfc5c1d1d1d1d1d1d9d9d9d1d9eb3172b212e68756ec0a6968c501991ead1e3e2e0e0e0e0e0e0cc983123e74496b2dc1c8938882c3e7218810d826c45a8d94a784364264b7fb82c8475e2259628695eb294b4a6a01bade916a6659ca565464ca5951a5713c985ba968c5450858669e63613555353535353535363636323e3ae2557936b097c6c24e22b4646a59392508766d2e5240b5a11bc61ae80635c4aae21c6a9114a4646464646464666666686e62c25700c498263421382962ea535b56c4bcfb84b99f4850bc2b27cb87cc5066dd16650558d814a04dd6a4c89fb249541542015a80538036a7b026ed1322a9fd2030f52f8014d388837ad72b0ce980b337d562e97cbe572b95cafd78b6c01a539516f75b643cba83cb56c0a0d8a36052daacef801475722ec71258794d40f98a463140205057579fc70d6a67b823e53bcc45413544d3435a1b464c992254b962c59d2800634004716cbba399c957852c2c7971be6a0a2a76aac6f6d866928a2da54b272811bca2c30850935041294114860922433c8428b2d6850031bdcfe5155652c31a03e8d45068c050bc642e502eac3585e407d1a0b0c184b18c642c558a8184b151538a270f8c951428cb921c4d3d2d412940214a000052840010a50800d36d870c37908a4059cb154d51933dd5a56254ccb402b5adbc18b9651b96ad994305ad6c318c62246cba42031104a8ca5073c983de1e5069629300109104302624c400c27c4f0220605c4a880184e623c4d81c094084c69428ca6295ca62c318589295da6344d6912e3090a1b4f08602b52d407d21596255a3b1a53800214a000052840010a60000318e000672b53483ee5690ad3942e539aa6404d99624ad4142aa6484d0133656aca4d0c0ddcfe1429684f5b7a9688b0b4346509aca1862f78f045175ff4e00b2fbef0c1173ff802085f5c35d141931d34e1e20bab263768828326396822a6895513ab2faebad46022c04f66d241a98c12d503550f5232c820830c32c820830c33cc30c300aec3120d6f72d5a4aa899826564dc63411c309929324274a4e8670b2e484e98b23dc7e93229ce004daa0306d0659b519e4459b636a0c4897a4259808bab5d94c944157351644132aeaa31f34a6654662f48c97a85267cca5e8b4c80836623c1ba11414654414638c88e2085537ca08a5db340cd018cd298a235019cd096a4631a665b4a63631408b82f6850605ed02340bd09ea03dd19c82a2ea2c68a9d22a40a300cd0bcd09da046812a0350505455dda14340edc3e0daa8184210872c145d0520c31fc04b990828b0c70a181db77c2c5145c6c800b0e74e0f68fa22a0e5fa80f0e51501f1c30407db880ba7cc5e2f0040e16c0e1023840e1a4f483c4e53a38299d941808f0516c14f24681712971602b4c4c5c2c0e504c5c44b19532e90b0f614721ac6b54b2120c4b6ed4c792a6264a2eb8e0820b2eb8e0820b2fbcf08200be840aca8f1c87a83ac3e10907287080c2410a0730384ce17045cb7a781f875bcb78781f87303850d5193fe07d1caaea8c95e08204b78fc308a8ed49d095cb4622ce626474e5742432ba507f1cb2030e9e8cac163be5bc647b380f52c216d9890958e672960095274daa20dd2a5ab44ce11fca05582de066c4881123468c1831b2c20a2b7c060b4fc013089ee0e58625385183540d51354cd198880890420018044c21e08600242456448810214284081122458a14790aaf212a4bb7809a0d032c68ac453081db2400224a80c9ca005e9181a9c69a0b9732284c63f9d0170ec289994a199e6aac1f74abb3a42f2c4459662993b0951a986ae85243530d4f3540d53045cba86ca181dbaf410a025011408a8888888888888848881021672b76c8f98a6d1050b345409b0414a82f03530b27c9168e0593089a4840637d5bda90b4d9dc4495972a2f4fb47634343434343434341480000480ad58d60df217ac98b8e190185301357b895b760b68ac7f82007011c1d0036e18802d3714228256ca5908cb4544e0cc645989b315cbc33908cb431c89fb80079cb358272d22ce5d2c16ab5442c0f2706ec226f112672e4158d0201b1421c4a1c0ae91d27ff817b6722622cbd94a0905763908be722b0fb201ad3d793fa806413408da82d69cbc1fa405ad3196f783b2089a01ad3110ef0751d11a27bd1f8445900c682d2806b4c64aef0785a135fee1fd2018d01a07f17ed00b688db3bc1fe482a01bd3cfa01ddc7e50550361a60f8da9b13e0f619d046008ab241edc3e0361451756f4e0f6198b17b7efc407b75fc58a1f580184db7f72d53fd8211d28d9a11d086187b8a03e5658ddb662876e407d867090c50ee5c00e89a13e4faa30711d98b813c65232714e323a036164543a3113e590558d259dd40a21502b8870fb435f50a0d62f33d9212b6ac5d5ed563954c54bd82f47a6fc96457714c273870cb11ae2c590abfe903175c64cef134122424489c8102debe1c94f3ae5c3ed13b1426d4fde1ff2346489d618c9c8c8c8c8c8c8c8284a94283a3ce843550e380892a4037ec2422162104a4444fec1960d026af6431544260b2221215560889398ce40b0950f415dfee121a7449e41b71b74fbc102996a13c8153441371d7ef396ed28ead322a024a0669f996c9f80c6fa344fb0378c060706e4e7e51ac590474b470e16f8c53c1347c7a9509be98fcbc959c9d2cb562cbd0c84a597b1587a1902960ef10f592e27f9609d98e97ce51d5567dc25ea2779e527cccaa3ea8cbb94cc44b984cc52e52b4b561ae9a8ca52b7850b131395293df020e5014a7012768752872846509adcfb13274cdec4d2cbc4d2eb007bb6086e3f07259e6ebf014b96a0ba7d25f6fcc949614413cc5c80c572bb6d8302864082996230dd0005b0320533bfa8fa0c321061e9f663b027cce4e2e92fb8e005d5ed17ddfa04b7cf823d612b18c1c1d3edab7003aadb4fc19e9782438110222c986e3fc80bac38299aa87252efd951b027e80aa48e82cd9e1c0ac013684f5cddfe2c68e9f665f634817cc6985082094ab7efe3a7c60dc6c3c7acbafd1d3a78623c521c0e5ad3eddfb027cc064ed4edf7e04405ddce49f11aa8dba711740377d88b17ab4b41a796ba05e43d699e401b5793ab6986a5c452025f750cba9db07bd22da2aca8e2260c20d51c3112cd555cc1fd80f301f802f005b4d6d4a74f41f082965ea136bbeefba0b459003aa3363b3d454768cd14800b34d60396e7cd254f9def0341273bd4a7df9d03410e04bf8fbc3b76e88cead05ad73a24ecbb5e7932ad4d09e11efd7a3b139c30fe4859e01e7dfebcf3bbeb84b02d05eed137c138a4729f487db86329b06da42cb0adb907bf53c0f476bfd3fa1da4b5bedfc191e83ba20c046bb97db96f99fa700f1e897855ddce13bf100cb213d351d599d959755e5cf0fb5a1ff830f43e100441b2def3bcee0c06d96dd16677f06cbb7fdd0d688feea1d7b5aaaa5a26a667473ece82f5963d427d66e80e03edd1dd0ba9ea2ceca864fcee4445a8cd081116d013dcee41680d7c47d6901d2882cda091ee27505b143088da841885eec7ed6cb73bad7bcf3b0bd3a1225b4add5b54b4f6bd6b5551ddeeb5447dba77589067abaadea84f57648fb4d9fdb333b06d00b447f74e8bdbfda456dc0e89fa74ddcd1d3debb6e858f7ce2b3baa36bb77af2ad713dff916ea80f4c4300cf511bb2a92de8baab38e08540a0ac4e6df3d283c285a0bc3509fcf8bbadf29957541a0e6e74171bf77577566538631a0b1ef5f4883fb5ddd2f1473bf83e5d98d71bf7378b301e9fda456de14dda2cb5292bddfbd2e5e53cf8a4eefe97ef7967af6b188b4f9bde525f58cacde10b4e6a4f4ae06a493cdc18e06e4eb27b5227abdc715ba263cc675dde6cab8f4647912b9e4457bd2aa0083e41b8661b7057952ab7a5dafd7d53125a135d73f9acbd408e9b961d91a437d3e6f4a0bf13c1239611a3b639db00c6997d02ed7d0b2f1df91b4ecf5ef367422f9a25d7a06e334efeb9c0e4870850e0f05bce2e9f8306c89a148b9d5a2b148ff812c8e5290721ced7e6730486abd2bdafcc2b317e67e173d17d01edf43af0b6fb79685e9d9928e7dfffe71169f385ad743bbc432a140b8df1b407b7cf7463b036fcaca49c6549dc928bfe6fe1d86f0df073003ad89b7f027c5e27e3f426be1bf9e773a30b1450ec53048116a8b02ae406ddd151ba13556589e1d18f7a460eea782fb9dc8cf8f9fce8afa7c1d15799af77b6b0cadf13fd63fa85b49242cc833bcddef2c5bada8cf97a4cdef6c97b4f99d6599509fefdd15db9ad01edf3f1a84fbfdecc0b85fc7447dbef777147a66f3efb49681ff6e63bd2b3af679536d7e9fbadf69cf572a216faea6b1424a075d6200a66a071aded56d8e52da2d54637c92a1cd590c07297d071405a59f211b203600b8cc0595754a63dc26c2ed87bce484889b2e0e5863e4737e349443963934e0e49453be909771b23c82f39bdfe0fc6868c6616f9d84594a63e467587286a543f4e6422da6cd1bb0e42906030609fe6429538609335b9fb182eb27f925e3ebaff23cba5ed9a48e713dab44e61e37714c1586abf8a94d2f7cc563b88aad90407262903296a758acbf4a06c392e2db42ebe7d19d299d702ed42c556738255775ac4f9ef9b2ed64595672ea710f8fa1e0cb1d698a5bc2f5421104c2ed7f1c84dbe7188cdb0fbdcee678a752628c70b925326492e6df48f47a8d251f822fcfd6c992ad580c57b55e73be6cd532f21dfeac398d929abfc693e5594369c49a1a9c19279cb3989e21819439777af972d5cc677ef20bc7f2ebaf92a5a64814dae4a899922c9d70ce379cdb4da6e42918aa4df23c3a198a1538eee19d2b3deee13df446a2be2708def35e673d7c59661d817cbdc9f3ce02cff24e7af12cbde4abe4276e8a62033b969fa19bcb381d5560754520c1d2c94614c356202875a1f475c2c12969f70c3601c981304ba90937def52ec3520ae4bdb31f35bd7f36a4a64763dedbbbb91eab6431560d54c5d4eb9c74d7f3ca25535c287d6d38923ab329c58ef175aebc7ac7eea1fde286cd9536e7e2db592a25c6ea8e445c05453295f71dd1b48c0d84347c5dddda97ddb3e7d67b5de7894c592c4e07e48c10f3762d06c37654dd1822f77b4704f2ec6c07554110aabb0d81e45a25e884bb9f5d42bb5e297642a85ebaa7964151df89215925c87162574eec3ad1fb462329945c77e545d1e04f1df387c6120ad2b2f1e229d3e98c88c75e30d5fa62bad53b8f445fd77d4b64ab432faec26819eb3ce6b6fe2a4f1683fcd92e6aeb052f8d3ce7b22c5afec4a42fde4326c7331864d896bb23119b80e45649724eebdcbb5bebbb4bff6888ecd269e64743321fef38fe87d6687746c692b60b024987664ede2d6dd62932a7997ad78735640b244fd5193f8dfcd466fd3245a67c8dd57769a636eb3b3048d687c266eebe60db05dc11d7550461a595fe90179673644a39c503c14daa7f3414b258415aa532fba0fbe90eacb4d6f2845d5bfde9bdcbce82dd759d5772dd2cea204fe32aa97c0272c7e5be03e438af2b9dc8b850ba9f1a8490523e45ca9d7f7e4672f7bc73ccb980e4cb9d5222483e3d91dcef6ccff3c30a965e0742e92ee79dab48596e5950a114b3c20b15d7f3613af7e7eb52f6a8794f521cefa55678b1e2eed9286414d8e5de95faf4791cc2dd2e4fae0fab3dbb3cbbdae7cb1cb313580303f90a35cf207cddc691d11adb5807bf90c7d6290cc6e260b52d0882b7ebbeeb79defdbeee8220ab82b5415114592eef7cc14ef42ce879f6fb3ed1b31e088a9eed589ee55a2dd1b335f46c8b9e57abe591c5f2c691e5f2ee7de43ee6aa8b95fc801e0869734ddf1ca52047d47574481518aeb96ee64abb6de56a656edac3dc54487b98d6c4d31f3e48fe5516c9fcf55739e5759972861aeb1f0d514156d00ab249cb4c4401c66c596d95e6ed832320cd97e598f8c0102845a200a3f285ff2a61649de5c4f03a79b29c7234f42ae9501f1401d96a62bf1b36e5eefab3ca0d4bb00af268e868e8a4b77bef2229aa333ad44d3586172d37128936672c9db440644877f1dced2e1d55e82e96a7614929db482b67bd78b64af8e35b36a748ab089f5deb47971b8b703996670f2af01d8570456cbda1e5cefa61693f68ed08f5a1331828bdfd507a3b7fee78a907c8eedfbd832120bfdb66d3ca1f6d7e2527be2c5863b524c7067b500fc57125c7bd1bbb8ee36aadb46b37655a2a21a54810a6694b1657a514155254bc908c195205159e47b7bffe4e6f4b0da98ae23e0e0429a59541da62c7b8d3bea778002bf0e0455a735deedc05c8225aab97fb91195ac6e75e43cb94688d5a71b98354905d6b8636b9b7ca236d722020cfdf8e656bdacc8941fcf8b1a4f28575b1fca1d5594e0ce3c58b2515f16349ab31ee5ec9bde8032bd4e7a8d0ddbb572ac95101bcdec1eb95399c3b5cef54ea16615dafcc51c17bebad52498e0a4abab7ca205e49e4d6d026f72316490371e74621451e202b10dc4ba136eb0c04491206bb99f572ff1122c21545913524d801b2cfac0fa982fa3ea40a8aec2e785639a42aca1b89582c287d591f45f0f4b24ad905cbaf765d51c7b8afe948cbd7d2ab988288a8290a4499200743418cd8c0078880e256012286fa143ca320a481a0865cbfd3624715aa60731e3306e84ce46a409edc1539ce06243311d29e90a3af9491a80fd6e24510ae190449927225d726d840f5f46dbb6b11c8a6dce48390f6d423dcbb720aec743cd2dd2ba790355663b479a8eb017972278803aec0c3573fe4b8e9d8462a547315041d48437bd26e7806830c4ff3762137df163da55bd478f6bb21c781413dae5590dfc3fe684b85dfae8a3c19eab24e1d409fa04074ce0acf3a3fd11a8ba13e1d94126ab2bc5cd693d4994ec93aa031d6593eb8ac9aae3c29112e57753620c177e7b08801b5b9ce7ab542652c6ab2c4a84856accb38cba6b7e8d9ce59e265b180e8fcac31ff9e9685e338860fbdb0a1686d6c28bc30fcc2100c435618b6c2300c43310cc730846aa9a72ba58321c270b420f569538675e291ac8733d68927bcc8b4477857477b847d0bcf0a9d78ae63953ea4f31d9d32bcd287784ab0c6c2309499a1a9b1917103a31165b02e83b163937a08cb87be84d7b13de4b251c8d7190cf2e60c06c95497c54c3b61784a677da33156486f40f20046bf382d4278f62d881b866f2ce88cabc2cfd8be1cd832f2e1c519688de686a00d482e60403811aac6a05c5581b82cb23a9166cb5c27bfa3653227ff436b33270fabe499240fd6198d930f6f70444e07646530489b33e9b1171e8b75e601b5f593057a7059e359afb3ce56b4e63acbbbd932f2de7788f776eee9786ce5f505bcaa1a63dd3b53593fb5c9baf71ddb5456ed026a5e80ca3a0c35afac2eeb616d1ab7658d1e1b3768dc96357a6cdca0715bd6e8b171e3ca947da33e323225f5110f5aaf6f7db3e9dbcf65426be0594fb2a465b7b11141ea139e455b56b10627f674a20d4fbcf18938bcd75fa3eb65b936bd917caab3bed5a5ae48505a4119342c5b552458af4b64e984c7d45823fdeab20ebb5093a48bf519bb7459bf61a8ab64736d6c6cbad8bc1343f20d6f731923910d0892240cf69be60da9d56d46a2b0a4246dc68ee859d7653dbc8d9c1664787a6d2ed354b4c697f5beb58cbe8ad6947a889e35538ddd80cefa2987c562f1175c8419acc358aeb2c7b4c97a33c1ce7a3fb9ce82511ad7f519e54903a73c6134e553e984599f294f90f58e0b72e634778141baba1d9067f58273d6eb53b3cec229ebd9632eeb9d0ec8936ed1f7ac4b97f5b60a4365d589ba80caaa97ee1bad9167bdc7b44ce6ac37559dfdac2b9bc3cab3c5b82c16eb3736ac4bd54b756291bfb9b9b9b9b9b9b9b9b9b9b9b9b9b9b93955cbfab25c67b95caeeb7a0d2dbbb9eb352391ebc6562892af68195f168bc35cd61905d43600da8375d60c54705967a99689679dc1b4cc3beb3c456be359af9b2d93f9eb3b5a66f3d77f684dc65f07ebec7fbd4eeb2b07d4641d56677d3b531957b5c9faebb74c6a8cf51089019c032a5b424dd6595497068b2c93501f96355d2e9bdbf0529b2cd76d58a719895e495807419284c17edeac294fd3559e3facdb406bafb35e43cb68ce3a9296cd9cf5d0d6e8b17103c7279a2e57835c9755ecb17103c768c47cbdbc7b6249470b7233e3399af7d75f3febf5f3c7559ee60f835516cf8ed5b1b486e30adec512bc11391d9037630bf686618b15b25c32a5d966f8b261798ae30adec13639cf08b2ab571c9253a4ded7eb7d95e579801b96639923b6beb34a25158aa62f078484b4e7b4b95d728a9c62af2b2bd11a5f144b8a85123d3ba5203a25ead35572aa660cad3116ddbb777f2dc1f2c0edce8aa2b57a517c7db1c4b5e5ad71c3166b8a70bb9faf2f6ac6501f300cd989af57b4b7e73691ebbddaca3573d7ae82ab0cf38c20cfd69252f81ec7d371484e283e672c8bd41bbedeb0c5f3154591d6726cae8cbaa474bbd77148cf0d4b5614f5e9de23517d6b89d6c2777749d19af88ef5af75f03c0ae9b962593386fa740f2d39a505c94d8d4549b4b6ac136691534ef8b34b4b6897d2b3a268ade776e7a068adc7e61656206c308bae624d3f20e428e5285712a194d292524a61d4876dac9bf3d91aea5336b703d26c93664428089136d9347fd46f479b355fcdcd4b4195127f6cd8a8367e6cfcd06e1cc7c31b96f6e3c7068ef769386e587afb8766e327eca452e77f68b5e4c82446825d7ebf06f5067f61dc6eedba9bfe099db14af0a447b8cc75d3a6dc5b36639d82ac927bcbba3ea5608b499d896547c3b25e8921c1a8451c07da5022e125ae4b46d84bcf604cea8c43e1c78f1d3b7a7a5ae7d4e1705074bb79ed7111521ba4dbb58a96799deb8e22cf0d39ca717395fb5cdceb862c72226d9979e93f1fc8b3d5a2621bdf3ed5edce7660a63aa9db5dd132aa9671ef6e8a96eaaa6ee7c58b1f973586d67ee8745d3ad63fbb0e6aa9bb2d6d3249b50c4ccba65ac6b7d67aaa9a31355761b4ac7a1fd8f2c4f01345f09e5d2775738a586795537808fcd150d82d755dee573ab1ba2d43dd529dd55cb16aaec69a9aab8b23851024c0c5165448e0ca501f51408b5b16b72c2440420586fa9d5437f57552de54d9818101798251b4f6148eae5741ce06c9eb30097cc3064ca8c66dfce407b1446ad4e8e961be10111cef9f2fd84f1a975d97792e8f97772eeb5c0e2fb72ecfb8ccba8c7399f9e6b27759c6657beeacb95cb6cce599fbd56ecee589e3e6431c9648102a45c4c461e96d212235ca973536b8c190e7cfcf0f5a8d73cf857ade27d2537264d2172ecd1a645329d9f943a465674f10233db77ff8f64b7b1a3c3b3a3933706037326c6a68b87f00c58c0c9fe4bff8ae912ff2437e8be575b6f99519aa8a0be260d60bc221f5d2cad5ca71d76666be79e993208a6057a2cefbc01f34eb074fd4873e1447d235127156ba25ea436e5982c9b4a4accc7857c8b37bba35363270041172733ea815a43ef47524fa41ff7329c9bd5e5fd7dc545345d6543de958c16aad82ac350464a5026120a744d68b55e95292e4e62ac82ac81e9617a1e98d4434142e3d49128914b6c36c89211d85b02e6d531c5fe44844392f76983b7efc983424ac46ac216135a20dbd0ec7892095c16c52aac33d4526c92e454e89eccfa06de60875152bd7549246a382e4a1f19188726dc26039456e974f94da540a694fc860cb6e84a1a59c17a408cb717b2ef501f9dd7b65d778f0b09685070ffe2d6bc5d07d3c1d63e0eeb24eaeb7acd37896aba46178d28e7f59d745f13d1e213f96536035069e7c8f475e779553c81a03ff7a8fe0bb1e90e78e0b5efc095e90f5d02ee1a6db6a5d49eb54cc05df2a41ae07ecba960003484646dc64646464c44d7093919111f70323a3264d9a9c09932e97c5e5b24e4f56e2c26226278c45e90c819fbfacd3a42b3fc11f4632c7fc0a664556513961205897459e30217eea5c9679593f41fca475f989c26535c1dac27ac837a002419284c17e932a49c9d2d0133b11b4dc0a43b662ab1c034f67a5a7331036e42cb6757eba2214a3b8a065309f124d4958257163000318c000063080010c38cf53c9d98826994c267b3823476709cb5e267006c232d32bc054267de11f9aeec4b94b9313ace54b1290c0e928248892d694e58a0c2ca7b4d933280044a98b0532441316c8968e01e9d26610558d359313a3331065900b826020c3a80cbadd0001540ed041051d54d041051d7e9257051d7e8257051024491daec2439e207e13ea889cc5f211489c9d8c68e28215a8c04346c2b61647d8c6c2c9880ac42e279d26957d02ba13810b5a27a600051eb215db3a53c0267db1a1cd7e48030233a8a8a8de25c7ca0ba6a65e30d5b3a3c354830ed40b522f807901c9052b20408000010204081000000000425f416a052892842a95d8696a6aaa91040fd70579d2152cad4057b034e51f89a8fce3102e34670f6f1cd1a5a9c682a43a1634d566772983986aac8d8ee54341543450074155a332282a284af62018d89eec40654a0f2de3414a9df10382a0e83317a696756919d814e4a5657ce5c908117ee20aca4fda152b46661455518889c22a8aab289aa250a2d168341a8d463be184136ae727ae4c5bfab811b425da16da52102113a47cf8f0194353a20d319b9a4195504209259450420925986082093f6e8292094a262801dd670c0f241e4a3c86e0b1c4630b0f261e5d7834f178e221c4edf30882da9e9435c02bb4a62667106c4283a209ede95eb14b9785b034a8a641c154fa58551f2f7ae663d532213fa060565dd9b1e356e3e653e523c6a7c947c9c7c7c7c7c7c7c787070f1e3d6e56995566d5cf6bdca8eaac468d1a356ad4a8d1532307b75fe30601a9dfa8544a562f643dec98a21100020000c315003030100c878462c1581ae592247b14000e81a464624c98c7922057414639c30c0302000000000008c20400661b3365606c379686bc31ffe8c81496af2b3e7a03e00c50e48b74e0a71700a470c1d5a6202dca7a470650a03b3c260e39c3437092cafc80c9371fc4f6685b66c3615c7f63881ec2b8fdcbe08788917f9a121c030c318ab2aafab4583f61a8b453e2a9e18672d1088bde80aa97f4e411871d0e4ab8e1775102615edcb65ac47ecb237e64db9af3fdf9c9e9102be84094be7647944322bc02f80a7110d70e8209afb4daabcf4d90854d1afd0fd164863c89262a89726b645ed9f0f220f7aa269edcfaf1239d754fcb8715a58253c8934d5a13fdb7f55ad3ee94359fc93b46e392e4f70382ee625ddd770f94b6f74054fc7091e003c5ac766a13ddf4fc74013b386e738f07bc9400ce567584ce8187a33286cb394179f15ca5c0cc08025915cc9b2b01bab3fe2e26f395fa358d216f4bd3dd96a2ee62005588b29739f91b7321f49afad619b9a0832ec673f6a6b89515b79f6f92584b1ca18857e2a93814c5f7b7b26717dcf76354f57fa393e049a73c6ba1b08bcaae9218de5047fba95b74bbe1d444746e8238bab4c170d6b578cf6c042be105787d42bc4666adfc59a78d192268b48a472b4d994a64cdcea44ae14911dde89afe757fb7e99818897dc24a6b8fbbebd22e541597411f3a8dba11682212992b30fc68fb1f34a12f0002b77ac6596637a9cfdf70460253b97e8a32738cdf64e64deae538450a05c7e54ddac56bbaba3960715bee28ebdb5056cabdfb7f81966e70b3340b0de7a38003707d22fe0d6cbd03c1133d68073badaddda3ec69275c0e5572c46462bb9ea985b305e2027721a5ae8a35a66e15af5936724baee578e429acdc7c86cbbf2f8d70dbb24420b8905847225f1d97ffaf57ea47985a1db32fd89a984216a07d05843648d48ad4230d1c4546e9289bc0a84b8c718271ff64a2fe18950bc9d751cb4055fba080b60840c8af7394821afab74dfe0b7739d44405ad06587d9b92b4148c7fbdfabdb8b5312ceed071353c82ccd0fc5c5bf2d9d6f81181a79bbf527a3d88eaab7298f24a0eb4d877eeae17156bbdee5c3910d80e559259199c2e8d3291eba4a0c81014e78fa5c771c9ba2ecbc92f48814fb8e63bd4ef94d79a2e4a326dec80036bd807a7ee260c417437bf40f215b355c9bbf582271000f71b0b44c17801f0c61527bd794a3ad82e4ee6b452e65e3891d39fd23f9ecced37a34a7ebf4c2b5a5915e007783cf758c176adc521e6f3798f803a6bbb18008e9c38b7f6e8aaa6e96e400e2cad91045242b0da63d5fbb14eaa8e3f43667d3f49cf64d82adc4b15806a485868cca22fe3603651faa6dd14b12c4fdb6c34774e99baa1df90e4fc1f43b89d92d9c4698a4758b80a5c0f518afb1ecb3508e9e566f6be652ee919151bd79191b144e4b59f87210c7c4bd87a712f3d6c1cf9a6ca565450cee8f99de743c3ae0da13f07a07f2fbb2effb00b041eb83c55d1295a8146e638a3e7a3ef5ff91c330a318d57e3a11d2a1a87a89ce2ff0b7bb872e9a45a34c631030351f0a4cb1bd020978d98311460fcd32512ba11fbac42076b73068475d2ea65e45bec7a48daa4af6274f259de12e28f354381013b842626c1079baa69719a0cd2fc94e225761e1055eaaaf05b42986fb7f3bbb940f05246a4c4b31f7668c57ebe2b6e6e05cbc589aaafabafcd34e7087a95b4862d15de0ba1706a03add6996aa079783897f5bb3bb0b22fd43680ac54f4ec06a90abd282463ce9baa76f2356fbc8b8bb26e5e473fa4769643c9a88c1be06ca3afcba8dfe5b3455de907ff728d3a39b52729ce91d70a96c89da1b77a74321a276b1b70740048c4cc9257bc1988a507e96df0e3eb65265ac4d5a5b0182ae61497ff08ab8f44e33f798d75d07005beb85a94d174ed0928481efc16169c8c5296f2f96c6c146d8781ec0883496e7e99ff084669e7503949863a0e410517c50b7706e341b3f94653d781baa7a83e153b73bdc4c2a9f30e9dda2b6cda1a865922f9c940e63be6f5fbe9708cd933758b5c66d613766bb49e4429488ca43e89223c24e690fff21aa9255df6916eedd79ab57709f549eed62df3ffdce5753bc20ac01da1f4ac5aefc85f2c607c4a0a1fb47ea18425850045f75f0d6a00566efdb37b84b09acdc41851deb6ef78e4cdf7afe08485743ce9e0bc27a3bf0b5c3c08895846aa3acae14dfa8715afc0192c0ac146c77b510f9b8db8b0b119a6b10ae02e8fadf4cf775634f724dd457e2b034453ec945879c2509f5c8cc60ccdc18f87b28fc60bfd190989d9b9358215898a7bd493f4355865bd4f9384bb9419e4be45e69c123b1cb5a0789e54e47a3a0d845293e90cf054390ada95cdd20a01b1e19f623ec83cdf4e157124a792590cdcc0982b5132396f891d883f5e866d0cb1e61f4c202a07256765da6657e73c7023b8319ebc1c6a2eb42b5dfcf7bcf7998b08c0960a84d9020bcf9d3871111c14333af2d8be5657da0dfea378001996ed6b85d3dce8e83cbb5079e993280fd29c367d9a9bbbe276d4057a74291927224302fdbc52c8f3684a92f7dc702dafaeb37b7beadd1ae4de43fbbac99de9f3a9375496656011f58699d217bd66775bd85ef15250f236423d9bff1a2c34751ad77e2046f592e0d9679c2ba9ab565297479839eb465bda4d36a9fe7af6585484c263199ebf76b6bb3eacc45208c4aafcbf1357af54f5846ca130d79c80a12476104d6c195a5a90265233b96cf77e42a6c27cf2c68bfaae5b0791368a1fc6f94e07812d250362045c82598e7766c6e7a70e3552c7869fd230152a8af9da5b5e2fdfafbcf513f51695a6293ff5526019b7c0a065944cddd5c24f15b08e66cd1413485616b15be16abeb739942b8fd8399c97735bb683db87cba58faaa92148c16929a396985859f133c37435c40d4e1555e37e6e70727d16c671f62cc8330d5bceeb3e7fb2d81664cd695cb8eff9f27412856455dae6714d367b343200706d6dc5cea6ad5f430b1027c9470e86ca9329d50cda858ba1a358e51b8fb773c09f8c5191c67e0da350540e62123a8b81738c10204c3adc3aa9fa019bff942526e91aca45a369bcdd21a944bdcd8157a06f3a122fb2559bf394a1653d09e99ba16bbd4596a966fc5d62cdf8f3a0dadb97d2a4581cf169a1f7ed5af03394ab81f4eaf56661a28237a58b38a0261086bd58cf3799167bedc6e69bb688758fe09181e639a44adc072bcf862dd1d979faad5bd0c35f2c4985d620d6f28848a0c11e5a899c16c0ec051a87a168fd313f038462c1f3cff23d52f7bf192cbc28ad70ea487f6a9bab0d08455e2085290243616bb745b812b8451603c931212352413c200f5664e3762f495881e88dd271e4ca5aa2bbfc7a236a24c3373443174943825b3878b30d21509ce55826d929d0e718b090d9f9e1def8aaab469e24d240de143717c63f493c62093f033fe83658ebb941dfb5d26de97b9c97d30608c88f5588893c37758b16dd6e2cceb86356f65e48ad5c62a0741ca547f72938659abef73cd6a2d2a5aaa555703d6e35c5882d88dc8a8cf433e864053aca3397ec5789439a394b999b4fc9be41c92d4d0d6aac1ad0303969e494b979eea3e1d2be94a56781fa6aca997bbe708e223169948096123a93cf512c064bafccc25848daa48226ae531f36f728378adb4d0e1c348d4d0c04cadaa16829dc31d5a1b96c85ecc50a1009b6b41f6da952fd39795654ae3d6028d8a45bce56c3ebc2ebe24bf32dd652fba2de1797cfa6003380b00556f0fc1363238fd27786eb0302f3c3a1dc23128a5db60ce1cf297391507dd47d6f555c9bf4b75c2b122a8d0d12c82b18fa8a805a4f3ef005013edd99f1f71b08c564680d3cf856354bb2d8348232aa5920f89ecaa19019cdd37aceff728d37237448450a6d8b18376ad719f1b69c7e7f15cb659961a977788d69ead03459774b304d8784af38844f8cf6980f33d32117bfc07bac7f4eb14d8faea77c66b754f748171ee761eef8f4af5a41c2b107077a54e31d4dbe31820c4f4ba5c34768d045673cfa8d925f8a29cdb7984b59e8be15257f13b7c40f620fbd4bff2aae125fc55ae904dd5d83a870806b3d425640adb6e1de8edae3cca55b673456aa62f602c1f6b4a75c3a18e860eae1af2cd04afff7da3b64ec522d22d033e14fb3c48012b41f23c7683ea8843c701d939351d89e59313dce7c1004425b76345c75b2e79901b3156bed276ef498177549e00211bd0fa8213580a5a6cfa4dc592e5b6801e835b9a6710c072652329cedd296048ef60226cd29406096403aa234ec2779fc4aba4da930dd4cfc1d995c18a2b7208c16fa0354edc5a7e6f236e8230833b31f5646ca78ba23c1f639e6f196151d559d353db64f6391d57f846831a0f4fb737743b16b2312bb753016c2dad4a4147a5fc4b9a1b348d47f6a46014cce7343f7e323c0d5fd43372d4a0cc5d0f61a2e6f9e4e874c6d9a602eec215e96fd97193afe0291191118cae497546af62569c9edcae65d690d02c425bd60b6ad6db09e64142ad730ce93ca7816048bba88b18a01589eede0ae73e6e49eb9ee3c58b4a1f843963e7bed377399e35c41862597c396386419ade5ab53612823c4fa74f2d5b5984d6817ae697794baffea7eadf1b2529b098a4ae8e103042f5d747f3d856fb5575683a7033e3536c2f9168fe252633c0212b95b45087a8d52a090889890e5f89889affcb44c0f5014408e98ff8b03274d2a15b9ab9ca4f40c245511e9526a481bc6aad3fb387b95cbbc307a3867f4e832ea10cbe8752eb0004efa3aeec6d1d6027e340c25b0a6a7c65cb0be99ff12f904f0548b3862733ed3990974907bad0fc3133b89e1766b5f3c7f884f8ed958056dd91be90f59afe4feaf373e07521272f3c54e447938c7c0cc3d3df48efc78942688b0dfa6ffe0ca9fc01decf79dcbbf73a2163a7dab22e92f07fccf1876e40f6b89fcb13bc4bf1fe7b7810f4d535832a27423c6b5bb5b88c039f3daa561886faa31da340339cdfa5275213b4e11c2b2dffe3f413aea290bd28f0c2748af3db3207df48805e9e9f26c53c24ccf2ff6f2ae26abf13fbc78c8d10677fe119e6f3d0c58b5c849fa2ae95b25a3e9a8859f182f54d6f1972f3f1d10fee6db7202159c8c15d7e935926824899ca6ef8db236ce45fa3434f89f8d438960d28929ad3b5b1e112d25e16737926f662741c7bd449fe17a958dee36f157a5e190a70c532ae6eb2e6109f9319f2342dd6c1e1620ed1d50df7f85e02e732c8546982230fcce979b9de2c2a91dfea2d454d9bb45852fc72fb455e9614323199c9061aef19ff4be7c1c46d423326547bf941d3c006eedafe797de6415cf86dbcbbe5120c650c19c655d1d0cb677e4abedfb32c97defa0fb5f302a2f10e8a6397292a6a49c912bec8cfbd2b541381f130efa821e92a1ecff796083ea70fd639e7ef7e26b81b7a3a891873d89db5b84445912d9ef5341c1db2b38c4e36402bb372eafe5f995a7fd34fdf8b345992ae2e34e02007f4f63d1e35c8cd6d7aa565ba80a0328d8bc16653dc43d62bc835b25d116d9db70cdfe0e1e46103d64dd2b28fc761dda303873589e5b115465c0147a0ec967a9f56f41cae61e86bfee86a84432bd383d9f72e88b0d0b31ba801a7ad7a6fea66b7049c892e79ced533fb93de1bfc1d2371077428888f7189000a46bbe8bc112d7389a20f2bf325084d7d048a7bf64e88d20462cbd9d1c3a54f6bb4070bb380bfbb5c48ca839babe526b926a7465b86b0b7b211c80f1e9372d12062935f2e392372f9a7fcb2801a71074c8b44a40b757906fc881e492fb77035b0efd90b1f0967ba372fb003ed00fb68a7d1bdf6ca9d91ce974e9605d93716a71ee712e4d2420daeee25400c687657ce89d9d631a730e2a2fbc72efd48b675ad739128a2f824b8e4d87bdc05c10bd69159010856514a634e82038605507987a1358a1d29c5914c310edaae989670791e11037761ea597807504cbfe13ec0749620a9868681b3a641d1d35c759ba659ef0d1f68fccfe6397dddfe75bce4fde797f29c480a55612ca518a099440ff25272aa2a6030dafc38a1aeeb9d254a8919260de4babef1ebf06387c180c43e3479751dfe5bf038422cc8f566129264014f774132de02640ea2852c96adfc7c02a3536479d1f4844150b5ca3d19fe21a8535f583064d6c0bd87891b289d186757eb32e2a29a987f7a141b1fdc477c5c12f2fd6bb6fdbe1d5df804d25c50a0fde7358c14a0db1a253afa9082540c54aadc82b7b3d71b6c115d5421e2bd54ebb657b74e01690210e324f8ca0d5225a1019ecfc7f2a0fb3cb6b217c67e020cf737f9de38183a0870e83f8fd83676ab8d41cba38c79300cf0224aa66f46a8dbb442754316482fc565d33a4ac82a83ad93415d0b16041c22b5cefde442960b2348ab26d7e8c4416110828cdda515e4d3a6c78b60e8dfa5bbe3b86ef3f2877793677b172f52cec875498f17a466f4ccfa05f6909867fb91a3f4f19c2c78ec6382ad85820680c0925c641fa3c27b7f452fb2ea19257508f6bce349f5a6329a85c1d3d239add6ee52e07a21831040d06167febb38c0d8981ac1951658938782d2fa1a918fd4b731918e96a2d07b69c412e19e48e56b5fff65262b49456e9dfafe451a30ac5aa3fdc1b95474fa7ca714dadad3ffc818ef85e5b523330aacabd644e9b7d5438c3ce821ecdd5e078e1f26d2905d5563ba814c14b0215a852920ab889ae46a7690aa75090dc0ba65173cb46d52414de2515898590ce618f1c179f9a5daaac571bcc5b7907d3e80049040a07d29777a4201510d9ed9a2eaae24eae7a13887e4155f4998f46935f7370b10570e854413640a816d218ce28a0bee1be3aac754ba8266c3fb5565260b01eed95b826fd81b4114325367b701c501498c0eabefb1c9ddd4df4afc61303e796eaeb131799590d319749220713fe25a1eb01d262b0f1a039dd04a0f5b325255afa8c7bf70bebf4adab26a1c7b3c41de730e42516f662e5c38ea192632f6c8510328cc23f29844a66d6aaf295dabb8eed7abbb2c3b9a89e8a11230d7316f8cbf795c9b7b13a031d0357103642002f634f770eca02b53f9acf138bbfa84529031a0aba96627b289f56d303524161f413069a119910cc888bdc0dfd9f0e0aa95cb12e1a8e46bf2160c834b46157d8398454b2d88c6029bf435c7d45515c1d90d0de81fb24b15099f5141c2908e7ea8734d9733049cea4aaf07ddf3cdceaa46f519e843a597b2a8ccb74f585315e069fb7e93d0f6f0ed285f1c2f69cfb8894f7140c54e78d7e2df8def4e0ccc47b00474c012af54d510ae13ff9e0c717b1e9e7eb725bb5f63c2696c5cfade7394b6c22554af3f771c53624390600143858e481cd7cd3cd5435d85a146949959b2ec13136009c0fa9a02318424490701369422b37ab08843c2c75388b6386fc27658e89327c9027563f3b83cac939ffdecc6e6646f7c43e05fe744d5cd864fd75614fea26a8ebd9505c983c51deacbeed964627f76da6bc877f53d39533ef494fa7101f00ac123a8f69e1578bc4e638e4f1860bd49ffe9f3c1aa9cfdd884931d88c2e6e22389b115e9a0aa02920cb7b7addd83ce54f930be4d1fb4a69a0b8c9d93f816894733858f1fd4acfa7bb0b74e02d7aef5c4db2c021baf4047e0aa5169aeb554f961d2ceb1fdf7c4b11354815501b4c3920848c33bf3347dbd4b39568da8baa4a01fa572c5fddefd701a5e4f40aef554f7686ef46bf039f4125522fad372a9aa56519923427a4d0860fe18930432b70801a4f3776b0f5bce030c0496d79767dba19c13f864c6eeb06c7225aacfd78f8bcdfee43deb5928d5ebe909e96e65bbcd8d97b55a757b07a1b684e973b7a7015d7716d9115ca1ae9e566be1c799208460d57e32a306d34e194f2a98ec9e5b07428b36b26fab50e77d88cea1db4dd3b11a0a3b067a9cb935652b365f1b656ddd8b1e2ab599c7663c53a2e2b8b4ecef620c85887ddb192febcc9268d1748b85f75968eb7f85ae417988852aa733d2b19a2d6655a5d30664ce9d5a119934fbdeeb77af1e0b8168b85a47aee3e707e122908559ba6ec0686d66869504b7868970ebad59ddc6162e4fa2529ae882fa137fdb7a26ba6b5fa45211098d769fcd1d9a9934e0322f480c412d226447168941e68d7751d9762f79908b01015d800a019f41913c4a9091b55388f6ed8696442175a3899979057985417c5513cde58065d980d0fa69fe76cfc4b9ace1e1c2e016fa93d2a53ec6c9e5b4ac3281e75af345fe007a3dbc2344a9582f0b91e88c42c3492540b1930bd9f8851c2ca6951d00afe3d2cc266e25e48cab5703107e06acc1a290862279abc7059c208cbe6f8340646a2c316b627b3806ad0f03e3da0adc13feca1126cce0ab618cbe6b57bfc5e7c126afecf4aaf3303676e4bbcb5a534314a1c0946984303909bc47ed013ffcecbf43dc1ef57fe608b3d9732cb8783c12ae2b2af1b34ce11d393f35a990a3c89afa883ed7a6bb3cdfa28104434e66b76fab9de3a71bb53c1376ab82152ecdd63036afb0407e28eb3cc87d359c41e38138361dfce88d3d1d1d6a84e7a50dcce8ed98cd3b91742a42a8637223b371e72f0cd9400ce888a1c5da9e82aa1fcdcca53a3bddb43aeabc936fcee8a509191b64e8a9adf5e16bdf057a23247b7b967110cc74a7fa0e203e860fa646c27ac6a69cbc881dfb0b5ccd4459dd74eeb7210cda657676f50bb4c09eba5df6040fd025e79396c2877dee9ada0b7332c4d2a129f12b80a7bee732db6394d74fe9623e99f7545de5b15db982a85e457180e61a2de5a0b74881c2644f63a9eb28f514d393dfc65ffaf3d7f9c9dd38481e83efc02ed2b1e0d3a48c0b1d3a8cf35df831c7d3fee6904888176a3830bc463aa30733eaabba29be4cbe15f33fc11b4cf99ee7b3420c5d60dd1fdef3341d7ecf29ce8928f0876d2cacc50be85157e495423c382a4bebdcf1e14168b9717aec1d8bc7a8a0d43761bce1d2acc466a955d516e52691e450ccc215a449ee6e410f02c4af2008730b80cf11796090185a9a32ee32749589bd8be14921f5da308f885f7a256e7675eb1268f1cfa7c2f6861b7420e67c6f39e91997a01cbcd8321e56f571a3097566079877478a4e57300f0cb9a929624ac3bf94dd1b020b8622660da99c9db42ba50ac335b68439a5b3f95c5896644e94af7ab3fe093e73e7b0dc4c43869a09bb4db107e6e4b64f2ec657105e1e748e26d685cfa2510751c99b6785040bd14984d704956936948e1e34714c4e99ad38ba5ea4ded49ae64bf38acca4668207fd7948850b93ac2e0227003ee11ef095ce4524529b60e9059057d0265cb2e253bf21704b5b83a2b93e1fb1e7d6773a32d8bf3325cddf4800a1a0552c34e3dbeb8e6d3f9aa103dce8c3747748d9bd2841bd01730bce7189604920b44986c2297da77dd873f3ec5c5fa2a91db214b81bcf4a6ee9ea26b7b7ecf7d08440b191783d21d894a7fec6fb6d8e8b0e001fd2125e097d2cfc18c0f870125ed9118c9c90c281a2085f6c6dfc5e76a5898460b486cc6d0a15370fea1b392f6f549b32ea73bf48defeb80c8a8380fafdfdb6ee14d33250284df289784666de8a3fd8dd66cf0a6740494bede834e764f52aa13f17695b90a1e359ae41c1eebab66461af2b68df7dc1b210bad147176b99c9044213e59294f3bb783b3750c4047a9a1338ca9998dd3bba62b2e434caecabab1050c72a7fb324009236c05bf55ecb2f7beb11b883faa75a48bb3bc8474377d4be68383091218761c4236ac1484dcddfe638af19deb79d8fb9c6563f08108bfc4e914e05faddb39f19bb55f34b310f9763d4308801ff29288f808db5e0aa43ad32c61e4eec92855422375f7d7fb6ad8bbe7ee162c5df4b975dfd3425b7217ccf4c278971d947f9f7e4e7f7a324795690a51e4335558b3d51ebd6901fff99bd20077fd7fc3110373b725ea5d079cd6bd122ca0894a3d7b10881163180ba5787b318432a5f92588c3bbf2416f0f0c15ef8aadb4321b4f2a694c3859224ed46292d822b6f04af930fde3a561c111827497170f017764c881ea562d0d864429becec6a47dbec3a36ca2b4fbbf5828d7c71db52d1b18c6461fa290bb33480d46f50c99d43cf58886fabb8060b12263612eacb278c1ca6f2f9472a1487c794179dc5905c3eef7df41b390e7bf38752e8c9b72061ef997e4bb67af06a9ac870c818398188e788cea629c4f41c69c340f0013ce2049c5ec2bcd8b90c878a56ddd4d451914353bb7b4aba67132cb27aa8bac32b0f9aeb7e97c1b2b45eb664aae8250ce52f6862abae4da210c31501b0a47371aa43d21befad1e39567adfd84bf54d1d3d8b59e7bbe22c3f6436077f580666fbb77217425f0cc522142b3690b1baca1af2f7106d47e11f05a09256429f073d6e2fb5cb16dd8802f7286986ad714c91ee9272afa39f6a532efb9a77a59e39ef9486ba6cc1f200f4b2ee5566a358748976ea7971ba2e767404238d586da014708f3aa8126cc58a35e760536bb56f3cc0fc23d13a0a684e6097529b7a5870880bb281bb0828445d6e6b293badb7cc691e0b58d51350fe78c1e59fe5a7369379a3bad949ba2fb658fecddbdf314520310de64e975951454c5d95767e410e637b91b95aeeb7e5c0bedd0105d4619628e9360018d9e24be387847a425816a3e37e5f34e9db7099c4b3dc8eb14dea6b66f9db8a355052222a81b757ab1bb33debe364db6bff2f151a19881b144dff92c3d346f3bdc8adc6d9b6e75da8d6ce5ed7300591ce7abb701fe3e1c3978be77ada9fa5d75a5916045945b8e6eb51ccce5c5cc7f107069b218a026195c545b1315597e5a5299bb72fe9e808e5a0ed4b600e0fb87d06d7faa6a48c40b63cd0188dea1d4f90030ae6a8117535b20dda9122e151e2f79207f770a76d7d61cd833c2c4816776dfc5f1bb6c3449c1864cc0bb0fdb229b954d2648f43953de270796dd1005bde13728d8a8182914a7003ecc886ef177e1409fae5750c8f364a9090935e777383728222242bf53a04ce13e60dc28e45ce095b224532de56f43bbdaced8b309aa468b2d33942ac9216252f5315b3ba222100af72cf21b72a2a6ea0baf617f191b1937108b2789058c2406985a32334a620f185df46e16aa0eee3dd80b7321e004dcc33d3684b55035b6b3e4c29a7b661fc53da525a5cf867e504e4e3bd19fe8c40dc433055707e26e2acd4f554d6259969990d333b93435193b811d84afe5991101bfcaf533e7b43804556cce0691700d48bafdbc0f388b65b1436eba729245d011f1ac886f87d75430f7d4ed1dbd7fe5aad226aab3b214b2f52c9d8c180372298ebcdf38cb0b8ffe95175207fade447120dba635e708b190c274394a8da95884c403d874712f0f95d2bc1de5ba41a0f6acaae2e111bd47ec018a7e37675ade92cd7d1b939045238099c474ad0c1358b442883c93baf97c1b8666e0e0c10bd8a43a95794bd4cf686d1d60f31b0241068957ad1ef72bc38a8aeb06633b47ea1618c449a382eaa4e84896662849c9d5f3b9e482411ec515039a2d8489947f65fd59042b1f8ca74a04a3e45ee8c8284ee1d01d0ea4471c9e55033266704e4a2cf2e4307ca78d0af4cf253756f2aa0cff8a723b41daeb4be702dbb491868c247bb0cb1836c14aee84b3ae45b440515f73c9bcd8505e72ba469b74a87a687baf8e7f6a17922cb6d18a5f1fcd5351935ecb269364da8c7021d3f8e5824be6850b00304dafee86a381d5f29a105a7071c223d55d336aac1eee275ead23c032a4be9f30c587cdba9358810754156fba753be18610c10845130ed45c99fb87922cab959608110a28c111dc8eac9b772ac19d293bf833e390cc3939a39f251b0c259a3522a9abfd5060bb48f4ace3f11535cb6b499dc7df4dc618c89fb0bf23172dafdf9da4aa76a63c7e234e1ee530223ef8b1c8d9434171c567a54eb22c4b4d48a8995fa9e5814519a2be2f79e713f2f018426424a674b9496a81a8e9a407bad3eb520deef42833ad27086eabd7e006e83ce9578f8fd8dfe21e7914f4dc9d4285ee41d28c4b093d3f811040110a7987255a0dafbcfc94a487eae4e40c3b1263fba60f9ac1524c243c67819acd8d5eee10e34b64d239dfb0305dcdd866d878df9805fa16509cfabd2a74930ad97caa54c159a75f6e2ec222d6472d124854bcf70531e0991beb6db79b710eef22bc31045869b36ed4e61e24d924e9aef32b100628a111ed0ba3a1d18267af8a79564cb8a5b046e10fdc755710574523075bc8d564dcd0e40c111ff0a87121a46333191e151ac9d5595e4aba9a694e501c00d687c25b4d4882eb0d95ac5c18f8fdf71ba43149a365315c3c0b956bad760bbaf3b1856d4e6f0c1085888f2d3cfc64c25bf3165659552e95658411695990f98fa5fe69afc3f1ad16ef0a12432b9a335cb7c35b7da1fed0a349bb4c539e26cc8a777823a35da97356eceb85e2023607d976c72e9251b8c99296437be1af38b13c80f1751e0713b8dce754230de470b5f0419a835a0a84bb88f3ab060fc357e1935d75c2297c9898c39123aacba44bc04f4c678a0afe8e97a02dbc415c14e3679268020034acec84ba10a2d8da5d86a44177d3acf1a408f18c7d0ee3a6e8d7c9d30424d791dbbc14153cdf4657753dc8dc5771e040f2791d8cee9e86271baabb332c801f23c2447815514b0a6f7f463d24d666c6776ca3dad39b72603fd1c2bd8dadff42adc36cd950fa48dc72e43a4139179beb79192f6dd303673c7ba53be40e3c00a9a2fe77cc7c7c9ae1826c4b161920bb0df0670560de9f59d8ffb77564b94934dcef9e350af6f469ae950540feb392f18e868099c76bb0f63414fc65363b01c469600c4559d450ff5cbb637795662b40714f3260fa99de7d6100997ebb7c473da8b6d34b393491dceac6701a095c7f38b41cc6b355a874231605b3dd155b766166c3c83649fdd031e669f11aaf75ded71b24e207ae3c8315fbc981b7ee4a8dd47a2e952695e6cbe1503c8218bd65841e1aa0ee3b10ffc8d052589782f72e5b461f0a8eb3db7c2c063e720f18924d7c042179e04f54a90ea64d2b03c259bc08dfb2e28536f4202c68b6af60177f812be885c57dcaeb74c3bbe9d8fdd60a1797046134f22c1002b0254f8a9d6459969a9080d2403e9a2bcca43bfecbd82b679b954963f7cf4b8f0fc2f6f377fa0de48268654c2d808b599cbd4339007874e467712a4d3f04dd7a5cfedefdec4861a3db729200ac8031877ad0763a76614ef9bb2ad524c5de50ebf830a1f006c216016586773cf8b831c3442bd8d7f584cf67faa7abf478531adf1fff184dc47f075c9ef3d7290966b2037f33b07e81fa84c5d3bf55f9edead8e81f350e7fdb7d29e1dbdfb4330324dbdc4e267c6f7b5df276d788de74dabba7aba3b300fe726ff2bebcf9f1dc051887656df1790a42f8ea16d993c8c0f2b152b773c74983d8cfc79a2ec59f91679a8135b601e69707ef46c144ee9dbeff729bb0045b44a1331329622458f936938bd23d9ecfe03b4b6ffa9c5f512b62b94a03c96b2d6c18c14c6b1fac5a02db6ded568210f593c268d998dd808618dd04ea340989fd3d0bdb761318c67fef79a4da150a15ec5edd22d1670058378095fc136b3ee45c0be86e11f2709994b35e231aa8476f961419b8ab6e557e74c65c6bda3be71b7b82ac3d33d8cfe82751f82981342e84e1f17b3ba1f9572324653203f190bf908b1dcaab9f4a9bc2ad601e62672af925d75ba4fedc0063fb2a446ff710f5709e37cb894bc9c707a1c8eb7a6fa1e27c4e6a2b4fe7bd63a84e34c14bb650bc60ffde13930fff892fae84d0f9defbf0eafd49f6a155f176ffc0baf7a1b04604ebc96a33be03e27ac9005f0aae91376c7a30b1540e3dfc226e6fd3c57e93b6841067bd04863d9994bb6338657f18eed98114d64d3348a88024b6bfac61d1941fc5be067549500e02737eaaf7026bee58d28934ad1eb2f6b1aeaaeab8d562f54129c58956db9d1fce005a96d4374c3f0f4399d0398b961a460c73a9d11e5c8a213ab653c6e808884f805b39025b6a6f3dad4b2d15a891c78176a93109e96481e14231b4d4b07fa24b2d11f8415207e252632454080fc3334ec51eec527b01a47fff68c82eb5da609ca670895c096fa6e64bed9da07c0a849aaebefdd0991a26003353a39b0c984c0d2988451034ff13a0865fa6562f24f95fcd9e1c53e399a9b5db33352c6079364df94ccdf870f7641aabc380917174a6961e982009c0c0513ebdf0ef88d8780c4ecd20afec8493208bdc6c0cdd9bda354e9a994f21c484cb4dd93e4c4b63e060a79c3cd5a666c4c714692e1de8f37480b8fc6a91e6b523ba62b8235a6e1fafb4da9fcb7235b51ac11d42a90aeef50a5ae24cad1dcdd43c8032877db3c333357eb8a97d736a3adafe4b44b59fdc3ab5597b763e37aaf53726cd60756afb6f47a39ac875ef8eefd6119f51ad8b6196542759d083c56018ef6d7ba32defbdc2dba1074fe4a157a3535b78482477940066b997e4f16af1ef36b35bad9cd906903ce6408a2ee0850806d0a697dd273c42192377af88166ce787feab1224293a2578343d29d7c9f4afa923a0e5681273fdb5090e48afedf58647c81f64a65ad52120458ea19ec9c853fa1127fbd910650a059b59fd14a0c22d97a5e66b5a4802f80c5283170c7bec5f301e5a8b651b4d0babd16c3505cce5dd3e8eecec413ae3eae3a1d945e47250c882b0411301e6ccab7123efce02c0900fb368bae50be2ea4396d6845f6998a598d1d6ef78400d89bcfab7df0b39adef89af690745d268d4dfc9508e653bee0c7badec19089e593d031c999c5b4d3411f5cb795cd7004cf99301f2eb552096c990b1728e7da4e5005061452052b99dd25fd96fba2214566215b05d40ee4003c7d838e9a3b270d366d5b7d7d089e38f0a58eb01a98ed72b2a5da8dc524ccddeee5e8d7c7f65342fa2eb32df0a0b2c11bb391825684c77420862c23cae9eb28de0dba9494a84a28c38ff300fb2494cb8b374166919a48af7afdf9b431d7dfc01bbb373301684af834ba81c84fdcbe70da436cac7c504b28d7292ec307bb1a9e39d7928e8d13246167ed8275727e6324f301dd375c6245ee67120310da47a0d243f8f58d666ad969a9b51fa4fcba30de5dbb35d7404eab8f2185182bca1b4bf88f7be3971b37a831bb0a9248d5558f9db37903ec422063a0b8ed3870a7a2247faa1df1053a25236b6414860162fd6002b58627c875e0f50eda9a6c84b094f8738a437cd81a52382995ecda7ac10583be26f43b16947c9d1d7abf42620a5b6c2e65370ed8ded884916bae80d07c5e1cd456f0c96490942414977c689892ee0c4968e2be708e7e960ac31e96bfb4106dfd8a7d2941cf1475d52de2040164f8bbf4655437260fdc6bea33eec4b526c366b8f1bd2afb8daed52ea63e99ee05b82d0c0ac6532a4b10916e9dcd07074a3a817df65bd4a3968c66ecebfb10981d8da46ce24da9d72f02353c17403dfbe59472db73a5776826e6cdf2f78bcc6b9bbf04078a955d16ececd241a11f6df4d63b2971ac16b5a6ef51bdb92e3a8866d907612bf47c3705a650d195c421ed911f69bcc34f97e1bb5e87163b64dcbe58fd7ed4edd626fc05eb79c0ea9d2bf095449282f79a4fbb19a6257437f192c905defabde5f94b9009d15ededf4a9f0f66e43bffe5023b69889f1c2fb95179d9e2ebd3fff454e8f77cf45249c009f43592497ce8565efc652b07c84923905e567c8594995cb153900788155632b9bd2803fc3a152431283332206b1be01e552147b7888cb24a74d11af914428aea690ab27f554595c0cb1ceadc002904a388dfe3d87815c83465a096838f9018f41c6f484848bad28e185d15baf047cdbfb5eb7958c48e63a4d7c106e9bd0b05e39000da0ce3f35f9e1f15c5998f88811ce9b6f17de37402ba48568ce2687dedb9d0eeafa285e0cbe37a3223994203a6243d16a0168714f82278e3f92b7b5d340a39008e72866f2d4af8830911eaf2077d1a347d8c9354895eb70356a105205eae0bc525ba672971446a902a202307425c6643578481bb2403bdd54e2b199b9abae7df86bdaf3b6db4f482212e821089a913873e0a6cee3761f61d6b4ea470d85c65fd9376a0d83a732d1bf349eec963af02be98d429f672011ed818051425f008982c75ca21c7f56b9b963bdc05d926d915b5037b8566cdf1f172d2aa572430cf452fb291206196db1cacf0bd6b3b8159c88d7eb5b028fe0de606903160f5e70bc551671de28ca4e8c0d6694fe81391f58d153f6476e892cc1d7c9f33108b88e52660c8823219db9a1ed03a488ddff3e1753a6a1d2c0f5acf9ec4cdbd1d510e9245cc4385312850f9bf944579ad8fc91ff4bf9001afff5853283c42e9c86daf821e3f306ce9b0999476f95da1cefbbc9f9e4dcb2f117cd7b0eb49c3d4df79fdc0d7ed522bf7fe9646975de9c769d288c4b4027de7547ce930dd4c3fe356284af18887cb4809afbc1667ab6142f42e9a19a691337f658c9bfe4c58f5b5e6cec2944c961643051a374b57cf1be656afab5f5117e745ef4802e3be8e0f0f177d4d8a8a0510dc0ab9601420e865151050ef9d3cec13f1b0cc0c7137a39d639e6bf54e49ac8e1f60f881c7cbf596032663eca3c7901c21c48193fc57382d24bd6f16f3dcf090b7e05b32dcb292924a8204efd401dd54e8c7ed078e89538562905ddb5579923e7e1b458005ec851072a02ab885923abb75dabee899f62d3ead959fdf63c540f01b55217fe9740cf158e59c01120ef87b7b91fb075e17361015e4a012919593f4f53f924a24723da4abcbdee3974c3104e142f06e6148354584d9e0b2e19690503dda690f79064bebf5c4251e137fc8f3d112f91483e210e154a974615b10c4c4eee12b79c0367a2d008261e78b8aa0027e0cd1c6b041e311e6ddfbc6bcc74a8d378d09115d850be266b6456143b01e64fd131b894ee2d2f16d1eed6a7fe5b594034f02f3722ebd6256a64e13e83fb15340cbd33485542380b8a0c62b52eb735494166caa0d7c6787f06b44a71a6a82e0dfccdb98a45d33d809e9070672ec015a49698077f4b31b72cfbe21052f4b62a75d7111ce3991c4e4a72785035b0c6e348b392a12a85eb0dc943332102a66ca5618290a443a10c54c9ea0f3f805febcc5022e8ac281cd9501bd5007ffe55cda9dea82b77b63e025e155377edd2ecb39ef95425e93381283f1f9ae053bbb966b937dcfb2442d24ca95d186603cc96d4c7f9b3e142c33a6c73a7c11d713aefb55f764f67e9b540be1682e8fd0b31bf021244a612340d154ea9b89eef5f29e070f8b92591b41cd4293a6b88b83b9aca108328c2310fc34915bb58fbbe86b8c31f17e4912213c346a869664019616069b30b85a743ac21690049884a231f4f2adcb96a0c806547c3055619a7470dc1cc0ed044f3f54344b873a552f9235c04fb29fd09ea24adecada248818ccad0805dae10bd7acb90fa89e2e76c2fd1b5cc2553446012ec1de13940b9243235273d8d9e9c9fa910796803a2d20614bfb4be0049530ceea3661e3fe3d6598b4087c1cca12e841f9bd90a43b2c55c7d93e66426190947539f2414cb1a5c01baaa87435cea65e00326581b6e44a06b1ab124020505f945a67d3a89159e0cacf678be4662764c2fe23223f61d9f8b688c8c50b8cd2bd3cd7e2ec7b312c462a3042379a50f11fd6825405d9cc1ac6110e388936f3a7bf3440716f00101019a30bb8453f680913fa7f91fc61854206a603df690e397cd3b23f2373f6e0e9781127734352ebed8c0eac9482b98991d9b4729dbf29bf25c5187c76f15731989a7eb36c3c02d56c03d75f2affca410b0df4abdd316ea3be260925de5ac33d9307af74a2a9d4731b80c14ccb4802e19d8b57b84f6838197960a5136f478c236f52f5468b635166837806ab1c98358663036a05947e621a509ad1709c0de6c1987bc4969b0c775ab67c26eb497557bbb6e90562c389c1e4a60c8868fb106bd5917c5e75be44ea0ce3564f8c3b96207b67daa96084f149b0ec809984572ca2ba6180c19a056041031d3bf4e5da00c801cb28c2eb7c03e47196d445f228487101af798f3cea52c0dddb82f9eb14bc12ad675160930bd27f32936981602cd1e1d97b193c305e36746b84595cf20e31a700f3cdaf5b5d4414ddc63aec5c24c27a672b339baa4b9996a3efa0e271d22a7e477a807f0c445aba8ea53546033df68b834bc97615ab638b8ba6236ea6f9e7d11d7487247e1e26b2af3e9d4e0884dc8e684df396b3fd64a03732bfbc12bf2f1b4884ab23b7104804b9dfdfce680e16efadefd0785b0071701c50221055b4d70ad7712d996b9eee31ca609afcdd2828507b49c5f7a69b73cce38a48065377e1009ee0173e3e8603ea040c973e69b610e4659cc06b3734f213a6020a79357a80e6191fc3e763d84e92241e9d449572e6c52cdef96c1edd52c17f63728073842d10054ff69472fe710f8dd60673d654444cffe90ab9d69139a69f2292f851f16648343674ae1f1be6cd89c2265ecf59b8b39a96afd1d7a9e5e6a0650d104d885dad8837adb31fe5250c15407f871dd46615e2d4a9fcaed60acc98f524f92e454c300f6724b7ebfa65197f794581017340d0ddf438efbc6d47227d46b04bdbcda7b8889ff3fd5bf4f4748fe6fd367ac4c489ab1ff70cfa71484be749fa817141ac7f6ff6f26c99b1916f1f96efc127111b01bc6130f20953425297af1014fb1e138b229011b32d0043079bfa1c3790ab4a538f61ae282f442df3e25cf03eb1edfab4eaf60ef1a7481b89003a5d5ca7aa86b7cd7fc6277dc43079f7a081334ff77d08c5f48d9e94b1b57187d7395dec2d886e1db820fb97021a234f48c060fef27add4331c9016c9829298699564c3e689b89776f1d5e6909a9b6b959b8c3349d3959e4ba5d4976b330381d2e8e3e63a368fa1e0b4acb66c7a19d46b4528c4a98bda482c3ba8da623c311fcfcfb2467aebbf9d8b2a39abfbfa7b5325f981266c26149ce17b38e37f27487d0624ba64aa8155dd9b625c87360311b143c0a66dfe29ed6def55ab209f85bae94eff404fdbc371fd8491d6f22cbf4e59e429bc1ca64f4e2aca6d1a00c22c42c31c9c7df2999f440e0e766cfda4184fb43dabca25f23b1d21e28abcd50ba918f9156da0c50b14c90bc8bd0482316d0393316888bd76db511b0618229d5e874cdcb652342418151dfc822b2b5adea072bb083c0766f77a630d41d5461905498aac9c53d62f8f4df66b19f13834aefd137af0dc8b977948f78e284a0304779f01f85d1d01f8a302675848b076a18d97b28e43901ee98cd138986cb3ca2c540355c4876df8c5803933110abc39e62e3d1993994ab44ad291408c5b7b9124c6dff42aacb3d64194c0099f738b12b02cd188618f1aa4bafe5c664d1928b8943e46ab1275471641e395c147aa783a54c9a348e5d227e588a1c60e0a837ac936216affa49971303957733b6772163e696411954619823fcab857c367580850a045198591c205c2536efaf186b65c913a2128cd4258d0cc9de47c22873f84694f36c7df882dfda7d84a7d68859eff7ec881cb99ba670a0aa58ed5fc41a706b6e6f9b6435c190caa2ad911e9ea3086c3a86e5aac0b09d020c9b34e93cd556783412eb1e5b9fb24b8f9cc34667674a67625aad7a25395a37ac08aba7344aeab35b013fed1997e06ffb2cf930f06cd5a026438c5b08f82bae7232bfa3c247d7d3212e11e5f6a8f0fb484aaaea7ad9319e5d9cd7b1992dd7c75628ba291e4fc08afac03c1636b1470237f0c9c0f2b68f4720d8a8ae98975a913f6a4dbcd1e18e7706a473162a4e9d36f85cb0a833f753fa4b88ba8a35585e99d94e6571cadae5cb466f23c620d9ab4998bd29c0032ea5813cb55e9d9bae391a769c9d22c5627628f28d1d03e17c7d63e6c0f103c948fcc1da2d8b05fafe30cd26aa7efa9f23ded9ca0350270ec8705ca6dbf9525fd1247c98fc556624b2d1b126387fd7c1966f2561b3daf9aef71e60012871822d0e80f8794cbfe954afe2a4e091fc556e2963a3724c48ef97d294e09dfc52ffdb3295d80875cd8a0dcd85f79c9afc494fc69624533d8b90e7709a9b4c7c6bd79915436e2072126245472f8a8d64918ffd26428e225a70b9755266f727fa4720ad1435b05f33b29dd388af706e93cbceaef9ffc4f8ee37a78176c308bfab8db5cbf0f1251fcdf4ec5eee7d32da049acf555b53159133a4d0635f9d0f01fd724323388ff3a12f7ae1fcb990142dfc3a0962386415a064cf88c4f0a4f113981cdc4bad08876687025947d6c18eb419d9d1cf7660557631ef8a474b0ddaf90b1f7e7de57287ad8efe517254b08ab3d8dd15aa2e95ff1af0127ccb378f796df1e2c905274adc2034605827e140c7fdb4dab4e7404eb065d464d2d563724bcb8276f7f7a57e883f9ce4be2ad19c84a47a50b80a5b33f2030b8451ce82beb85b325c50f3b9e21d93fa0cb1fde12afe467e24bf9316229a003e7940893cd4577064a1a0572f7961aff47be3980bbf1f2d40c389556b8538a58f1c9e4559e7c4308240f9e4702e9607604db6ceb1f38a4efa80125c454ca9075044bc435b08540f1046f60b7e045613b9403ca99c21a1b0e2b2ea72e25d14148ca19930ff2e678c77ab3a43b9912781d971e16ff627e4014b9ed92eabfe90145b83d2143ee6f8aa03bb8ea68dcf67f86e08b02f2ebab699d754c931b70637eb6340a318f15d0551b470b9dec244f9996991e0a39cb2581230d14316b827ae0321b38fbda6dfa80f46feacea052397e13757255b72025a69668a24968f33361551cd3d1d13ace7a0674d7e02256def764032006282899da1fa504c15f3eb296b32530dd22ccd7593c923aa26c692e69bcb065a1286ea54582f0b7bef8d0fc32b6a3eb8ad7aa57612f87b356cf8f6d451811a69bf20d375cdee93c34eff5533b1fdac491ffdf117e4f2fe18b58253f116fa50a2c25cdc5cc9f71f3d087c9424f44c5a88e5ec568a89ae58705605e69f3413fa57d946194448358144a4da86960e1231820b56a4a84d8731fd02b3965ca19882d8888d2eb5331257f13b7447ee0c0de4eecb5b92a5d3a86da7265c464dc79e614633ef493f602ea67b153897817e88c98801ea7bf4f93601a426e9463c43dffe37ae1337b90813dbc957630588f454be387c5a5606e0c144d2d356ebc4ea5c194a3181f855ba91a8aa5a07aa26c830b8b702d1fad3808d810c71b87ba7c2c053da1c36ba565c15e98fdb25b20f44c6ee3b2ae81ceca5548900f0ec835eb6c256f9fad9aa70295226a9eaafb99dcafd0f7b71cc5b877d922360d6cfa1dbab06ebd738d9229b106b23014db099c673ce2d98ed30d6277cec97ec582078673f6987f82c79c6ca071e56eecd682ae93351a9b593e051c6252d2b874ae896ede97caf7944ac140d11f32b4c4039a134954b7a5d1ed2242f21c2a24f7ab8a57c79cd19cf0bb5cda85d3394e66112afe3efe3f2862375ae6818f2723b7484616090de8d8207664f9d44a2148474558c24d188441cde73dac145f1670fb59144ae28462cd07df39c34b0d071d7dc0ea38791f11d505f439ae6ba9f47d28eb9ff486b10ca8d54c309b632cc6e52c4b6100a363f7a920ed51b87d5444e83bb720ae5530e0004d7ffae79d72cc26b48a5038a041c1d9d00334f00509336ea8fc883cfa89f41b2782206e97a69cebd29c97b0fd6d15fee7b938be96d265be5c8aa4a3424a112ff4724bc2a3761c458c0482d69190fd95752035053885ee42d8449cf1e0d399e658270410a338049807dcecdd1850ff26b6495985e45d4c8fabd77cc45c9cff8dcec49c7234eb376204ec5c98f074cfc5e6a670800387cdc93d1323f3be0ec18cee472f144b5023c6557e1a25182bcc2b0fe5d1be9f79037b780277d6583a82c284cc689939c50f993a5c3c394cc311f75ec82d5ec6714490e2b93abdaa5247c9ae1cd13f5ca132900a4704b212797177860370c112d61cdd8dceb2ba18a00efe7e1a7d2deebe2f91269b4386927ecaf5ba5cff378a30860d3dc2bdf87e980df9323daafa86befbc7e63e026758260b9b9ba693d5b3940d4bf706f9893fba456b5a2eefa4ee961664587b972b7824148d6993d567d571c1807645494274cffe77ec2e9b9e3b50246960285a0b08cf0aca0a66fcf93a6c9f9db59670798874b3a3009d85d9f77f53106624a98ebe956cadb5c0584fdbf47de69fcb8c19ad25900629504db0fdd27dbde37a98e4dbf947c7e2e83c743a040297428364858d6f30df75733745d1e18dc23680620dd3656b5af98dcb7a802e61a268020e21fed93245ad910886de0fcadda4422e9d2cb50af97fe4ad8808b4f0456d42d3a7fac8b58ded636db2933807d1f421e7c9dba7fcd1fe9ea00925bf437c66e764df825d5d7efbc32f328c42240f8d844d0ee9e5497089756b985c420cd1ea0223ca67f5de100685222ade4ce78bdf252284cef4e92db4595c6433316ee62324727558cc266731a3d5862588b6e78d93b3befdfa6bd1cc9083d135716ed6bd50d3c583620274d91dba5c7c786ebb1aa8d324e399bc8e6fc8314fcfa086e2a137f49d756b52b940d3d2aa4fbf1d5a74e409431d82f6beeea11b006facb78717ecce19618816abfca172dc6c7e1e2ff5f20ef24e8d68138715a237c1f87dcdf746e9dbfbc7d41363b974f569765efbae622168a243af513ff310fe771b80dbc7cd18ab89f3ff93d72c25193c158855be97868d94157dd66c380c9e0785a1e7735ae6f4888a92f1cc48c06b9ee554923c88f634a17fc1ba70a0863b2177e9be381a66a43abc33a0d686a30c837d07f2394a4d05cfc22ecdcf626599d25e9fc9e1c68b8e5d67667a3265348ad525835e682477b5ee7038a11e3941f5e9f5ba21cd3152447e727d089c553448d0798414c1f27222121d3528f095992613f50af4928f45cc73d198300f39a20e5eb8ea2dbb8d1e8d68ffd7873cfdaa4f0d96451406fa104de9144c32ac3c4b963373f08fe77e3cacd5e8d2e153a3a26c68681ee18a4ff5dfc0d4dca6df77e6413dbf079d803cfd9396dfe4b6a44ea5a79724039775093f4aab91e7499ef47f126549ae61d0705a03b7c9d16a5a7a4bfa156de1e81bb4c5e67277be943530b9d665bd5b70c3c81e72f45343c77eb9023107e6807f0d3a34bc44274ee4fc4c9643b1255d9923a4a5574fbb41149407e2e29e0db12dcb5a3e11ce4408fee5ca271383f1c851d36a847ebaa2c944324cfc25390be42715840a18f97696732d5f4fc61d44f58864aa2106f856ab850bdaf9348ad22209d74ed00e8c94329ba826c952de57361183a1d0ecce09c36533b2d914893267f96532c38db7198404cd4093ac204eade12c5803aabd49bc2361301ae13c9be29cee1eae6cb108b0efd90e0b4f02a0302b95c01c1e4aea972cd7b76558b409abac5c82df7bec47c4c7289f066679f35ab6cc08eb277e0fbfdc6b3b9474a871121cff6c0e0d3090deab0b01233e51052e4a780f5819b69ab859f024b080c397440e0aae9278410d0bb6761c9f8816d9f02968effc164ff617684a5483bdf49a9e411133ebd041ae1515b39bbe81bdaf4d137038025db234c0c01babce4a36493448ecdfe73fc475a858450d4a1d6bb8eb262b733239bee7d16fcb0a237106da89f1c9d536be88b1e6a9b876b68525c4be45122c70dfb3a70618153e8b96f423d24a353cea753bba5fd232fa490f980523ff298d0f12321e58ff6e3e8cecbcdd4d513e06aa9001102c03bda52caf5f0e9c678c86fe65e3516f470cf1b02eb6508123483cdba10bcd38af4d31e200631a3d0e61a681191736dbf805067ba4a9b624af47a0dbf517af1593338c7ebf9071d9aa322bb509e53d1dcd4e35d49b899441a397ec750ccba65aa0465d8a5f86ab968f0fdd3a2945977dd9056974c2542ec1cf666731d23edf290fdfec1a9608f9a464bea814c78f3a59251c2605078b53ba9ca633416c4df27d5ecf8c3458b6a9c3365e1f55b526d0017d8426b390c3921cfe7743416136bc83f9bcc2ceab55a40ca4866f315df931773ff6cfeb1f839d739f6129069f44f3de0a9a508a3701e8e98a47d57d2ef27a8b600a85eee5cf64ec48ad3921a58ed8e0c76553ebfbba72bdd2fc50ee1899143466c8a1655812dff3e5113e00381d7ae934df815fe00e40e3161bc34ee862603b2fcef673f1b3feb372255e726a5ba8c8b8d28e199058b4ab8129b358474b57d46db2bae7a8eb408c08871ef7f1a750e7e6e9dc2c6547f6f3e094a4c55b0579feaa7d14775a250a9ba239902507f86709b900951ae7835e199defe007bc3d58644028e71577f3b1ffdfbf58d8243fb92a0214beff36ac4459d4cf0660548df71feadcd988f050e95efe70726e3fcdcd52eec8761efc925afc5591c94b8d8ff2ceab446153928359e602f1242307a8a2e278d05ba3fb8efca007468bcc28f53c31ee3ed6dfdb171b9fe695af568c82361e036b69abcac11c0c54c8cee557d1279132d88f18f961a61d4eca9edfc472262ade6799572f42339557a96ab959c23bbbba1ae5cad8b5f23f34f8b27a41a66134997f2eb07eecedf89ab9ba29cec4be85df3028b298f9aba64fd7d78c6890a2d39d5b21489b8dd8970b81a82c8c00f1f7f7fca78fc1edfddf8153ee36bf00477b59b9bc8d0d3f5b61ae987e10091a4b0b2e8e99b3e4d14603b2a0c50e8f1b16e649d968ffccc243f24656ca0980f23e44abf999b3038b98955cc72023fd2e3854eefd8715da0570f8bc8160045f4bb77b0563a081dc3a432d323e6c121e9840ca7483925a8b40a0706b20f2572feab1a8095be04b2e1a8ba1fb083160e6b8fad978d9f3695ef8b52d966c577b5c07c49de83fed0f691bb89186632474f8f62073e60a8d27c952372d9034db2a8e206d8a9827fcea0197952326fbd6fb9782259db546339050f9f0f90a0ea9d32e3d60f50f7d37d6e7d427b8f68d31e5c1c38c47b72feb33332b436e5538a8b8bcc4b90e6ef8d5080a0a4601ef8df86a23c537af51cd835f5e4939369dd54a49c152ceb15c0e5a7a9c1cf7be9b48009ec9bd24246bbdc64c5a66f6cc6c91bc267d5d2b466e6921b0bcec2bb91db93a7ed671c230b98c4c3649a6ccbcf655c58ba578b43637af9a58248c45e734cc93eb12ef77b70bb6d33e57cd255788d4a4540c7f6f57a9ba6dd2123d3f4dd94d0f68e25c562932859d2bdd17b64b030a8ba2fcad66bbaffdb458a488d7be332b1a6294df3bc69b58a72a5fc7cf90ccda823f453298d82d7e3f03361a4ff752737f31a4a00b853f4b95b413031bb711445316fc8ed35ae649d903af96113791c32c4b03fe49fe3f41a9646b247cf9601cfaed8973e76e56626227fca9d99bee2aea0303104eb8e6f4dda380ecde236042f090e2d0612570ec54e8f8dbac28f547805d469496f53bdf02f4d30a9b78592532f6431a9af90be5a4ab58dbef5904c21a869af4413ad46e854d52092ea9b5ab119bb93dd3a2c99f4fb5d83c96eb8464f34e69a9b0a03fc287e6a58de4491e38e91fe01ce0784c4c40941703a7ef65b912725f825a61c187c958018fdc6993bd46ae8f48eba993d587206ce26ba178cb01baa07bd1028c90241a0c9d4ce9c3ff7ca0ade354ea1f3be8650e3e8724e802cccf0cd782cf5cfe5404d74347fed04b0e86c9a9a9e3003a548f29f4ab7130832cc2005cedc8251e43e8f5d68914e89f868b5f590eedcc1084c98361df5923deb80796530c9734c3a575e383e03e076eec1e591c0a203fc45f2a0257074563db7a292ec3ad095b77170360982670198e32b285574744e63cd167ccd02956793aeb4d0326144e9261a764c66c199ca7a9b9f0cce30f8f2db44d5cb1e1a0794d8436c2d90024d2f73878a6914a43f6bb097612eafbe29e5268e77c65baf58b2f2ef84997877e8506aba89e8468a067783a248327c1258e9c99a77072cc571d9f87c937f2082ebb42f4e2e6c88c76ab8273c0c8ccb7af6f99ba872153bfd0a626540d96ea986e6c47cfc14b2db48d7af843177261b5c92d45d27d79587d4776b7ec9898b9159b7e77cf5b16dac36ed7a449968df30bedda41caaf42654c385dee087af73c1e41f769400d14c903469b6e27b934e323fdd37b49e954a226ab29d9154b5ffcf0b4f6153bd4d2a76ec3d70633dc9b43c8b49203ed9621a40d7f2a1645be1254206a2219ed0db2d440137e28b2235cde0cbd1a5291ff6cb2fc9f299d7270047120d1e1b7a4a78a71a6e11cbaf7cf723a67009d56d01a316bd62d3b08029f3169b9dfd86dc2989d23ed022e6142b44a691005ad58700e9b48a0d610b9d9963819b4c6e3741ccd011d4e38ebffc64acd8c371845a5ed02d1a6665db34943dfe9202701e906366827723c36a68c803597f021f6801a0275374ecfe611137ddad039c5f3705b7710a21e78896dc8a93f20f24f39cae9ba05c2154801872444e0dc52c29f3607891078cffef0e50aa08a0f71f167a8db3cf78aea49f8809750936fc5a0230f693a5ee689a186ffe953ee2abb1029046a7066afa05f367961751ee8aef11c29870225977806af14a1eefe851231ee2be381c1d69d112645f8be5ce1749a0a736fd0070a44bfd07402a1b302556eb31f161d2e12430906e4431529e0ab07a7c48344a7154811920901b57bdd239bc2192ef1cd974dfccf221def7897208df0a334c9e1b2223bfdc09530979a357fda328b598631252ebbc8864ae6bceb3505d7207fb6dd7c3fca44f45e4bc96b8662d38285fadd4399d7da6c75104229d9eb9c0e1b83025b911dfdff4a8c18a11a826707473bf11c97b87ec8da7c2908dbff6326cad6e7bd8aa49dfdd0a8b81a1b275480cc6380501db1915a4a336f80ba4c804a2972c50961e3c1e4901392eb5431335a67601483d762dd34874f125c5dd79075416d3131794fe96ce0cc2183bc3867de88eb1f196f257ae95a8712978657d0cf5b59db8e969340877a12a85e27c06902a70323ccfe94809e4acbee1b4a95f6530e06b60a20f610d8dc703d68a04803d46820e09aaf4e3e54f4c4dc3eaab9f2d34b84ba9f9e2fd54f0730ce440d70b0953acf45ac87f4a1a5cd90dca5c9bb34f0bacc8b44000aa63696c53dda6a337b1f04716cab5b9fdc4f869de648607cf727b0ce192b043ec87a85097702ad99b5f11d463b7f1fd5834db64ceed80f8164b4b98b8bba725945731388d78c43e704498221b71eb74bae23da2196ce727759f3f4971bd0cf3aaf5715221cc0d75a10c6511c8478ca6acdb1f7f4aa24cb406c7b1c35c9f603cd89c99a72b84910cdd7701f667df8fc6447f794b7bb18105f265fdc8b288e75fa2811ef9ede0436abb56963836d8d09fcf3cac0a07a1fe6d0f2810355c7ef451c022da69b36aff0bbd3ccf833c56ae8e2f3fe06aad1eaca2b3468e25787fbf68f7963a593919e791e0d50c4eac957a5e329bb34e7e387ea71fbd268c988c2778151c7032a34793b71910d1469d81e0e0740ce0cf8d6018611d80c5ac8a18b4965cfbcf57a0e34f7aef905e5742074df2d778056e8a3a303653a744cc00f091002c43034f4d69cea3a7a9a384fec3d5fafc1a7a371997d876bf9a225271b6b933daa99b9f20fa8e62c2a1e82f29e49bf3f3134b3615de2a9de7586b70471df60bc25508795197cdac516d862fba8cc7521ddac42d63164afe41472ca5d93c7ade65a2734c96267de9832503ddb260119c6bb5243915a93ec69c8af1ce280442bb76fb36eba45bdc471aaedd4bd0185f23e31689487011cd8d6e5d18e20551f03b799de5edeb5e765e0d971b7658991f19de1c1e42074a1747c070b68cbb4a380a42e47656e359bba0ecd53808d5fc9cc268b099f6827c9a801ce3f600a682ffbde5f3a1b03711340c7ce7b9aee3f913798b28bdead2a8591cf4cc84204da3283769a414da31234c32beec98aea967590e8a410b08421a3504ffca29f24324d235452a20cb74657960824a7d96bc8d2971ed03a293a78529a30af9648481325d5049ebdeac26b4f44c6303a959a58c76671bc4db57f2ef9cb4623e14b647d03101bb65435ff1c47a4813a79822b8862793d5812df98c06464afdb38b18cc060636219ee8c9d164a6a0c77aa31e14ac8daac9e0c8f6963a2720b2b712ec2e8a64ed6071a4511c32ac6c15994a86e8a0d898755c92f9bbbf45a5a4157319e05d86c9835118cfb9a94b2ff92093fd242914a91cd5dc899a1ea9a085d7eb99cb67d41c1525b29953c03c4f9bf5dcc449630c2a50475d65d94558fa9da17e35a4c005961037da30c5b5d9e7aedf90ae5a29251a3a07c4cb84f0f29727bf1fe65dd34bbe263425e5395f1ef2e53074e28b7146f6336b3158d8dc8ac4565270aabe85845c922027691b38b889d48d644b229821dd1ac8b664d045bd1588aca4a1496a26715198ba8acb62e19e1a018979d6b7b635a98ad0a54296521fcab4b63076371748851331c8a3d6fa938c11b43e2d14998a44d08fb588350e9ec79aa1f52114c3e938370556e73fcf0e43bc579f958c3d8fc2e39e1690e739db1862753c0a3bd1a1ecc4376c3c62ea43b7d27180520d7f73b972beef95c91f7064ca115f3973439f500b33376f13da1aef668802ded2e5c14ad3b4f3530081552b41dcd1f82ff05ca7380f50857a663394d85b0d6daf6dd25b4813ca35b3f2549134471d31f7ebbb2b1609aabcf0566509b719ba41d5ab247dd4b40ec96bab0f98038282df7e377b24194c0a642152087a9e1843cd93952f0b138ddcac8e73434bd16921e8c81f8bd5199dfac791639eaacf15e3928f33f2b570c0fcbd5fd0e94451daf96252da859528a3e358442abf6fbc6e499559297e1e49a3c1337319b0dac3ccb9b1efe2b63a72368ba2bcaa3000e2ad05d9087a2f215de1274011bbcb00f464425382c778a9c050edae4c4e3b304888e73c7dde1e6542adc5b8900d30e0e10753533957dd14cadabd382ecc7c11cfeeef693400e10e5aa41875410adb2ae6668d4febbdf07e72ed9d6740aedb10403f0de6a33763099194d00d1a45b8c706863cbd2ab65836d86342bb1f972d92675fcc60e35c6f2750bb8de4b1d9a447104a5008174fefa4c3fbc1ce71c1ad0af1896f0c7565697d38435becd43f730da02686387ca7565595259836550338ffdf8349736da6872ef485ed0b4781ec84dbebfe2f8a62d0022290b1ef4f80b9b529af25104e429110c2d5e7e08e6a6e3ba6d840aed7dd822acea4d6d1548dc151bedbe003e17f86aa88fbf57cfb3a134a53207724337fa045d9e34c73f7bb1db5b8338a92072ed6d0861d88d13f7df22529185069fc4d69bdc3c869a13062bbf28562eb300511fbf9655c42c0e409ca41b03b596956b712a79938e6550898103ea306c6d6e919ef3d1fdd2fb5380e3a3202688242b43c7da93c5355b2f61694e20d5fc67b55f4e90d432198f0c4b9aaf6f6eef6a8fc040a8482a9ca806a78e4cf0cd49d5f2d25653566996d64745e7dcc2d29a6ffd470554b5d004583d0267cd52e1a442f5a8ed617f000a9d1234d3059cacc1b6a984047ba721ae110c24182bc77a056103e2589c1399df8ae2668f6296e89d24ed53e8f0401544ceabde0d1da191d1be06db5bc9b2c4f4ebdb62dd89ce915502d17af5bcd67f3012da5bcb6ea64f82290e7739ea3c252348225f9a709ef2a182575a39e2a53ebfb4261883176fbeb0ef290314aed9178d2f513a4229a9ce9e32515925de8eda0dbdcab242ea2db140b9127b3050376fa2a98358f935e1bb72b086a98b97b7c2fa76a6844965ee6c656f00a7345785dbfa25f729fc8145ce189872d761ce1d443091864c7c78a565c55fc08244242c6d337b04692232842078e0a1dd2ab705a93fa231eb514e27b7e0ff0aeaaeb634442ca70fcdab1d604182db3e04084125bfa77a769f7ba55352caffaed08013c5c3a242ab09e36c6cd89a1e8c7705a3203e3105d3cc1d306b7b04c8b6ae3d4ab4af08841db5dac0ff2ce0e3b3afcb74fe9377403fdb45207b7d7f2a407e244c565d11f35d22aa0b0b78c9dffee60abfa672adb3194c16f7f76a9bffc59da85ddb0905a7f39356a19a2acb19f837774f40810b402b74af188214307c25c5f968902ba66b4e810b465e3f2939a255a397720bab049688faae5cb3aff095d0f78e7c9f67559a0a9ff75056fa4976a072b4c38b181634bd39f0ac3b6d4fdbfa49f978fdb19e11499af4e99aaf707e129b15693635160e337098897b5a63483c97b130d6a0f76d23af8cd682ecca6a32ee25b1765cbe816d42f501db64198786d3b92d48fc772f310b27fc42ee4cc959fa7dfa4433957fdd9fb02b91cf18d6110193f729d640d07c4cf8baaff1cb40613cb02928c0fa931700423bf95b26d6da198a6c0d50b9a64d91ce835404f88a6791c4e7d6a7f88ca425d8dab70f46979ce360e8e269641c845567d5c8ddf77058674c58dcb2d7b95d5511c207a8898c89a9837d898cbdc470e00c2cae0a831472440b7bf521617053cf0b44d5908e1c8b5a047b10a74408320c8eebbe79a421190a00f06b39cea4d6f44ff16a17cfd91f22b80d4e5c552e6a57a8e91ef5b94adb9e0922c67beb833db985e88ce7a38b1754daa3615bbcea9dd95c14f6684dd8d233af50c46a5fe45a60bc39183f091f48e94242144561a20b335324a6e8ab5a4bb57b0b65b7da16bfe0c01f0809dc2c9c051565285205b889611229e025ccc6fae02602c9ef361aaed90b247f92d60a39494166b7f86005ba5228138fe6cabe1e1bd3b369d3243ca29c3c17331a243f67bf7606895be07ea75202f8d1f176bd784fc8387372f4da482f2ddd8982e4e4b9a9af12b008066681ac20a162718da989d8cdd9d54fdee2e91ac46116264777c94399aecd2606563a8a2d03a3bf65bb6a0dd30615c322c475464c612880f40defb013bb5f2a2ae941fc0ebdab5f108ea20797b2eb589bd0a1bd670f424602cba45d7e165ca5b3952992c55529acc53fd811089828f1a452e2c15ebf4518689383c7902fd798259e2748120f362689bb9c2399859878eb4ced5092a0279b15a94f380878c3aaeec4a518f4c69435e890ba88de14f92643de58e9d994566af99a05d63769c54de3f7bfc4c66e5f91023fd227d7a102b2157725ba0a8f8687254348d84606105df3e017052053343cd1330044f7c3d5e54f56401e5171baa33f38296937a8723029fd6e125bd2239e4d7de1fece531bca8a0366c8c1453310515c3d34c1ab7c8a25b824748bbdd8121b41a6fb49b751bc4e2cd26a597553a8dd0c280001c34d8499997b137437f03205aec3957bc4ea2c2e447f73048d7971c5225ffe6e287eecc55e87b2f493e08e68e597861641a01598d4d7be4c38bfd70f436875ee344d2bc707b05a0ff4fa8f2825ce0d171650814c8a733e7fd4ac7874b68c7b978cd3371f7ed1b98c53024e9a2995d2c27a8bd7634ec7f728952ff6d0c8cb56593268c0d648b4f0abc9457374cf95975be7f35b3e2080cbb57c15006bf91e3970291ad6d5c5ee6cc9b04f46aa14f2411eec749930ae9dd9b6be0541b7260a9b78a37af0a4e9c6d567026da8b6f2d07f7492e4f1ef86476417f6d007b2bd453e4fb3274bf7c5ca898692eba562de73b345c8fc223fec48a461bed38eef92d86fa35c9a8f39d3ccdb0c54262b28b0ba40316b01e788c3b82de39d090a45188b34b9480c8163e7cabe45070ec42bb46c0128281e30c53961f66d84098a5fa0b5de90af261c674d5bdf6ef8f76fb040c70a2970bb56aa2e8052c02b74f04a9e9001c5065c8aa0f5775313bdb0fe74fc2ea7d913d64853c67a265c174dcdc5640aad4092292cd83dd3e1e27fd4d1fdd96a658eb11f546f80c393df13239f6b818f73239f0c7102d03e56a2aad9bf22f8883e399262b07c74bd1e3bdd59a468070f557de806b74d31ac95df8c91cf1932603d78dbc56558549be2118070e54fb58564f2fdd6cb9c81e79a2addacf3ceed1c13a07e8e88079060a434aec30c47f83b3b26d4f5c1cb198a722a13a10513cbd9b1a2adcae1481da7187ba4217034515b3ad006c364089fa989161eeca1262f6cfd2de1402409d1a1c720c03f7e949586a0b46a3a4bfe83a64b51f7afdec04fea5acfeb48f28a9e6f432e945633f240d6c8e96ad2d82185634ea15d4b9e8b055cf4a74331cc5d652be8986ae89acd266b8ab273f272c60554815cfdc5819729407b9a13327eca4842553af9125b6b2fd5a04dd6295b9a254530e07d05c0c789890dcd2ba0923cc8dca3ece6fa241747dd4fe09e712b57133db7ca9765a8a87980396b0f0c1b42ea36ef98b3f9a2bf09d880e16ba7fae3e8055f59b5eced301980a8f2af0fc9a83f1441b8e90f5024883818571ca5aa91f525b12cb858ddbfa853fb59e91885563296874577f776c1886a608c65a81da3231ef72329f7031dccd00cba0e32c8a019b2e056e6540a3f32381fbd819390be610accba9467b1a3971fe0e804b3d539118d4cd836898c3b70e494136898bf11f3c94365175be9589023c7d8d858ef9b55dd66ada462ae1b5a4b6e779d84105fd8abc287fcfb752ca25ddb3a8720ff58dc71a185a8f074f7d7932c465946c3d68648b06a2f8d44690eaa6f49e26b91f4217265c4c1cb4e925ab358262e5698197ae6fafb9b91e6fca1217dbdf41a8b3ad8a3c418caa0580a199a32b3e4da31b53ae5b1c5da6c3ad3fad374d2b22aab678a7c01f67dbb242f69253eccf46b58d5be72b949ea754903a57ee582fdcb034d943ecbcc976b8414ba5924ac3c58345325661693ebe4e390f31e6196e4a36fc7967859db1a5275d9b216291c8850978491373f9c885a0974599f17d1e22e97f6cf532ba74266a73f4c71914839dbd72cb118011df5f21ea8ec2ca31cf1e5de23c8afa316c9b45565a72d0e8b494671e78fa0faf9b71e6821f42c8931d0dba62c38bd0fead6ee568c78f04e4b467bc15dee00bf38d72cb3871d8c0a83fcb9befaa1780c05534be4e872599fb9c3cb66148689f65a0df06d527b4cf490aa67a41959e9ecd7fcbdd15e46c8d38a563a2493a7af282a0da566872a317feccf9f9ed350369e798fd5e488ebf61cd47b4610150298005e5cbeec5791ff4f466498a1c62c5861baae0ee339da259f83a5240c2fedbaad2491317c7f938135bda2618aadfaf67c44216b082e52bc7d24ea9733f795189ff43f193951e84d9d036a68ff044902736b51d18e7e1ff0e4c5a68364ce89cfd1fb32a5b08673fb1cdeba99f18425fa521e667074a241d893414dc2a161b78d4eb00b7787c618c5591efbbcffd36e2643a1efe2836a68c4d2b0dd04370dca771c78e542a91c05bff0ea526ed712ed6f0849a1c7cb3e7701e7b8094403cf5a7a18c49d3994fb782b7d0cfc11935fe3867db918b7fd8112f0ffba53f3cb1ea124fc33d01a6e20e6e267c4ddf839e78804baf2820cced5786ca05116924964c88d18de93901aa384cf9f04d37a4b0003b21f86a43ad32d9e09a289e44ed7cb7d286aae9e24ca3e59594a92b2e062891a01f9c43253b1b69a5d62412845890549697b20b7e1953a2b2de9f3baf8246ee029323fca6b11916ab6e38db3b4a5a032c981023d4af516df88a7d7cff9b9d0bf5892a21e0841f5cc9342e7df890eec52541481a489f67c5b903d54ee4646364371350155676b252b42c07776124444ded9766862660a39bb05f2fa2193c6b1dcbb25e4a243508c5f7072f436c081859f0c464811805b9810bfa675e80f2310896538a450332f6600864c79e48e80e996397934880b46051bea4a5112826d7471e8f34b349fd0b35f35732f8ce31be764e84e0c3d31c5e66bce71af34918acc82a25f1bacae5cc6836ff437c7e0e2b6662b407b4584e2a9d9384b4c5b704936aa924413eb48aecdbd1c519a2fbf09b262c954c0b7c9fb4c33eab2b61732cefd11e28f72b6e559804eb87e1c88f396b351d19cd0ac34896c74ef92c2387b4c109fc3c4c063d726576b4bbf9e17e7507c45318ffaf0c4fe9f83b7845c035fc756153fa4e71359dd49149e23c5406467ad3ae01a0291c425e39a2be327a52455b2c5224263f4b6d22e97455e0376d6d22f7b22be591c6eefb3b04dd119bce20f0c2521df792dd0a288a76dc12a6f3fd2b4f9518c368f1883c70fa1168c78a6d1568948262b26bbe9383a79ce6f9d55f10d8c7e44e2e41373ca75748c06cefb972a2e1e2ea64e5a137edf061a78bfcb62318a25bc352015854a5f4b53bd40ee1a5a11eb56079345535368556fd361e410008c6c991497900c0eae7312fd0840520b5f6c63a4af8a5c7c40ea19c8000ed4442db25893e1f445d93bcb3cc621c29e86c39a57a017e25f75195593dbc2536a021b4c9ff9040bcd179c62ea5c55adfd0760e84f03db0e5dacd8437d1daff8983ca13564346035e8def45d9a2e1781ef3842f7c5037ec25fceb59733b99f38d7de4cff564501c2bfe53e51b37eb5756ab3d75ad030bd516d4c0b5c15c855aec4a3f671bcd18480dbefbe77d8546a3ef6b0d667ba0b074aa403544ccbef9d32bf1749213c16f78533cd0c1f1ff08ed6b8202ce347aa1050eaa42dd743d911108572be22669d7cf5beadb1f02c75da65c250aa970f4761ceff72d4e40f1f7028f61bab57fb04e254f663d021ed3f035239a068c96e3cb41459cbaf246f1f2cf3c174b55bbcdb25145754521a3ef280fefdc633ae29935b84ebcf7250e28156f940ae7b9a25ebe8c27895d588b32c10155dcc043ba1f82b93dbb5146c31d46f67951a7a7ddc7cf350626e1e4aa0eb30a08666f517f2fb80b94e6c0a20c8e880de0ef674d6df7e5b2d764fab4eda0dcb7722821c683e6b17a24742123bcccba99494e769a1018543e6251b0482051b51e24a6e0a5946295bfeb1a03adc008ed628c01101f4ce042e2244b80c53206015251d5913e65d3c4ff362f5481ce8284847397009616392cd218a8259ee760c2bb6fd7df6c07710d429d0735d054b09de6b3d10e5a3743510c292a3859b19c7177df1bfa1d6766b846c4236d97b6fb977bb0c790c9b0c7148834e7e5578329401905f159e30c95507ccd6dd11e17d0f41ac15f7cd913bf23c9e8adb219f18b2fcebed652eaa7630918d4975de4aed0131d35bdbeb2c2f351d30f7fb8ea8ea977a7fc9af941f0684b3fcd478e0dcb714be86efc93c14fcfb698113597e48d3bc0bb9bc124df37092fa774f4a960f41d3bc2a3cb9a20a4faec84abc2ca2f0934bd010a769ba625a65954fb6843bd6129c1d99238d654d2927edbe817d31ddcc4966dcac8f1a1131739b85399fdbcda3df583e2e4789234e72d51958847653a17dae60a4e9144f555faa3ffae9e530ef5472531abc6793e53ea5a20a7a059367f3aad0824fb8a34fb860dcd11fe4c630b8a351640bc6b28e3acc2dcbb26036eac436b1b85dcdb737eb32d25c5f3acd75bc70eacde84ea54b9e0d9467639f4ddfdae2d988deb7869ecd088a67737f9e0da94a691a5955e84e54c578cbf86524f7bb2b0d4f157776a20fbec0e2a9624f8f157ab8d023869eca83a78a404042005202a404a02b72dfbac353c5a1aa82a1ea82a14a833854bff054728aa7924c62aacf53069e34f0bc81e70b2696154c2c2cac0094fb560c9e4a0ab1e1a9a61427215c1e085937a872b8775041ee2c9ddca75478aaf90325a6fa4f4e65b85ff8c942edb6223e767534ba3250f3c8950103466c1b02460f49b172744c7f71a71b6dcd45cfca5756be22a34fdaba0a201616201620162016a076220eb5bc250eb5c4a19638d4f24e8610cfe9c473e239f19ca0164ca28b64e22299b848262e9209cc36987384d00bea325e5ea490509671bad836c493e94f2832649c4ef7c2fcd47aefa99391bb092577737d7a32fd189d8b01721fb575af0bc844eebb6c1d8c026621b71cfa066d459721cb88a4974757cd31b6b77ab12c996f9aeed023d489faded11dcb03d38f817d318f7f5cff76e378bf7b5a3c273124539cc4ba0254333313fb5c09d479b05232ec21275a28c3286f7ee166187e0ee1aa00de19cd4595a95333de49d937c1348d8ca32c656419234b2d4b982c6d96a82cb12c5fb2bcb274c9f2f5d9cc4b2bcb962c69962c594e1b1fa4299bdec598772a59be9f8d75496a7957caf2f2f0d9d4cbdf67e372893b1a87b73436985373d194631f46d290a6781889ef8c2d03c38df1016f971103060ceac5e5d4c2b2adc82bb2bc8a7c499e247fe5474fc66ed883fd64e4e926658c81d613b67befb077d7bbfa0e9504cc2bb9a3efe63bf92ea6bbaf79302957934a452f79328fce28f231899d7c7223145c73f13136a27494a6919ff1862a883263a3472e2332934edc3ed25c9451873ad16f9c55d17b32dd15692a66fcbca269601e3fa53c9b95c753279a463ece6815e5e926926e4af16ceca3e9f1f28ba65161699a96c7cb2d5a45ab88a978fc4e7291b777f2498e97489e8de8f1325e4ad134a3ab45d390809aa6f47869a45514483a91e35f77128a1c1fb97836f5f131283e9138cf067bbccc691a9db8a455518b1ce316393e5611af88a9c7479fa8a2c1bb41dff0e81ba80d72fcfc994a7837ae9c977793093c515599c4f0f83069f06ed4274f6c90e3e55054d59e988aaf3839f6e8bce1dda84b96c421c74f3d3c55dd6122773406395a42b80aa11cbf5591e3a515de8d6a040661040b395a4031152f8477c38a1225498ea7405165f9c4547c954155f06e585ac020b460418e8ff1f1b10cef8625050c428a33e4488562442bde0dcbc8a5d3a968243a2106ee6ae411caf1eac9f1dd1c4a3263c2b668d52e6c94894aa4ab62b22d2c27d45d5eb51b9a615015ca9583e4055f392e2d2c4c9e3061f224c7135631d59ebaa4a5f6b0d49eba24c73f5b77a2aa42a9502a94a8ba74eabb7458fe728b4a56b137d9abd89b5a54b23d0b06626fb218c5c394556eca2aa6ad46d17244d82d5a89da8ae92c2a1888e9d6749615ccc3846f5eb6b716974856ad38f98262a8ca20c7cb3bca80a20059a028397e8ab4cbf2d122b37cac8f16399e6216b576a4b076a4c8f156d5b9762e235428aa2e27da08bc71b9e005116fe1ee42722f287214ca110696911c5f351d746651a37f29eeae9d8864c656a3742a3ed37440692ebe0a71ef4e39f5aef1c6b10a5072853263cba1f119b7b6c64657166635b6b9b29dd5d8e4cac6acc61657566635b65e599ad5d8e02ab55d3a3115cfbd607d3a9be47351448c80f46f7e18c5e3e6f99b27f656ad59792adfdda523696c974e1300c8bccc2f7733f2ccd3c640e6e5c4281e32cbcb2c714482234f73114784d74e8eaf358a96a32a31b33563ab2bb944c320e2ed3cc4738337de12cd43e2e0bc907cae0862eebff93ea4184863140f21305f3acfa61f7fe934cd930fb614251173e34be7c9c48e3cf0f2716220f07de9e4886f7092193acfe6c544d59d713bcabd176eac06c88385267ea005197164fadad5ba36ebf5a9ae19cbb2fa3376b25f8c512a41732b41a51652f802132029b6b044004ad08b83b32941b7f08957bce245a23978c520b026aab25fdae8f15c54d9c7d106772c4af394330877d69d55b6d96d7ba9786c8305c8f126d3d678142053d17b32f16f7581882fd01539a239a8e5e86f008920132b4173944bd07c44e34c83e7e02ffca9367503dc829cf572ce39abc5653967fc9cf10cb763a294dd5c8e975376b7c49d2907e1ae136ecc27259cf27002713bcb4f885f7367b8f337f2acc9f3fdbcd4d343152ff5b2bc108fc6bafccca3a1bf917134b55e3f2b4e72c9e6e635ffb060424fd6c29d4ade12396ac1149cbc25b0c130a9f6f9fa54d927eefad1ccce89e929c624eee2569b4e3a8fe10b4b2d07ada7d3bdf415f7b3b64e5e56539611d7c67ac2e0f628c9bdbd95f4eeaa702b38ec5736d3f6624abbcaf6624af4d246daeef596cc1ea820ce858d44b83bc7cdfce0c0794b8a5c91ad9a13771defa78fc8d67ba6b9d83d6777abe9d45bf296fc686d4d814058a8839d3f9e8c7dfc0bd25c542204973539aa3c02fd681a21a20b51a2660fbc20e2953865103c99a80ac1065a5502110e9205951fcf469423bdd1ac1019613ae946a8bc741c6d8d201951ba8a099f622a8a4422ed7074d106043e7b4db2a6dd643c50446840de851d8aeccb30c3389a8b436cafeb8e175313cf1d5c51d717348c31c6589bcb9a002db9703b696104ba3130cdc53e80ce57d6061123b825b1b776b3318b33cdd5c8f821ecbbab3d46dbb2ed6d2fa670c09a3b5cf84e882cc436237767813c1f4f3576182062660bffc934b6a1e9904d1fc441b8dcb4318a876cfc012e4f3c236dd868154c9fe24ff505d59e6458f280a0b8b208476ce05121c773e0a976bc2187e18b1c6fe736f364e2774455007ec29063018ae8d59d7d0d40b80278430483c8c139e1e17991e31f8cefbdf79e5096f7c53c99f7d6724829299594ce399380c51e9888818918a0fcf082b2c46282c8524ad9d598f16e643008f977b8d53c19798b3d66dee0c6fc2c7863c60b0216e0a5e4257c27caf23509820b9c15b2c40247c3686d4138dbd90f4ecb516f919e705feb7d5d4dc73c99eb160a9efee56b43c1d7cb3b040ae29a79e49e7270e1bb1b44a9b0116b866895fddbf1ea6b7cad31a853b15ae1d6572c9b8331b83f22aa4e2f45bb9a0b344db7235b8fb47b422f458f6d0d3b24ba1264cb920c682e3e3ed634178548c2b58123ad4faeb76f5edbcbf652c7befbee5064b7b41c56bbb2b7c14ca5e854fd4bd5203c99face871bf4072f887aa97323acef0aa3dcc5c3a2a351bc299e157790031b4e62b85c78d50a5175ab88414d0373a5afa765783796f88b4091c945cf90eb2b12eec3320f17e6676b65af4f7d72dd9e8afee0a52c3c44890febf4140fb19e108725e0ac2c0c0fa7d083b37a2b16c429534e5666bad472c423cdd515940f7aeb161e828ab7ce728a6b5636948f9521a878163c7d72fd0ac61153b526d75b4a2d6b9b89a97aba7131551fb17045c7de71d9cab1749a4645f2442157ca73b2e24e916b14b99e3eb9994aa15fd025558bbb45ae272e72bd0cc27b4f1621094ec8f5758a5b799e4cf5b9f0a477f1c85b412d094a9edec25316e13e9b58555e4fb7689ad2ebe90f9e6a0275d719a8e87a2aa5551027522efae4c43592ab95d3d12f3a1aa5a33c57d025b9fe35d522d72a9e4c9d564c2667c8138b5c4ff13c125355946513b79b4047729d5372ad9f539e0dccf514e7a98e78a9fa5aa734eeee4ed0112b6e4339d5fa7a049dabe5ee3facd39e98a2a73c3155634f177b628fbd660c6ee7ee4d791e70dfc911a54ffb059aabef2d899b7a1e17cb57235cc893eb4d2ab83e69ae843bc8666b6577c3f27b0dd45c3d8e9e36b81dc43942aae2be2f84c8dc410871ea6b853838b9c69ef95a3fdfc51f21326b1bed89f5b5de77a74a1a69973cdaab4ad534521561d9d35cfdc53c92a7b9fac8857ac9d334daeb2512d9d3342fd7dba9599889341c81eefc8d366770fb5986798272bddd2892e6ea8529cf93a997c185f5b6e77174cdf28cc14d22560cc4fae4e7c38b1c6c8c42b8bcebcf4ab8ba36940febd72deba96a74a39618634b86b82547eb98cb4bc16f75e2aee5daea76636af4e0b370dc5210259f1a85dcef6eda85dc6f29379830dcaee463127a36f02cb02615320d72c8fdd83fef280b723f967ca24c43ee478983dc8f32cbcd0486fb6ce03b8bd843d4f403212abba3c87d19b32fdcaee403f46ce0185490fb2a38cf660a813e2a5c2005411e52507fce88210c727f4aebc71091d218247f954841b92d884b3e259febba4411a378e4d8b5f8b0a0c105b684d7e3cfc55afedcae8473c362ed3cad8a32cbcaa8066fa97659d79f264dd98b8f8b2e829e8d2d42a4417e8f3bcf068378682cf27bff3c9beb1d0a3d9bfaf778e407f91df23c1b2bae21bff7904bc8a7295a9cb4d88065c90a1d5686600a8316253c4d913bbb9ea49665a16e58b26d7192fb52d3815b6c901b7bc7b224f72bb642875e1942358521f72d93c45d03fd30016a1204a58453c229e194704a38389abc2d69f03f5a0ef8733b15a17b3d1718a429725f27d706a325223a888660df91a68891ddb0644cc85e27b979327cbcae0d72bfe56849ee29a2836808cdd3e3f3d34ca0101cd2d9814d601014951d951d951d951d951d959ddc2f0595824a41a5a052502928f74b3e259f924fc9a7e453f2811bc4607218349dcc0adb06bb0358040c835a18ae4bd3c97dadc21d995991fb9965bb996c77901bdb3a28648a29f823d5c4037b4c3c3e269e2a4c3cb9af22040fa50add13ce85725fe5a7fe5c262715959fd349bb61c9f3f1e75a8f3fb7a2302d725f7ab88c50cf70615a5478e921f7ad75bdbb8c90fbef3ac3ece0ce8fcbcbf652772c2ca817efda0a1562cbc222f7315a31f522f7af6ee605c19d97f873a574c93408b9b788472c4983606df18232fccf853f4d26dec53550892713358b5b8b0b0e4b9ed805e7c968e1c2772e9525bb00fdc0047aa5ec26bca796c7ddfce9f6e7bb3bf189de7c4d2729633f3123ae4fe60eb5457e13a563c2315889d3383fc16e3474ffc8afb9d6b11accfabdf7de7bef4978cda6f0c5f8628c7194dbe6b244a26753ab966d2ccce6b69916c39e8dccaeebd944ad4596f56ce0a8a3f441ebbd57e7d5bdf75e17638c31dacede7b4f13654190a486b0bbfb3e99f7da4d0e9f006394321ea2e48b648955345b3a49f4d7342c5fb92d986533917007795e4c5ddcc11d11c65d76ba98cbdd6b027562842c2d959c5e2594324628a58472e83d1bdc6d3882a2190d66d442ac5ed7a96227cbd26c6aa21a1b964802c02da3029a8b52663d573008f8641ea6969c3fc428b91842881a53cf251b8002b1d8ac2472c429094532bee905293999559a713133369a7bb7323833444d43345c34d4d86ca6b9c7754c735024318d10765c6c0bb604f2bbd55235168b654f7b2f48cd5bc14c56253b95b4184e74130c497447272e8bb2e6b412cc8e9a3ad4984ecd65910d51c2b458ec923050d6ab3eeb44231a52dcbca454c1230cf7ba27ce01478c319eebbac54934ca127718c8f1385a469531ae4cbec892c1cb424ba3737463974c2a5a8ef74c2b36833335167dc452fed1add6d3e9d9eca7987a5fd14c229551e99248b734822293b692b1d8961376ba5cea0bcc0edc1466c29031a28c77d8871bbd27bc62522991ee8805d31a4e91e84492a3d8a447a11565db93798f125e3a1af5b3bc9fb70bf739b6caf482ec0284108e4411cba64013f61d63ecd8b14759b0b271d6dc3b9765a61ded4d946dd39408be263746f1a013c810cfc176f0c2da9c176e576d7773a2fe4f1d84f049f928718da9d7f0fdc8f1893d4393ac048bb5f01eb9cf068442ccc44e8926d4187ff22bd210da4146fab238e796d5295c79e7b470cb1cdd34132a31f39c3265ca1233cb99a8a4a99229dfb41f1bde205219bbf8ebf2f3383a5eb84289bb22d99af12f57996b941b10afc6f3e1717d9ad5f817445f46db3f20f2534696cf0fa3783ccf5f561aa23f9b475f0fff287dc53c28bef976e5e1a584c177341a62488321f76cfaf452ca0f623065d373768c30ce092794564218e31862c4f717fec558fb8bfc240b625e378d471a9ff12ec2348dc7a67120b123ccc944e330319a606834186e0c8e96cffc7cefd5e8647a3b88037fe092096fbc4c57b09af173426ee6d9c0f7f847b51c516ee18acfc6e678098ff05435ef87094ca290fb01656159cfd6e3d4899645298d3047d19f7d7623b08bb067d88964b77f98c546d9062fda7e644760b7f1160f5112b10ffb0c0f71b9fd9097632fb2b21866b38d88cb9fcbdf89bc1c3e6aa8225e0effc3e5efd61e6bd19364bf4073fd1f5125c2d9868ad8868a1855017bec4664983d668ffd784fb2ec023fa28aee6474c7629495419c97a194688e1ec1d4091c08d3a4a54fbdc2b28af1563f20d090127cd13a30a7b92d7a60128b4032c6861d66b38791c1e84ef2366632fe80428c0d75982d3bd4ea6158307e409cae4fb810e78adb9da2266594bf79394a275c9985c82c0465e11ea8ac474e0ecb4fcf5979cb2d6a83f16c83f9cb7659042bf7671527a873ec30ee033b0c3c4489fc1078ec12fbb087c143deed9f6df627540ff81eb3d3367acb2652293de6903ea21baa0786d91e39394c682f3d2787f49cd1b1e7dce7886eaff26383d886c343f2c9fd922d828313537dc4059a3bbd482624b98f0a3c68924f2ec8fd44ee132afedd1ede08ec0f1379c70e3111253edeb113b15996719ecc14b7cb4c5986fd2d1f2db6bd28711298edad4e51f5a353f875ea47730d71e011880375e0df8aae14a91d9385d13531aa8818bbfb44546615e7eec9f424a34f2ae615263c12b9fcad34d1b51b31bae94668773161224a7cfcade8a7b68d26c5494cc7d1a3edada666d22ec2a81e2278455a0f199fd73eb9cbe444df83e4185ca97cfac4947cf79aa060cecd64f9624d9be82a1b6a7b2b183b7d9acc2ab2941667f5ca7b32612a4f2c54b9b6ba15116f55c1822a11d2fbd9d627721f6f7308a9b74c8fb1a9c8d894d898ddedad48b38afebd11f1a4f8fb7822f7fdb73a94b7b1676f6f05b749855c4529e5cfddd374b1b41cd6a346b5fa9bfdcab6297f89f2bde2da9a89469f5a8f9c97bbd41b1163435d8ff1b782b165877123b4c7c0303011253e4818755d7b5f3b918b511746555c44f6781fdafbd9a39d9a4894c168305be9a8ade52f1bcb5db695679be9da09e788ac8a69e5870990e8be4826f4c8c9113dfbed714f9aa7989217699994d254a4768b19ec8b79d9c3158b04d817d3459e98d343883c2280f7c6bcfb0ce27ae1e1717466fd3d5e721d637d3eebcfdd29b70deec9e9b9e17b737b96db3521e1be192d807c74efe754801b80d4cc361327cd9f5132a333a384fa84dc54c8ad45ee7735721f4229369a67121aeac4ee39a769ba2330d4b9e41110487e713add3be35663eed7a77a71ce18f1a9a3605f4c4783641f40fecd1e51253112f147099468b883449056c94f558ccf514237d9724227f2e4020cda6017602afb5bbd22e4b51b119fc56bf144b4cb3f2f20ec02ecd30b6eaf000f63804ef2fc836dd028bd3f8d679ca8425d2ffdad26eac2a80a8cee493742f492e8a48be661d03c84320f816670c4d4fc9defa7c708a37a9c8ef2d170c667e3d0788f9723118220cd3d2838382b2aa34b32ad5c05470747c7a7a9c8c211518b5a22ca6389feadf46b83f985c6675cc6cbf656b6da40153c99a9822b80a5dc419c1286e5ee417902c481c2ed6f34fe6dc6a156c45bc9f88bc5b92c12cfe6fa7c079e0a72e1a5e6e775f52d21d7698fbfdf3468ccf8d35015f710894a3d6460ba41e0ad60cb31dc43468ecb0fa1003d1b9d677323cfc3262e5b8ee9f7df72481fcd25cd4d2d985c102ec9f31028aae06a1e3689aa7fce777dc48777ad13f3432835fe0e0e65fcae5db6d3bff9b0bd954b8dedadb8edad62369ff9c993e77d26ac22cf43297a90e4f9f92d9a0342e273d58ba7d6709111e3166ad8cbf74981095ce45786fca4b08429d9c64c8610ecbfbed10d8a3c7fc131e4f907819eccbcbc221b695af61126327a36c2d9894c69c5d59e1d7e5ece4b275c2be3c8d8deca924fb8f0566651cb7169a81ea796dba9e5e89183bf5d184615a1fd3722bb8c73dcdfaac65fe346c83887896497f11a9888121fd9659c88f6ffad6c4645a7711fa2d318a25d748a7d943e030fc9deca82800c0bd5e3746a7979abdbcb3195e5302a8cb5bd2c23c76c2cf7618371bcc17cdb50fff672199bcb5fee1203e79cde721cedd372727941c1c060d981b1bd15cc5b554185cf4a85f4572a894697645a699d3cafb293a7a9084eff453201452fca2eef438451f45a8647cf6ec4e89996a1e889a028461591fd6222f7d9499888121ff7d98990467f2bf9d2a577834d626a8ab6f9d17c36af6d1028a626a418e63437e7a5122e8551c4ea1970b07da36a5a36849036e8bc21c8f011e22413a6b989ef4f7723c1c263e4f7fb5435a6bade808141f46fbb5a9f406a3d7dbdf4b9f52f5f7fd5aa152701ad9e51ca98e726afadd61a5517e679d2ec3d9b4969882cfc9ecc94b782103b2bfbb7c17e5b94935ab55e98cd5a138d46975452316d2b2c2da7b76d9b8ccf88e68bacb0adc8cadaa7517abb59c7b67ab97556f381bde22148c4543c76abf9b0b7f09023622adede6a1078ab1f6eb8fd209087621a0fbab20d49a2ee047962799a25bcec4a030861849027434893f0441672bcdc82401e1411f1f231366c924579f70ca71695bb7ce512ab9bd5b4b38c8e5db4edc8dad388b0b5de7b3afd1cd7cd641146dd63b843ddc0295984bde24ed4edc8f5dd8e8cfde51db9bebb9f9607e9f56217ddc029797451adf79e4e3fc77533d9a22ed601a7e41116d55beda4adbb2a1fa91cd3ec481ba91c4763a3ab5cc340543ec24058ae69af5b27c2416ab28a65d1de1a0f162c9b6bc197d770e7229b5bb197875a036cc9f492a9644da552092b5953a964b1923de1d3e964ef19acb5dad6d564ed76eb765897961515124ccdf6289753b66f59e1b285c124fc82f10977b70577a7ac9d0577a7156cc2dd392e7715df9a5b3b8c0d47d44650bbb1761b3dda8f705793add501a7dc32dcec5d4d909a9a1d416af21210d5232fac7eef2dab49b8f5cdc353dcc17a89acb7c98b004890207d19049bc4ccdc97050e76f2cb02073801c82f0b27d490ef90e385c02c8bf8e429ffee00e1dbc2900997df4126907b36f2f13d2b932255e4aebb221326cf3f1b148f297f96cad73821d093692639be6687537257f17d32f5150399afb9b3308a880984629c047b8d2a0c43ebd92ffb007a6b339d9a93b73932dcee41c91289675355b217d08a2cdf72eb9d27233f9d58f2751302b385d9939173ce39e79c73ce39e79c1d249b60dfec532e67366cb2679046e57159f6ec84af4afc29cbd9e381c8fe9128c31d3dd4f07b32d5ba30ab3120cb2c6d0197ad58fd846d218414e6d8ed68e9438c315e88d3a379731d23ee82d4706d4118af0fd46420f1d7ef7de86a328e98ea083caedfa3b35b4cc6616cbfdd5e37951f48f45b381bad8a610fb3d30d18c7a8e8ae06475471b147d3d434c7848cc39c891f86363a89f4847bf3e82408c0285eaa9fc44bf50d8ce271fd241ed7158110856d84b1a1e065bcc80a662b02e6db7dc07c3bfc06e332f0901fc687c838cc8baca017577b6b39ae19aecb557e7a7d6b37bdf282b79fb62431ceb21d6ed1aaed7d1843e56dbae8efd22114ad8ad13415f63c9b9557ee21284154c1887934fa7b34371e47fa7b3435f7870b6edc82bbfa381620107772c546a7e24d9b1097b1a9e00e929e108c02fefc7576830ad11c7d8ccd46c380d9ae8d3e72fda0dc381f8e0e52534262851abc97d674105fad78e448d366c2844ed8f352257cf5c9575828bd68ee65cf066e3c464059e6972dec2827ad3952a9042b94a78c726b8e2cc3b6fcae5777bc5c5df2fb7b94924cc3455d8719a583e60b33a0b9f9ce257907a03c4fbfb03acf06e779ca45f73c059aa7502815caf3d6c6e3c9cc2e8c8c21cf77161379be2ee821cf05403aec7832b349dd5e9668b89d0da24728cfb3b1140a9b69a2d1259534061c7a71c9706bd663c76c32a10445155dd2d123334aabe891989a2fbd1b4288fbcec6683651753062782a1e17e8d47c47990c51c21dfd11825661e3e28efac48c70477bf214e1233b74c85cf18fe6a6adf5d109b78e66d0e8cd264179de06358de8f3f649d34079364157de5ea2c6addd70b9de2231eb4c4cd56c4956fec30a2ec2fd1155477079be47547113e7d96c3b4c90d4c0053952f8c1ca3ed82f5e87f9c2dd8f5cf1556ebaca4d3de619506badb5d65a6badb5d69a593d58d7593695af6ca6d7ad833c3e58ae8287b0bcb51e3135bff29e9f6e98af3862dde82fab5a4d03c4fa7b92a785ab1552f9428693ebe5b3b99e218161196655292d69d998bda6c1de9954309cf230fc1ef768b8e6ea81785ce5e89f3cf69e1be4a20a0e35cc0364e271f535e2aec2294f058d74aafeb26223d389a6e9a434f200ec40e4a191e6ea49b379eab826b6bd2619dbb07a1c5637449e5c9e5be7922729cf0bd12a0865e67a2a0b67be3e9bfb8945183a017754703b77d0c80525aae00fc55d2d619cec240b070e3d997a69652b3f26f07632cac50e6f4ff3f8447887d74872bd08d7239d0c178bbbd375e1b9860ba168ae1e1e69ae4227a0131bdc69ae5e76713bdb77d088fdc50e759aa66bec5d904ba7b9fa6b83396db8f2171d47431dd1ef33fbebf5ba6d0b0742c9f5d7a15839164e73f59d3b0ba7474a29e52f70d5cfe8731b49ab6c748abed6374fd38c447d5fdf3a6d4488f8d166cab69bd58647a26a884ed5218ee47a6864073ad1343d2557f85470e8a5f2f0544afc7836589e5fb020571c1da883617008f2b40a894ed5cff9ec3293f39a6cb8b425bf532cbf5b30d08b097f3a55678543d8352d0bb32c6b599965699625b2ac91655dcbbab009b3bd1b4bd419efc60e18447d7dccb3b9ba1ad83b1f729da689f364e69babc7b6acc9a53dcf66be9e0e4d21a7c8d8ce30dcf96bee8037ae7a855c993c9b1fb8a469b07399665996655996655996655996590be3ecb4ea85d94c1359f5c26ca689a017723e3a017b6cb8b473e66b4e27d7774eabacd743294d3331dcb5915c6fe93c1bfbecf5564ed5b44bd3304db39a96699aa669224d1b695a66eb85d94c1359d948638025a585d7f5e416a42663f6137735b37120cdd726ca38e2dc82d464ecd9a59603fb8472e5ed77e4eb739b6bb8389aab1fa2b9fa6bb3b265e1348dbc0a4ae9547d95180e35579f86db0dc1d51fd15c3d97edaf2d484d1ed25c2d4173f5f3c9c570089aabcf7090e66afd44c3ede050ae55e5f58d7344d374aedfc09c73fe024d837d6ed1e74aae397a1fad52c1cfbed6f77836d76bbd029e4df6fa219a46a3c1ae563779619dd94c1b690cb8d81fb6d863c6ae0c670057b0cf8ee01e22cac68c554fa87e85f07170cad8856c9f1d6d11e777dbb38b1b0f4f3992e1c6996d27182757be278c30fae42ec8037af012b529b371569a5d1a0316d0986b0e7ec646174f48e241c64e6eeedc93a9b9577eb28d19b7e52881975adc6e36e1a269acf74bd7e576bd6e312def302eb21c032606ac49965db82093249f26dd0452ad04c51493393c2a685684e614a977b30aee3e17dd8a6e17ee7489e276e132e493fb2b415115a327a6849a264615cdcde1d1c47082b612b4d923bc543fb5d9184e783436088feb5b9ee68e608df06c6abc6f9558296c112c116c14cf66b34962f444558c9f981a821582456283f06c5edeb740b03f7836a8670313a3877b67ca9de5e1deb1e4cefaf40138ccbd899955ea32407c868dd7b0f1186c6389bbc4294b9cc4c6adcce04d62e352ebc1823765ca942943383838ab9c1fae5d89537e411de63fa3d1bb6a89a2cc46719a00fdd4f65e005cce6d0f0ee0741b5b4e13759503046ee2ab1a78ee81069e5366e0a987183ca53c99be0f78e201e399870dcfe339f464fa3a35ab1f70135f29112244899b65e059872723f1b4c393e91878d2e1c9f461e009b34da1298727d37fd9e61cb46d7a91e25686e69487c5f889c2c7c6c85328aa2ccf4bf56bbdf764797c6e67795890b0f034c78293fb526a3c6896786548cbb162599068395878b8689aeb5b9698a5e79e472846cef008280c97f4cef2b8f03c998e176a9a08574c2a1d97215db95eac1d4beea690297753e8966194312c04e66e65a8aa6cdd67be98505686465cc8fdd1ca50eef964721155f5de2a4522d1dfca4fc6d153c8d221401946eda6662994595962cbf364a4b89dcb9090944ec9d79c2c2f3292e5b5bf96cfa0c8f2f6af23922c8f4991e5afa1dc3e591e6a3a26eea1ae763757ecc21dcc1742609e529a7090e893e77c327668b44a13dbe2e272db198f1a17971668dd65fb408dcbe95b5af0bb2e2d5bcd4f2342e58283d4b46cb465a3b7d6d6524f6fd9ba9adc720bc5d97867a393f932ef6a06e2dd9d4d62aa2794f6e1d14c374cd436a7bc545f669b7670c3a39973781c94a699423ebc3ff7f06cb6f7a71e9e0d7e7f4a9979783632de9f78783677783630de9f43cf26c6fbd30ecf06f5a63bb10ecf867b7fd2e1d9a4de9f5f3c9b1fde9f73783631ef4f2f9ecd8cf7a71c9e0d8df7a7d0b3a901c445405c3bc5e90300f1bea53b313aee3d1996c36cefc9ac5cc6f69e8ce9df30e9b67fd8649e4c3fb501600be2c9f451a9ed8727d39fb101f164fa319b8d27d358e69bcc2f43e6315087b12d7133ea30db12a78cc24964f0e8be008f002db3cdc4541f88edc554e6620388f70bf6ae4ea01780187972cfc6c51e6a3aacec82df9339e1ce7acbe971c44e0003108200342a0418a0a3391d6de25a4260eeb88ecb1dd705a1b0264b1c64fac422a9b66368f17957ce7213620c2c4134a8570ad7680e748444f40551135817b9ffa40fa641c9e74a21f7df688424f79fe80bb9ff444de4fed39890fb6fb3b2dc6c88e17625969d6703a15cd913f60a581e3029586890fb30282bf9644fe43e84581e721f625719721fd22cb79826b72bf9acc880d6285842d60f2a2928eed44b06b9df0159dcf82ecb314699c5ec1ebb792aa5bc94f2ca4be33ea639ae1b9ec63b29a38c324a6e8b692e6a8fe1b81ae724c6271a9b3435f71c6b3a518cc4f1e65c248237fa311ea6692e5f654dfe81031c64bc9204c9de1788f0852204c9dab6dd90e8147c370ed23412dec066bdb24ce5ccc3a5f505d1bf402f816df405d19dadc3245270cd27d3334f947c328d2fd01c9c93e6886d7bf6bb65f73f90e523e60ffc3349dc051982de5a971b90581f6f611411f0b5f110d1da7267cd999a6bdac4ed668227461c4ddf937fd6ad8c1b7dc1ed20cef58eb15f7cf192dbec6ce47e6f169e5bd58941bcd808c8dde3c9a8e214b77b5f64254a3024e268c87307fb6282d4c4e0bd8c8adc4dcdd01d1b622033bdc43e3b052e6821bbe4abe595af1a4cb90bd97646856c63263795152021a3e083c834b93714c47f59a8200bf965a10229d9ce304011861e2dbec8102731248f80252b71332c49c9b66672cb84b2bd32b995cc902d96f5869a7f59e05c01356fca74c37eb2cde4466f9ff644222df7f6b2c049429eb349a7e2bb2c3f6ae476334d20ee4c333f6aa2d544a34b2aa958da02666c8ef13ba2eabe9a638867aec7cfa0a8c21eb58b3013d1df0abbaedd88eb9a66afbf1586613531159f6d30b82fc38c2a02fb751ff6596ef224c7dbecead824aa26132d5e93c90c8ef81df133f135f17643f5517debd88bb08edd87750cbf98f2517f612b4b2aeecd31002401e417df71394a21479b1cdfb9e49968671a63eed9c01c2f6764df1df80e3522ae6ce18e04f9e930e5a031be5fc7289ab7e2673f9b6749325ceb30c7cf5b1a8f1150ce3aca49b71c5b0eeb97a603660bbfc477bae578b83e788926de5e72bc1903dbb7b239383313e19b4afabe1915511353f035324e538d96e36ee1ea9055077c32f0b0470e134cd498829676b33d19f8edc9d44b47266dd56edee33a1277a3dd7496f78e8ab8b1b2bc1de5203d0102d828c7256fb3ceb22ccbe0ab22a9dd58ec41ac31d13cc50f834a14999096c1ea91133f44890f3b1a61d887e8191ef244b7d7fad9afc487e9f110beef03bedbc7ca333c24fb0afe35c96df4bb89ae6d4394f880a822e447f721b10fb1bf1759bf8787d8e221383efa080f51e263f4687d84df651ff14c4c591fa2fdc554255dd255fe56a5bf15b4decade214a7a94f010b81afd9eb41109414c59a7d64718e2c494659da40422439440e0ade63191f9b7ea204ed6e0b51e39f44cc0d5fcd994f8806f3c04fac494c44394f8903c31655de2f8214a7cc00f51e2231ee2217027a6ac47cc93adef344f077db2f5b78aab1763d922b2a917359e7e33d3898b2dc54e10ac60adc13684a788af77a377d8bbec9d664f6f45524a3bbaf7a38b25cc224c84a596691866ccda4f8bd12ede8219478c75eb68ecf8b41c126f2db72ee688a3a525b31d3c6b655a8e7938e71cc28272becf2ceba58d48f4c885f645389458624b9fe07b5a8f1b53af4f1b2a6b181831ae0c2cbbc532ee9df260cb281438f321a34fc4c46ebe8b5bd319197d22461a35b2ee9d2d97c9e630dd0177f9c30f4000118138c597e8326774892ed125c69797179807800723c607e3c17830de9b50de20b20004200a60cae1c24b010c204b0d40eb8123a6705085c8e413271a19016ad0e05219cd0f29206c64325a8e276303007026ab09c08c00b2d734340731b70019cd01d5017de2de18228373ce03bcf7a29c59c2b975f2344fb9c52c9beb6c93c9ad009d5f73f646263704e4478f5cd806c8b296c3001a1171ca9429531e02b207b3ca680e2ebc8d33469bb317553a75458a2a151a20a88975ac746a547aa6547ad4e156a4db5546da744e2b5269c34bc49cc404a4e3689b80ec4d23e29429f14d99b2221981801509df98923972e8d0714371606fb41caf43f18034cffc7833336a0278c1be914f8eb731ab2dcf20a519463c129332446f303442d2a9f839e2e189aae904144edc0e1bc2863029adc290683a786e7085489e4c9db84264126b71ed1d94ccf5393e6b95fdf63ad5757b8f8335bf5b8993d863437668ee40e142982bee34e093e1e136ebcd32b5c1ddb919f1d81e8c27470891e40e1bca71e4831c7fbd1b231ebc20e221569fcd25b7514f7335b8f2dd88278f78749a46a7393877728d50b8dddc999a8e2d437cfd3c9978ecc84b6b0d7868c8f27327c3434a830be1dcc9726e2324239e114f6d1aecf1598c1ff1c451cfceede6cee4892a179f2c0ca1092a9062c91556f1b327aa3270240865f8c215a690811156f173277e1ec120c498850dc56ae124f6383ada18b5da5cb4389894e6a4d085efb0a1914fedd21bec8ba1714f358e0090dfe9136e466572955dcdb214d18bb61898ae1826b56397d23a3507a3f56de2205c9e9f1a112e5aa8210979de46d6aaf7c393b1e70472c455eb8905fbeca8c65fdbb5706659d2b2a66551cbb22cab5ad665599865419bebc4f2b5dd99d18a25dda468e2f8ed6ad57b9f4fee7c625f4c57e2a9d7f55a343471a46419457e91e98332eda11eb27d5dcf6f46a04c9fe3fadc5046b87c7e622272431971bafce96f65a71d321e295a7583703a457f5af2f2ce46eee68e8d2b94a9464fd4cab41fd2ede74ed35cee528893bccc9d97a78df0684973940a3707c9fe0645fa672dee9ba3e4e226be9a479a00f4dd89b4cd1d36443768f65d4b7992e945f3087e4f0665b18e8b5e747b51b4160bb17217e40165948e2b6bbf190ee52035d948a62fe1d025b7df95727aa839214fc86b4ec35d9492e9a350a6ef2214c9434fa770e727fd253111f997534c44099179d49fefcb298c2781f90d8a2a1878b445731475a1e65fee63fee5d75ff0102517f6210f8387a02e3fe485dea0ebdd8d92e7d53809cc71f4bc4f9aa33728aa465be0d1169367f6cc9d7904b593e95fe4914c4fa570df4f13d48bac503e6060301c8a29fa971759d1d5436dcd135374e565eb2331b5e4ba2e8ba32d2dc77578ed61932640b16e0d445756b41cd7ad8643f32f180ea17cbc1c75141e22ff821b27a6e88bace85b8ba679adc512fade7a4973f4766b26cdd196d3787a5ba5b21355a39e98a26fdcdd5cb3937e6d2468e7f6562dd7e5f656a39e522dbde7c2259c8dcb375d48b1dd9dccd775bd7ce364c7d26e9cdc38c9b97192b373fdc6c98e0c6eff65e144273bd1697ce364a7e4834c7f5daf54cb7155eda2585cead3506e9cec3447439de464db5bd7b90f5fbe7162a46b4eabe64ea7a8139c2b2b22ba8c72451f803ca467b75626a35c1ff3484cd1cf1759c90de543fee52f78c8e47991b913536e2892e96526b51c374e74ae4bd3e265f18d931d2752cbd185942e869a7b375dbc2cb51b2738375d48699ac6dd8594e65ee6c9dd0d2af9802375576bd5e827a6e8ef5f828c983efa892a68a453d7a936fac9a3c650a7b9eba4cb8a1b97b3adbbae8bb60e4764a13d99de34773a99bbd11699fedea00e4a91e94b9b1049df41cfe6f5e0689ad75b649f4cdf8af692a6a9a247d368e7a9abae99ece8344ea6ef60cf294bc9b47ffa8a4ce9cbb4a7f05e944be117519e341451a79dc8afbbb0e81e1715dbea53c95fdc9d7224e1978b304ac76312295840638db4e910dd9036987d9c0eb547ad07d46e8e303af6c34cba68eecc9da68199f629cc3476729fac95bdc41f48ed66f41b537e4f06098b0d396bce947f903eb59bcea2cf8e48163d6a37107694935a1989b4d92bb3af51e5f2d37db8bcc61e2fa6aed9208b2cd5915242893132d17123ea9eac3dd7e6447f1a8fadcbb276db0f42e822d28ea3513c66be9ff96220a38f6edd8e36ecf6e2ce0bfa167a3640b4776e7bfab9339d805d12ae7d8b4ecadaa196a34fb21d451b0e0534cdfdd15bf4b95ec09de6e8e9cfb5ef8bba9f03ee9bc24f1519fbe8526b00f6d1ad0e9bed5bd331235b6c4fb3bdb7eeadb9859e8d3d7d43691aedf41da5697a884cd391049c922ded7046b78cc2d5a070b55b489f06724b4d8726ba24c3ed28cdd18b2e23ed7944e8c9d03794e6e8357a5986db610d25d337934c6f257c2deaeb88b9f1dc7932f4140af773a746e7066a3fe64f2ebd7590e769304747185f26ea5090b5d3ace9d80d7b6ff6d866ffe24d86bb2090275bebbacb76da62280652e229f5106bb056eedcf76a6c3df667ddfedae0c3421c862004e38295c5b509006b4c45141c59bdaeda2d05300d51c059d526002a8a95dd4676c801d0ca4e18032e7eb0b3a5a07f9eb80193953db6a560868a95dd621ea0e0acecccecf6dcb0049c95bda28082d0ca5a99dd50169f1e9327880074b299ddb8191817ace0141a2cd1a9c1a1043020e167b563eb31848bdac20a26a1073f40ab2ecb222aec90869d95cd32bbbd363c11b4b25a663708051c765656f4640c402b3bda02676555b2ed6111850e7c56a823acec069d1c6181cfca9632bb05608b2782565625b35b0a601341f859d52680dd52f0e2f082a0556d02c0db15219e9565c9ecf6beb082d0cabe28e1c8198456f694d9ad8f74f1b3b230d906932005157e56f625b3db5b43173c2b8bcaecf6d000059f9585c9ecf6ba604268656164767b4e8010a997a8346d94954dcf3a866844000080007314002030140e898462c150301e09dbdc0314800d8fa64c6a5299c8b32086710a3163082202000000200018699204853cecc0236e307511c6017d919d3918db7b8b4a88d8f83038892b888146f2181c5d8eb9b60548d34bb06c41b399dde4294aab8f46041b1ef7e299389cd4f5d75e9e90d75347b4ac740007597ef5d3b94803978ffcbea411fee6d7e74b045f1659fac0e28ee279dcf803213403774b59b36c11f8f3af66ca87ffdb2e2d52a520d65cac241d15c49a4bf27aae3476c5e8158de03cc5f44752b948956ac587f084316354f47f5d08fe58812094aa95a48e83f4c76af17878186563b0a665caefaef2305373cc8ce18abe24487b8d3e2474b16a8285fdd00577c3ffd6fdf5cc7b9abd1de320d430696ca49e68fe2d83f31a0b9b83be9f2b861e52352849effe50c24db6b013da56496fde0d64ea24a9e4608913eaab32fca9f9a1bb1dc0d8f3480909dc6709ce2b0338eb1f0f10af06868ee577efa4d86a40ba5326c809938d76ce615e610fe4048c4621272a588e57ca740eb20d0a76aea5b29bd1b832d80156f5f2f8edb072a8d5ed0be794aca8a3d9808485192842ed5040b6d56ae03d2ce24f794503871bdd4cc2d827aa194d44039d059afd453898a0f62c6d81cac0e84e64604bb1ad4f14f094148a02d5a3d08d97c9a3bb936bcd3b85fa6353069e7edd71313b2dc5c64076090074b51b88b2d66633cd3433d9627be2c183f757e23f5961f2b604a77bb2ce4b9d85ca3a3a9ac68d524486ce6d8c75300eec892b7d28fccba39487ddf928803e4b837d935f3193640228e916e1b112f0e70f72c4b17d77a5df6bfa51143b3b51ee0291323948be336e078db30d053c34789d5dbe4d656e48c4c540b52910b8c685feeab984b4387ca4c581c48437abe3005e0ee6f2ff806ed4611d239031a297bcf86cc352ed98d6cae58f935f63fe9d18fe76c031743e569fb92e6aecfce7d28b4a7c662cb180836bb01134ecb3d6c4da319409d10737b8a1e65ef0c5f751ffd2abfcd25f4f64b626fef5943118c944a75b8ad6fedc608d8d4005a02922ca2f75369e3906fa5a5746ab66e576a5c077a1c8be2685040ed809ec9e2dae5372371c409e360dd01587e0095d237ad9ee37ba24ae8154f63fcdd2d23d07f1cadc38b2c315f08650e705dbee68ea236c43e0d8b0ea778499305d7ccf334eefaba39a8cab0cdbddcc33b0d243e6f9befedef8a80584436465aef6754db01028b0b8f39678d981cb8fc3c455f28b2a0fcedac23b887ab57bf97ecef11635898e05e07c7a8285a07297595c581639b6a276e6747ea3242c79e92742b0bc3c3aa1b0499cbac456eaa821eb791e9e91389f891519a7f1517686b94cd0bfa9e2ea2901d448c6edba4f21b671f92c5aee3d608a7b67dd104c25a74ba881c1c99442616fe74938691aaae3b9b3b7e22ea407dd8340dcea13597122b3124031c1a2d750ea6ae9a79b0394c021ec451120c0a218c8d432de66b523556c0b20025736ec9cc560116af9d156897786aad106c56992ff69c771fcc82cc2c710e174f92062c3e895638468ace346b3e6c8a0f7bd119299edf48890d466471792e38978b1797a61d69cceb13d266537fcdc3451ec9f413f111226672320fa9abecb8ba214ab40f1985362d47d558141110c31404dd0f34863ea6b755dcfc7114544a7acac14e68805ca5fa232b5fb6cadfcab59636f5623b5c0648736ac198da8e998ce01bd3f3a90744a079cc6ea80092d126cd86892f9ead7cbd068108f7a465a0f965a4077df409547e37d4af5fa8911c85c974d9bbf3c0c82204fe619051c9ca4aaee3c6eec998d106d9aeb87709734a4a34bc0c5b7f00e3d10bf10068c838b449f6a9fb0d8daf2d288225d22f7b1c6f4202f8d61fb6ee03698c9b31abface223eb00ea770a7ee6edbab3741da8e8d69fe9279e4648572a4301d3b1bee12c2211018cc9831712f747cc49514f050c12c63d1a8417948b9f46fb9bc02457e552a8ea2c5c2b38fe1cfdcc738efd495ce8aad58c2b537df0f1499aeaa9b6f1b1c676554287b3be3e15fe62c6a01d07f8955e41a72c07b773898a63faee85466c9b40b387c3c74ebce332c8eb04712250e7ff174856bc1c6f935350bb5fde00eb66ccb3ae38f09d195fbd0aa55f0ca93e1a942657bd0235ec6ea67a6a7691996b9623be48a7304d1bd209a2cc18952878d1dd400da5bdba163f224f7974e53e4ee01cbcbd9cfad91eea488904bd8913055273ae922bb4cc25712fe8984c7dc5b53c554d01178d022179564dc9c2852a07694aa767c65c7fbbcc598ab1457988e5f3819a24f06a8692d65fdf1b80cdb5eec38deb4dc5d09a43a77f5e61840655f864927cc6bbb3ccde1b94028c28a7c3d52b5c1c4e156be051bf9ccab3f2c002ffe8d09f84658ee6ee513182b9e8f44a5a8db4c2ce6938f5761eec1332950f3c70da78b49a8658cf3210262a717f13150fcf0b4700a1d4a0db7c5a66b1a724d9aa5148a709ec866b0dde9c49305f1013d112b806c0209b49d5a53c518e28bef039daa5cd13a5b8efcc3c430e43edec7a6321de232249fa26eff8a3ed388a00f74747a9e59c67167f1da7919e224ee134d97fa92c61fa39bce9c4350917f2ce8981e60a806833ec2cde418f40ee9104455c0b059be35ea282e0d9f73883368e3a8d58257275e716d79a7fde11221f8e4291a9ccb959b72c507645e9568a29b061b94a23c81d9868a60af914f88e384b965360a997da329fcac3bc7352d12059aaac7bc91f8df74406ca83e4323c4868450eccf25ca213c6d398c063a8e5080a82d74e8632aaf7805d0a5a74966056382c1aec40601acb2acb96a6a39dafaac2f6755b6d9bb49fd18d0f6386dcdc533c1268c7e5de14ee30cce4c33819e5fcf0c7c3ff6ff542b3baf6185fac2351b20ad5d20ca5826ad04e1760e520f44f1247905281600733793b8c434eaf33cc584686ee4d7d82b1a840abe9f7048a267384c867bb29a0a2f32866e1cd0798a32c2df3499e73b49ccd2e2c707e8c67dfca972958fc152d70d0f7d940987f47065ed67b3a319bfbbb336e713cec69800a6074e7a3282b05c1216595db79f53efd6dc547efe41e173ea61007b5d8a8d8b13d5415b7f8f3ce0be67f306b71a93a71acc05160d73cac7c03e8408c42b701bdbf454c949ece186d5137b636e85035b5ce124b4670995183d721d231bd5fd1c3e43c5389b80d5dc74649b7e821227dabe8f720e32d26c0a9bbbdb9cf00d90300c7fd066819a85cb284e31bfa314f24b005b60e4de20378eea6f08c9405aa900b253eb0c7f7319465eb07d1e14b0da347ce867f12af8ce86869a64b514552c25ade59fa9112d67f3b46c968ccc6f1c93d04ec50c518f8fa26635789a07a892cef314095b8e1ba63856714bf6680e710ec15debf00b5a55b87e6bb7aca8146afbcd3ca5c7ca7d55cbeee7446cbc74106478c898f2b2d5c3ef4c9685921c449f716879c3775c85a23da9fd86ed92748fdc1bcdfd0ccf330c07522613fc036a3d8b721725a7f59e7da5cefdd0dbb74e770afb1bd79f646e398b5b46126236296b8e82d804160a76c933d052e4e63ae1c119143388c3cfbeee0cbd19b1b1ac9d040530ab49940cb274a1ae0bb951afe401b87c7429c2d7a052afbabad35e55e42986b54aa94f3d1826b9e58199faf84ec166619bf5e6e1caedc3c43ce4aea8d1d9b8f7e9fd1f5214f37d1fcf4c15a61b4df9237be1238c8fc6ad4c3f586052588e83a2354f5c11f038d7d984edc05ad5ec757c62721a497c519c03bb7200a3c0013ee51af6b083aa593af2b8e0de4c6c9512fa813a9fdd754a2fcec42f69ee197229aa301541452011a9da7e0e4fb349e04dcdc93948afe1d257fc2bf2aff3bcc8515f0a09fca08835078d2c09a667320958e313cd24d20c989be83d5cf2c90ce053a4d28af11dda3a652cf2e53100b49c2d6064608924a62efdaffaae45e87b971deb720e11c315413c8c1379d536440fadceb5a52b5f4f3463bc8c6fc07df0dd62c0487c51755255105dd261cc11112d6db4f67f9593b2a45965c92c1210e215db1587b821fa8b8043def8bae6dec78ffc2273c74ae4a84eef0488b70f630b3dc27a8ea188779d6aad817643819e34a7445bd00bb14947bd9fe2be3c660bd772fbefb43986180a6bd2523ee4066cd53d41c3606cc313c32383b5ac3060f9f2aac055cfee63bdff422de5c6356d0521dc0bb05d2f763a5ed184c55fdf091532c7d2b5d4fd124393cb4a63d89ae13ca9aa71e06c3ec3bbb84f8abda14deeebe24fa477884546d7fbef786cb9e04b460a6d8e09599528129db864309c011158d7a1b0465c5df80f745c6dab62c56d5ebdedb416a0db3bfdf7a60c725e38a7341c419a6986be16c8ffb24ee0db2acc76f18944b8bc86027a16569a60c2315f1e3de18e3af88ae3670744c9ae0fd784fdbfa3d8f57b6049845212d0aaffff143df9308445619325a9d5c81cf230e9df46cedaa5dc55fd47ca039f47ba1bdb8566cd72cd2292e415d20ab8a278fd68580853e3815d8683006edbbf73de3a6a5f5dc2ff5769e9580141f2b20f6982a2b06ba67fa3b81ed3f04628fefd0fcd1c8a187939f035aa613e47e0975594cab2f9bed113b453b19973d109f8b7d8b98c1b9fb675268e45b142f1aa08cd096f1d6fa30ab19b41c3befac4b9a74c0ad090ddf6051f089bf55e4486290cf83c079de31eefae27453585a4ad656b130acb69910a670b9bac83e22d19cbac9b511fdfcdd9d5d4e7495f10b16cacace4f21e30d06b22b932a5ff9da90ffa8510180892b9a95c5a0c935f3ca24a02de848f6e5956f82f9efc0b3bb466a8394f5ca98220f14dde290b6d816effa048b3749c537a6a03de669f25a31288c45f33063789dc7091c4d760361f7ef7ece6521b098a81b31650958a6623e6312da876dd1307b100599d1031bb4b58e1baf1e08172d5c4d4c8e2ff450a64d01b0cad1663f4dc67673c03edf4881e05fddf0c6b56343c105d767c9e561d40202dfd682b79f6d87fd2920af21865f7119f1937d951877d2727e6d831dd5e81a5001bdaa162e5d2dba632d922f8fea0901a5244d8aa16dd07efe0420a3533aa7ceb2d544334a2ad3e5fcce5028ba9bffd62f9eb11c3cd09dfc58d6744fb10c98bb7dab9b4d4ec0f967f64ead75464b815dd605f0ee42256d246b56775b985b4f60f847a0f874dbddd3ae870e6d2c83b471e20b615c7de11b5b7ec95d3823a7b21fd2d852d1b4e955164c1439608ef114885843a2cf7140290894747524a306853a10259dc7cf2729643c2318ca79e1676cbf55af0e9451dc8e48a211251cdd40c0b492ffed66aeaa24d0503f0c0ed061a14835d5fee01b79195c42c718b5d0451233a569898db11d1c08f4fe81b79117ad6cc1b38911d828a118d9ea4cf5748b8e48664254c99544c926a4460aa4542e685579d5fa6ffefa70ed397aad49013568644a60d35b5c14db5e88bd9dd215f455c2d10a75affeaf276d9db34f07b4fc3cd9d1317dace63129ce86439fd6a454ebaaebcc799e4d3d60761bc55bb5f6f57784c430e690b41e90b542dba3f1cbdc9596ed333c49ef1cacb906892a1ae23524b2e4ef76283c90c55ef634d350c99ff15f976a92317bee877cb086e623489691094096ab0534aaf7b2e3c52e6193e04fef5d5fbda831c7045237a9ee7321e73731d5e1e5fd8876b18af5f8b9d14a89e3bdd702379b0993bd9d452a91a651c760c7e6243fbae93e1d68ff6e04ff7ec4773f9a773ffa9b9d9205fde7b653ae27873674759d18e4d0d8716470ae20cfa9a05a26ee88b36de71930df7c43e2dbce10d29b0ac2b8fc05e8c25ea56a75bafe2d3a6b1568fab8ac3102663f30114a342cc10eb400e439416482b0f79f91be5ca5dc5dbb6f5b41d98f1ce07dd0ef405072781d8aecd5967e709b5fec8770dce6e75699b62c7faeb66a3e2f958a5e2e71c53f659b45128a9399db6ac73b6257962fc60c130b52097cfd5a28e9942462496d400223d7ea9abc1c83240a39cf7851f440eb5c28a6439d56b2764251c702cec596403d288c3fa3962a9953ec5669cf47230d68af0ab2d811a2c621fafc8f0c126704c75bd7d55c20e495aa8c01005d646eec3113fe54de9cfb668af1f926118387a35e8d8a4c75610cdfb48278e92cdc95a0f9414109bedd36fd5a33a0bff2861136f6f54dd9879dec838a8d59586010dc6316c1444737dc5dda57a304abf8ca526c26ce214413d68de6889f9b438b53607a5143a1902c3a8b14ae447aa5c702d9230db6647ebc50f58462fd02e738e2eba24168766227b6734ec1ea5705c622eda5de97948230c16b2522680d0f072b75d9ba425056f9ae0e8883e39ae56edf2e123d3e7707f3faa6a79d2c0b3374500506772ca191b783960808b13be2405f9c2a2b5ca30f6d54ca1558b6f775c29e8518f43c1cc5f98a214993f4bf7ec4e87810335c842a6a3ce75f7c8b912d9ab874c7e469b50406250d020fc8817c67023c00cf75985f74ce5bff53400c0c8d0451f8b45d91fb1a9d6ecea11452805a34a4c1acef9059ae3346d0f7921140fc2a5e51f0347c08cbe196752a0d5419cf3d6021a8f07bd391582179f1f6d768370312bbd260c8c4c4f6c7b31df4cc6134e27f703247577e92b66623acbf965aeaafd35afa6bcfa3bfae786e8973ad4afa5b7542c311125044e930801e2848071161b89ea881258f28af4b4477c9347c93c041c88d46cee5f66adb2170428a77d40875682abfad54795b73851fe1a9de24cec7d4392a9e474dbb9585666634f84a7a5d4a4936e3b6f27a96071f77abf51dc5493f52a5886e61558bff885e0675d85a0bbcaa3512d090d2b13e34166aa807a1b34e494971757466f190da58092c2c10c0f60e6c6c0283d95b0d2dbc6da5a81988d8db8088fd0b60d17e9afbe3d89ce6d11b66fd2ddb82c2b59a8ed0442a702f4a527d757f088ab263c689c62f52d6040333a12a0c5d609db20f60d4bca8fb10ac9460840c58d5959d797e6c0389cd52da95833af01b255269b357a930ac9a3cf43ba1086c2865a30a2b205f480e90a3efe9d23b5b03dfe7f163a3055b60e34a512ce9b17f5a5e8be1987b33a3377311c9edd581a9ae0ec42fb88865815710fe01e2aa54f08880be5c9aa17cec4137e1fb0a7442e004ad3f1aed4981d30ba80474ce80b92106d6ebfba89207692a7c657e3f3a7924c6b056a4440c58b48aae3ca31dc1767c08c1dc88ea5e7b63fe070818bfa8ec3b15b7588780d14d990c105b25cd00984316117fc709f375db308d2c6d223a05b5e2539e19b1d6acd4afe3c38af66e333688d23a8842acf43b3d3363305c8121501f37863705bd3056c7f20a7aa672377e5578ecd8fbc093fccaa64aba72a2f1500e4ad704340ea9d8460e5ceb27c256f9cfe593d06d14118e861b7edf31e86ee81188abd30b7b621acdc31849482b6a80637cc740743196e632b86cfe725d45a28c7230a7e1be3b816e7e37b0cc9b80311c4d6768b3e23808eb728396d1448f84a5cb92a491e2157dc4c7382bff6e7fd255c99b268165b7417bcfa0538b70646f84520431ba8ec8ed9d4380fc67ebe794b3f12367a51d8288258df17852988c2c2e9388cdacc0c395d29c77b8a700d0235000b62dbb1a33bff006f9d7ce086d64c51f2e3a77a20cfd3259c1cd5183344f1f77f4c68378be115ab2b50968460f8754de5b10e9b7835e296f298ea87888f7665564ca5880958ab56cb20fdf697fec7567508d9d3fba6c11ed52d151653c57a705c4a291fe5bbd4b198fda3c97d9d1628a8352840326386d46bf46708cf99ed6b3453231d991bd20a9ccf71cde40fae100f498842099e52286bdbce43d222142b72abeb9c77d85c19f753642604a8ee1a546c25e7d2cbad0137f08cb0ac8b3dc9fbbe7d641994244d30babad0995e2a5a340c40b0f698285aa30501a264ee063b44dd4a5e64a31bd307270c21c1405e62829614d9cc9da4e59e9fa939c2be8f7127514ca4c1170801279f4c6f5b4a9c1fb9e45ecbf50120c188d3824927e7932ece28f94cd64d62e619849d1be5f799fdbc566ed63106c29ef42e4c966aafb60e12ed2d0efa6aea0325dfeec4bca7f13ee932858c770296ff1658d9554a01bd6d11febdd2341683074cd8d1ac6e4af59950a525263b2a0bd7f8c8c12e4ff958df651a51c6f22cc893c47506abc5398a15f269086b654330a0259e28594215840bfd1633e26e8473d190839130210cd53a29ff71ea0bcab25776b2029c71a48d012316abfe08df9f79d115bbed8ae6825a38330b21f1d12b0d119cd25b09f1d29d5ae1b27a860784990fcdadc35c84307a578121414e671ca722914e3b1b145535242af283d834a252d94117f9e7305edc2ba543145d5f3c2e4a29b23f1458ec3da4363b616c405fbf7d2a84cd72349364f02f45a75cc50ec88a84495b5d12c60b83728f24e0e4f1dfc69ed257a04a1c19e172452c6de0245bde24d143c688706cf06cd1a261c5c81799773d126a5c9ca7d0157c2f2f0a9d0b9e89160f6c24a5d1b732241b8bc44c88bd2c2a8c2310d916c26f791fe18c21e1e24bebd375a6e86c632697f5d43c2f1c6742ca38f023a1a288d207eb3c934f61543b655136eed6d70bc3f1a60b60ccadc5f1c4dce9184215c473e4ae95d4b6b77f09ffad731ca0c7d45c5fbaf81c5893109599d6471593cc94bdf1ea799d00104b676622641651d226bbe1c1d699b76733d5103d247b0e82b4e79af67d0bc1b3d4ba3678af6bef9d9087d0c0702f86c49c73800be29caae30198fd33c888c99bd491b780db254505e87904041f6bf8df3402a0691bc2d18348f82d47d6861a7c7af841674234f6ca865e1e1a81291fc4b7105a50dbdde08ff5aa2134e9ee8c47899f62001eb96516d8a3b106dd8ebea36db7ce86dfb15b615052c78138e53ea2722f2cc3acff654b93fa50a87d8085e11bdafed0a9aff0fbe7fbdc9dff253e1a2fdf9e2700d12b1acdfcd78a9a487a3da5ebc89e255cd5100a4092b1d14579fe51b28e21975f483a650b17bb52ab3c66fbab756b6d7265aa9a43b04c125b28fa83416a3ca7e6c30f4a542a0e35aead72379c01f734195fcffd294fafe46a0b5950769bdba870ad46cd53bf47b5474dd4ab94684e05809e63c37a6b9e3d7ff51f24f602bc7c8948eac5e1acb66cf7809e648082d95f9be515ffc591712887ad4f1aea66d91f349a863dcec6a5e18743d75890df7ad9d1e88d8d55c77a0b01ab3aa31a73ab3abf9b50b6073e77fd7efa39b2ce69346fb488f7a9be0b45cd4fde609207fd36d43861475583e9a993da981ffc40551169492a922d9c434cf3f19e12deaf75bcaa9c1ff1a2024414e9a580d6e9e6d803cb12d84fea1d30785869a138df39d4de651d1a1c2eedcd00146f2f281baa1269ffe324f8d99fe206e8402e83189354ffa0943d694c7072df4732e7956df1a6a0e774175173c0f5d4b037cc354cae4639d869a4e9f83f64972b10d36205850055f1ada83db6eb75ecea135fe8402058546e1375ea427803f2a69cf6102c51944295a34887230167fe91ede072bf34a4c58754c9049eb1887091fb3697e24bd49dd8d48582358dbfc08dd681990f19f8e0aaaaff972630a2c13883f5f2bc1a7a460e3cd2893fb18aa14628302a5e24ded77b1ed0c3bbc19ab95f4c3e67fe87344c29be6877873b77f8d00a1aa804470190e77627a7fe9615e81b06299c297b7ae30aefb1f6f80984062924a0a88dbfcf33516c108102ce7d446634a7ae3ae681daf10bd10d4e3c54f1fbb4cdb218905206f6033f5457e113598fa50f78110be1a5c8a5d3244f46b2bc614e5ddb8e7808a430312e8e6a69f6ebd288ee9afc0b9cd8fdfbad7adcecea1b118b80db11700189868c02a89ed625f643c514911ab378221639655f0c38e43a014b66703251c8742159f2cc5b7d98a851b0f68e1a5e19007c7b0c0784657e27e104f471670876dd9f8ff0277812aa1586f41bbc61b482ffdecf18696d1d620bf7694443cd36eadd3655596781874f2ed82848d5a1e8748efffb267ecd7a496b8bb1e517c5d65f4e47ab38c1c7bf638a1f0c2713ee3ad8c21d4cab94d337580727d8278fb8070c96fe5049ae07590aaed1f99cb0e4e6dfc23eee8e01958eac7394a46ea95be20154dc52c293426c2676d5c5fb1c697213be20cfe1837eb51f760bf3abe61caa02b2516b163fd013cb5672ad5496e2273753131514c5b6f3ea5842d91727b5ffda81fa8c0163c2b3c65920b0930e43df54f62c83b68d40e72e362488536acbeb05ba0de5e04ff6b1e673e29aa418b9d3bd92728d2948bc12c8d91b0e27c2122cfd5891c1143c7b88899bbe13822c3ba51a71416702fa55ab5f9a92091a81ead5e0c1da5c502dde5f4a860fe1bbbbd0108e13be8af8f12b5ec618e53cea4fc9dd35516964e4708d46b8d356b812d80a17b679479653f557a52cc7bb7180e83c97ce884b08ac0daef08784c1bcdf5a025d41964c89ecd912e3e38dfdcb13d25974e13ee86e25cae0a7bf1f788fc2661795eadffa9a023aada5466024bf0e1e8850f6ceb55820f4c4593e043eaa32fc107314276c99cc9c25f13f07ab2c978675b8a9d5c0305adedec3ceb93b2ac8471a04de1cbc9e27ab72d0f039f7290ef12bc9eec5be95659d9f7de5f6c4526937cc599388a8ab1d881378655ce3de14a1e911f4708e014ed87e06118138968999a3df8f50a69ac7fd01921fbaa0aed698ca6cb17520a01e2c040d9f78a65e327b1a2913217b3c9aa0d24084c10b706a99b61cfb8d11040e3a52ce92d0c4307be903c839e28f06099e0db142430ec1a6b1d4480e3c60ee1130b12da2f310910832483258d9b1cbab21e3e546105a41b8d639274a0311307da5a060e62140329fb8f82fca2d5fb16cafcf71ab3a38eef2efead5818318069da224bac1e58a451b981a4391c92cb9136b44c5b61170cf70ac7702d6c0edcf3598434ba5df8e843938c78020db17bb398c864b8a24f5b0f06ab9aa247b87537244073a889b992d50844afafd25d957404a427dbcb1c8f95c36b5d598101f0667daaeed571a05dd4f1be0a3fc6448b3f3139bdde38aed5a0d3c55f31ba0d4cd68da4d2775b84d21dd50252884640eff34ec440f2d3a0b2c6a0d2adcf9aa3f5a27d05879e660ff8ea7836882f2a6826fa39781f0199090f844ab6e28bac6d085d8c46ad78e2168d426fbc645d1a7bd5b106cee22231813d2cd9391924711697e87e66552545b4ff7b48a58d4011e00158b877808d5c8c5c48a7d57f295e1c7daaa61324287364b16b72a89ffee12094576c4c251da6836a4d2d49879df78ca0a1d67c4945091b94723b7ad7501b28e2e456a7ce57a0b30b070458dfb4023f8b48c4d00c3622c224ba7e3f0cc787c2db545dcca1cea7ba1664514df77ca2b89bcc79d1ab5c90852b4059e453c800ebfd822c8ced8581d54359ac364bacc0c2f42ba8bafd822c70238a11beb21d1607b4646190232b1d75b32ec8a2eabdf2d808f9d3aaff1764d16fe4ec9a1f8d2cf41459377e2c3aa8e4af8a0559fa88e4475934bd2fe6b12d1d66400d63cf28e53f65cbb09f21835d969faa161beb9448113a0b3c0ab2386f73603ece29c1bb5e90208b96da06a1b82c86090047eb2777bb90a069bfc831f1f7d33bc31c464d3168c98cc766581ba478565dc40407c6c69aca75878ed9e4457acbec2a29fb76a9ca67037095338d05a993513732677a7ac94b49f3d1e7b66f643482f371a5792a89b1e8c4e9b1519fa22c007e04c3843e4d1019ccadd2cdd2aae2a712b4b4ce4c16a4cb186c8af14e5cc4c61296a27e57135e18d1e3d1f52ccc553586e9b7eea47ebf907ee109829591f907757b017af04a3d76017c2f143ab4a5d7fa014b16632d591ed25b396075b4885ceb250c2093e629f524a15aae8ec07036e442a8da618ca296d2ed756df028ecb91362091076b541d202a0e0901b13017694ab46849901f1a1a55b7b3c1c581847301f8fba0dce5741a44cdc5a1360fd4459f1d84679bff6facbf5d1476ba79f7bcba9f20b358d1f2fd9e56f68bade9912702baa2c25d76b6421cbee54098ae3165cba833c7893b18682bc86276dd41a8a6af0f44da3404aebde47eedd4f7217daba5006c65eab7294a6f0a9bd3359cb37e13b9c2144a2c1dc69ae500d9218a9780625239213793429d9d9e212cf78ea6e4ea1d7e074c6c54a105bc944b89a5c426bf416b09d9e5604a73ca713ce2e597869a544251c9cc5f893ac0a44af0653b624925d8e7a570d63fd9d615c7dab0d09ffc6ee94bfaa582bee6f28052b65a0ca04dd39f57656e9253db6b2adb9e88f8303a486e58072d3b3680c9f1c9ca49840dcb2bcec125fee79f4347a34be87e084937758e1905521d53c65c422336ad8ae3be52832d9106a550df6a1eeab2a6569af1e85910a49e46b14ce91f2c16cea0c6b12e85189a15bcc48f8bb4223cfd4013f726c197f39d41edb8818387aade46c116236256f01a2b688f64951f0dd2e6c0f47d21b52928e07435a9e32907321bfbc587324288e33888fe0c673a2f246f051a458e547cfff81be7a573180f5ddd21a11da58ce4cc26cb1048468204fa918d07307be7301e3e6f1ccb5facfe2e1aa86af8323f01c06d53e415ab49af2c4e2ea466767a4ef98c901648520d2f43ad68e55361195278aaccaefd831b56be89b280cd27665e35f7b818b021c0d5ca2f873a5262fd5d956635cebf0b2852371cfe2b2e5f52b182041f5b54d628292850c05090f2bce01cb3fbc2cd330fc2ebadf8e7ded9b086bf09e7e83c0d4e5b98f886d84a3320de4646ffd85df09c00fc33404781289ae49e95ce66adc0343240ac15512b3219c6a6a93394a505fde03a0b400b18cabca06fc238658083996d6baee496c9ca063b6c477cb839dcb0ddb91920a0918db2eab574f237a6037e73ebd196356ad7634f137473bf60eb76c54030bd085445c5345ef4ec6522bb5ee944e7fc63a9c4916275435bdad01b479435e2da0ab42f744338136fdfa7659cbe386c98c3f9e0ee00b199b5262442343282ef767c2c0aed1167e21f2c456e74de1f9adfba9b751486764a39872263afc56378a1e98c1da168022c2308a49a27cf738d71b703eabae5944509250f441692cf41577216c4f8fae626499721d2e69a225cdc41778ce0ed85118b07f6bc4ec52bb84747a542f3e25634e7e855e09d6404aef0ab4ed58c0b2335754c075126e299a18995ac4321a343fabb2201a8857d54c731630612ae2a1f5752b57cdf000d4726e2b6a009fe3fff71ea86f5b40855d14febb52e0cd6ea070d181a2fe43c65beb98cbfb5a08619540e54c04f204edbe1fa5eb8b04cd07ab37fd6c53bcbad7d8c3c83be0d4486d657a506d3157eebf02febce9c84337d924895920a528e625ed705e6d171eb208b0c8048842614aefbad39e9f54dc01692f370d509740e8aa94384335109ca17ebb6f12a7c9906fdb581f169184111afd7245c761d2c8cad1a0f311b5561b2bd109aec9fd32b6780fc2556ad5671e43eec641a04a802d3d08ac695fe0bd1c1d45ac1078faef420880195c334644d6082615d32aa31a17bdc67565b5ed2035426e68dfd708f664a04509a475aa5b2fc42d7d10ad45a718713a38fdd70f546cb9d45b23aa3aba1edddec8d8422fb2beab124eeb934d03a1184dfc5e2ff24ca7f22f1f9c05f0ed05f0e1c17bf2c0fbf382fdf9a0bd79e1f41e911764ce9960786ab36948eb0f13f93093eefe1d5b7a9c516772960b8877bc7194f1a23d8339d4a1ef09d0eef9473a004adad92af35cda979c5f8cf88662b22d8666e77071010c60832a1b2a30b12e09573af4d88657f0076660f6d9e1766821fc5033cbf046aaf80ca0fd1ab364b9b728403422db12336bcac7d245322c2fa1c2fc7212fbe61348b8b7b9a666856010c91879e619c893d133d81988075d401f6b4c64fd89b262e2ad74d185666b4dc0fa136415132f891b2a333542183edb03b493095e106dfc324b68b5305f9138a58fcb83435faffb33efd5b3fb003114c0dc3f50ba80b1fa76bb8c286cfc7623ba646853649027999e5824c6e0132421f07940d0ffd96735f3dca09dc828397e94007e9c143b4a041b4d8a8d2781e140b2ba31f45961c2d69bb815f980a27f8de08419ce244502d43cbab684c09e970ef9d73f994c9293c0d5281db9412c45225bfe0a7e3659a59d0b04852a7239f4fe9164c0b91208cfa164a973722b118b8a343c11737a163e9766220c42d73aef20428f64316c3833463da733be803cc71d06e6b74b11e6a6337adf15c3d33cc138ec1c498e4a2fc864d2508a7d794d253b577316c472df73904dd478567b19c7a7468272c60878006b3705d594837821219f69ee28914b1414cc9456548085777751e41b127c8ceac98ef94e1b32be97fa8e919512eeeff8c2cd86eed6bfb386ebbf8a45570ec828d17236d129923815791a8822890fd2ae883135328fb269b05ebd3847799b5dc8580706d147f0ef51955ed0c2cc7d48e9280675d795711e9a33a58f7445124d5ab9441f83ca1b253c1b2f507172eb5c64fdcfdd2ba481e67bcbd07f67f12af6a036e9bc26c73095e03a1273bffd8afa559001b13f696cd914b40cfcc0800409c08d5ae4c31c2a61c549bebfd736f74edf419a52d619b5a36729941c09b2d8641c4aa5d6b5c04d7928052bfa37e1b94b38b8a2d999389311d0cbcc69d09ba5b3254bfa2842b37acce98e5510c705103234d4755ac81e150c96cbddd0bea8aa979f10ad4b94966c48f9781dfc63c913c2d85836b3b4ebb01a9720b5ff1c62abf1b6e61cf96dfdca8443cc8e6e78f9f3b013102e721d585f01f812d24efdba5713fafa806345727fbe1863ad8044161f61e5b1ce5f101d8abf95b92fd6b3b1ce3a1800665e5e90cf27f820c7e5b25d1892d24f7695bfc4ca2571574c09a05f4068660e2897c4a3289533ded5231120130490c497836a1e684ff5ae842e7eb0a93f24d2171840db657febb9780e2037dc659f537129700dc3eb23d5802202bd6b7a73140c0a07fa9fc0ed31f0dda79a2766a3a9d48db4f60eca92f89f1b74ba3a3d58f42976709234f88df7d4640a7ecf2f4ada76b6096d4ed12ddf806df6c97b7ccadfe86778048ef1e4f888698921b139e63f43b66131b925508832d755ba89f7c139bb543199263983c990d400a44a0b909e86fefaf4f7e7ad55996d8b8da0dbc54424f04a079d0a478e4d7a19ceda63eaeac45c1c6a8425794bca5a012501888aae746b7ce0a1697ad2cb4d89303d21c65c5ba15f3f694382aff606e41f97e46b6f0010c802c93901e9dc3ce24a5faebe376d755d1c5b23cfd827dd30b1cf6ff595adb828469e04499004eb7f98a887533abd0cfe2bebab7e9357428aa7ea9dc5efa713403f6860a9e2e03f0cd96d545c409d275facf74e70eeb3081513dadf442d3cb142c25fb9d8e328c31ac4bd9029e853059af85c08d9738e59979302b46767598f58f13a55dbab8aa2330ec8627a2bcaa9ab169b634aaf656f017ae08d059ffe9e4bd79d717db5743b64ede0da329d2a9d99fcbd5ea3354aa4377ae0abb5bf9b15287caa37275131e69bfce3ff429756911867010ae918e3a5948fa49fc8aa8b6b60f60df456aaa4c168df75e390e680b885aa6903b731dd0b73dc293dc35de2ee403c91160a904d60708c6be0f98cf1fbe0a7cbc52011f6f169b18c4ec2a37b85ef33c01572f0a7f1f5211952e027546e53d5d16ab5112e2401c9a9cbb3e214e7ca6b4008d2f2b7d7179b3d2a32c360322328dd8e81f99048afca1443e76ba4eba5c3c59880d3d9b7db0a65b634701e5ad42cd3d4cfbf80cbf20593dc8b13494afab63f401d32a1821967310892d6f71949ef0a1fcb5cba190453acd93ebc35ba6eb774c551b56d144fdf72c28287b09f460a8530c0632495136129e4b13a749fc2668cb08d6a2dd89579e6ede8828a26666e66633f4ee3d46a6ffc7ac6660620f0072e19a6e66babf594e8f4cfc0bb5b0fd5a6cf8e7fcdc5b9de6697ee5fc510edc804acf530ec0dc3540ab6530fd1e717532be4d17a922109578b39a31ba0126b8e364b9ec621d8b327a395ebb7f7d3e78ced2fa3da460ef928cf5331a08644a156c5e62a356b2630920c69bad52ab23a96972cd2cab9b20311b77426acfc4a3fc8349e295acdd1ed50fb917148ca26f2de6772fdfe8973bde0ba94266513a208b284c34ecf7fd080fc9643079992c59f624820328875452fa0190e821df7a7f992f9103fa1ed6d0aea49db541e433f60b3ce882faf3a9446bfa8b085db4b08db0a014913debdaf35256fb79cc122874b0d1aebb62e2dfbd48a02c95cd58409cd7e7ffdd4e1493b0adc2d2205886eecfa3fe760c880760e649d081df44c4ba95a9553eb25ef067d882017f6226a5b51a5415e64b6d5779360b941a0bb1b1d24a5da365d3a004f0f1b3f7f06abd48151f830ea8e1d6026c9c26a1d641ade089d90bda2b3b59e4590fe0e8a23594d5f806339f8469c0b6b05b4c90968730fcbcab06152882be2118701217204e3259000718c0505ac0c2bade30dec65cf227217934c6e07ddc07f808858018e1e781e2555cd8c9939bdaf18087452feff89c512c45f6cf6ad89b352cc3bca71071bdf2a1e4e1d5254baf72336f53d7b62a92e4b80db052ae3613930dd4d278dfbde813233990f67f2a70a99f02827a85bd9b9f0d71b1b252effccdcd455708fc56d6f1fd04c0e698a969f5894f5c02d1eb617bb76773b91a29cb3a75c81dce83041f7300f11c3b3879957335e47e535a062ec187e5bd30f8f60f592d43a51dcbf487cc81c16ff7388de1813dcf2686342c32c4f1f7d79ae2f66d511b0c9655a97dcd2d73cbf49203d6c387ba89967839e2cd19764a586f5271590c0865c28b4d569d23449f75371e5bef727d613edde17b6264139009560d0e27e272d231a89fe91b5a1340dc99e671c42530b1182fb18ade5af61e965a32d36f4be17d989d14e71006d176c30c11a3d84a80bbea3fda6105a9070b598aeebe14df35e45317b641f0a7c94e7d4b454615a5b6985a6603635548ec7ec3e556113f91744835a5e2e32954e787f046c125a10c60a28ef734398a3a342923035b55f3a123b82a3d4e6dac42eb715013e0f59e5415b7f62f6c7d98bce628a99b59a3a2a04b915f60cdb5c00caf94d314d9fb14585137cc80e7409d59c109b1d7376e0ad6a302b5ec8004ae10c0bc809a544e4d15f08fb843bfb0c365a0ffb643c8e0863e537fbf738a56c24e8aaf431ee415b94994b1da377cc16bd2ed5f27f4744fcf883c31fdf9a5c515499417940cb6b48174336f28d326d17f7defe13f448d3ea080e3ae4315bf37dc7180e9b1be3a9fd87d7deb37ea95545462a84e5882e02c64acbfdf031c95c7be497b1345e55b41d095c16bd310659d8ea85cf8bb554041aaadec6c1da0b9ad2430957f2f178e61596beb3016128302a1cdbe562f50f70b144e87927dcae7d1aa654e943552eb560d0103d4a317446051ebd95b9e0f25b63ac4b7f08e7e575076b3ab2cc9a6a82d90da484843e04b63c605bc389d318d7cd6c9ea500dab4b4501284bcd3bfd4cd4dae4935fba56556cc8058c71d19900178d8192102772e941941bfcd9e34d65d38e0d885f890e3c1954266652bd62dc5e962acd5c77d6ff18906d93977f0a344ba0c10cad00a750e4f06d70ad8953d05b44418b4641def41a6102eea02e04b2d1007d7ac5d7fcfbfccdbe0c5988c05d096660aa2e1110f77e0217827848af8b1f92ae0c0d29956642fdf55444901ccf7c0e8d7412b4022927f5590e9bf6c3e96a3fb077f38801d44c6cbb778b978b90c15ae7c4799f58ad2b413227faeee704ff06bd0afe6028f755f66f43972ffaf2c184cc4288240ac8116258691f2e133acf7dfa1200392df593b8a433ec1636a24ce0830d951306f8ece32ea1270850a3a6fbdd6668d1734a71b071d7f155cfb3d59d53b26ab2013b3b6f7cf927ea7ac22ed66a5df0da32424383d728598e8b950d06cde0536f4dc4711763baa72d41e65dd5e5b7dbbe04af03af225382b0c88408b1303fa42fc0c768d7c89c045bc353b35bd70a72d8bdaba1c1eaab105e7547fa896403e4e64d0abe32b141285d2aeaf196bfeb872e4c82c1edf709b3ad2870519a49c6fdbca69fd020d373d8bc5f259b46bf61132bfd2f5ef42bf6062cdf1100d13137508cad9249d8c20ba32e17d68808bf0c241abd09872c9e9e2740986af9ecc6087fda780078e0a45fda0f9229118e40848e3df6063632ebc2df68c7093ec5e14d3eab8d8c963ad159c99582bd05de379adece06329e0c5e22761b36bb961063a9cc42d4905cd61829c25d5903a0439d9678607b1f069e87345b74a16fc36494b499fecc9fa15f5d52c89ca6526f34de7ae01a9c0f7747c812d913ef349fae51fb586c841d1d09f0b9f6df57ebe575c51e10b421aa33993dc21866d786d08efb3e9a9331629039b95045316d82eb2686754446f378bcee305001521717e3596268d3a49264d586eb9e5be056d14dad900ebef7d5c39fb421f12e19e5ce7ed7fbe33a67631c7f3de0620be4eada8b1fbf536f43458d95d55b8daa5d47f4815cf59c26430c6aab73ee93c88ec01587915c3ac3c2d31a69ea5a544ecde3eee3ad7435f878588cef36b945dae7d8544da726d2cab2c54e3db403796630be0ac6ae9806638b6a355235776af17d5108e072307ca65d3e945d3e99ab5802661e776d7fa1bbdbd2afbfa1b19817c1372f818e8efbe82d6fa60408254e30690a21ff1880329d9b7060d7122a5960e7629de356eaa355d8d205f52c7bfb4bee830642302e4b396913b90a5587c3fc88b37947acbed991ecf74144e985a7d18ec9ea8fd6780425507e349bcb774c29f476052e6b941cb8981c68cc4946333b7ac7b841b15dab301cac3860c29c01e8ab4558f0f0c97203161216af9d3ef1e5d413e7dc0cb0ba948e176521cde6b9f9e854ca1063e24746be5b8810abda0f248f3532c98d80810cbbec31adfdf83f4145c99ef5a2d6283354f0081464a20c14b09b37f2ff96a796ed4d329c9d6cf9867ff1ce949670f20292d5ee81c7371c46674ee44bc13e84d2180858b319fc54e8af3d6e5a31031bd4f1f6ece52fccd0c1ee303815d727131b499fdacca6ea4a12009d00fd4b4e786718a45fae6d40b6a820b05da137d2784eec42da732582ac79506eb714e5f918289c1c9bcaa5d3ff02808fcbefbe772bc66ec00e8bb6e77f0de8545370fe24fcf47c1ac5072c2f931594114727b2cf270667d1ac13850c7a663188218513809580cf34711c4467791d641c22dd43db92b6c9abb78a5f1fe4df61ddde26c9576bf6d93f89214b7a919af4ecbc70bae83171aacb5d18624587146e609473acf24e0908a492031e3894245e7c089d7376e9d4f26e4d8ce322b5d6cc128b8af145b2e4318dab5e32e076230bac49d7d43fefda5f4bc1ffd5d3c7865f292a5ae758c1d9e979a3eea220c4b7bacb59a9e8d773cd3f9a4ee580cafbfa66ce9abdd08f005b23fdb826ec82335434d9fec9abf71f3f810698223e9ee1667ccb00a88d5ca2f4ef5a7a9b5000df0ee9dc36bbe1a9d297df5b9a7cd9798e4773e78515baafee0d9a32953f3a7c63a962518fa77601760766b2dfae2338b857b5f3670dc0d50beb1b2a1a4e212d02c7efc65eb21afc70b306d1e2169314b86795201be2b371b69cbd05b8e05000eeb742c421dd510ae4180644a600eecebcfc5a518b0b9ebbf61dafa50253431a8ec1bd0861376088d6e629761b7ee6f06c455804f6aa83e491991e5a052cf3e194fdce816b3b879c9f28b12d78924ffa67eb9f8fb5825e50343c80e6822a20dfefac3df568e4f5cc6b4451cba49c2b655e89e49acddb33ae672a50b4a2a305d4cfe8d22fde707436c18e690580ea852a2e07dc5f010ff4552ab90da9aba086ce551172bc889a536b9446c4296b5464144abbc1017eac3c37eba8225a3105e2e7ad8f28ecb85b403b1431ce88b715214dd2307f96004428e910f631e55305d312072fe54dfea44b87cd0f3314910fc46b0c55d6779d1dc8fee9c8dd26dc506427919122f24fa99be1ee9e07537a4b0b2589e356d263a7f124280bcc7fdb450a32cb1b2682131bd7b1de49609b155ba836fbf54c06350533af19dc1886b198c00c153cf138ceeb79dec9be8afaf8056e1f60a0f605de261b823e6361f9a4bbc294f7207c3c402f2699f39904b30ddeb3c676cf2b9b0a590a6da9fe9babc9db585141ee52f20cdf5536eb6b5681637e2a6d1a71001596113066bf9d9d02013a7eb86c027cd0ab5cf33de992fd32b397dff9f7a6f89fe15d3a27e65cb8e6f8b7615f73ac8eb051aed96f0b2b98012263385d7617c003749996a25d6cb297e16c36330c820c80d1fa8a2ea7061c30a10251fb0c14349a31b22ca1d0c2a9d4d8ffa7b1054c91b621ccc3db98a3d376ace70abec2472fb6170efbf98d18293a7d83c3514d0d691b135cf50b4799d6cf05aebc9dc741e794251b7d955f0137406f80f4421ab81e3892af4054d1b08e821444f4884ce89fc08906110f29484bf0a87ee3ac2ca5d9a2de241ba11a8abed7f8de1aa204ed07320705bc58594195ec8c60cfc50ecaefec9357c1107f290b8bceae4a579efb4dbf7f8c6d68d75c645c8a75be3912f4ea667b2a9cce0a981d6ee945ee4be415e3abb774e026633203fc578d819a46b419dc5f28d60baa0c5c8839bd399c12dea78fe04958d6bdc6f42b0156a078f6ceaf532702e9b08546beee09e67be1c5cb0c6d65b3cfeeef1c9368866dc567c7e07cfb78d567d86e4420eb1125bb1c20f60eda506030331a7982563a4524fe7127803ee01d7a05888531ec29c6bc25bed12efac639d80820401def6401969df998ab140c5c60be89b5e109123bfacd6ba6337708e4cd1b892b7e1d1e0af347d6bf2926b1668e4b247ed86d0aee5a22ab61f276e53d8feb60e2a83debc39216a5274cbf30f41fb5dac6eb6432d7f70da428a8d100bd66e7005bb514c1ddaadf6ac52bb890e1858e4f62d731796087c3ce78e89c831de76ffa05340a2fdd4b47648ea1022c11f87a438c872ab79b976f3c3514526487e26039d0dd9ee1ac252a2a5051ab2b8f3cbf5168314b1e8672a3d2667cf6b1632d3488e2ea4b0bcafe99bb881ddb9aa28587a3fa130bb21e790e6a51ef4683cc51f80006b573bc2bfbdf2a29dca8c76c6555bf70f2c0015d0bd7ed7d10c5d3fa91ced6aaf76eacf7627bc789040b288032422fde09981316d864186c04cd7a4ef815d8e52568467e67a938b76e4920d5a6ab3d6249245642171e30f9e875979a69d95d5d79d1cdeac825123d403d5cb76590f9ff0c4932dfdb74b4b15ea652edecedafac45deb5766a6711976cf17235e537b8bcb92f00b4684d6785e841fe6ee6b455171d3ec88c9b07c22e84a147e04d526e4c69931f4063c3c84b35bbae99ebddca62d342633eee7e5c5163661c0e2c8aaaced6f64a6dd0ae2b9d9d7623a2579e07f4a433db7b4730bdc156e1cbdf98e0ab32924a3065e71e20582129652cf0b504ef65370d6df2b983397a915aada5f5f7c1db84402efee07143ecbe176d2a7a9150eb152510b9494ceb4cce0de0a010c7ad23979f749a79ce4e9b6a649e2ad93f39bacbd2c68bdac33cabe96dca403b672cf19aae8bcd554c39dd4caa786e31a93f06043666f1bb96a3a669aa337f7bbfc6d35a9f52e51186391c3fc76c0f9eb06868213a2e1a2c76a3d421f3e1f6f9e280a271b3637bd30a13e49cdda2b3853c510983eab1e99421088f03cdd7d15b485bd33708e8d711e36ed799e9645f8f8c0a45ceea83ccef3aa1e2fac8b34b38a54e0534d41462754beb291b521c5bebc8ea85974ad8fb760ff53597d4b47bbae32cf9267c81d2ac8dd434fd95c79ab8bc9b2e426b25d333c89c4943323cd1a454af7ca6ab971d54f1894541457dee601a1e595fab33389d759791b6a96ee32db0144034c8c8cc043fcd5c84d0a4150d471662945ce7114b200aa324b04949c737ea6224108eb70baad2dedee250bf62b5cfb8dbf9943300afb50f5a0dfc97a483f555e8c6c268805922350fc9c831ecef796d50b60c3efddd2e411a081634630010581bf1b16906e13e040ccb162389fce8d02ac97477b1fcec306fd9aba054bfc720772d1b518a43773177dd605ac08732a591ebf20fbe01b4d489419490b77bde7bdf1a0458b372ec55b4639abd562ab15a83114d414952d9efe35b32b17e2a6f6ef4c5cada7ae424f1a528eaa948e90bf7e4fddf4b9149c29915586ce94be93f020a9c8c5d342b0231823af6e3b5be7cdd7c0dcc23a6075a2d8720b94230e0567b264a4a17ad63896c6f473cf009c8219622572bfb83ef2162941a53db87f8d51a986bfce95bc7e70c02d7904479dff38c0ff072a70eca4e49ba5a65d487aeda903ca17ea41c77ea0ea0a3d2209baf6581dd76b3c838ae43f78f758987b24a638589bec588f691d512d35a18b645b7a5750f141c2574d95ce44226a0a37b456e23753d43b808cb4199169a60e3b6cd1b6bb05bf93375dc8d6ba8d8cc28f9b2e68422784a6b120734c01cbc18dc9fc62b8565310a971d96ab1f0e98b78dd8f89552c320491a9b481e5ef2ee9769e5915bfe221690b9f71dc83985b8a370d10f8e7bc18c096a78fdf44204c7288313d5a9e2ac4eb3745c097e198a13249c30ba0934d3e5b7fa03976198b755f82073d63217a4d080335372ceff68ced64246bc614d024de28e23e2fba109fcbb34dfb208af1736c7d7b712dca551cd5aa88afdcec0ead1175e35083fb100405b43ffb3e124521698b2238f4cb2f29ccf3bbeb4a14d2e5585bdeac72410ec5ddd0f2419c45ad1f9bf17626de34a55bebe62df6610d85b9e55abe42c46a6c928c376235f3c59ef3dd5a8c97f107432d6971e5b3bfb6e496d1e46182a7b6eec0f8425078eee2c670a1df0430e7bceeedcd2927e22c8a70bb482f76e425a75f9539bdf89da8adc3299fd961071e1c90753ab35bda8cd6b27ac0c09a52aba7efe12025cce79391909b369b487bd0b2c3e068ba618031acfec21763be580ed0cbbf7a849a2fa61b4cd7bcb01ca8e9e9778e16c05512265c94a97dc7dc702bb1f8f2218d370e50a6b2b25a2056314282309b36f122e082e4cbee3b71951112217230e2b523657ac90cd1aa2bd1e60415cac18b23f446910d64807d0c31a6abd6407bf821dcd9d06bdd8b8272dd47a049bfd330794b186f80901b4e278d41710a30e524c1818d3cc10a1d1f307a6a2261b3a4162dd72183f249b40871e6fc6a7a07a8c6b4e2e2703d5a7b72bdb1922a89628f89c3c9e8c20d77b894dcbdef87d1bfa0259643c24c9079c27cd581ac9f38af3b6791b6155ab01e1d6a3aa124e835453e07cf7fc060e49f5f89dc9a950b36cb450eab97f0422b1f3dbeb6e5121b6cc0b9eb524c2211827093bac4ddf1287db43d1868266b4cef965812f1ba995ccaf021741bfe372f0b4d08ce5193d4c41ecd050b6efbbd10567c04e2e7ede29fef63a581600a089698ecdaad1faf6e6f97a3a1659a19531988efe93aef944e53adadb6667866b1598d824063c5f1a8e2b45323ab45218d521bb489184990226759dd92d222039c997201259291da83a4656db4cd852e38b0135d27d77eb1d67acefad76ef72855e7b2232069c8d95b831a73486a5c90de4b500747ad9a0bfa188c64e2a0bab34f325f7c911841a9f0d01bdd7637f1428673f16a6f885aa3e3130e197ccbe1bd1ac324cf9004904768a610990da19fb72083785f05491b0068734bf9469a0e95d0630b689138cf5b9079ac961058f21edbbd1b667b2f909597cb92d2c83e5f16737f7d5124ac468678ea387f054e4c05281b8a7f42ac59e73d5615639c0641eca1ced0fa7e23f3629a55b3720ed259010a0229d77adfddcc4eed355620234f75eaefcbf721c6069cd3273dd2abb705de4b4cc94f6a36669cf8971335c999990f2fa2badba91fec6d635568f98562d6caffc47b190d2d118a40556aff35306e0055a262291d7a33c14b9434856e5c812f4e065e895261dedaee0aba99d97fcb7523effe3298ae12bc5647f50e0930102e1661af3709b55c8cb7c3eeeca2bdc650e1363313f7246a47af3e54c737d9e343e0b18812fcde8d4018509744c10ab9c25426b8fb4ede8e0553903b1abecf1dd4af5ee9282e264673046ef306c8507bfb80a2ab8023ef479dcc2bdc61a4fc171cec3bb2031cf41337903d18951ad73af0c466f4b7b97060047aa626ba0df5ae037cf23fa32086a437fd0d20ffd64c44941cf5bc46695b82d70aaa468e74d0aacafbe5d53494c81a4bcaf5f2932694f398bd2618a445f1c24b38416960545684a83d3d41a731b0f94266aa88d5b214bfb7b25cec90e5a085ca8350f540439948355eac80917ce58fa4cf5b0b2342a31a87102e15e8f463af8645372d4611dddf2adbee1b10ba983ac8f206dc4f26a68feea0557ff281a024e244e1bdad89a02628f29f2ee536ddde30dcfb70781c706a4f71130ea7d11fcbdf332465b55a628b200480bee045f7dcc8a6b7e49f8f95d517e854c883d9c903f2ada8c9fa5e2bb8aacc39193cc1981e5b6a47f4583de2175d3b07ad2399853feda0c0e0a4d033c713bd35738a39a4db329368d0d9e7e6d473aa102241ed684795fa634d791058395937acc82371a23afb4f6f16b329bdd1182ea0308451e6451331dc19e907ae6b071fccba49a544c237cb5aae964a5aef317f01af86b3f8ff855f82d9027ea783117696da227da665b2d822467b79303dda38456860b0ed411516ea85bd8149048476d05226b458e0fff419210193fb2e71c31a3e72381819b8a2a414560ce75d8d14d4068ad316705c1c111cc8838a80c997a1d2c80b4c0ca0b370a9ee5b4b2caf9a6771cab747d2590dc9328118fbe9fd7dd499436c8675c1ca0d8da120d1c4859b78412e52270071c8d9f12e1014e56cad412307361bba42b70fc624b3a6928415bed432d0af50a95f6ec1e45821996fcaa158a004139c6f9f7de0e40503641da14352d6205e0c168a9ed249473314191dba4c914b64666088f0de14d37c22251c20a4274719b3ede3298d4e6aa379fc3129297c83ba52b38158fae052d2db0c0d951a677843c72bb6e5e85345a2822b316ee76f3dc1ff3310f3a1711febf5cae0f8fe827d6abbe69b69e7ef9587953395a9e95d0ee96e7eba04a4088fc5b57670006f8f58d051a4d954e5664ce646c9c5fb8bcf80299bf58f769d4d154f973a96b2b6a087cd93359d4de54aed72d9cc904753cbc234988430004f845f21dc1a03596183d8836227d2aec3c2e2256f1f16a8191e939937e5b8b18ec8a53898070c26913666aeda838b3fc263b0cac11c89905dde1eb585a6b5cda285d329df9b81fc3d55ee79a9675f90a0d768057c8ba8e8275d9fed2eb242851ad95ec31e27cdcf0e8129c6b449eaca55a3bc95fce32436657b8c8d93869baf85b572cba847a32f85d8aae036e838e97b59016a7252800e4e0a6bfda5cd4e2e55598403299650c349859daf0c28df140f09422ff24931f6c0648d7d648b6f121bb2a5681c9598f56f91fc3d130f4090b153a1f1d2e63e9d3ee37b6bce2ae5752a6af5c2271b76dc4833efad11a4fc19e24ccaca6a540d5da4987d21570f8c8209efa6806155ac91de086f2ac55a0a6e5c358966be0a9a00774e6872a9d282fd6008b18856474700210f20c3947cd771eeadf2ca4ef13a140b43fe3a783fe432dbdde68092fef56d45b6d0f84a071c71c7bc65b48a617bf8a1d5f3138acc16263c26ed3460d88febba689c177a49a3fde685c74a47efb2934be6bdaaf0b18b89fdd5c34b65144e140a0fee77bce28fce6e870317436a5488a69ffebd4e48f3d4a0f27ba1c6d82badb3edcfed4951a8363b6e816d532f922b26c3013baf124fe089451f2536466d63e00c8be408e9925413e3331dfece5fd3ea66c7af6ab0b4cb91a2571eb55ae64400bca7f066fe526b599539d6d1a9ce3a22c3e3c535786a4ab4da616ba766a76b01693536a7f6bef4ebb465e0252f01e0c2af6c26b3c275972479823b2325860ffea4fdcaa9725eec36c93ce64b572f9d5cd3ff9fd22d9284a3d2c9a07ad164ce4df438fa403ecf11ca0f75f791343dc52d3b0dcf791fc23ec18b80e23e0fc1862ad695bbba5162366e1e4433432d84154529144dc42c80385a277098552800615a697407d622c91633d18c62cae045b0408c377e44667f8d8f8ebd63e07f18dc628eeee2e8205713297f06db472bf19c6629344cf18d80c7de73095822060b9947688960e10718a782bced301e91d031ed944b698cea3ee8be83b555489100b26dfb34e7282a99ea04a88d2da898d389ca622a6129492aba318d8ecd3a9e335de1d2b4949d637c2b3d6b8533b9567047407b7150acab47aa79bb412f8a173c8a3891f63759308b41f0bd2ac47897f3e422ceee39156bf0665074d9103d106e41fd534869e830a6800b85a41c745cca3da607071f0fe20796d10f310f49d410aeca7c2ecd36028ab2524aa0d665bf29c3a9df6414fd2652806b0d0b5455070adf01e286871e041aa9620cbddc6494dcb6e3d0148d32347442717e06cb366062f3511f43458c2f88e3c0984bc02b1b75e7e905891fe00e060ccb67498ff274f04d62ee74a1617f59de2142b6259b05dc11479e1e6f4e0221c9e3c9e8ac073226a85d8b452a5c29fbb21929f2af8df54231c38dbb8b51e2c43745f7da1885db544d1a89e23841fd0f23a8ef0908f8fb48cc8f8532791087c6eca915b823c1a771d466052b5b945e93e2dd510d90d48974402eac82fa8563898f1f129731fbb5441556e7b9925134638ce6758329a8d047028c026fc4dc6def4e08326b20ea33fd951e6a76dd3f718cf48dd7a1acb615d1c94936e1dcc0529d8e85fec67c589552cb1dc1b0403a4928d3322a942df3a06cd07e6cf9c7ea4e462fc9bd26b01c970d23a1077ada751f579c4313be20bccf864ce2edcce0bf2b9a79853f14732f9157b1675d35e0156eb0c4fd0c1bc337e85cb4f43b32565e726be9923b1bbc3700080876d10fbf3a6cc4394185bca9e28a9b21b13e3d1583cb2a0a12c4fd195cd68790208168f7cd9b396ea665f88e7f4374fed332b7d674c4d8905079f2affd554a67b4318fdd2921d935c2b90a32242435684ebe5deacd3f18459ed0afd821f85ce8295e468618f5dd443e06c5d2b43b15fb2392fc5a298fbe5aad471d230a97a8da977d348d8f820f81f4307e66f96d3e8c3e3fbd05f601e37607eb0d4d121e383d87776993502fade7d064a30968eda4fbe556304ee96cd7656a94b8a89e75308e5937b4ddb8107995c4ffb4d0feefb73540355afc9ccac00175972cff7c3d00d73e0b888c94b2dad547bce72f92c4279520551b7e193a55f1984c2c83de3053587aa80a7903746df390e4b0e24a89facbd9d3fd3c344ebce5fce7de2313b26c51539c0d8d24faeb1937677722d53df0cc3747ca9d4149442e3365216a70a2dbe5524c99518292fc02ca5cb9df82cb3312d8608793db933b4725ebe19b20a9f345dc0ef7a8e2a7d0c50f9d7a7adf168fee0f21dd1d09f341e230af373b2642fe6b81cac8e9a727e3ea8fe33e481893196547f033431e84f629a16c831d82b82087df77b1297aab111831c5f65bf6353242dcf17c9f1ed30aaff8780e31c99a3ae0230e905ae9c861f7878978f98bc41e0209464c9f4a4a6b2e268620fe00385661036e8a2b043c269cd81ce7fa4604ae7c38e47a95e14066af971bba5a1584cffdc8baa2a9bf46926b0d59e7185168fdf8567d1b326a79721d64dc6e79635e68207b01eb5a74561371c05e117dd24ec7d92df3b8be25e0523544d6a605019b6a163206f369cdd2a7adf279ad5d1e5761cbbbc0ad925956f41c14b53fafff833b8ac4baeb7bbd8867d9cca0ff21697e831c565598cb1d4cf95e49c082f0ce6d12b5739feeee3f6709475665635de90f05f2949e38edf8e3f366941236be9b1e4d19ec2ccb6158baf3139bfe5823a017b5c6bf8ceadcf254d2257c0e13c4e91c33d0b35e1bde10b28b9afa819e8d99f0869035e89f655f96520c41b8af53423d162623f2aab1cbc02d87e1484ccf3c61abacb4a153e637c0dc151c1a5d8662b795941483397c0392af5555b0ec1f71a9c52d4868c761a2e2becba3d61323f2b7494b1679ebefb9764763d369103bf98b2cfbc85fb211fae33064f188fe574950dbb03799e3074bc35637677473694429a73aa46f1766aabd5c1d9d47aad24d9a5572844246b3a130dfaee0503675b1537d532a1288b2d51b27d3073071409dff77300117528a7c3d54e803002a5fc8ed799aaf66518214d97c4ea54c0c6c3f0251bc1c82752ae26b4b3756eb0068b84206d06b645fd4aab760ea0ad3cd651005c1adc1bbc691d93c162d36d4480060ba8b4c37bfad5955097a9514c0dbb373b8e2673f55b17e1b538a7174d4fa42776a66e5a9afaf73cfbf3cc4311e9da04e23cb43196420c0cd6d82b4052c8500c3915ff8ddc02a6ded0d94c068eb24c622efd1619511816719302c6f6698ade219f4b9dddf9ef0a5e3bb37395b034a1e0b627b3d6ae09cef9d859eb60174dc5910e03b01d16828725de80115f80a0caf0cab4d361a1f852f991c65b05a450facd92fc68514ae5fe68edd30e32f72517686b33039c1ca62e04932cbb15136e440dfdd229c69103a45ee5f2685cb65e119a5e9c3e53a987fcef1f9b52da912a563ff9638329dac5dc67c2d2da65d40f9bda7d9b58d230528d2fa777e906021ac3a42b31e7db4d2705f1688c3c9d1f228a08ef0384a9faa05ab455cfba81ace3537ed8ca5b369886d43ede41a3e6fa8b7a9878c5e7810ba0a6e58c0dc5e9c17547f59cc29df5d23e3a372bb4bf923f146c94d3998c46ee3d4669a8d940197f9dbe52c4d30c601a82ed7e03dfad7d9efa1884f6f6da143497d3c17e5c214d375f22a5c3376a0c0f0b99231e9144c8f1c7c333fc0747298ccfe5a37928760e1f006915e21404a80afa402d3fc2f7f9666beba2a37874419ad868a5d2d4ae56b0885efd2ec071afbd694dfe2a18ca1d9e954ef37a712dd25b3e5f564acbaf4aa6059753420079660a44086c42d242a28c71d7960fd914902df86f62ce155dda365585110b99e4f301732ce0d6ee98152d17da802b0831ec18e205a0f500feb49b88e84386884439a5f713fb174e476971f79c324d917f700e3d87663bf0010abf34f279dbdb351602991b68c3f49f135d0cdfc65d6f543b6cbf664f8fc797eb237f0c983f9fbb645c721e97dbd8b16f4199941748a57ac00a46ffe2f07618dc6dfd0bbf02682e1edbde097b9345a8c8c4624607843093fe8035ddde3aeb55a53cec5f104d206d62b8e26fdc6c99b59a352c4a19b065d05a8aa2a530ca876b6ca068b1620dfa00c7903ea306f4021ec0d500978034a2137d3e087a59cc01c5399261074fc683762cbb221b48baa6871aec1411de1298ae4a5f6bcfcb715d64e5a32763e1e976b705c28066121681156e0e14c91855cbadb7a1b802e37b7143d0b396163890181c6f582e412815ccd639e62be13e1fff51395440b928d89375f0362c7dae694f8291e9c516880d3a08bbe140c209d52959b122f4d657a705e27d2a82489215712d2540132c5b94329204ed69cbb1cf5e1a5ea673ad3f9a02d3ad69f6c39c206f626a1a4c91d6c0c236b6aba9020e67e806cba0cc50246777427939a3ec35cf8eaccacccd0391ba82424f12ecc5a00cfe768b6d5f0ef3897a36764d00ba8c40ce12a01a2d3f1f4fa6c9d702503ae58683e06d1ea80f7472ba446f9d1a40e709500b545f76a25d3b464d65ef17db0c65a7557834a05ad39c849815f465554e854b19619c4ddcc908ff1b13b9d190175e8260f9a114ee12ea463354013920caea49e6299873f8ec6b54909bc678c27faf7070ecd882eb4541f0e8d1a2b64587f93076908426d8c3d9572a739e5adaf51b783050819864caf1ebee2b600e91ca5347024a1fcbe08e6a36c80cfb07043e4363e2f09c83dd778ab5cfcc3c4175327c23c551628d982102f246205227310b2d59a55a497b42cabada6cd0356e6b493bb371b648492028a1f84cacf905189490f8e0fba8f472900539a9f60dbdbad41355355b95d16dcdf2ad50d77c1038be008693070fc35a0efeadb13cb0db87ab0a29eca24a83da689dfa5a9932ca33856aea9c0ef73a7d772903de11da1d368a4210fce1393049e583a2db87e6dd56302b43995f4102c085e4b21e3f142945ed3cc96ee6cb738b6aed6b859dd9522a72c8687dde9d8a993a196448d62b9c7f378434dad5dd8f13908e5d71b1ea0635686027c330de0aaebc88ecf3c18a3a0290756dd8c3ce434535bfddb3dd61b88ef15dc11a30d3e46d3d2b4fa9f2e3b3ec1f3f2e8979c891ecd23332e85dbb226667cf710e20d913402069b26f3a48ac143209740e84e8340668151cc711a73986a8e29eea00a14dfa7d68b9110493fc72eda865344357e39a545dd9de1bea14982da4df1288ce9182a618f31687f869368d081119e3417210accf9b965c1cdcabd7ffa27e853c4d46108531ec198efa2bad54a4825d30eb96ee4f229e455235c8e60263625ef73963a0f1d3fc259d7ba52068302250feda182df1ccad1096d3327c8cd723e825e0784996dc23ad3f0c9be149a32c2dd39bde8cf84c1c01d2a4bc8f76d88ec621b4c95491a1742461d4a44c11d4cbd9b7fbc52449ea3d09974f44c65b7e83b12361adced9840c57e74589e155f933d4e27e42c291d43ca84e573e78ebc3332c61165f427c6e010e860c0ee3305fca2cb138eb3431e81b7c20384d166e92e9ae92fe98e5c879f1e9199e9667a1e1f5527ae2bbb41ade78eb5da24207cdddd10309ed8878f7d1bdedfddc33a8de2c9f018fcc68112e6793ac04e75d44697cd739a84ace0e9d8d4f3360b73c04b580d2454a1904922fbb7541dfbe49c602bf4b6a539bf09d57084260c1f3ec6156e2122e36eac8279e21ac4cf07a94acc12ca659705875550ae882d0fe2371edce36b1409ba7181bef2f4d93c2ed947f4866bd0db1d2685c842cb2fdc49c4920bd4c4d8e8a78a11b82b639b81c1edbd242495d9287758c0df200e72b705e4d63912f7a15cd8f237e4f20cb5dc51d2ec31f043896e2343ac804c6a84b331ad91da017fe0562083a9e6082dde695832fb9f947aa13d7af188de10aee26d42002d5024cf12115259559847a9a4c8438c963e36dc3d6a45396dd12959051ff6ce64179842fba95c9588707430e2dad1e43a8989fe55eebd18619022ac0662d6d9c9af1adfe40eb8db28278145322f2430f270f775b2851b071b0c1d56284170396b15896dd5f4b1b647b234d0bcb413278fce274d5c0ebd55f8494481db57a967998ed82b96a33e9adf4d6a981a76ffffec0800ce6220c5419e603c805a578beb31023d1c9fa29184fcbe0d836c39f46ea614f4d6fa9b75c50505400451f1f5918ae14cca2c2e1cb384b6234debea8f04a3961b3d491af8f3103e31665e1db2bb09cb33c327f37409332b396e86ef3003f4534ab3b51ecced23495c29c3fe7de83bd3ff06cca2e74f8eefd912b4ff2d0388bf03fa5d9aaee483bcc954d26ca4e5f0da0b72905fe742baa26e326ea361816a8cc120ae51d72882a33670e0c5144baad24e4fe7db776267dfc0c3918b19a4d1558b7846cac03476a9859f4c5529015c194eabc47216d42f23303e625365457eb239ce10535a88ceab55d11b0f4013282b3882d90c2398122a1e10a27f9b41f24b595d08ba9869b05176e54c3cee3070363f93d5118fa6832d8780a37ac83832a48eaf3724d2cfdf904bd1e7c62ff694bf8758ab0e9c284f2e187724c6606b2d1655988d632412f3f5ad535016e5c0880a9eb4404065ce1b44c88f76b0abadd1dc97ae7f7db97eb5a6dd379c07875af893643f4ad296cee4f0c24c9ac9490099eff5918e284aa9afd69b1648001cce282a327c42a1ffdba02ff8aeef59e053d9057df8dcd4bfce451a4a84a1484d003fa29b29a28425d7f30c5e6202e0429d4e253ecab6d7c69d225a971aa3050b6411e789af513f9b61c29fb414bb97cbd7f1f5e2e3740ab44ae12a282576a4a1ddd0ce8ff8d4ea87eebaf03bb46841360e7950b35ec8d613b3ca1d3fee305c75dc6a7ca6967e7d5577a42de2884775ee31ec6c58e74561ba058b1387737d264e1a82628d0cae352d566a7528278d46e92e41d35edaa1ec128ed605bf5464cd5c895a25fd27d974126e22b15e2729b0e8ef9bdf4941da7457c3a2ff5e51af3d19d2fc9dfcf9a67e9663a4094fa70ddfe7463506d8bc8834fc130f6ef718a249024ef9c9fe496b64abd533c2c38af384cd36a869c7dc433980244bb4aa4eefff7c7f2433765a89c13fdd2334dbace5ce2a4fd748efd41a10e97f19885a804f828050752411303072550b424b831c07b1c98653ab8f02108849fcbd5ffc51fa9015fdbb91ff4c4a2704c7ffc0b172b8b7bbecc3fc430746e7a562551b3be57d4a029cad32b13319c764e735be2e8c217a431d3bebb69c1517a08ea4a9b0ff80c8583f1558475cf6c0c3d43e336ab72d040275e421e238181676db0400b8350ccc8174321d75ffc7d36dc6391b901d21de6a4e0ba239c99a7649ffc4697820d6c06771316b9c711d805688e44fc503b911007449e067c0d2569730e5efe3c08a4810df490060fcd35617431356223516d95b72155656aed2e235fd84e2d5a003fe837d98fe85f718e04fba146ca61ef883b823f86d3da257cef045af50bc46af041636058b181892342165ea1f18d6c1bed9816ba5f9e5a5b761076c8da04f2e131cd8338fe9166be1ce20fa28e43daa46df3969e69b5b250f07e74c1b2bde799426276958054026a26c54209fad3cb5a57733b7187ad60579f16447b7888830b8366862da04af24d8e17dfba822bd499eeccee2fda8b9120c513c8b9ffa1b71136bddc87c4645871b65a8d3c25e580d45062fb98cd8579768cb3c4b4d6e3416be34c652768836962f3355f89219752da0485bb61e975f5fcb59a8f9bd7fc348d88b84b6be87caf79644ca0bda46c064644242943ab2cd6904c1da743ea810d1d939bce937ae4a206a1f9fec4bcd3e94c94fc10daf02fb3d600d18c0de22de578795bc5c24d7c8a946a42b1112fb844d51aa0fafb116f3ba9c27a0133d516ca50339504e547b3f50f4d43e3274824088c84930a532ac72a95c654219b330bff2e91069491b9c0af38fc55400740710b6854a41841512bd0d48cd8ef39e168ee8d60bb02875b80aa1ef4626b8fa138e862ff67d183568140716f2822c0a6f55f9a4e8de604bd2eab5304f71a77fddd084fe6b221479a84f3a9e04351c2c04d4eb27553f37a0c06431087442470e87df648bfe83eafa3a0ebe198bcc292e1c66ad57e7d1c043e5220c550a94c978042ad107a91f518df61b93d820bc0cf49aeaa50b365bf2785181d260b8fa72ed6c88c51f9f163574d817c2c188d00e0884fbd90e7d7e2e08074d11fb3067f7d043fc02786c2c26609929da92c942e61b6bfa0eb17fe03badd1b3d1d98bd1d795d2d31e4f8802360308e51967fa6422d57d522b7731e93e64c10b5b50f923bfaa6119ee56fe9197fc9561369a7768ef63043e016af65c6e8a78f8fd2ef0a91360bc3e9d148c4229e1b2152d2002998efdcde925a1b3eb024200e7c6186af9f6429e73135e6a879ed8cba424fe32c7f61c0f3e8b0bdec9288648c109b18f6b7af3201263c3d841344d987c5905c75d53273f18b0e8cd4d03b552a84f85887969835eb1f4b10fadb3673ff5499aef22f19bc4429de3f9ebf683bfc8dfbf1fd54588f959ca21742e236807ec7ea357e3c3b2cbbbc1519543a188e204254035d18b529625bea065047fbd18e5f9793ebbccceef1821dfed391001b5b09732565540fd33ecaea0857c28ae5c8f9f70c870b339d9d0e7e2d9086a1bb4ccdbeeb1007eb4ebf2d881e6373b91e12e36b5df1795e57af1e048c203c0e8fcbadcc4147744185c9fc09c74c835483c34748a3f005f05351b0c9ea96f78bed73e27f807737e7c0dd7be702fe0710ce26bb0aa1aabec0acb3e81fdcb82c68b7d488019be5e38355a2c9be351ace91da38cce2de0d316beeab85a79b16681ad96bda120172311d46c103196864c098fc9619ab2d2e599bd03b3008e2c4e4640ba16f8407093f46b78cd20179e013a6cab084f5b7a120bbec525dfd5e3abad8795d4190339c4ec73fd104a7d2096813f01f14b2715fce9928580e36be4a726229d284254248313f50cd24b8e7c71eee608d44ac4b39f60ded26c07bad72548dc9475319f9eba31bde963cc870109b017a35a3998734a174dfe24e1a45601d08f52620c1d882773b662062b2ad74cf1a4c6247ad8717c216943104a91f40844c5192f8d60bb85223c7cec66c8c77c13ecd49ac0fe61ed1d7a0913e758f90ac55eda14855bf714ee771d12f31f5dde564ed36909e7ed0edb243e16dd5841a122347ef5e44a958168c87bb98442aa328ead4dc3a29140c7d9940fe2fb4dc12245266a8ce07173f7c960db44effec6f56ecda9ff3cbc913da638c0bc1b703d422aedeeb42162721ce85bc48a382c22589a465e350fc1e4102d4b9eb1d5957229fe23de87463e6382125d7e931933fc394ce20e7c66f4b1e0cee47020ca1794f7d561bc5ea0abe62acf5ff580d5826206dac767674b531bf3225d188a64a959dc117a9902b1e497caa3d75649c6889cc8c04051d8d819ae531d9730c986a3182a07c68873b47b1edef5aef9364ebbd02eca02c3b9f8c99fcaa70d32e2730fed8f09e62db9de7d4a63212104ee54a32d5b71dfcd06477b104a8c939aed3e25952b058fbb1ae4ceee95fad9d7a410ec0b021e7a3f5b6972b081c348909362cd7577221c30398eb6a5c31a4e3479c1f09c5eef25391defcfe6e2fa4ee1c582cf030ffffa2eaf8721a799cc1369818c70adbf092d716c951f79dc8c6118167d3d18cfda4fefa197afa0128e62ba28ccbe1ebbe8f73061f4a2e81d0cf83a6d98c40596a19dd62616f7c72d8a4e57b80de7e376dfadae762c88e5b4ff151e54fa5b8729a6020a0cab05f8808fb42020c59f4d1079d460a2cb77644139df892f2dd8820ad5b2553781c87c8cbda4856cdc8dde5f724cec0d269056da79fc0af75c66ceffd013d0fd60c1d06be1a1d241e2b1cd985c06aaa82927dcae4f48a1f2727d37df6ab9127da3c97afc14ee434363039f81c5f02d7abd20823b19b04655ea1a85e398e9d94ea897a3cefe8bd12c911d1e21492a73c2a1ce5de44ec0005e9bcbc46bc111287a2189a330ae2d4c22859cc248c72027eb9c72ca00efe0e6fcddf123ac78e563f8c26a53c90b9f6d6ba3423a45c2a5de00869aa6f7add9ea30f27e9b2961c5163ae113cd5b455a6e6d343d77041f62b335d323cf1309e5382f8538c830c80ff14805948f9fd143dff1f810ba1dbad3cba28d173cd2d694699a9e809a119eb490705021de2f4bf90277bdd9f24e8fd89c0bcef673e9f016bc1048434628c642ef9dfe39bb7ee5e2b00c9660484591147fddd0b9587b455c9d6e77a17be9392870cc9ab5bb18c43244984ee8c81294a7a87a847be362ddfe7de088623a45ce20174c4754467a47396f0d9f43ccf1f7b9b5e486702f93c0b7038aff802a6b51023b89feae02154c892bd1280683944e2f628f17fafb5eb8189d44145cf4f06503d3c566739ab37f89455830e85515763b265d8af3d6afa51174bfb3dd28ec691bf1598e055a8aa1ea2c2d7c02b5913de73909cbbd02ade440223891b87b7fb0f0289b23106ab62f53b49b3e6ec1961a4e961b7ec691f0526e83050c5f642d295d2b9d9793134bcbaaf4226672ab6f3a5404cfa7c15f75bfdb0580570aada2d35c351f685443aa8ba9664eb20755cfd0b60204bd071ce0bfa4d4272d747c25448799c4a39f9d28870869f49130cc206f437bcc978d9b24cdf3b0a949f3c59eab474427d49103b48d896726a11c7f5949568c710191c51dc7db44bde66e36aeb53f56f17dd312944b3fe9e126c8b7726d6d15cb5220106bf7571aed73a19fa176fc575481b849613c2a2224a309bad4380a4d7d33ab1c01218201e2d164473b1d6d9d84b52c05d948e15424e993053211823a0f89d557d409f378aa9638183044c3b8879666800ff8133c788bb79382082a34bc15470d17aeb035c7bb3fc663fb5ade079d73c56899457f26071a55057a225ae0043425bdd790a000330650ea2d55478a764ebafc9e002d2124704ba741898614b581b0b12ffa03d388b9e9679584c2c0799a9525b012ad0e5073e7c456e30f4394cac69e3e160f5d9c77b771c470894ce59a7f1074559db40115c8c40f77db80f9725ee72516177f3cf76e121a0aab1d661157bd3fa04ce82e4d54d9090eae7292a705a72a483d2c16511ae4422d6a3568413bce7d6a190043dc0288a7f554b138ae661635cbc232fef914324da85a05a16c6a750d7ab42626dfb4f60f91e0ef910409cde92c59808dc4b7cbff5e2207979f095888ec1827d86c5b05d92d72156361eecb5c149abab8555106730f6a081f8959ea5a3ab9f41eb2839a8475710fb75f530d400a9a8febe179bf13a28bb566b1e2507971319182c7e3b58c1764cb722283e6a9531760a6cd3607aaf200d6258cc6050b4e3175cf756bc42fe5e36cbbbf683532bf831329c4c5ea92122a14a2c51f853d45f6abe98e5738790e66a4f4f47832f27e06dcce2380dfa5a7818858084cb3d9438a6da1cb7b365a43d3a4202cd9cee7da1adfa5da2753f6b4e6fe62c74095f60c8da786cd4ef61232e72a24df62c44fea39cc5ae65608af6ba70f902e2d4c202cd19af2634b88d6f888b41e332b89f6bb45aee9c68e5a05d3455c8c1a8c939beb425a20464cae667d125a41bf778ce81b41e9d647b5ee3f1d065448b60f03d2d101c9284171ddc1ab52cebb5cfc065c8f79d7e238c65021f0f9e5cd1747049b77fba30709bc2cddbe98af222d56adf593cdaba4bc3b2b5465c3dac5597346267cbfe0f005a352531d300624f3032a6897b45c2012b2e21c55c59b7db4ff561fd26da7d587feaafe39d93ca7b316da494cf4a55db789013896f25ddeb5fe0b221033446d540220202b6feee5545ceb20529e0be4b721dadf30782897d863498500001c8a02c1b7dddddddd5bca2465f40a140ba70bbb17742f50792177e4c4f604c9516721cbfe55e46d9c30cd993f676c349fdae090c87686bc55e4fd776245720b563ce530ddc24ec929947316d0fb0b517156d0fb0be99c057bff176ece42e1fd6188554fe1d3f0c7a727904f51bbe56b904f7fb708f914dd2d56ec52d069f843a727109da24a1f44a75f7a213a456fa7d0bb090b5f08053da42623498adc8c2421109ca90cddec547212392a2369fbcbd0c9d09d417f3261a10f1fefe3e3e373e3868fcf8ddb82f386cf8ddce3fae4a0af26ccc7f7f0171308a65fb87d6ebb8c1c9221243247fd0790635048863c55a38c51dadd528110ab40986dff05c48010d391eb6eb72b77e4da6202854a4e1972b54ace4716c0ffc843de4846f240b968c8854f12be0af0478efc4f01dec6e8b60e8074802b0e805b81e6c36887e201906ecbc8eea6aea8ac1988a807c0396b062247fdb688f8d0691856417b41f7c2ae4846c2434582819af22fc00ef1079007faf1f14830505d2abc3f920b54178ef747024475b9de1fc90fd5a5e3fd91f8505d39de1f8905aaebf5fe487aa8aefdfe4864d5d5e3fd91f080244975ed787f243b54d78ff74732545d40de1f890ed5f5f3fe4872a82ea0f747824375f9787f24b1ea0a9514f9b4ea8003db1fc9cc7714797f5200398621390617b287240fc57084c4858c7b18b1fd7708b6ffeb88ed9f0389edaf4304dbdf3582ed8fa368fbab60b45dc817488ec10355e5ff23c7f081aaf2df9163004155f98b590b9a0bd95f618e6188183a5055445495ff4f8ea188aa7221db970ab956958bc8e320f23a7210f91ee2ef0c81738bffca1040e9225a2cd1c204db3f8624787c0f77a12c9263a0812f16320f1d0391915d1abe907b01f78294178c5e58e285da0b4d5e389a818898f79f812806857a4f41bf7033e2947939721bfe03c82fb69bf2dab6f169d582c89e3e5c4c200cfb1613e8471fb1c510abaaa1cd537b59c2d10320ad561fa4b940da2ee4930835a1f026f307fff85811f5105515122fb49722522953593203e0415f327ff0867d987dd8f87467b6fd51587e995595bf8ffc52c40b51507e51b293f12ee353df69c5c16e13c904d0434408308001bc8d1395b5c211f5c8592bd06c6cb7454477531edad8521bdcf60f401e821b72bb297fa13c244a0a7908120a79084d481e82c4102347fd83e4212b1ce1bf02cdf4fe4474a5f7928b3a0dcf4fab153ba19cd08f2c54c5517f2359687753feaa203da4463b89e41862b5c78401e49308e7949d3f387a0e01c9270e55c5423e696ec31f281715f99f229aa451f2c8f6bcd5f8f473b7db3edf06fbf15f0ee7abf491c5278d1879f27a75a7241ac96fbb29ff1ff99df4289dfc296126d08c2dfe0a7968096c852761f96b379bfc297de4997d4d20748b4f247fcd6df8c835db484632e4a91fe37fe1fb0e75bac2167511911f403e6537e55f249f3e32cdfe5acfa350e74944f7d47a644ba3fd947636032a5fd9b29840486220383f76c2fb9f00e487e534fd94cc9f92b4a9a119c530e607fc400f065fb7b5a674e35fb9ee9debee91ebe691ebde91edd691edce91ebc6916bfe8c55d70dbb7d3ef59ed8feae6cb7e8f336a7ad5fed1bba56958f4e59ff7d2bd7cdca75dbc869789e9067c03b3d63b117a397245e9a6c7f00e4b47c210ad3f7292f43bcd050ff12844b99c1a24ee5a44287a64ea5e68c9d158b28e84eab1644150b27158b2c2a1649dba5d429b2d8fe2e56ecb67f4b4e5d4a9d02c6f63f738a02a354a5c8552cbcd8fe65d6414e7dca4eab0e62dbd3af6dffde7eb58db50ca36d0834f386213e8314ccd2a127dbf62f17d67a332bf75e7bbdd9be56065c0c79b3fbe43983d3fe8dc53c2b3897b3d65a6bdd4c01dc17e636f73bbbb37beffddcb6bddd0e63eced3ccfd26020ccbe09e43a4db7f718c88bc5ce1d9cd704aaaa8adfd3b8a669e36d3fea1863ece3a88fa71ceb1a8e7a0e4f5659e163fcb8a66dcee193811a35be4feb13dbf1d370168d1a3646f2aa976e0c1bd462d207ce94c6f647da357c72586fc6006fb6578efa756fd57838de3c296c0c63f0560fdf07df887fa86d086d586203f8f7770d90c06d89ef915f343e0d8e7a0db82d528fe5936f44149fd4362cb181f49e1473896d036e0b0687c151cff3fe4455ef438fd4f5a6740f77b35ee054616807f0efef103e8d0a57d37c7fff8697a6f9f4f7ddf0c22edb15f340a3c205ff7e11f0af2e12beeb1afc43fc34df87ff6915c407dfcbe14d790f669c82530234ec62610ff86b6b2889cfcb7c59f8b231cd4f594c11b56b918d65a1074ef29ceedaf0d7c8e183bf0790dbba79fc15e38fd55bcca71597ab3a92e6e6bc2d8cf18a860ded01e4878de5956cfc20c8e2cd4eb61899e56ff24966bb4bf7bdd41af2583ef5760c25095fa897a32fffd4659f5c25cbb7d8147ebf99f16c5e78c6c8f76fb2bf9be397462fbdbcab0abfcd2abc6c64a93c4bb907f903aad427dbe9b61994ba876d06efc9271d40336a15eef57fc00d1bec7153482a0c0dcd3cea87643ee6c91ed555da98e53d9f2f66151cbddb7c9b67c17c1b4de3bdcdd7170b259b37c2f236e7db709fe58d9c6ff336da06ff33e6ac313dcccb9f626ab2e96932cccfe49797c927976f613933909bc2cfd2e2a2dbe1580ffc66c68f9b9c76d76d1fbfcb0da29f45c041c055b00e0741877778b783afe11711ebd7a08b8c230de077e544ef23e10cdfabb635bee331c37ad8fce30827a8f1ebea65d45131bc31f8eeb54efe7d23e5d5362c29e25fbef85ff89ff945e39b7afcc6afaf30fc51db307e387ef83698dff77d36e6e8f73d198aa5b7b1db6ac0173660c8d4f5a6468dbaa9ef02e7d5362cc16fc37df25ddba069bc0f8bf8979ac6d32a8c25f9f7c9b738c05ddf9a309a21f7c92fe25f66dce4acffbd98f3f7d9993bb8055971524f66897f3db73d6d6b3dbb6ceb99c66da6718c1bc2cd7cca76d073b9ade7966d693e9aef4fdbf33c6e6bf3f79e3d6c6efbe57b713ef7c347dff636a495cfa3e51791efd96a64cd5623ff865f42ea1aca17bf06d2347d1e2d337a53d77c0c9c7583152c227e0de18bdfc36d51c491fc9767bb2daf76c5bbf27954ef6b02cb0cf1abeafe878fbe772b4b5073ced3bddf459d70487e927f8d1feaeb8571de25e18f79c9f7e05b51b3d4ceefeb0ec12ffc3ee8d35857fb7db72c310e3958644f8e90218794cffac95920187ee289baa9d22cfdfdfba8ea6279309f3ed9e9a8a3c253a7e1d9e3b65cc4e793b85a2fb16854953980299f2a8a4240299f2719cc5c9e0d287358e2705f096c51d4690dfb7b9bb6b6df8a4d989743088bec4908708e8ddd7eeeb4df17ab4f4facaff537551170ad452244c2c851fb60b64b58247838d39af449c059295a83b35216dcc3f03cafc5ba4844c06db120dab7dfc33e10fb2b1f4f09597148153c657d2c0a3d9c69c56d6b9f851c477cec5b2f878475d43e7a5b35acfbe4486bec1c8edaafe1a8adb1eda3357cece7b05787385442b0835d1216e02c70436d8ad1174f8228e20a2ebc095971c2f23c3dca59e3d7af7116f9a569d31cdb7ec5a9e87d53466b4d4655f47e994f15bd4fe6b39615bdb8a2f77e38fbfb1ad4e92c7fb4036ad8b886a32cefa8fdd33eca7eb51f9e7e6d60b308711071a8611724693aad7fb5d81985ac3834dfdff0ba5f3f54616807fbe3ef60b50d4b6886f8db2fe2ff0aff86972e42fed535901e0b0acefa121f7caf647e49fc22f645f17ea9543a61b829efcd31f42f82dfefe3ff7491f2495dc3fd22f6ef4e37e0861f866fbf48f8f6d32b6d6737e5b9aec1ea1a7adcf17c6f081508418811cc62b15ccbabd65dbdb5bceacbd62194c0ca0a90f040099ee0e2555ff67bdcf185c3f7f0ef7ba2aec1da6ecafb2545fcadaec175bd297cbd0fb5e7dddcc1197856a725fe1c07fed46ff5c7f5abfe9ef66b035054d7cbfbefbca0ba60de7fe789ea8a79ff1d5b75a1a4e44f7770b0fd776ebe23bf3f5942f65e36b93a5a83b36d0f8d0e4f2a635b6c62d927cb4bad2a97986df37da162605e66644ad95fa8189817fb3ae522d9eaa5df45b39cfa4da5c71902e72efdcd1040ed922ed2da66db183652996dcd1270727d9590bf97ceab242a8fff976938b712db5f688b1512db7f65444577b7c5e345e501238a241cce1ea2d8dd206633108247c793e3b9f1205d512508e72c9e2e2a2ae40415a12367f16451d124e05248ba2d9e296a8a089e284144cee289a2a22edbe98e4db7fd7140cdb35b72eed862dc2cf6d831303a4e304d287bc85154d108c16fc79b91c2f7e5b6a26256a5715311ab718b648312d1ea0ec9aaebab01de9687e179a250efe82aad91745b66144ff94b894d91519955d9a615f38a1139b4c498345e31919cbcf562307b563ce5edf0b6a598970479e5adb8941bb35fbfd0bef7e55bad636f57d3fbc05d4d30dcd50cc55d4d71dcd51cc95d4db2dcd52ccd5d4db3b4ab5932ed6a9ace5dcd93655793a56557b3c56557d3e5b4ab797ad9d57c81d9d58489d9d58c41ed6aa26476356566763567687635696a76356b6c76356d6e76356f62ec6ac6b065bd2def89a7fca348417d95273bf52b3b47ad58edd9eca7beabe6cfcdceb6b37ef18d81b65d6813c71c59de5a599ab65dc9663a595a4a9799ed347b8189b1a164ca199ab2a6bcb6d3a578ab4e712a55acd4f7dbca9768e264f5641565d7779ab5e22d18aee47cc87f70255ec4ce59e2136fd9d92cca4cca6cca8ccaaccaae6f6d5689b7accd16619158c2d6c4c9ae6f006fd9b0ca6905756568db190ccefa7eca4b414539eb934ae3716e35bc35fa6d15ab69f817d74853c92c6d48b1c6f6c466b3d968664a66b3d96ce693a935a9d56a35d48ddda11bbbb11bbbb1986b3b2f0cb95c6db55aad562bf2e644b3bc648c185a3177e5eeeec81d4c08becc94cc66b3d96974b9b5dbe4d66eedd66eade5daced96c369bd96637078359fead39b2e66a4ebcb3d02c2fd9128297144316f03b674a66b3d9cc747397cacddddccddddccde5b59dd766b3d96cb3d96c369bcd42b7819714c312f899b627369bcd56ce94cc66b3d9b59dbb1db659dbfd3414ad2db4366b03edeebba41892df687b62b3d96ce2b59ddf6c3b8d46c33bbbdbedecceee3e4b1bdd73cf5d1cf10e5bc13bbcc33bbcc3bb6b3bafa3ff2854e8b4f0d313f5e84e9d367a48b8a8d3b23c9d409dd6d4e0e0d0d83236e0b7dbf2a478ca7f0a8e4aaecabe92e469efe6e893d33afe70e31b6ba104b3edf54399dac6d65a10b41604adcc9819706be4ccf732efa3cc35c1c6a396e1d664f227233353db326f9a00f8f42eb1ed4562db226eee0fdbdea1d0af78d20dd5f7884b034ff8343421c4fd8d8dae0180382be96e8ae6ac5292a35e0aa3a2ae35694226855053fe2764928b9af22f855159e41615f52467913947854006a1ba50205457aaca0faa2bc707d5554217d585a3e3a2baf4fb9774b7658add540faa8be7fd491e54d7eafd492ad5d5f3fee416d5a54575d17897ea0150d299f02613bef4e4ce7798f0fea429668a59198f936b55c57c09393a2974c6e93df92ea92aff55be25a82a7f9e7c4d5055fe3a0440be495495bf2a5f1254953f8d7c95b84b54d58c5cab2a75c2a327bc4ece092f433f8ed6bae8047d6b269c2c7f9b00c10cee13f23521838f1bb3c68dff3ac4798c1037fe0d6e7c1bdcf83538771a5daa919f9239b00467746acafcf732e965724f7099b84d2e0a6e0aae0aae0b2e0b482b64117679738a36b935d36ce5a624901527f5ac57df4b4198eba9b10d05f7f69ef65c135b559e874b5cabae8c4be90dbb56d5acc9e717e34f019fe761ef03adfd6cfdeaf7fef5034371b479244b0eb049d8f5af6326358fe31fd8723ff003c33083201866f0bfef7b5c8c310e7f02df9f9bbc25f63ebf9ee781615856eb177bfea517a71f064b8c3f32bc380ceff7f80b757853e2e9de70bcb78e75ac63ad9824499f9baa1e382db9dd03a7bd5f6f596b2df1407e255b5325ef022459cb7b3da7d9efbdeed7de1dc88ae3efeeeedff779def77ddff77ddf87dd5aec570464c5b9f75e6bade8a007faea65c1b7b97ae8cbca502ffb55f62feb596bbf87575bcec9be5fde3f916e84c74bdc0ac04f008f91b7fefd70e8ab570dbf66f0ab0c7dc950af8a65ffaa8f2b76ebf5bd0d905f11a7db77a46dff2be2f437d5b054bfe225fc6b4bbd42b0e76d6d05788fdf821fe6a1243e2f51832f0b5fa30e5fcc329f57f863f8329f97f80f7eef005400c0fd009303c07db5023c0d81bb8b68eef71300ffdca4971693df87410c5ef0be67b5917bff03416d84c7ebd3e14d55bbfa8ab0c3e338628c492f9fa5a3e3388e7f1a71e3a85319c627c97c7e4894e58803aa38a09e1d7e0f07bd7006d10ca2ea0ac7177ffc6bfeac76a86b558dd66e7006d1db131e9f1c53192f871b6305609d56dceed9a3f8e9cb10db577bd431705575c4998eb8ed3fe2accdf7c518b8ed1f8eb85bed8cdd17841b7508341fd1e7ab89a28fbdf1dffbf8e87adef0f94c7043cbf0d57c7cf2f7e20d1f9f1745517cf07dc4077fdb1c4f5ed7f124be3b9ef4303661ae273fcf033f13760e9d44a7927356550e633d198226ec1cfae185e6e80b1168c2604f8aad0f4dd88d1bad93e8543264c26e3c398a3c9e247b7e34613e4f96648f27cd723f59929933c05e4f9a6ab097254a46389e3c5f88602f26730620bc5b4fb29c45c04ea2d37496cc93c54b72142dcb799ee759654aa7cf2d6f589db65aad67b12e92eb6ecd75d768009f5edb914fef11914f2fd10b9f5e5a18558927392adad3ca8ddd94f8a95749e1d31b63097d7a875a2d7c7a65ae007c7a67287cea38219ffa14d8a79e0bf2a95309b2e28db7402c2b6cb9508405960fd68f4f71b6914f511ccef48c6d9174412e099b06a0b7bb9a42501b489fb1aa12753a631b5a02f4f3aebb2d1b230fa3b26c9ca8a8dbd81885311bdc256221af40922be421226049faf8647b23db4db672dd242cdb4db2b2dda42bdb4de280e52ae4ab0943e1abc9e3497b027d35613f0ff452923d72dd248f5c3709539224e92e37b275296fe4ba5bb9b272dd61b6ae6c5db9922c2529b6b0034aba29b7b2438a22a5851d09a4d3932c3f269b2921ba29f70103c26c86d948e2c856271634048050167400a41f2023bb1f40820841c1c84e48ffd069988206a2d333884e514274fa28e814ad821686e28c1a054e08f704290a5c7d82348e3e7c049164fdf99ddcbe414284843604498c060d225588e85ad8b560a5852467f9f8f9c1e381041182420a1f52c16347005e5ee8e553e061fb61ab2a203a0dc3203a3d4f213a45a150d0a176d58278d8b6ea5357ad2c4d58f83972dd3aec2944c54a9163bd9b30a19ca3fe376eb45aad568bf5d584ddd0423a47b31015471df643743795c349b9192d31a4c990a3d369c68c193b9fdae0847237a5db5949fa0941e04336a4e62c58189e270af5dfd292faec920dda79ca6a7c6a83b64fa0efe14080bc8fcf7fb1f3e7ab0903f245f21220ba9d43242976647724e988ee48eec89423b823b526474e5c5c5e5e5e745ad8b590d4c29558100a4280e416925ab0e22810109298b37ede817c0009b223004229fcd81100a1147e005911d920aa2a7f1e99d4652bdb0dcb76b35cd96e1cb705a70b2ee0768c4f676c458a10c94474446c8caeff91a423bb23558ee88e3c39827424ca919ba3cec29273d69fdae05ad8dd54d24d1120460019017e20c0ec126d14f4115b084e9a4732e4ac2099b3809ce5a384af1587919de5f12fc1c89111dd0a341c1c1c1c1c9c15682d2d2d2d2d2d406f4d5810ecab09b4335bcd545792a4e0a6e46c6c6c6e90c86e0ac90c091192221ca5ddd40b372e72312e722d2d260c08a6d31b36ec7d3e1c4ed8f77052e8b6e04cab0e8072d100926088edc46eea85323ae541e91415757adae8972418a4992916c7cbc9ea072f5fa367a6f0a01f23be9cbc984a350646302f2acf7d30c3bea82a2bb0a4960cbb1223f38fccd11f1c9d11cd70d1b01d4c2ecaffe522fd1f09ce94c68cc68c87a63322a21179eafe0f2d38619ec584b93c8b098477e9c9534963162ab1385e4e2ccfb7daf598a0c7480849080a2a460c47b0e7a8c704a8d56e27eec2ddb803773d477e4ac968c8aaead618d466e41f23da4d11fd28f11f9d96fc3384f34f0c760596e49261561cbdff726271c0bcf842bfc0c9be250ddb7d24c8483590c44f5347fb7ecae8b662fcfd54edb66efeca3c757f362322daf7d26851f67df22b53a1921ea31e25c250c9ee394a6120255bed565f8c60d9427e41a804d1e520553c48aeaa70424896e77e902c2acf142b7c065becfbe14c5655f77b8e5218b81f444dadbef8c159417aa8e86df3ecb4274577da7354f61cb5f41c31d9f7c99ea324f6fdafe72884ed6056aaeabe1092c50123428519a1aaeedf67315b7238bfe4aa6a68879fdbf75b72a7d2cc414c39885155dd0fd244aded2049d420465424b6ae065920d1a6388aa2660483ddeea6927e62b21f7e80c0c0be9f9a39ecfb2de6cfcd3ee920b42aceb442a1a5154a937d5f08ed0a3112527396f72c265014ac53b228b75c54c293a79ea3971713f67d48e42c2124222a4b084a4a765358d4d6ca08ab5d8f91873fa8ac1e252a7afff2a0e9a342dafd971c445755f7cd98c5b1d2591e21285584909c15a48b8a623307a90521aaaafb29d96d0561525346a8467b775b418ca829256650448f91b3820c51d1dcbeefa2531e2bd029f6fd169d7e14a827f67d169d9e75064decfb9e926dd44e69ccf6fd5486ed6049f927f6335455f7573a8be36787ca73ffc680877d3f5de9f635e920b4aaba69cf518da3aaba2f2357db951d7edaf364dfefb9df63336d4f625e8a2882e6adfc3859f62f191a66c553f761603b2f07676ace66a6126fe5bf4fca94a9fc4fd2d49432727e9cac9fbca5996f369a712cf6d2c9b01dec8aa3f773f24feca6eedfe41f1af38767931a9694c4999a4630d8edfbe612f74d2367797f9da466937d9f8cb9b90e73f372ba71b9b137161582f5f3626a4af6eb0ba7e8bf842ce6f4226dfcfa16b1430d669b737853f83f9fa87b7453f86ff2b5dd14b6ba5655fa55296e349e801e8c36bbed5b9cb4521176b1eb8bbaea82f99aaba8afef15e1ac99afefd19cf5f2f53d2472bec67c7dafc97f8df1f53d246f888aa3947a446c1c86a764d7f782a82c9c24a3793810552fe6c97017bb7a316f8673d5054eb1a2b2bc9aa34e4899a2b2bc234f06f5f113b5e5d9a8c04e767ddc446579374771d5457e7d7cab2e5b0dbf8697e6539d6d3af5e7fffa38d5552383c6798266411a08c393c8334d0f26060949288ab700406443fc81a13892e5104e9a5fad72cef672518cbff99918ab9e9e9e9e9e9e9e1ed48c67ea31d2fd20465edd4cab1b93dbccca88d56d885b8f0e3db11e1f7a643d42f4cc7a8ee8a1f5186d1bd24d0aae0a93a9bc59c6f672d150fe24e14b0f0d25f95792d54beb1d59128d58d2ce6ebbc3bcb2d19986e71703e399daf46062be1cee0a1856bcd06531c58a93a6c4c262c2be9bf3b6c945ff35ff34ffa55cf3261111259a189b5f31a935397252c384114f52552d9104183ad58189e9a1c4a3c3ddac7851a58b9c1552a6c0e98ecd46a2996c218282144445d02d088b209c2e0ccf134594ed071141a92c2125909c2564444565093151d19bb3846a8e62515b422ea8a9db120ad2394b2817f483ca12dae24c514ff4d99b9d42d26dad86b03581d229eaa441d2f6b799675755424a0819093121541372c116b92fa754a590b25d8ab34aef2f84f39b6d6060ca9b6b86705a14ca847d9f040ab55119660332f96503678a67be139cf6734b4e1ecaf924e14be74bc8c1e55c9193d3d180ce4c87081d229d221d9a4e4d878913eb1cad7080d1edc0a09ee0af937764507bfc4bc83b4f541bfe31b91bf33043bc574e0f4c4cce1539b89c5c4e2e2767cac9059193cbc9e9684067a643840e914e910e4d87099d9aced1f6a729ad70345963637333cbcebbfc454ed24a6823cd84ae6917e8238da4a1dc53dff2177997937472d2d5e99993b412da4833a16bda05fa4843d148fa66736302dd6c71e6a6b491d9f86033b381c2c66603c506c9a60a9b9b4dce260c6dc2303c4f14ead310077b5f3f1f9ec89cb57a62765bab208e6c66a0cdcc66f6a7cdecdc331b286ca0d820d9546173b3d9c246b7fdb1b8432a7a82d60411a8d315932f75ba4ae2d3773584c943953018a7b56751fe18260ce663984078c77c3669981f5a1233030de74e0a0a0a4d7c3e8bfd748725afa2408a7242b1cd9e3c11840e934fc293c576495e54e9e2a1a82a1a98bcf3c4d1528cdeb17d4ccef4dc27f8983873094573d4112823d415281c6a0b540e2504940e95840ac35326360b82c72adc4982e289caf304c9d128b79bc2393ac5d19cee260625a413aae22d1cbdf3c46fbe2350349411aa062823940d6584aaa1ae40e1505ba072ce5ae1801242124a775b3c5ea0c2a8824a72164f172f4373e27c273077c9c5e6f285cbce250c97a4130f35758addd469e6e8e9b29c8860f28a08e989ed1ffe7f1a6e1ab1282a4fd2eea67437b5436527b783db91b273db89b283545550b6ef3c51779e54d49fc6dba5deb131395d6c3aa74e575aa72b26269dae92d8fe9eb6c1e8746584cb172e3b97305c924e3c9c62a7d9490327a25268513be772d544e529bd6dc20407232382e8615c72a6bf73b4ce24d110b15809e9869b928b117e2538bd1cce120e8e09fbdecbe12c793abbe42cfb572e2195a0946e261d4c31930f26994908d3cc44331d1103639ab0c9c8a5894bcd592cffc4ef9f346fdfb26ce0bc252825a4d24d67a7a59ba97443edb4748329dd7ab8997430c54c3e986426214c33d311269ac968fbd3d851eb921d820c1926ecfb32af6c39a5c7613cd9ab276a104745491831842ca6fba187211c78927617bfd31d5b29efdca0f2d8906e5270557c4bce9c5cd3735b19324a511475231123d178c4481b4d5053a3d11d8f7c742236da683869b29713b71075231123d178c4481b4d301a8d47a3132c3a0d696074fa578bbad1b66aa2f21c5595139ba34fb213bb5655b1aa6ac2648583d1f687d1a94e8c4e7f081a9d94c35d01c38a17ba2ca65851d153063b30a83cb62763bed937dfede5a29bcf31f34e14476fb86afef0ec18bd83543b4b4eced2dfec11dfe41375534fe6e49437bb8e4e79b3adb5ba5664cd67ca36a36ecade5c779eecd84c70a658c70412378dce375b26e3bce49f29334aa6f2d82f05692068e62c968adabf59b5495579338d6dcab6aa7272cecf66679b78ca9b67ec27433cd905f91024438720da6dff2059900f299fd4e661048fa41f1af831d3e161048fa4edff63f64303688f2b091c311e44f020b2156d7f9ceed8725c49f020e241848e978b701ee33c4d9e81061b4c58b2dc8aa8aa5c475417cd57369dbd6a82095112312364abd94a96c48492bd0aa2feb0573dd4d8e601a3f2506165efe8a0f2f8e3e8bc83746f79079777a6e46e6a078bed2f23a4b1c1848825dbfe2e9ab3524872d71195954218f52517699d421895b50345459db563c326d3abb1214199999711258665f6764e0c06c9996ddfa6a6c6bcb165be3b1451e3cb8c4c29fb0e45d478324dd8ab01491b940c9dbcedf7a5fc333219958bb22ed2fa3f1e2f76443b45edd86eca3f46de41ca3bb79b82d13cbbaac2dbfa6cebe570ae767d1926d0cd1635cfee2bc1597a984f776c2f5926e764337fb6998cc93fa8ac5a4b98dcc351d4b638dba6354a356c94376b2fb3ca9bffbd5c9475bd299d6f8ea1f3cdc63181c45dd2f8669337485779f3ccf67251ceeb1c1d661c5e2eca8f75785337c76c524779f369933bca9b5db6978b864af824e10be731cee3246709e570189525b445453d687753415754d43f08e7446509392174e4a80c6a2b8514926eeae6ac2022473d2a2a2b280ccfd38b79312fb6ab14ba959199574ff2cab692c9ab97bcaaad96c8ab529ee1fbf2499d77645053fe39efd4a0a6fc71bc92cc0ccc4bccefd460478aea7279ff1d1a54d7e9fd77a2ec40d999c14e143b483b32d889417579efbf0383ea9279ff9d273b01304f036931d3e2072d62595cd1224613a178355b53f8891a34d933e08d67ce0a1f3f1982f933cebd33c06c075420b64547c19ddeb05147f106ce1bae36f63015fc17f456f8ef975ea2edc574b18deff53c7bc37f310dffbdbe4bc23f73c3f7ecbb86ba5e1bfe705f8b675ec9847951661b3f3996fc511aceba8f53bc431d7e3553f03e0d37f86994a3353801f81e8573561536857cba68fcc7dbd336656b2e20204da1e9ba166dfbcbe14c4f169c17959ebb7ee8a8dfecb67bb35d1f9b5f1fbff7690df2cbe1045970a632576a6492b63b39c122fb3e9e6d447254e6516314199dcceeb6c6db79fe45b2a71c8f0ceaeb94bbf794bba75c8c7dd2c5e04c47a4525a81efb12733f30a9ab0f1e68db7cfd482536ebb98f72937de50b27cd2ccb6f28c5fe6d486bbc71d8237ec7094995911c4f65a2edf0c61b24257cb5bd4798f482392a31eba1ea3c8e8f2be211a917478441aa3380bd4e90d5b17a1505f9cf66f4a5b4a1196a4b5d7da8d6fc9b1403fb5c2bef5fb3ccff3be5a55189f480002082050eca71a14f6ace7d98b04597196784f3ab6f17d9eb635f57df67beffb3cf0fbb0e77d5f6fd8d7c39f0782a0077edf873df0fbea1e97940087187c74dff00a5fa736fc244b1ce0b369b8dbfb5a7becf68a6f483dad408a37f815c136bced45acb635e579a08680efefe2580cd7f04b20e0411ef396dcb0fd2dbe607c4ec00fe3cf890f7b453f0aecfb16d4b6aabc1063117bff696c71b84a65199f930ce209634f1cf3198667b59784f1d92beb53ad976c555d5cc9f116fae909d0c3e0e7c56456e6d1d0805d0d1248f20c00430e01474c163c5d1fe30f0402fc80c01e1210df0aacb32a499224107f9261e3b76179aab15a6110a481a218c4296bebe2b717c420fe3c24206c55791808206a6711bed8ba2c108c7fbd394d85eab2b46b936846d89d2361b759b77933223bfb6eeeea6641dc1c888f2caee14c735fdc2119db1833d91866db5c163708b7f9133b2f2ccd1aa1c214f7b1a767b01b5f5ddd8bed1edec3c36a5d144b586317dc77f41dc55e86aeeddaae2d97cbe5721e2a168bc56237766dd7766dd7766d9f0abc56159cf6fde6ac27719456b44424be6e752045f0f3c22ac41cbeb77aa526bc71e6e54659e9e8c4f6568c4b344111187ff0948fa36c37c1f7d3d7fb405014a7bc58d4d17bf1c59a460d47fd71d6f807b55e6da3b71586288e57f37c7a54953f15671afa84176b41569c1466b76f756ca778c9e1c4840b15970db4c480c50818e3a397295e723831e142c56503fbbeb7c460df771623ecfbee85e68fb531daf7b4e2b480c989529592072a15e4d5b1189d569c16303951aa52f200f66aa4289350d6c82cc80cd8108c97c894a24c425923b3203300969ff7d140b1af684514418803eb85e8482314a2155104210e3e708607f0e8ebc216daa49007f0e8eb020c653ab02f948b01d01a7d1df0a0fc8422eaca0ebe8abb429a40e5ddc0e9ff63718ed9d5c2d096ec0b43abaa4bdbd73e0c8c685144909534dd58fc9ea7b1c635fc9e5fec7d60a86bcc4f31234fe62b0ea36cdf5b63377551d984819aba2f934d3c549649070c54d7cbdf375da0ba60febe0988ea3afd7dd30fd5e5f2f74d3ebcc902a61eaaebfcfb26597599febe8987ea32fffe18bb2d15ae29896987ea2affbe69a8bac8bf6fd2a1bac2bf6fcac1848329b6ef09f529cc7dd3cc77a0b4ccdbfc7dd2cc31ff42f3a75c0453f32e2c35317f66089c3be65b3204503b66e697cc40036a87e28fa50aa8efc79cdbb82f03b3d3f1664f484ff76372518da681d1e30eaaeabee8118baaba273deaa0aaeebbe8714a55dd163de6a0aa2e8b1eafa8aa7bead18aaaba6fd223aeaaee4c498f38a82a538f5554d52df578033d4ac9e3adaaee8b799ca2aaee8779a4a2aaee8379b44155dd6fcbe4b18a9aba8fca231635753f5d472cea89bbf7c79bfd7bf578abf7668fb7db32c5c69b2936de4cb1f1fbefbb3fe0febcfefdb40b9331668ab9dc4f4d317b8ac1f88802d4ce1c2f4bce7bd2eb61fba72c1e0e87f1560263c4c18434de2c06b3cbce84745b2e49279909c96577dbf677ea82b311606c77493221b9ec5034fba9cb2e5f5955d97ac1ec62c56577b5df1c45ed300fc88a93d66cf78abad8c4ae8f8f2acede2142dd36830887f06fe9c10ca2c5046f769863622db8db8a91c5b4e06262b9c7ff31316fc88b79de901773d4d39ecc511a263d18ed34a6252676539fa6a9c5aaca3f9455950381b7306648c7c47270da4f636242dc594dcc3b223f8bc5211d4ce09361d6a101ce9ab1abe7e0fbbeef738c2fa629dd0fd10d56b711def3baa38044dab534ffccd5058624f9d5708ba1e761ec79187f8fbd5cba9f241c92f9bcc84f12bec6f7b9a12c7c954fe6a1243eaff23cef3b6be596c7967945b256ad338f9bbc24f636f9912019deab537dd67d7e5f1d6d254bf87bb8a3c83cb4e47bf2616cebb329ffbfe097b98eb97c92ccf5457e3b4c12be868692ac5ee49b7fed4a146da4a67d025931c68e31c6d856b2548228fd654c8e62ce55f5a448e6f0a6ce0d665b55a20944ee4fcca1cdb449b10c4d2032afb60522377e30a7d5b66dc942c3c60aa8b7d0cf16985e6b087c9c4bcf86cd43dfbf2eb971c6796809fedecbe3c6b7071f5d5bddcb62b9bf8c3ab94f41569cf42cc790bc59b5c73cb44404ffcb0c409fd8200076c8b3d1ef25f081206a19806e05803a043f6c06f59c4a6b7ea5a35fcf065ff44fa7e08bdfe38269a86540b77d51d49e982b7e319727aae61b7368869e4e57d858a7f6f9419102fc14ea9da7af26f36be9abcb571816dca2439639375f677cf56e1ad8f56beafdb0eb7b3d54568fd1cb572ec0c07971eb02298b1e9b15ad9ea39bbaa9d5ced18bcaa88ff33a98645ca35089e509891c0d89a86848bb21163515ea1c0d7fc0c383a2ff289419b33ce46a93a3e791a9dc7233a7581e33e7a8b905cad4958a4ab452adc4448c1882654de9a8458ab7fe5ba2d8969bb33c1a1a4a3c4d633692de148bc3c4599e9cb3563a47cd2d2a6bf50399476973cabe6fea4a45255aa9566222c6d499ba509bbaf04153579aba1a6dea4a472d26aef434ba250a0e152386603953ca45321e7fda7364e5eb41cf5c770a97de903964cabcef13ab144e849cd8c2af2654136a2282522021848490d158ce28b390228410099909f94188cc5121434262579272f21201d4578c979187fe9384af9cc7c932d42b47cfc8090246e5b112c48b3066e8e484e610f0f54b9c697d81ad881748d9f75fb617d2ebd6e3646441594386e6fc32f23f4e2ee1c9d490ce27095f32d0d71145c74d07153a703b84d831db41db7104bac3e8751483c288504f3042edf1a2dab84f665892a3337388f7d2d1b05dedb93d473aa2e8b8e9a0a2b284a0881fea88b2efebd821446dad8cb063765babdd0e9ab37a8c761c51593d4a843feac0815a070ed4816bd181fb747aeac0cd7618edd791c5b1d2bd9cc41c8961144f34c12489cfba6c3a6c55d573e42cef5d3717ce65bb4f9665699a2c366860e366830a1b34b0816309c19ab168ac2358462e27366e36a8b0816309c19ab168ac236ce06ce06ce06ce06ce06ce058462e272e2732927286f67d1949393167796f9aa5120cf8b9b8802e304fb6e41db22cfb9077c8b35c838c9471f98a59cec9b002337e6096651ff22cd72023655cbe22cff22ccf724e861519564618d0458933b5c9d5684633229acd957ddf666793c48222f44d268c7c9309d492ca43434b30f8e58c0c2a460cc796d5ee4a92a356765515c48b3a832ff6fd199a0c2a460c475449b66025ce7426b7daadac782b7f3a5365df9fc9cde84ca5c9749a40de768119c78fc5e5c9d30b10eacbeee58b1720ecfb92746154505330b50b6373182878761ad268a20d0cd2cc14cb5383bb463d4ef20c2ee1d380dae07bcfd10e4ed80e660596b4d2ad7ef09204a302989a0d068aa363a8442c94884d4f3235230000004000e315002028140c87c482e16098c5a9e63e14800c759e50604c2589c44990e628850c320811430c10011010001991480022120f92c65ea8408ccca20b1782545c24585948f427c8e5540bd8f2232ee5896db717b4d7005067efa30ed30c8dd893e884fc4ca58d4c9c8386f3e03e87b42145c827c81754e779e6005c759e1d83a88b885bf19f70f1e52343853a0caaae039e1f02be8f06c17b22cd0ce41bdfae8bfbb614afde5736ada5c9eb5a0b394a4dd0a73185179f8fe4f02f42d1f684b3165aaae8b28a2bf92302356ccbb719a0c8150291e769298dba26c28c847407647a5c53993976bebd2f30406e5c58bbad1ee22160476e8ff24ca4a498d28cb972ef0f0fe5180dc53b1614afd95012fc636d9f00939abca5e497561b7b5a2ffdde2e8a433c63daf3d161f356181a74ad6a2d1cdc86a7460afb30de5c585ee5867a065e79592c920f53da03816f2afd1ff8fa770e466659c2d810bd5640d152b79875791c87da751b0e28f289d40b168b4f5225474227368341d109c4ee473e57ed71f53a56b705f6498b4ae2751de9819a700e0fc82268040bd1da2f8ce3f4b50e8d35ecad9d7fb943e4221d6d245d27294da20d750895a457cec51e4763e4285e6df6913bed0a22302cf50f27dc8ffdfc549bf72df70845a5133547c1746ddd174e6757ff7fcace2c1243902f6cfb0f6bce1358baf03888b6a61f4cfa39874ba63adb0bf5e69994fd1381cf36b137e6177b935301bea470f3234a4fa2630f8e2c7d706c190a93113ff9a241e171d4e23cd2d8e216330549a73615ffc6560f0cee8d8a706f42e10881fc215531a9c9dc1001cf9a9161cb24d328f4a711ffbb1f41fc4e83ed63d5ac24f7c9d5d6dc16a0e9f32986716fac312b9b7a964d413ea799c9bf1997bbbf0f992fbff27286092f741fb8a4fa8a3786b72ef840370b32e8c538c6879337e22ec35f8934aea346220d965de938d23c6ebae386d2f73dcbd5883b02ddee7c894a1b412d38b094167cb0648e44740771f4899ea7d4aac7089857e36c5ea4350326172fbe5c702ca3280c7607076a3c450bb8d1ead7150d4a308eb10dca6ee0264644322edc810e3764bd39c18f7c0128f09f0a0801facae51dd0d47ee41f1a8b54955aa1c87abc10301f81375f329c1501d0fb2b5ce4a264fd2d7fb09ba7e775a0eac327f9046e7b22a81afa17389aa5dc0ddff45bb761224c45680f3a970da64d6262463ed1f2a37f582e980d058fa32743dd518b401d7be9961706257b96f49156898c8d40e1c142f384c0c1fac2ed63e0303f5fb351b58b08a87d741d6ea8c52abf6e9a7be3b045b98595a1484cf53fc9d0a40e903afaa62dd825d09e0ac7c905bcda4088948eb9a53b5030c3d68d76d63d9a0c510542941111374badb2cd4b90ad1f736a91266d7e987097506b598f2b793c56b996e8fdacf8079d6d5b4257e8abbd45e09222646ceaa0cf05bf5eca8d904c9479c7c834f41c2074bea7212e0b96824d27b21016d1e4e748712a64f28a75240ef8338c50f432c36c6f6b45378064b70e982bac4a8f23c9ec73820aa423f72e4f1257fe502ac51f2f8b2d8beb4bcb1924cccd1aba2bc8b78d1fd4113737eda4f8431d6e4a7de245779bcb6e389b054e74e90fed3f937fc4658b76fbbcabce2928eaa5ae64b87a8b59f274fb872bf55fdc7f46720f36d019c6c6d3cd42ef6dc1a9ab100c182f0920eada7a540e9182cab9cde0e82aa11578435151c433e75081b602d5d2b86ef35c7d7270e751711f2de0799d1c67b1f3cec6de513d9a0a5733951381488ad08259875584eeadc72592f072d5c6f403a167558bc5e73fdb890de45684d2989522789c229428313547102c2406397f6693c4fd9d60b158843e7cd0e514e5e47942c01690879e32d670a8b58e01481bad0028076eb3c0349d0247e8324e651b5857814617da69c3adb708cda5b4c95952807dbc1ff1482a3d53f3a1391334d3dc78f4d9dd2cc90f1a447f6ac6606959cc40aa29b28eb60c266354b86857e9066b9e2eea26fbcd01cd3b6eae4f840589538f34fdfea0e6f9726f9ec999518097363505588bcb446c23d93a09473ccf020eb611bf9bea56e7b90758ae2038e259669402bceb8a7b6bf58225d7c54c9bcd0c45e688ef6bde77f03c571cd911129be2230f9a26c3451ed8ca2a527e4ac89f4e6d03f6d446ce847a2ffa12182ee7f34f4422aa7f1346ec9c09a50110c1614167b99d7b2654cbd16c144a8da3ec25b5992873cafaec624de81ac584eab221ee7df818c70ae53c102d580fe06aab481ca209d55ddf0aea22b74fa44252354d68b2fa4821dbac1e445be670fe733d67aa2cd2da72769b632828ee7cd5843a530317bc1e409a832d2cdf3337996a7ce752c23cae3c69cebd4b65ae2930bdf8c94a62f328778b4ab221ffa6def8d5a19527fb14c43961646cfc9613b21e172a997f024e30137afc4ea15569c7bf9265b9265e91aba7b9a18877af28dc84de5de341dd79876b70e3a30055fc7ee29ce9416f19105c13eab1230146acf0921afcd16a421bee0a0c39fe209b505e6a780b76593c0134d021818705c8faf5be02641e61604cce668b8c8878283694f9bf84ebe8949f90eb9426563a89dcc1167ffbcffa56026508814de4f2199577183b2b5f0afb16d16338c574a0bb7e851af60ea8abfd4148f58e85520ed1aede4f6305b5dc17365a99c4cae2500885688ea3ad48cdad5a38cdad31613c0580b6ac35993b9449a30a83ec734593739eb4d18b1542ad244499741e506741213bbb4ce17fdc85117e1fc5ebf636b8768a65fae110003078adc3442b833239f3c0d1613d08b7d00aafad83251e06fcf8eceaa72893ae5068a6a667b524f53d01023d5ef71665c69bc6a7eb2466a69a1c848b72927f3d8f3525694fa37c1f6f35c727150cc6883fd261a4e54383004945bf9279efd9a2cc1814aa0a29f277e13e640082df3e70939117639499ab2e252bf2e9130dc8aaaabea14fbba535d335c913ff6c30a134f9c511c7409eee04d7fb3cb8e7554e0d19d6f80b6a11e6afde0031ae6058139aafdce3095bfb8a7c43e3d8e3b6024b8f046e054524d5090dc6a25e10cbdebad237599c1acdb89865e74d7d5b5ca62897dd09c33c485637aa7359b78913855254901e342870337e5d847a615d2743293459892bfbd302c91bb5d7ea0c394fa19412257d6cd79c88f92d0b9dcc705d7172b8e0a6ca375185ea39f40ee3b9b4dcaf84517dafa7aefa97e20dc7cfc345d3acb9d7ec2a322f17c65dbe6ff955b902a1b0b63f04d21badb623798f3b2ccfa0b4b3d0a449d02a36e6c099311aa1a5356488c2ac09dbf14966a65e167e9ef0f82cc2c198787c662aae973d9aa7e5d2711932dc9469f760b1e73ceced53b990ea825417afbab0f2c54f652f0c6a71a043ed96533e1ab5d6a6e586d6b7b4ec2d563bd83c7b77b45b30f9d2d4a296965bb48c2da365dd79bdd9cd9d44be5ab5d4a0f56f186deb96ea1d356ed0f86aa85569596dc166e99d6a56557e912af642500702451b1c3a8a641a40d4b3cdc546e4684d6c98354f90b9a6d24c66f5d121a0d23aeae3aa4073feef1bd598b99dc1a12fa3df3a788b12cc1f701b7e79672a2ceefcd1ddf826d7f5d9f131e21c48c5351246c0b2cd8d3e68e275ef0b3826b0cbf99d454c3ede7d2c904fda781554de942960cc88b00d10f45c384c56250574ad766339c1924aa60b6925e28b13a9f31ec4d519db70c9990f8e56091c70baf19bb80ba19415ef15f2ee4b804e6705e80a79fb12a0d3b50234426ebc4da316930cbf6175f98cceff1132ee55402bfdee9f001977155091be4d28052dc910fc32d88d50ca8af70a79fb1242a7b3024484dc164aad16a9965f5ebb3fbdf77f0c1967151091befd20352df4487e0d7623815ef52ed26e38a5a0ed1c0d69dbb4c4cd0096ad535a746825a71fe7cf0c913d8deab8aea323685fb6dcff5d155a4164c78b61ece0e457301eaf07788458b6ef4cb86e31aec7d2cd16e400988bd3f704b1040e542f607bb9356f5368ce26d9078bcf361f2312ba4d5430a17f41c6fd60e369d42137544c418a3ae565d3643f7c580e0c6e6f438575b9de3cf95a77354af409f12c225a7f7da6f35e17c5cb27c4f3766e80d834886abbfe4e1fb8e4b3b7798f586c1f4417cb5b8450c96a1dc9a5dfee078f0bdb150096addaa4f06273089e520b51d3d05e84438769f449495e4c405f13fbfb722ad8bf3cefc1624a47863c45dc6401315459a4c8dc2ff50529f7688b077593a15a303559f6f3d37b7590b8bbdd2a2a76007e9a446827981428a910ab051ec076eb1e08eab6864e1645cbeb23ca07290453c39be3c024dd04ccf520712306969d9b97f04232049e1cf68c826239667e176afd8a57fb965386769dc26054ab200140befbd15a5ae5724f8c4377ca23f2fb988b8b2818a1588a8b8272c4146b1701445cdc4f5021e7623b0f9a4acda4ba49a59020c2524813932b6e774bbe6d663db2672ea49cd385a46e23919a1a44f455c98bf4f91747a4aaaf8d62e5aacab9f45296e080d7c6d66810d420191297a5e1ac21b0ff078a6f23a474e66d9229e550b34377375420069b5e6a411e6ba1ac9d0430c85b472d1edbc42cd2cd6e48bf633c07988b58011a9f8fddc36329391615a045533e11472766f11243ec8cd0f6089df92ca72054024d944128743f6138bc111813cc29d4992bf05e1a9cc7ca5b46b3d1ffb383439bbffae5d9841652807782cf601a6e733f9fdbd9efe7261017b51bfcf5c11f39dd3248fb02d4e801d51ec70c1c2ad8ad2e29e144cc89216227a2486464962cf6ffdc62fffaf6e317b9bb6e5023bd0097eb647a701632caff8bfa6bb09ddbbcff7163c319de701fffff86d0c513ee6cd132c2647e538ebc1132c0c31db0a52bf6ebb831c8a46fc39f9ef00d48f5da2ad44b88d9dd8f2b87bb81e8983fbc210dcd543fb70387578ef79efce2a393b045d882aa290c302139f691e9384b39c72cf0411b171c131f5f418db2d627c41431c564cc7eb47d503c3ff5f6d696e3a7082aa3535df0aaec066fe3e6530129e492360b4bd977e81cf8c42b22f5aa05c5d51ad9a9d17df910425aeed669ba1bf9e664dedd9dccbdeeaea5c7fd2a245477f9df4019587f1f56efc402a09352b9b9d993565db0fe70a2bd48695e62e114122eb7471f844bce29f609aad47d84fbfd6c4a249ae47df797f0d7bc0feba557ddb6ed132e403ded5e756800090eac71c8e120cef3cfedfdb766812df12937308417cba99f69c1baacd0ceb4772a797b0d537e0cbf4a1690cb2f62e2119332445884f32bae703e2690cc8184721c32e706e08ff97ffa111cb167ccd636fac652b4151d75467aa91561185a7d748b8bda780a7ef762d05394a54789114b80c18358f6317ff5c170965705fe51efaf937e89dbadd4b4f82f89ddf985bb3f70d8a49e3eb8c925573a9b943a1d7a5f49d3abb8c07e8b606e4f1f045d64955910600823431837d83eb469136dbc05d524cfed658ace053fe25bd98e5bae38fd2cb2182c4ff10ff725432d02c3297f3e344677301bd2a12e6b738856d3bd38808531be4354687d61263e6bf410281b71daff7c43d01dbcd01303fc1969448571df41f2d0419c06f17cad9063025c8bb2a66ff3af718f07b209be4b76e33a6d72d54769ea8e46ce144648d8f8a0667c65cb98943a2c9cf6b0bb17382230b7a8f00a2558930673c57bab4e9196c152b70177dd1f7f936f9cad061802051536127947436ca26ab979f47e95ea6cf703f6ccaf84a89beff47057f452160c75c3f1a76c2082647c14d4d9e1db6c8a2c112967bb2c051f7f1929f5e390bb693bada33eab7f970bf5c0ceae0a5385cbe0084f562a31f0680949d962ad34aabd3c77c9c78ddbdc6039de6b7b8c54693bf8575c51f8048e1bdfcab5b44afe80e0dbd73617db245b270612a7242d7b7d34192f3261787ae47d23a689997ad86f78733fc5230c88dd130a357c66fd9f1f8cb9ebcbeee625e81b870d93b1863b54eb7d036bdeff365b5decfb556ee263c7572b94492751d39be701e4ec9f6378604143a32792e9f7c1abbc0464450d002a04cbe7903dc3f625bef02a4d1394c7e770cb8d0b08e858e7c5aaa84594dedbdf0c2fffd478ec9c1ab737d16252d2d8529c7f4a6f94a00ef53796dd1ca8773cbf31448c6110c0be64ac38adda09fbf20f7b32e4da68b1b5e261b5002f66a6ef8f2493f511967c6a096f71c15a0677c2f106e464cfee02f41e4b44c3edc0f631e83d6d34b1b00d7e0ac8e80e37d778099dd13110e878463c141a57a197cf6d9880496dd70df7ae62a1ff2676069a9d6d7e1576e1eb2ad80092a15d22dbf1809832f913acf1a7a24642b2b8b268550b57371e49f8a4361476ccc4cd6b299dd908f13c3c6edd04d2db32965906123ae3e51ad349f89742a241d9495b117c8f28e53ef60b3f5624163858ff74522bae9a5de174c97ec5336a4dd4aa3f6af9d9be039741292e5e8197d02f57929eeafa61a90f02d939ee42b0627dc36d21b45ae9c4a58aa9db3bc24a60715a690d5679ccd05928c0d5743e26a6bf82a1104732ee6bdd05f320fcb5443b0a58d7f2f49fe687451dfce15694f44d4b8b26438bddf201d65f214657a426a971b9ba642fd32a9f109d45a184618c6eb59d7cb4fd54b348c9c67e9fa1f84708306f9f328229a6134c65e1da5b337781a31ab171c2ad5c66a542e5ec6f4e8153654c5178f0d40f326d00fa4932508dc9e56ff949cf25a8099abbb3f626b831d238cfc6c98be250475991fb717ac0b45cf5548b1e12b3602abec1de05015eee6cdd8d833fafb0556589462b06c8095d0f766b7cd5dd070bdbee114aced59e6826845837340826ec6098b035c723ea05dee2ebadf175babc597a4daab26366c2bd9e7d8ecf7912c1eebd72d3eee52a85b3738f2ff57d8eef7f73688d4b92ac5be989196d528ed929a657ae936c65c49594e06da8bcd858f78f6691d5bb92cff6feef1daedd87119ee3c4d8bc2e47a55f41945454fd0667225fad0bde18def8c137f61e9e098b023945b607cfc7db8bc4816f9cd324c2cad47210da4ec22c5b7d8e446c2c7d0d3ecd5ddac4360aa26e00fac75db883a013be23466b64fce1133ff1120ca6db92b69ec1934f095648180194e10da07797a3deeda6d1036840bfc9752d79ec4f86a4b6b0f76bc684ce15566a66e2f4552d96db2c585251e382052261b1625dc15efc5e12d50102b833fe6acf5f838463d84695fc17d3c26db371590fda2df8fb9a04d6e16e6df4b7d1ebc15dcd7422b8cf4f6e63d0088c45c2d855058e2a8e89fc07030ac2dd8008a78358abca75fc012ca82388b91e9275c8b1e0c50fac274c3102321c6fb7355e94974a21c3b16433ef051dd0889691771b4dd7be17ec9b7848103e85c413dd7e02ff4ab74687c2a02edbd6b0f56ee2c772778e501cce08d239ffa398facda411ec168d1beb7479c3f76a7b15899c4759211d66e8b478bb8a73ad3dd8bef060bcbfcacb5971643105f2dab64d51b1e98908f3b842232fcc3937e64a61b80a7320419d96c7855defc5ee5a7d62f1f412b79c7b2a9838cccbb82dab85d11827e8e101b432010db22a910b8033a0fee90cded04ae4e239df7ff80a20794dafad0bd1abd70754f5a930f59c2e274968049de341f343875c80cdfdac6186d41acc56a2960ebd136982d68b2092b5af9543c176f2475955bdec8ee5d01d9737e5716d9252a080674dd5a5554223e3cedc3adf51922c0aece51f40fd0e530633b967c004e8ee66946a33f0672626bc97a9504a528d93a53c49b11aa2cf2a3c58b889545cc1dfb639285bd465a97a0e7e97da54fb2bd176f94a53756f41060763cda4324f123a8da5564dabb23f010674665bd115e0affa108652a808dec5b659f68ce5230615a6f1772d54b09011ab6e7da6cdef5d544bb8908984af906e8c757b911a1a7f426ab89ccd47c974c63765fdc732d6a4f634c67dee4bf0d7099a61c57d9dd6afcc98309386b0b1bd9d63c58820bf5f27b7734ee8fd7462cdafdc976837f9818e1e5a2df8b6e11693af91ee4448f2fdaae377ec7c0d7998e7726eca0b2a3992fcc964f15ffe04bc0fb5af566a6033d51ed83cd519364b55792e62cbf685501187ebbeb959f73ef009d0e7b203b50eb9e18f300eef1dbcb8a7593ff4e63c9d2e9cbd527ef3aa10ed38e8dc10f352ca22c774c7e6147e5948d7bfd49c8b3ec82fa21044b2b2d29c7a6291a6c6e1bb382892ccc8ee68324cd5cc4c001f6e4e2a8571087436c3db3fea489883a1a40f6cfd2157bb0b526e7a348248deb0f55cff88dd712be4844cc812000ace670a6a8309a5f50305e8f668c14d4f3dc2006102b6a25d369069fc9511ee342fb8392d41f92d56a661ca70cc93b5cf071e651d56560b57669307cb1f5298e083eb7aeea4fd4ebaf7cee4f8479101470974dd48e8015b067d37ae4eeb689eb184514ae119475e5447c44f10a6b4d217218f1c0fffedf2740e89dae1e7060fe0c91cb2e32b8168c5e90660766aa0d5845dd22a07b2a1a1abe41bef74c33cadf4f2c333c52ee0c1834d82dbbcc3c03910f56db16315d2c9b04faef617915f7f9b34d8ce328e9884248ceb9aadbdacfd7f9ccc1cb35707605bd9f4bffe26e30860ab21406b4ac3177e069d0b1f977ead92edb0217470c793f181d2c16e3e30f5573b0617481b371bdb75ad2fb3e6a6790d5b8713143297ba8f86f3f44afad7d32d0fdb3f0bce6f43c3df607b8ada081b0b7878d00c766e78bd181acc8be73705b0482da641a053c69c55f8b66425f59d8ce0a4c407c9effcee2e2b56b708029800f6313118d3dc4736ca1f495919b49cffde430cb341a39207da8e871ca3f61445a078568f496679f953fc1a966ea0fc07de990cbd2fea6f3e17b1f5a63bd55d6f7ae13c98890f0ece3f5a307c8a206dcc831e16a88be91b8adcd645264242b384ac96f8c96f9c0a1206da0bbbe9873016a98fa29bf74cfadcdb250774283ba188e06cc899d536b4aa64a3d85489a39ec80c66235a495e9cab133dc7876c2edca03e643e9320665318341c4a7b0475218614bf22a1408a62f32e71cc64211d2c8597f55250d98f04a32648408cba94a3644b194bbe525cb625ae8e825105eb7738194d8b02cf5573a3a435bd690dc2f84a9870316c00c2e5a721b6edaf2a61a3cb22e1099c5b23847ecbb7cd6eb14ca5c1a1396d5d59b64c99478d6fae5a84e4ad5133fe8f96713f0cea1dc8b5630917d05c91b5c0ab6a80fced9c131c11c092c7cac4e60c31ca1d46f21c5b5460096083f40084f06dd038f278a35d5fd1f701238cbe7af3a9eb857039c42c60ad310bb8c1afff5bc1f742ffd470f095ce17b75ba6c31414a62ee57bceae9c4e203713bb333b93cd6d087bfc962e447bcef928f1047ea7da12646d03d7084d651d27d29a43ae7e3552082e87fa75ca1c5a3e8d7124b53257b5891001a6058403fc07c5a86361855801c1654948cdab5af96a7934a9003921c28ea1e8e2cbd4b64deb9505a47075e996bd52150da969bc617bcb2986c5c6ecfdcc94896a6ba67b12bdf73515aafeac8c2583c5888e16387588d4e8e159a57f4e633e08de6b0792a0d01286dbd49730be89e5ffbdf74c039b6ee068270315bb0b138a2d8101d59d0213b2669594909ecad893c9966f775fb401e695f5bb0d0b5ad97fddddabb22e77a74e6546ee758c3fcf5fcd68b90f8dafc3a8de1e621d835e58cf8683633c7e6170b7ac3760165588e5915bee7eadbb4dde0609f8597565ed131b7ece14259e52454f7e87b28062c5014020421392c53204e7d12247c19182e80e164c4a9a047b73ad0296cc46c5c0e59d289dfdf003899f38b4a542cac06e607dca2aae7985c5e57588dcd9c7e75b220fe1c4dd9cd573091104e705c51e41408568bb7929f818a7f8873039997fb95377c4861d0945f1235e35aa204810a6a3e0f42b770c107405d55225807235093c3b9c6b536e3f18a31cf5df1c7b5fc85d8382a7f509ccae5e733f14e08f86fb152f9be1bd1e9a320563683d67d16de0ce1da838928b515c4f77a88f9afdb31270e11d8a3e4e8ec1c061d751d515cd15d939d12c0eddcc9f0c2120555b676e70c043e7c4c53d3ad77f3d9f763e6a378b09b8b5cccac7c78b7639a2aeef1c883481342750a7a700c0c7b27d6f77d172ac42f8cf80aaa37197f3a8dfccf888dce5a87acd70a720de0f1243db30a08c5b3211d95cd62123dc5b67649b81ba512fd50b85ec0817656be1c60c14fc67477db6f32d8cf379d26198c915ae84ced0936a8c80ed8a99465b845455a0340a1d0e50c1ec93178dc360a090669ad5b775145a2f50e4588558f8371328a6c30e2b7cc3bc377351c3d9de30d4dfc7bf65c7184bacc43327634d9bd0366db2e88e099c70614844d21c734667bd730c3d7474d7bfba8c74098fcc14cd2ea8a8c0072a9108075ee090466996613da07ddddfbab4efb799fbe31bbcd0041f8a130b0af4f54ed443fa053abefe7cf406eccf71317f679f15cecefb70d0c44d96e0cbe3922c0f3215b7a88a068432106e1feeba91fe1794fcade5f3e73b97346b5dd74c263fdc5db27f2caae98e9dd47f6f7653799daa0b89ff613ba8b8cfb63d1a546d1a5d91e5b505665c940113698c0091c2785d7c9702a096f612f6f0e7302ebde1a0de870c68a3d06e4fbea359f4a817412a08bd04ed1a39e9e7976f91fe353896abfdc4848abd6a447a694a56daf43a3f241e838686f0ea8a60a0e18f9058fd65d4754663bfbcbdbbbb38d041207cddc03f8fc89c067cb1eb55dec6a4d3b17e49650acda4ad3b05f081fd13fd4eb2eac2badb8578c258c05385e5453386a54e021fe933ff6b22bb00fdc431fe9ef01ebff93f717665bb2786f2aaab66fb60114424d0d2db1dfed660cbd03a0e0c7534d7f8ad682d6649accd7af5ce89ea3d4e3f1f8a1917f3aed69821522feff6b899fe2c878e0021949ad8af61196783a2915dbf026c5e7ccbd0d89f2679c63e5e9fdaf56930ee685fb5e851027c0202bc9d23465b621053ef08346686109aff28a56359fc2d63408b5867bdf15764e59d1d2ba538a9aae5d91124566d08dccf6e63c506fd2bccc07d11c0d4f48a053b8a430de8cdb5c2574699668cc63738c3874fe48e8ba7b829d9f4a1c411d0c05bfce420f9da92cf08112e4d5a1142df0504ab64281677ffb48755bbb5375a16559dc06fac23cfbae03f6a54aac7e13a45f3c1eba962d7102a3cb00e2625968f1a9a9d1e3bd8e8d27a00ffee188c67a9a49da64de251d7d78d33105e6ac9953a5185a9813b3ad992887712d64362301a9b8530f86dec3eb1e8ed506e34b9c94d62131f78a77b624777b35f34bb3501b44360070681122e2735fcf493d7b7e70e5e6ba7397e83f45c459c6fb432a46db5531552120ca2355b4c8607ac4fa3c7a7a81200c6777d0c91740860ee34650a9b82d2eefa4cb31d37360e355df18cfef9e495b62d1fc411cc46004d51122f7054040d28da903099f3c738b35e1bf09d69b53af20c5f52717f18b0d97421760c01558cc63ba50382309f46d8604136b322d3cbc6fffe0d3e79f4eb5c0569fd1ef217bd8e483bb9cbe623042ea075fff7c58334bf01f16159a04723a9a5dd9bf83f99ee779ed56f4fbc5db65c0f44054683c311bb529b6742bfd49b329eccef336211ba34eb2ed54e4e901f7fa2b431dc66f26b013494a4f3689baf941d013dc45036d5a90e174077785900815fd8949de5742f1d6931ccf690e842a0071c44858576c72eed601c6045373c2603c0935b998ff1ea9ddff815c1578a02f6dead2fce0f88191003e00a32b9be9046d217a4daa57b4d92db2bcb5fdc0eac527cc3ff51083fcfdbfb6606cfbd38b94661e52bfd19e4b2efd3cb2a64e8796411ca7b2bf5f2c720715489830e4da3a77262862c3e7e956d783956e85cab4183cbed67738c016d195dbd1ad38be0219a383f8c7273ec1f1c1d595adac29988948e934c897c30cb043e48a27cc04cb418de653123c8b99dd3fb47d06491f9bdcfc69597f21c79fb2a495fa7fc99d8b427c597bdd7d4d6084ec05d834e4430ef41104f63c85b6fb2bc7dbb6e7a1c44b011b2d8fa20e5deddc877e8465d34890921a9611d063c7fbcc290004ef9006f7721d2d12973f47b15f2136aac8b7cb1fb601f9061604a174982ea7711411ad2261379def5c1086223372a1db5838692996620207a1c8c975d81136e4a8e76b0fd837792f4763ef78848091db32b79ced3c7d4881ac84bdf90b7a643c26e4a2d47cb874b5aeba314fd99aa759c63882bc05cc88650fc3ce1f74c9a898ce3421e17dd83b26d23811fb065d102797efe53f60ecbb2eeca4b6061a198ab45b2f9751f795f22d3317ad7c04fde9d084ec89046616d0997339c0e737510624cd954d6411c1758bb4a6badeec866582f9666f4cd40ad2c12249cb63d9a6184c9d73a2432a45a2bc1337f93797e1ac303980b0ccbe506372db02753236a293ff224707e513ffe0aebb68c9a1f381ebcc683d21ac55dff2871650b6afdee78f37d93b96c8914ceb9463bfa39fb21b078ba601bf68819863b83f0c1be3c7f16763bb046ce71b2471a506f17196e38b0fcd0b3066bc83e64371eaec11be05ba0603b552c93cace8beb191ef3b30a6030afd207fab8b1e0c2f64edc8daf9e1d6637e1a4ca387aabf87429204c2adcf1781c71537f60c316c43e58b9a9d2944b3a87a8e055952beae1283384e78849851b510b41825542939e8b366c0307728862a73567d8f4735739bd81ee0d1ced0a60fa2f7c2666a4b08b0db0e30f3632de2a2c62315e22d87966a28621d7f5614f876352899a69ffb3508fc2003b0d982b2493b686c01655e0f2326e88372fe6f42aa7f7efa4559eae3b59dec1336d60b13f856b7f29dd556d4eb3f77d5afb28948e82aa3a5a08e0c132d22acc240edc9a5d3cd5eebdf63109bbc806d2cf32f962a12e5c4526eff8a6ca1c3dc7536938c75461f86a2587d93714775556463535bf90614d7363abf5fa7615ece272dbc41066ffe7006a262747dcae2f076fbef575d815af37db2e0b1eb65f58a65cb8d7175581d4874b2a13b541551e5cf283257827a9771b54eb2068b51c36259f9ce6196642b8e5b473ec43be24d479aa6f2f55c88e9e1d1f35cfd8a72394116e4165819542fd69d10d2dc682c4b0cf2823eb7636f0f107368cdd4c65e36aef6320112921d17e1f6783b49526c3af6456742b3ffd83fe58509fe5db350cc424155151d24f9061decebd5d908e3f1cf58197d618aa7970487675f5499fc52dda8211f34e2542e6ec7bdc4343214aceb08520ec86470f3197ca9941c8d4a2c6ffc12ff331de184707e9de48e903692a1d967aeb07930e9572b5f2f8ffe0558e44ca0c953971f513190ff0a943d538398f632a6ad94fa4b83fb03350d1350ac3eb92c50702ac4fdafbc594365d7964a490495b4101b30c3a8e637c6e58045ab4125ce225dba9fb9506038aa99456e75df8cc11bc1f9fe88621a0534697be8244d699600f53dd22142bfd0adb7513e6293cb7d94d45a9f71f662d7868fc48b57b06999d9f64bff2e32a1ef51c069089a1c38f8ba096eadc546a21c9aaac8832f6f36516531ee2fedab5238079971210891b87aa310c5ca4f6ad0009893b0760dfbc35e8f95944812dbf58a1f00c070384c22d17da8c93a29a17d217ea4db020def5e86a38b10d041a1529b36c730fa80c914d61d9b1c4e2220c6ca3dd607dc736f80a55e2a71215d267082887d5fdc28266d7d8405300a9c48b2cdbd5ed17f0a76f1fc84b316c9c602100971d8db7feb76d4f7192f781d9af6883c74df0dce1fd363690177ecf5734ec4c148d7ec6117cbb4d8c54de914c83898b72648007c43594198a6dc5361d1ada23304c80f4c10b0b871ba5a380d26c4fb0fb34aa540ecdacc1c3128f177e8058fe80a0794c38056c334acc18ad3dc2659c46563b4959f7805887b733f432ab5d60120a3ba4abaa80843ee0126d407d17280c1650ed477c11038afc36b79d3ab81105a40092bbf4b0b8047db2da7b63e932b2c7dd905bb4d46921e1bd45066cbcb30e6c7ff16f8d3c46f69f08a60723f21a4fb5759e1307b569225a43e0b41de8156dd45961bf708db71ce17c086358f1961829986f23ddde62c255413384a1cea65a1ff509222266a023603c5107bf83917576fe90431b1fd1189f720b66205213472edf528da8b764127cd00edbc6565cbf489f124345746d2f848e549cc161973decc64c5aac5ece1a7c20df636066132b91ed0298dc86558976f63fab334e8f696b5709f8a62312cba2780f10ecc60129e6b00197a58e7829644c947b532a115e5a482a14e49413382f5775d40a22975f558038284bd82411d2e114e02e281907778f2adb89c61d5a1c71db14c836bd566f4d235ae9628e668727fc5ae374e7c0fdf7ffc92b8adeee1d7d4c2136469f99e9a1a5905eb25fc75caff447d6e407c3672c1ff0921480190b07ffbe1d17f6891468a5c3e9b62506a8e2ba0171594b0527f1169e0ad5a0af4807204941034d207838afdaf180d282217a8affdd4851959410c4832821d8daea6f2356fcb56c79e6d0367c6f41aa1fda35fdd77e3a4b0b854d10e9dbcbc8a37350ebef59ed1f8017c58300db49365c618d924211270dc1ebea342c0b464c2491ab68f490e3ad44eed9dfd61f9cd31fc1f0c3a2d0e0a0ac1bfe88b00b00954e748e54e413dd62c4c335603798ed2064c33d40fdea6f0a10aab626fdb6d2309bde558b619f24f2a5022420c948932385f4e678e2924d45b681f3e9a30bc8ae6a29230cbe79c78849ee466ae9d498135fd9e15a7866550608c99d40e84a3a634d9b8f77b828a0457e2090a63a4efa64ddf3effa56fa9659c69f43d7adeb66c6d11f205eb47edde920803c2cb077eda1940ea29f8b04aadf07a977ca700f4a675241879aec9f91892ed052bffd21f94391f343ebb229045274852868c5b5321f4daf4f80241191b33ebcb51025ba7eb2b1dd63679261cec72297f1a10b5e7c1bafcd988f9aab8a29332d690b90d9b1aa5857cc9ecbd1c8bb82f45b25f8382b272fffe8a4e48125772bd2b94608faed0f5c50a930617cb1d3d3337158a45be36bbcd465f323d785479d574fe02ff610be268ae7b45236de5b7d7db5c726578a335dc164aa144f122c1ee8d7426c13449bfd12218d3ed3c6461c7af26ee4a1578cfc72717dbea50c25f89ddbb70c33db1e2d7f6fb8415144ed27d0605bd69d2111577d5710543fcfe4ce2e15d0afcd8bbb1d28c30c56bf2ae9609533d2eae7ae6e74177b4ddc13644bc6c4053718b0221fee491abd8ce993f9229e4b285ceb63a1102905115b61fcbb79ebdb4db8673789a4d9a9588dc9d957378d7f3eddbcf4e73119160ac16c687b6014429e7735c2c85633bf40a9329846ac7a055818fe706aaf2a0670842ebc5480f8bc0d3a1c86f3d5362470b153df96a18a04bfda7eecaf5c79a5f9b06841ab6e39efd04242ddbd71fbe1e8e608d5ddb8c3a310c3cd7e2ed99c5e01708e18229b69da354365824e01d6c44100a4857d3608cb388811e4ba937ab6053888decc5aad9a3547db46a58a926a3330bc19067d6255780340ed29ffb78dce8499a2b695f7c4f61286c630ca34bcd72bd89b56815f0924dfeb54957a980bb5241a3e04caa17b06748d9ff87854d904e53d480f956c35e6de43fa60cbbfa4aa4bb6983c0585c19c094a2f262fca4f45c70989c38425471b52f63eb3e188816fc4143011da5b737374d16213bdd3d347fbd8c7ca0d8632eac3499d3d1c9a7e451cd01cd1a8fd98fc2ae9e4429e8a1a5effa78e16a920d7897eb49e18e83e4ad39dcbc4fc924bc42d1689e1f8dd3484f840e986e91ff4279935e42ca7352492703f7ea4ab998ea0538e72515663f83bace80d6b7049534a69b5a0748fb2cdd76d2c69066b9db37a00a324b50bc57fd5f3c833e6ee19c2c1e061b7d698141b41cf5381eb09183c18a330f2b76ab8f526a099b8187d9f1c9f78992d0bd38a8a9da8acf47b678ee124fe4cadc19abe7252a742831de7608a6977418b95aed8f421587e9430e7d6864ae19d06b6d8217a36f8106f332c5876a0e8b8a5c8b3e1de19f06e086aa5f9a0a1c1caacb963952f4d88572e8462b0be14517a6e8d36e0179e5df91bb36b868f95a3efab65eb2f980c1fbadac0745ff5c74e0f240669dd48efe53eecf482d480a6ed695e8d74bfcce462617ca09720c5beecf811802c1b308d3ca9791315fa1351fa460f48c23e9b8ece6abeb4b3f2c5b4dcab13680f7c84e15e34b9b2c38c7db980e98cd558dde2339231170efed29544e8ac79fef9c3711f65d9d093c7b525bd85eb4e83dd6057e72b5678804f3ca20b7f62d7bff636ca23bb958dd99602ecb6200c3a789427b782b07b7f1a7b3be54f47d30c5bf0b227c9294d0310fc887a219660106935a69394d8b1f1415016ae03871629319fbd02c4eab54b529fce2816825bfaec22f409dc6b8842d8f1acbdf8ce0d1eb54b7b2af250deeebbda7785a4501fcb03715fdf9445775b159249e1ba5cfd4c5e545c09a84767c1f78b014caba869e90506e9c2e3ae3e39a851d6ea580a8335ca69649ff62f02ce3c3826b508ba723e14a09564a6a3ecd5f7801d64eb8dff8da6622bf28d05e84969b11647857360d9c4387c76845711a49376038ede0e73291e6634584d62ad0a18c0530473cabffc975e01a6c038ab5a4919d73ea94fe1f80baab61f4d74780c2006a6796c926e43d5f1583ecdff6d614b5c0a4e915a1449ee3a94cd2572c89ce660bbd5742248b5721dd8f53fefca4a1c42fa470ddd526438d6c1cc342708e666398378650027364320b34b41048ad0ed60e353400e0d6e2325c5e6bf56ddfb028ff763a0908b8b16b2bff54fa1cbff10590738a520c0eb2703454ae164ec8f816c8275ef89f351fd51e440a0a613544b01440077838ad2e489a2a7310686df138b583f530e06ca3809ea6c2f0512411c0eca51430bcbdf85f50615c903f75bea2ca6edf21489e8a78263af795e3d050877a07dd254a2b56d9c5aa26d129a081b3b9cec1ca4e15065250e017d51436e28b21fc93e33454e7657885eae4f5fc2a2bfec226072d1602e3698fe48d7b7306692bcf852292880fa8943229a4eb063d401c709b1be70794ed32d293ccc05a0fd2e830a5f1ebc01235128ccd80d067a8275d887a3e36e534ccfd92d8858e66220799718015f0a3201931154980c00c951a19525efc2ba01fa5500f0e09a9b2d4e6771e99267e37173ae86077ee64bce38234094102f992e0ae0ad7c852571a4e851633dc3315da8a0be88b463125e394e7d4750cf990adf11f49febee4063f5db833b57a93d990cdc598dfa12c60fd0349d5232e9a1de681f0217948424edd6940c816396504b18849e38168863406756bc67598782ce3a5b4a1c99682168c36229c9b7609e3516a55eb2996cb5ffa5cb7f29a50ae899e5622ba7947c2c7881e2a6e491a65b8bc03b40e1a8bc79df4f8db65a12638ed09c9e2837f7a25cb41f810541e22477d2146681634a50491aa48c381c0ba489d7b37fdcd180b22c0aced3f42a85bd9a05ce0fbc82e4110ac6317d60b9d1c0a015fe605cd7e2ed89c7ad0bd4083e2f02e61648dfe4bc38ba98021804a729d8cf41e3bd56b011b301b582c0b949e48ad6681d7b0d77006a8c697e5eaf577a5183111a305e4957b976c1b3f67834e54291fbee31cf02e9c475de1ff76f4f0e1a279ed9af049237e550bd0fe61f7682cea1af0ab1f25f887119dd2e803957356e4c9ba07333693a1ee10c0708f9ad32b2cf08de2781daf17bee45987d566cc78cb36bf8ecd03e2b2c43b9943e66977e1c3f477c29c110c14fedb7c7cd37445b201140f19c18826d0a7ab3e8fdb3acdf4d8bee2d40d99f68b972a14fa4e0ef98cd90335e62f43fa4a122d71d187f638a446b6fb61a5e5edf83fb49761691c29dee301211762b62192814b1684dfd5c1bc39a137c655f475ae3b396f464150b79ac64c68bb1963990cddb667178f23777a3261d81a0c7d477a7d4b965f7d38e21a5f432ce888f5806e82a133483a071bb1a9f05e14a88488a8900b5cffa7d81abecb4e472398976dc40b3f52cd8a2c1c84181c7b9fdf2d72fa2b15e284dc264f9c6e47dece0d07c120c5d321962f040644463a1f1b28371847c82f7ada3773a0eff9a36dbe7628034631f1784eae6214911194516a6dcb04ad57c83a20d1318cf784ef8e66b03c0e1894f1b16889f06e3ca86b561049c01b4b40ddbb9e88c9439afc46d7210daa36a1a496042a507a44642ba720998f2962438330ce0bd429c44d234564a4eb10741e0bd21176192a17f19ded812262285b93f0ac3fa45b8596ab863601482ed68e656dfb0a94d6e5243629b8445a15d352b218ae057e3e799f4847ec33c0fde240a0435c0aba70b8bfec225e03fb2f2eed092fc3347003c0aa5c1b2bd33d6ee0674e7e7729a8eb0cf2e94b373e58f40e56f278c5c39f83f0a7b1784d99ac35f7e14be34b33d73a873e96a53363986134b898a0a12c80c3f9f21af609fca10b408201a2541a4fede34052b3bbc499398bd81f76f00274fbe6c7d8725edf9f27d6cfbc16824f359ab44cab2250996b9f81409768adceaa6d9304611cea0c2470bc6370bf1d80aa5f667cb9654b25800c182cf19f7ff0073a61e0211c923cfa9158150830060c9110894abf80184856cf20b9e3e094223ea75730445cf45c6f80ee6fe2feb9f290f85cdb74058428fb0d871c1c2fdc242a0fe55880e8b172296652316b67c8ff2e55f08efce65c52ea09d14ee6cc6e14288c0cd417b11a267ffcad965a1458de5bafeb5d83596481b1be9daa41fe1eb5a250b3717d2c613a05e27ad121fb97a890d3018d063c7dbf75cf45b5674efec4b3d414b6c5b9ba8c61311ee8671dffea91c4b927534945166965a835b422b34c4f83597ebb1c19dbf812e10e1619946e60cc5846d823e0fa713022b0fff03cd2b78372903e92d604d321d5dfd2e3783e73afb6f523ddf6fb5d03886bfba75a9711b6c6841946633a154b20ca7109d3da81b715163fc0d73d0556b76f851bca91d64f85e9c36df6040553a9d4d6cb268b4a1b6d1a555ff56d14fd5c2e3c1f4c48072e04d6f7602ebb6766e4057df873c1658e305dc41e0f8fe6f84bdfa6344deda8553414b984ae391595bb7e1c0c05a397dae364f5ce2ab11f2df86e695c784221fa3f433b54510d8da04346be4bbbd8466ac8ab1e0ac0dddca8b9ffdfbe4c48a98e0704d07fc96738449dfb8a5c4169a01204326f8fc57059c163a25db5d9f3222abc706d558d756bab126fb2f76cce13fdfb11a7ed6874f8fd6e2215637e85dc64efa793b650f7c01a8d1c28e9bf9894e02fb9e8d80c979983e54c9aa2148d99b1e80b4bbc673030def5083d0a225fc42bb2690d02d9e7445b34ae1d1ca84b9f94819f60c391ff8179ed1e655f3a369453b8308a5496c9a4eadc4d933ddeabbbfc9f347936fc601c287273d7aab984432321577a9280d28a542bb810d299c7deddab5b45323682915bcf607015ba5a6c32c3fe88719c7518ef61edc653b315f5f17f6903bc0bf8d8391c51aa17d802bc753ae8c12f55f7b341cb291c38ac23a049f8c4fca28e3bc0541b97dfe4361f451fe4dbeb476640de32cdfa5addd7043e5a96c7a8deb7383c8d60b6c25db07503407ae7bac62856e9cc93c98fd8f141c83243683ddcb079d9acaa54e1dab4115fc82486127537589e9fa0ec18af6322de1911b9caf9994aa0caad7789b2c84d494040807580bddcba48d317f709dbf7503c6ccc529b6bc4c3e667acd674d5754cd90d4edd149811dccadc8222271b2a64afe9a80d89b97def70588113b3fcb14bc3e2607b45dc4832f2048237c0fc7dc47dea1518445a589d2d5259b26c206cd28372a18124b2352046976f81df8e360f9e1ba0555315354147a01949e08f9cb860464c6591caed029c6f8077610261d31da195b632d3d9d4f57fdebd73647130b33919ecf72f169f4ac46f2f5bdfac75da3fa73079ccb383521ed7b5c8079a589b9d699240ba9f995bb4f7af5797ce187b464efb0a3364b17ebc6994211ef14a31ff9994fb4c4bf695033d48e74eb6d1a53570b123cf40797e041bc4d8b6744a721b3c03505bd3b4303993ddce816a099a90a93300a0f03899311d923a8202c657aaab720718d42e655a54074db31a324b3b332d40b13e544cb63b8cfc12326a60ad1f53162a52cdac80fe60603cda0bb1b49f4fc51db1206626a74d8185bd0f86b1bdbb8ec2a2176ba3b3f4096b1df9612c9a227e411362989a70f6af3ca60e9243753f3f31943f78d576efbd90743e38ae956e59aad62c209509352ec96e13ace444920c64b37b6bf37ef7719287e37f062ba039eb4298dcc7ab2085dcb0f803e2ccf2b719f1ab28b7531bb60e81fe618bb7db136b108faf9a8adeb6179a11f6237235af8f1fcf91f5b354559865bb9b751b54ec9194bdcf3da27652ea854dc52c02cc5579190a47036f3e6ad9a166f073bc7f2c46790303fd82eb5648baff9d81c1597d408af9a0052bc8fecff44ee15b6550c22ba15235d5af8bf6d055079fab10548131a9da7787871d394bd0fc5fa29a2267a8857890dd27e54c84afa1ce9d02d88658b6c32f50b04e0600e4ca7458801828d7bca0ce3f2843060d949c55637c9b76908c21907e276a092755a1a27ee25c548d29ee1d1862cdb98c17bdbabbcb937a606b0f6adb71b925037311d7ad7f7bd48bbeeb635aa6b8c9264a5e38e5bc09b1c41b50e1f952ff8a82253b79f0868aa99e33a6c89e20d5f40c48aad4aa56c9655d85317f2fec44546c05f44f1ed9a4849d58a59c7b6883739e751e80d7f6fe608f44e21084dc3b64188998100771a39bc6008aef62a49809bb77e6b2ab50b2edb8f24ee837c125ee3d20fce9aa14a87c06138b754a6e60844456bb2e48f4ea54b31480fd8247dc6082e3aca3cd5c48f87dcdd9ba489ce88ec50d7b6e3884c0363c2f8fc061699c600f6c12498cd2459c368d753d0851f912f740c499641c0e9436589f85771a7b2381b390ebc2a853a982f756f944f4f0fecca05dfd1f454f1929a84cab5b16a5cda1b564a09d299509f777e26c0ec7a26aede7ff45774cc6b73b39b57779a0773d0aefc6c2d8932d3c78e68cc3e4a4e00218681b7d3186d5f264b3c73d2f32ca063252e72af5524ce0635b42af380cca11405ce0e31bdd4ca29aaee85be37e66b3b49e164ba57523ffe46f52070f6006bc6cb4e6d0147c474448d15a120eb31a920e4867619af9d52bc428288dbe038b2712e353cfcfc1574dab553ffc68d4e8830f900a6e5fe093f8aa9207f9577846c51187847c9abc15c400d9513ec82b6ef459d470d62505dd331541c37d52fefcb632aa5d9d5091cce0bfadc9e61c898592b383579079f54616dffaf7612b813a79ed1049ccbdd52abf817dfe47d53b98c3322ee313361474bc37ed2d4776a4b860ce25141fc40f473269141c630008fc7b0037c675dc6b9d9fea3ebbde38e1c3dc8e56e73ef0f74e2921c362918386a34af133458a782758e3a1625b9be338d5542546724df5cfff2a85497ab4865a58fc1b2b1f65cbb11ce26250ab754b4357a94769988f51acadb60885b8bc1b749da59dbb8f753d8a45b5a47b88b869c9e177b0ff6c9c5537e4f58284a0cfe1c5d880fed73ea8da27707d8344351ceb38f045e650819412db7d708484804534327029c6a10613d6da88980042851ebede35958ffb9ea436f65834b3cd479dcb26e66ef0701973e7c5bc2ec3c59b3b52c258e0618eccdf1daf2731ea933a0ab5d2b21ef4ebdf5e916f0a7e753a7019a5e6b9db35748a57d068e917010960407f2873086bda417d015e648c5340d01cb5bbd7c6a99e52d46b5d0489e01df48e25edaa9e78640be632eb146031e898ec814491faa36ce021d52c2066e69211a502f78130c9a982b38c27036fb41a5c017f6d432d0849350d7976e9a9e02194620788cfaac1a5a875337b9412a5856bf305309a44de644114b733761948e4c35836a176d1ef5e3c146e929335ee6d5478c11cd91527c4a8ad032df4e0a3e4370208b7af1a25bab27d617f82a0feae987262849e2ee8f0d46b2ba576737d8c2854c44283567550fdf7c688def1f9e30913940738d97786e0cd0333ba941923690ec9478f0867a9114577fe8e236f13db9ec92df24ce7997501f2b3d05e046a572a128ea8690645e149f9540fb1983af032b857701aa3a9de4269799b772bfb4424b606f3faa083c5ac171be64668188a70e323c5e47049eeaf635647cfdbf576576558da395004bc94a4de43a9af660f2411ec8da4ce8163f8769db3f9c5bd0bb30ce801a5caae42031d259bab1348409092bb17f59ad4c67fec39609597d4db53c5584eb8bd395d0f1be1b8282d8aa4eb33cb2b0200c23330d0b22ee1cf2e0a7a56ba5a86b2759a789f01946cbf9cf07c516e46418e34324ca033e990f98c93ba5a53dbc8e425de59486ea6578483844b0ca73bc5ac5c0cae43941e7ab55a0005bc1b0ed3772e4433a7146a9d983fbb032dd0a97f21a2941cb1dcadf1eea8955651ae9ea087fa11d0ca031b5f4bdf49aef4719c7b1e42d4d74854dfd6dcad1174235b85cb60f62451d6c93ff67248f63259d3cd2afe37f4ea5604d31d33408fab20ca6cbe15bc3bc43d45ab22370b909f0e627113e9b7afb155531b50228877160ae0641c944b8f87ebbba0dbef0a9da055f46559710f9738e5ec9d76d875fe762c6f665d09ab288f433a1ddf08aa1f6efc39f98007e249d0f387d775e45e5192ad1d980ff408ba6fa1a74543db084a931e968aeb2e824ed0e5d16c9f6eb11b9fb908fd2a23dcb18ccd0ca0d9bd86f310c65e2035250171be927167e1583bc6e366f6a4619f9baa770c1e8f3b9e84abe12d33356d5ce4662a402c203008d76182f4778ab50adcf362bb118379a790cb2f59c5ff57aaffd91218248868e583051dafa56c369cd495e3d7caae542411704b5c018cd9c57c38956dc8572b018b4261b672638a42b458d91101096a318fcc0f5b5cda0aa2182234097dd3e25761f9ce3f1acdf5cd784556617224b4244fc5859835e775300a22b2efaa8a7af2ab04ce6f39dc3dd94f4dd974734fea6e81fb52bf1e3e750b97eab59acc5599e11b21f1a27425baa2e0ae35555c4809a1d483412a0863c026e2e04bf74140ca53d279114ec4b82488c9b1c63304ccd0aa891f3fc5231d7d08c9192823f38ae0072523baeaa2b0a43c1411fb6f789ea2be149890b26378464efd6211b95fe1d38f2a6727a788a0efa6f35032f454c886e0fae05502fb718c2143c607d000dea46d89b6a8a1c3c87d16e8c1966dc0999e2f4b463ee7128dbe4944a464a2b504861f18495bcffe6a72702834477aa26a142437e11ed34525e440922201b9e7c84743232906ed718801bbdfe38290f5d9f2012b9061e01bdd15587e1e6b1c6bfa7d0cc09196d389393b4bf87fcd98153a598c5c7e2b1e5fc097a63ec05b354ec033b93c00e42fbcf6f2a4595237b026acc466d8869314000b19d148d36503e81480a414213ce00794072a201bec9d7fec59959e45a17464fa4078f43109538b5ba41b26c3d29fdda79abe3f20fd42c6e73a63fa5317cfd903b6a4780d442de65adf753e08c3febe8cd5e6fe98608f3974c7e7e249ba929099e5493ef8c7244e4c524dfa0414d5b7148cc6bef0d6c5d77bad15ee5cedb65e8e4e0ecefe718cc1bee001afdbf105fe54c1e5c05df9cef3612cf1fce25bf1b18c3befc08fa2e599f048358fd926a090f3bd5ec1864f5f07b9c64b31c7291796df30fce93f93307b9bc7331060cd8b95d5535a874b27a3a4f6c4e7a376dd9bd1697d3fbc924f647088e631de6f04777a7981e39b79fb9d25e0ffed6ff2e6e3ee377e117c2ee46f227b309f0c34cb8811210f0f5a313d4774d9f437f0cf09976d2dfd8639a1848c87c549d50589a8b837eb35066b64d517a448017137300cd384cc472deb72a7b84ba6cc7a1e6bb19271232774ae984e9445911a30675c76de31416271f6081676ac9c2a8b4931e6af9811f90a207f835d5cf6d816328a2f78ba686fd3c281346b99bf8d684b1589cd98913c618511853505418b75cc75718b539361f5802fd29f0052a3736bf17290d0b63702e8c69a5c95188fff5c2c81ec1976c4e1f8631f10486716800e75217b4415bb2f92d109a2e8ce7fa98ebd327bb0be3c6f3f69008737c60ec7f8472cae18db0aa2967579a72975f08e0d218c631c71098027caece46e23a21c8877c7cc0e5c909d85bc3715909e0a18f95ddc13292486a0adcc14925a3df876369ae6ae39b6c1e3ed44dc8fa43c367822bfb616fe83fefd3b345314de1d44ce5971cf6270ece5fdebb7bac3ecd3e3dba53c1289d096953305f1dde31d0694a48024644981de328617a02a04ec6f98db2de57cc8f64d320477232d25f1efee163b32268e7f0cdc5934d66d43b82a2090aee9f85cc193b80949a13c9b7fe034910804d068d08e8bc2371bc291019fb93b6fe2757af741076b709315d606f386eda640c8b174d19e2e9abd158d89652baf06999bcc6d7f3f96ddc1a93158e0f3f4d6c9940b12962dd6098915a074fa8e1dacf8fa057f709f0c9b3ebda19861c6cd92c37243d674a25edcaeb8e34660fd19bd10ffe0f2cb2b0ac5f0e549711a81d57d574e8fb8e2e0c3759391bc8af8cb2e1563074bbbf7010f3b0898e880444f06116c6e30c8223bf25a5494aef2ec9c745079dbc8227441e6d702e8ed60ba3d0ac8fa41ca0922a41cdceeb637350dbe72c9da170d46630fccac171f3361dee1e628256aad49019b8640f730797bea02761510d641b63d58db841c45d48743a9e552200fb3cf2fad2e2c1dc661abde067c305f981ab86c5ee3e4b24eea1c6ef0985cdcf3cf41b3f444e730ed806e4f50524507f09e154bdd434a1a7f1d7edc71977b32424ed6cf5cbe53805be7b2b46b5efd2aa168b73551a3b2ae21c2af07f120f487581b8f293db080841850abfd5dd4cfc3883c5f070d2a103b2a19840fea2c15c4e6185e0c50468650d7e1a5213b166341ae396effca26efe5fba0b1591f34ac7acd44ca56850d4317da70a6b27a25db2a7a3d76a4dfa46978e52cecc47fb31f66ba817a817f09c765a2010e74d37f73748777899f8f389d8764c4226a89da1b8836b11a1d4c78ad694349886fa84ea996d2cebb3a94428a233fb8d008b3e4f4d805ee45afb5967c5addeb62e62c505ea8824ac8c8edc4fa9f9d3c89dd85a8c80670a1eea247ed6a2cb51c5ca163db73d948f534a2fce8c32f66660f921885e76519d3a52fcd0b6ce2151af916a4472f5e9f1589f50c7b286496461e81838a2340839f7ef8d5f9a0604d1af26491f37d698df1edc014dbef3a737042ed1402603f543d94bc2ad8a2eca448374585f3df88b60f4d73fa8c4f31828ae0b6848e29f84c8356acd48213e200fbb96ad367540155d2e1f4b9c8146ea790221144b8a8ba9a26d055afaead58f6652f7a049e79f18bbca56407d5542b30c50799bf93267d5a9100ddc8886cda83ef8dae308ba5442091d52e8878f21fb0ad6fb94e612d72b87f5f78b68e6cde38a30549accb836b9031060c5b3e6eaaeffeca1b83e0c9b40e09b9845b91872355afc4e186190b527efdd97217d7c60254be40fcaf9552c96b61edfa0ad4f38f240b3b42293158520066ebbb9886639e3bf33366b026b216adda81d9588f10a00edaf0670bb3a17e8d1493a096fc5f515b63636f3a7f2a4b8de1e39fd49d1db0fc2ac11d3749e709a7ea44d755f3d4f906fb2b370e05c6732f4bbfa7294364e717d86dca5523bda706f8145f641b6ec6f473373431fe1c7ce225888cabb78c705493543eed0d2254b634a7e658084733d699c7d2219f238079172ae4f856601c7116b60ca7a182cfae1a7f908e8201d82e84dd06de91f169ceb6f261dc6dfd77ba0a8ed7fccb9073a7b0ebdefebfa3d5c5f8560fb1a873ae8cfe05825d73f0580bcdae713abcb7a60838e69bcc4b1a7cfb89b3d801827a16a93609cd18a3c0de2580d0648a91e346d1699a4d8ec818109fb52f55b86fda0a1592bd0ab062fe8ea85ce74ef41ee7ad340c066600f4a0f218ac2f121113aec24ee290692339097d213e7e4936255385d4843572aeabf61e11aca570533f7e36f721e5071c958db5a2c551fe84fd463df254cb79c5830a5dff681e951d8fe873f0487e82f06a67be6f68ba729b23f70ef4b14986e3262a7ff7fb7196a0746a98636be579146d11db6b241b0f7971384e3f698939d022919f29a9370fc41a86d698db8c3484f61717b864bca0ed6b73fd1370e949365d4c819561fce665c30c8ba2bba76b7f653c344aeebcd5dfcadeceaa27b237a631538f6333baff4ea6e8dc74a0212dc616516da207b3893709f2be75371b4903219aa62bc0547fc772f70b6e6a63f0e321a722556acd33b1b195f98abb93e53cfc6dc0df573da09bcd5370d5f78916d16c709789c266ba85bb9cbe288840dc6bfe5bc85c7682871b63f587d844a53ec048251ef03c37dd22a80456ee35a85753917070770cebbb33bd211831264ddb79383a5c1ae030c1d6f9fc96436e04a8a588f5edd9f4673bf00a8c5e4425a2bd387c9a360a4cd890a4ac48374717851ccd7a449e8eff4b2601598659bb504c8824f6f620996b7b7b996144a7eda7b5e94a834cd402cde2c3ccf0e1ecef036d524ec0b3445ac7b38a2e6ed2eceb2c1a76340ca13604d3c11e147edd8be376504f60f45ea67aba02167c3ab5ee6eb4dd24482e1216769178fe8f0aabdc4ee8f2031ed8d57c49d32b6d758ce79b95ec54bda58a4f5a04a40ce5734d3c007637bcf308f8b564e91c632803679cbb1d04d562029921015673c298541823ceffd43a1ecff815a87161791aed2477bee8c1a8db7287f311a8aaaba8c04e3417a4656d38b950c19a44a2ed76c8dcbb05bc3e0cd8e4a940481b5251ab0f11c7e1923abde8de0a77b4cb4bf0bec12a7c755355047b453004a09546cd8657009a7b036b3e9f0036516083bdb566a6e797f646734f456b26e55c852c97f3dbf3c501effd66f468792c7282f81b257cc5846e06074cd616d1513af692d2b0ae554fdee505f270e72ec0fe846ff10bdc388a0ac1078021a55371ff54f2ce5e3d72b756984005fbffd905d884641508052acd19a80086495ed7a8a1dde0abe651ad4f2325da77ba0e98e8901dec96602c29917e16a496782f9526bfab7084514bd974682a1e57fd75404f11d18f49fd85d028b83808276237ad8b3c79fd6e774c5fb37abb0dc2d8e137c52f5f14631c8e45276783d20a36ccfd1b111b76cfd30d597972a87db12d6286b0d81b938056e49bbe116f2fd8670365d94000ff3df150cd07c875e541e7dde64a20c43b982d3823f10ccf6b4dcd770669003401a8633dbdf0b5ecd5f5231502ce7282992571968b6f094754cc4c618841b553c1dd7490907ff4a2f89029970b4896171a405b97a836c7261b8a9aa647c2f22c37e31460d6cf7a16134686b9963a49f2fd7f418b514934338fcfae10673afda936d47b91b18faa4e88dc67e530aec02c2e0ef32391be8e6868f116856ac1286ebe7742d288209a8626e3c88e86635624438f62f9c8960b788c2a6d41e36b78ee526d9921b18b91850029470472bc9833b103e0fea45ef6d5350229549245c915666c7e27ea2b0580f966fba4d067c12944e12c0c1a2cef7e8783b63780cb831884a581e96966e390d825ae7f4985cfc6103998c3cfd6c31a64a73dea0a51fc87f1f89f3ed5b8a2e85432a1db0a15602afd40e9bc6bd1104b464eb8e7ad6e30ac8022bf0bc8654f4aa8bf407268010ff0ba28d02246770310c9ad6f238d08d29eda1af9e8df31946a0dfae04912206034a7c6b82b6eb8630431215d19e463cec57956843ee8023f6d33734060ce778fd304d84131f3996c7cc2d1ec8a2179e8366aafb0e4f3fc9c075bd24d5580f83b22fe0d5570204157ab6dbb53134f786ee20054425401258e0341c7d6e4ad96963116afa204c4d65deb8bae8ae19c907a989d5f780b64b3325bc24b1b48bda58053442accc479e1f19ca938c010d958c112ce629030f797b6fe79bd1a14d7962cfd164fc2dd83cf9289c0eaa2c802b1e3065c70e4b2b3e853f9dae2d6d4c8ce3da180e26d9255ecedaef2a94a1b9e699fe3150c0fedb4fac0310334e13b39d54aa21fdb198b598dceb660e1634584fc32c4e04672d4ef832358c12e6a0cec7a02c25896d450320b5a292e8cf4f93d8ac6874dbfdce01067e9f0f99f3c1600d5b8f078e47ec96eeeac24e1d5c9ec9e996284213d28e4cb5f23ba6c19068ca2bac95f358a93cbcc6b4570d1482aa1a3f6c040168c7e991165fad21f726ae5865dd2611a03d453c3e71462053162b46589011f1ca531cad81fe5b9bfb96c7b163fce4a153712f4d53659d5dbdf77d396c8fd35458296887dd85d29cdd450999f28ac54e3348adc0c1c1c7040355a1dfdaedad055df36f6efc6cdc594eba382c38911c24428fe659bca54609b3e4a21c2cada6a8f57fcb2c27448076a341e564f5e42b647739fdad6f1b114d0dfbcc1deeb7ee10ab17a1070070e1949792550823bb1c39aca71ce5f469d0e9c97f9818fb935ecf610eeb4d81b8a16e4edbb5370ab98573caf95007848599b7e62c8c2b463fe6bf4f6f64ee438bef454c42b0dc59218cdb0e470c6106dc34aa09c9dece10b072c0a1444cc7ff548ab25f07a58d1cfbe2de246c8be152f8dee6912811e633bd3ad901e96de13e9ea5e9429fbfbc65e259f56d0b6284775b7e000d184928e6a0c225bcf17062b4fbfb827dff6f2b49d27f6ec2e6356c9691d4b7b8b9e059b251c555a18f8bb1317ff37e46a11d2d3bd1d21dee133f08d5919ee9dbb1337df0b9821a41c57888449e55512fc27532971fc3d93f677120920fd7850d72a30f4e8e894141f70b85ef37a70c6b2bf2006829c3945a50cace5c7c4cbfaeebac3fbf8637403c9d79f26b50049ea14ededfd014105e1512338763b37fd7b1189af0983f7bbba86ba02f84043c617479ea0b4404b4804c6948763995f34ec44b14680303339ccdc0e2f09e3cdddb8cb9027d1861fc7ccc1164f60f2286022a7c097f87a57c0786b7722699d45012f87973d6c59bf1851ec474b8114c12d3a5e380144c69560948bc4087668f96ab37e207cbe2bc5b05ae3544b60c56309a114d73ad81e387b95aa46d91ae85dc2a72b5e883e50de0cfe45f49f30e735ba4cbbbda8520dd22add6126cc2c10008476f3618993152e269fc3cfcef4c2ff90b1d7e3712c40f9a219ae1d3b7dd4837111121213bb80cd70c750cd5aad5d67ad58ad5eaa9f553ebadf5e9cc1d197c91b4400527e4b719203f1f8a7077605cfae26834f1c6205d242082d04c009021849d71c539dc3e8d2bce414676b701b82016b7e3102f26954a8d2087bb7d97916b458669b8b306e52897311a7d84879420303ae9240c45a97115a58f4efae82e470a768db767935f297b374d04bc0c2419364d13014fca646459c98897cab151a4128f549e3a10496bf0a40ce2a0e1f69b86a6697e6d0477a3ee0694ddede97a605cd4e51c0ae5ee41c1a15030e95a6184b990e16dcb25e57043d9bda66abd9744fa69342987bb5d1a689272b8f30c717b47f2438d5e038f3412335c97b7fa2e2afc2cc3dd5e14930c37e25101e20e882241486a79b314c0c635c780f21b1125bba36823c7ccb9dbcd4564e7fafd25e954119a35c0f5c0b85ff81ff67200da27d9dd1ae012c38dd7f1a33e1a1b4d035153075e1d9abd2c1c0d27381af03de199e0e1db4212686baab5d9f8d9b46682bbc1192e9aa66b208a3465423065a009de4adda264b1afa341ea36c510c8f4e18d1b984ba3e05637a8a8a93e3544f9288bb7ae1fec08659c92ceaca65c7063578d3d984bdfbe976d1ec8b4489fde6b140fabaffeef9166eff6e3eb7e74b9a6a2c05c1e7cefec3d6bfaa2a8465a834562e32a83edc311774d4d39982fecc4cb5bd3542a32bc956d7d93b55c8b445163fad4f8c565298ed429fa1431d5a2fb547a98de509cd6a8e853bce6831767450a5e9b0c1bd32d5a9b60b85bfd466f52a9578057532fd2489f127ddae0cc0e0afc788db72b37e4a2513545d326788abbc8908b989a4af5c97de1c6d374cd0c02302f5cfaaa0cbf03d29b3ec53ee11c00013872bc72244001f472c18e88f4a64f95c571a5525a9e3637be2bac69fad4a71c09985db81bbdc925980fd247b86b20044647c14d034df037ce46eb34aa71b668546341a3e04e2d042a12c5789b06c9a5df9ecdb3b99161d8d1a7eaf047340ae510a651cf0627e5dd7891b7c6c2a6ad6813bca7c24dc385bbd5148d8e177d8a879f3bce463dbccd515509a82a0554954b55e9a8aa97aada51553caaaa5f43f8b6f652475c2ed7a720b223ddcd1a8822e1890333a5954d15b566558c6e755c71ea8c30bd993af02e980e2d47f81e8ebe81798f56317acdbae6e68171373813b3ae81a7377001d703e3368da3b1856bbda6fa646558f509d2bf6cce64938a31dcf8cedb94c9b0ca7eb406bb704872c43a54f4a90f3f67fa44825a53ce1482779d20c363345ab8fd7ed0077d6a1ce14c9fb648391b2619be1a7136709c8d2b439abbd52daa18636fcf66eb5397639096928e2ac76ff7b666e120aded80aff5de9bcc75fff5b3701528c7d10fa5fb71f19040140993a0a947f8ea2e7ed74fc7f5ee8c510691edbb284e8637a64caf657a0351a3c311de017f93a149cb1457317a95754d6bf03b62b2158d1ae16ae44886afb5699a06529a9acac2ede7849595eab75bf1cc35d5a7edd15759956b14a317690df608bb36d1b4065f5eb0772cdcd149ef971ed651e59a6a2da33cd61444b5d818c9f028d9775c414689c735b5b838b779c0e27b6815bb806b5ae16e4de37634167da2c9f0b30a77bb3e60466c3d5a833bacfb018820341300849841630816010c80003588f07c4ea80b6a29808d1b4518a0e40008c09173f820ea9e2204d6ad4839dc777b354a05755d2291cc354ba668c6199ad5bc81a6fe1c8271c0394be827fcdce20ebdeb19f9b3923f1f51fe5cf9f3d8a817f3c15b9096f885c49098f39f472fe6fc7cce396956f22b93f1db2719787b59c6dda38e17ef86cb25ff22961c622e25d85d29039f4e6bf4c28f07bcdd10de2e8974ad046f5ac5022b7e1177de176f084ab3abb5896f6bce915030cca2693f8974af7d3110d55a4d4cea62d1b47ad79fcfe7332fd0ccb0ab6bee5934ed2791eeed5b53ebbd24d2af692c2c9fdb4ff6ab5c04f8d91b2b25f1ab1ce61806636883a111687a0fbeb117d9f142ec25425923f602f3277b71f9f389ed70f9834148b8319f7cf4b99d9f978bc785614defdc7befc548bdd33b188ba6fd24d29c1347292c68410b5adb376d63c1eebdf7de7b8b7d3e9f579f873e8f9f8b3e2ff95c28b8a479bcb168da2fc21b895482b77b5da320e876662e07a2ba06cb0c6de529a4edc629a21455c6507051be4529a0a7ba1b2f404ec41408b4e3881e303e28a0c4120fc284902786bc549f8a3c232f0a1d1877328ebe59765d4e0442a9fcdda964ae4d3b159a2cbea5947e3e747bf60dc9f433c3d7bcae3bec839b80d771f43c85a71fbc3d2b72490986787b1343c2e60fa6f49fcf6d2acc857e32fa8d08a5d4e68a7d0a61f757f2ae7937dc097410e86d237b679e4671817c2ef356af87cd16f5e9833722f9f339c45bdb6412914b622e1f7c612ed389200d86a0acc4e6bee2ba260e78f1b099629b655da463e8c5a94eb5f6f9c722dd5b55b09a5d95cce56807748e9a999c66f72ad9cbf1c9aa6ce59565d0076d82355deb0ec9c8dde0cc3d8ebebfbd63c199d6e807439d2a3b8c629833d370067b152a9fe9d37d1ffaa06623ddcf075e17ec9d0ea3512aefc35476eb966657c9b263a853e59b557986e17aae52f2904ad639ac6c47946d6e8b2b57bde344ec1c4d5d9ed7f18b53409fe6f57e8f3eddf7617c50e087127dfae01797e9833021a44f257a973f6ff758f2bee2dd70b9a4e4820e7faa777db2d067063ac2918ab72720c6a3e67b5b3320f5f79e83b2b6a94dd02cba775813345fcce51e34b7ce1e503641bf5906319709ba28abf75422f9613c42af984b952dbc4aaceb945a4a7f5dd7e6814c274669fc1c477f329729fdcc2668fe7ce07760931f6627e6627d1ecb3ea77805f7fefa7f2239308a4b49a8fc8751f9f1901fd00fc1288651f97f3c44053b682a39911c25635cd7da75d7da75775f1d8d0b661407bcf3f5f3eb169479e6bcc733b3ed1e8beef188b227741028f401fdf39981fe7101e15741d9fce7cd5967d69ffa5beb07622e1f5c9a5756926d4262befeb995599a599fcf2deb936df71920923f9f97dcb28e037e3297417758096e826610c8650b3bbd7518127dc51b82fefa27a3bfb2ae79437c7e33cc857e0ecaee71c0fbf995f5156f88cf5ffe64d8ede7739a6d44b07f32d804cd18bcc3aecbf2e08a65b1ba4c6b6dcd6d1546191e7ac715208e06b1e06ef5b5926c5dc18d7fef514404f3d545400f5150fc401e8af90a0afafaf9ea30f315c630f4b5b5abb569871b67e6a20dece802bb0989b9ba736d9337219fceb66b13626b7d94f69c50ca18a3847076679851135ccbda8d48f3a8d5e251abec38605ff18670efccd1881f8803eb561c4441a0b1c3fdb083a6837e70413fb8efefc814b00a3139e01f54831468327c8d77e365f897ba06df4ef793020868dc1a5df76828058dec7e5d1ff1f5b28fd6e3f5f8aff4c9f388b7205af691c1cce1c2f7b85a7bb7078c3183690dbbb21412c9fa655dd65db6b7ac655978e5f596551fc6a39e25573ca3064bee01e363620c683962461421b1165a639c516bbd3d7498b28f165443581f007c700f9c1e1fb896ce1877aa2c5c45dec91e78c80c553a3a944cca231ef5249b649a5167fa3431311ed54e50b6d515b3fbc9f6f260d962d673c5cc66fbb1a08b56d982ae98559a6de8125d3193d99ad8936b6449b6441a9dc890e189783a1af2740319fe1121399061944153b2c38d53b54fa5ec5424ec173d9777b079f79dc5d938f79c0d5a81f8567ff8765780f86105838026095708b20c7706a2609a02334a906f060bbcf968c1a554d0c899383343ffa878d84b9117183a95f066b060915a7416f11569f75e3784314a39e77b10bea745163f5ad2899f162e278b1fadf5b75724f72f983ec1bffcfca0a0cd2041d48f2cde7bf2bd13b13d5ac35e36a3b5928ecef03d5aebb3b436b395d540133c7439bdc48f37031f4d9f5c6cd3fbcc2ea91f147eb00469712898e9d7394afc68f09b09c3ddae99875fdc8c3e955afb2bc1bb1c37a7c5d6e2b2b85a7b9705d6ad6cd2bddfe7ab90539672bc6c4e29a190b31e474f599f8340bd3b04e81f86e29dde61287e00f3301472c8901fc0dcdde69d48bd3b4c3dfdc343a07097a71ff23e4b49bccfc3bccf430ce3ac57511d4b2d68bd5566d1b4595aae61f3227097ddf2ddd7e1edf6dbde66280212203861065708034e121207b68582752bdbd3f2d4e23e01517f92c31aefa6fafcac7020aa043331fb9c88b5043f1df57ce221f39e0fa1dba3b9ecaf2783fd732239de6b36a44df272b85b7ca2b529bc2313431376fb7ea24dfd232e49147773362eba24126f222676408c3140c8cb3d456b0f7450e6a6146ec445f2fb4b2db123473d2d490ff6dc3a043cb730143f80a1b70e45858075cf3d180a7a6b7b331075e1174fb33ba3703fb804e339760f7e3225085028725cb864e17704972050a1a8b69b7d6010a8f0bbc1af069a9e96a94d5f4462d79b543e22d3d87cc988797997e79c15acde73ced5372715eec3adcd672f2eb5c62086945a96990c223b8c01162432c9f042862279e21732141103c2bf8c410c2cdb75dd46f54aa40f8b9799b3f05ae9536fafddef464c65f71f105561cd4ac11b025ecb7931be18bb31978eb0eda519bc1422c33f0153f06e98dc100e0a193e4204688e063c14c27d11635c744c3472b79b5fe644cc103f232ea8d9485731f27bc3774c763e10e968440567a69452da34c6dcedd2984529b2238cfda28bd473b5260f330bab0a84523993ac928ee0c6bf1888aad1267929bfa34ff0f247f4e813762951a1cbbb46795e2bcbdef5014a7e1dcb7ab426b18fad25cb97d240166f35b42cddce47520cd39a027664473c992703614d6bf259d19a948f264b29ff68a07c32506612a99ae6d879b7b25de7d2bb5b7a89865bdd3afdcb568ace70a5bdb45824cd70fb916635bb158981fc65d1ed629dfda02cde81b2b00d490ed77d4ba9a4d59995a1e4a83297e3077ddb304a1747637a91648adc7f59e4c6423abb381af1b65696b5b087ed855d2f8b5ae4788ff37814e068c45b78c9ec89d6e26136a4b5f897bdd42bd2a648c4132fd52897036f2f8a1ce397d811ab6fb67e2e8a2d60e28844b89dab5bcf4ebf91b66f8742b8f9af5d17727458c8f11be8e1cd4921c7ea9af0611c26b8f00a105d39be311cadc517259e586beded70365e8e9738645b26ccdb2b0516177493e741371005fa3c0807a2ee67fcfc49cad90022cf8374403b20377c03e56448f27c8624cbc9c600448cb3a1d9e9e87349a612ae753b2d4c42bd2016b707979ebe7236ae53f72de526889c7203516f1bd5e47997fd904735a31434cd1324a93c9970820455a11049aa0cc3c420207f3f3108c483b01049b219a9265011dc272f4e6b37d322f7d25c993be36c609fbf3b7036ae5f996b6392a24d738a3c31cfe7824a42a20b6271e101903d9f0b2a09894c64a43547fad403c8a88bd3a67924794e615d5049486691c9891d59dbd9cbdda09290c8e46424005055955455a8aa4455655255275535aa2a5255391b9de7851063460aa23ac7bc42c0194766c8c42adcd8831b841121649c8d15f80d089d26ac57a7770a67a33f7f6920459faa237db22e166c90e72129a5b5d9367545b7a5f5ed864c2acf94358be4f99e466609e6092c9a3c8f93e7dbf3ead5d1e8df2eb81ba3d4c5e953f5f9bb459f3c9fbf489c8dcf08045fc8f3da0ccf3faf3e37646ec8c00a2300c7f34fe5f98c522310781c06c6b4f03653797eb3afbe869e534c9e3fc5d8b871367cc8f3a723a7294e32168416c20b420c420f841f082f84200841338af4c97a006ec8dc901122491ba1d6e76926841833e2cedd6ec8d010dc4d882442247937fa03f0fdbcb1d0e4792ba2d484d2134a4794922845a15406a5254a6fece0c6fc0d2a6ecc381bf5460f201677dece7081bb7171de10136e33609067c454df664891e7ad89659d8c4828324a29b10757882410f53e3f238a3e55799e85c6d930e5f919a91945f2dc6618c9f3b607082184104208218410c2db0b8b5fb8b48937464b11fdad4526c993a5466b538824f32c33ce06fc3ccb8c42c89b1049f284f853e368cc4b2edcfe668d24c9f34fb436c5c893c6c5d9de07f2fc7c21c0429ef32e499eb7b21eadcd5be7863cdd2dcca57a2f337215f74c381a73c2f99984fb6ee1239c8d7af7e93075363242bc1b74665ade919f7d73ced0a4b3f1b2a351f17535c38c03be7b6310f9a648e9201cac5be908a5a4db7ca4b4be2529f7cc2266094360e32b44fd94f6e9fb7cf5a694b6830e5e3b72cf286ecb8f07218410bed3574fb3cd7591e1bb16e98b39b06e25ce084927554aecde1032d64354c52df1db3d6ca19904b216889ac033c157fc0434c13b356478d9e2c8d0926177b1234b87d303e230d13b4e046991d8ed30d1a78d32e0dd21c743278690d67a389c98794407429d1b676bacb534dadbf7660d8d13a7c20d85eb24c8610c859c9ddc99d6dd4db3eac61de1b68033d0044fe96d3593a18ddb810d6d621019da4094cc81d094a3dc49c5c0d6e9c2cab68763590f8985e52bf7902dbce855b32aebec784129924823a55b58d4aa95352deae9c7ec93ef5582e9d06a756362a41ceec4a9d9f4a2b518889a61b41847328c78ea98e0eab4cdf03b6a6ae64e9fb63877a61771eac497d31aec223f9d984a754ce1b4091ee7bdd82f763f3cb7c099485a83b15fecc9451719e2c01a3a033f135377da049f8426c3faea358ad66caacba288229a6646d3344d8d993ab5476bf0881d64b8a908a7a0538c4828324a293cf470e368bc2c649519c9b9dbcb790e47b709bedfd402fba03538ad9854b436655a8373e68b6be1ed699161f6bc680de2c0189bde504a290ee4420c880371bc8856ccccc8991863a4f469d19df1508be4a6dfb6eaf547f4c89e14d4486b533ceab678a9723f6ad131e2381ba236b5bda41caa6f27d979b2fb7ca8989235b0c2355aeec6ee0d115310356562aa5aa235f8de0e7c2fa731ccec9a3975a009fedbadc1ee0d512f31c5c9a816e8161e3d4386af988621c363f4864e3193e90c9ca154f469a3d52ba582cad029326c9cda5b64f88a4e416528153426f6690cbde1a2b55aef2591b47efdfabdb98384b578d770c5f49a10478271e9cd9cb79dd51ca32742292192e8e4bb068b0c5b8b0cb3c850a77bc7d9d0a962741cddefe160199e8a6a35a9f5a4d651ada45a516a95516ba9d62933671c0d0f0809f57c0b32916c8193e173cf9a36c1766ed674eaba9acfafabc41ec3444cb4060f825b4f3f706b9f60f604c32c7e5998e01286ab40b9cb225c05e95e9f7bd55c1f5cc5e85bc5a50b3f2d4a70163490e2add2373f33197839140aee01c540826818c2dda64ef6023c01204729a4e002670b2436368d13a74f554e5d976dbb606fcc5a6bdb767757d7e301793c251e4fc8e311793c261ecf89c733f2784e7175341ab78be7383aee78ac472bbe6671bb196914ade8d149f188b6a235d834eee6883ec5a658ad9e5a3fb5de5a41b596d41aaa55542b66d1968da714ae3ce63293381a207ab3a34d508adcbda3073dc8c57a75b55f8bd4285abbc3257df4ada650285646568db8d4d4d634f48676e5a1aa7aa82a95aa7a55655585abca87aa5aa9aa87456b5957118baf2aac8a6dbb26c61324ae6f14878bd6e0c5b85bad2a920c946c94aad67d58f901087905a1d1cb646d415a46988bf5048eaeb6d6b6eeb07a7a2beb5b1b4fdf593ccda2176f887eedd3181f16fb04de1c9dc390a8b5091a33faceea4c8e58d5322b55ec0403ae6f14e3de5a72fc9c515c23328e5267aa0f2a4de35212a48f0e2303a3603cc2f5b687cf47e5f3f9e7937d3ef8f3f1e1f359f97c7ef87cac6b46716bada363f8d73077e332eb70371713c5113d6aa5244a83d04c001062060d7a05c0daca7361db169e52b817de340d6ff171d382b47cb6a9535310456fda047f3b36ece8b966f67274b966184ec4981b633aaedcb88ad16ffae432cae5a05c60ad4d36369309d7f3b93a0a24457290c43b00d13110e5fa08ca5f7cbcc3dd3a26bfbb9dfc3ec24472c4a7034def949e94c9f82843690c8674197808e98dc18c8e828738c0e5a8a935dcad833c994c9ba64f40e85d17dd97d38973b8f1a12b5ec69d74b8f414dfab42948326d925818aeca0808419026407052cc2c8222987fb8eb8327ccc4498cb8b27f98171dfd3f1322dcf39dc88abc9c9d4b97d10126e7cbfc017371abd46820b2427860c2969f4acee48c15cde16ee56539e0c61f7e9d9b4c49a280467824721bdffc6b10eb7668724472b1c4ac6e1a30c44c9c0b5487f8b34c98da771ba6a6aca81661bc98a6cbb15095584f4113cc70fe49d353aa5a4ec65d144c0cbecdd3c2d5a831f650fe7a6b5a669ad6b2ac58931c657b75546b588c3a5bf81c3a55ace5585ab1dadc11eadc50c877b82af4f5b1052ae8f5a86af291c2423120973b12e0634f1c6c81ab8f9ded3041c638c7cffb9fdf578ecf3d8fbf166a287b98cf212f72f0b42aaa95a248c9b916a766529d92f2ba374c1f4e8530032bccdc9f0d6c2d85a8cb1facb355614bb110945462985871efae41e18b47ac37d61dc3e02d24787451c4d3348736de9c20141f790af8c650bb18c12b67c927ada8a4f8ef04f82e0de2087fde1bad9d1ade51d60dcad69faa64f10a74d59f4e9354dd3b4156eb87d11855bcc9d5bd2516df486a6b4e16e518b0c3fbfb81b29a31eb7703628c4e9148be5e1728d8295ad2941bc229dd54c77a61777aba98a7665d90bf37caef593b4ec85793e145b80176164f8476fe80e0d03558bd4b86a6a65255b6cb8ef9d1f9e3171b4fcb270273a05a72dc19d9c8d790951a47b91e14ed7dc4013fca985e0b429b8535be1349c0cb3a6b1d5ca0f4004a19900d0485a839d93e11f17b4ad0fef5af901882034003c5a757ba1e385831d064dd3d0d0d45a7dab51d4caaaaa5bb577a4f0d612458610deddb05815a534f6a0820409173930ca496b65a97441a39cb45696bd5ccd289884311d5aae07c30bc8d2a8166882ce4635bd684d83df5ae68ea371332ad2a6038c8edd429146df2e12ae45b69aca980e2db586bb4d9d9b46e18026f8e8e375585872fd8547d5076d82c73535f176893712caab22f256534d53430676d084e1ada2dc7b5367d420c170210edc022271365e550355c7879ee0be9cabfb89bcd725f8411897fee389f7c83b2725de9ec761d88bfb9439ceb7cd85b9488ab9447c97590e3f3ae7b4709ebb6c7bd955d57549815c8f57bc1bd791a8f883b7ced7db86bee22be4e52b0ce472f4e5abc2a57a87371ef2eea7aeaadc85bddc3b2b9d8cf45e47ad88b7971d1257cde4bc9cbbc45bccb69b610f7922662df226abd30dc6ead2f3ad6dbab190ceee97eed5e3b720578c1f8c4775179dcb62be32f772254fb117770bc37f407f59c93b0be180d9c518ab5f558cb8544f0fe3e16906aaa141ae7c3d94957840596c1386e32f7a2015be0e3124ae783728de32606da4ccb56e1bc8f28a77c339bcc1c37ae5ea9501f115de1ebc8c348bf0d7f6b0c8f2cf0af92aff22f4b4c806d6597775663fb66f9fc54dbc312e21b956b6b295ad6c652b5bd9cac2aa8295adb07334a0555541ae4c1f16f092487d300948f295e5e587209389c80e0a42d0b9c936dfdb4bfe92ef9665599685dff36048d86c610c7b31797c7cee3d58dd872c74cbe4389b5f02a2582e8374f2ce547828a18c6ea3f54e29a5308b5ed4a9928a30907a8a84fd17ef86e8d2f2e116de3ad3fb80b7b64e2c9225c3b244d9b22c0b8bea69bdbc111497440fe3e88704a29e0ce807208238a6fd637a0903de1f8684f5f92e6906aab9423a3ff97761485cd9ba9c2fb9096f2c1adeb42080c01be98795f7aac25ee48158bcdd929665fd631dbbd63d16de82b48024de3250555246ce2cda3690df7bb1f016b37533cc3d44be471d99c5c85bf56865ef555b252b06f2a875d727fc2deee46abebaa5b23ac540de4d2ead2335666429618a28366a09686a1f6e7293bff72eb25eb117931f07f4210b1d67a29b6c2cd9334f15003079d61219deeaf15655f0767b703a2958070563961c3a0b443d19e819b16867b920cfb16f2d19c35b90168c01f61e102e6117dd3a8e7e329045d36e82b793ee076f1789e7d64519a8e60669c9b72494b9d6ee8194e0cffd43026a23333ab5920484b7202d176f1920923dff5c979519f36433631bc8f6165e3548335ca7647bddbaa8adb5d65a6c81d85fb7be0569c9d088eb106fcf1e623c64b6f76431633cacf52a8c3c07006e5f8d192ba8fbf2bb4847cedb27abaf953d2e5aeb0320737dfbaaad892029e581f1403117b6d63f62b7b8933f9d7d6efbf0bec44c6f3b5689b958a04bd006caf7f0137be94c4d5e7211881efac44ad8c192c388b083a153cca5baadf5f4826e41354710cd11347304c91c413982608ea0ce11f42e0f8f0479f0c55bdf7d66d7b1e3e84fe6390e983b484bbe70fce20de18e03da4c87ccf456569de29b3d10897c5a7251c978ae57559605e19c734e6ab11fa87c610f0abc2217235e87f9dc88c0f8682ddebed7a3b5e8701525c7d13283692dbe0744b5b416e39d70b79be39c524a29dd673627848f72de77258669cd4713117ba4211eaee16e0ee73ee6abd7f64ec81c048b0c5f044b8d1667c3fa3797458e2d59cec88f059372fe5ef29efec75379aa27b34dd24899a40e1f99035126b80734d5247daa625aab833b552d70b64715d382be197cb5a48519f192b08424f494398f54775a8ba7fa06a7c5f77015035126b826a93b7daa8cd437b8537502a7c53b99034399448333c59764b20dce145f93405415034d46fa2473aa13b8932c83d3e2b3996519dc090d4eaec19ddeafcf5565ae6220eaf159d481318359e6649d654e9f9cd35aa2c1b5e1e69d3e8073446ca0fc0ce01c013693fc9c13c036b2937ade75339a435949f66c8f781ff7a05beb791ecb85f1f4c8ddb48bb7f9968732eb29c3c8f158b6c938e4f889b938ecee652f9bd5fc9267b15545c961664b321f584956c35345c959723c39b124aba46853fca78a692dca9c9c3e75d1a81a1f9620dc77698f3e75ce307da27df802caaeeb6b186536b3ad66f8b0ece2c2f72b198c021a57725950a2c77ae39fb0f0c692f156abe8de108954f25f4d8b7f18a26676d72c4b5ef5f5bacec6f558ab731065dd7ee42532c18e38f178ec5579ac554ae2fe73988b612a9e52b8146ff07d411adb15cec7ad5421672671ca15350ade5743d36634aa25bf4ffdde7b0f4268c4c2183bdacff5dc9bd15cacd7e7b1da7879b2ea9fcc7a67b79745ddfa84b5d5f53c59f587bd58fbee757b5d5736bb5a4aa795372b02fa089ee3ca78f97a177b633c0490edcbb4dad35fafac0521e1d6c71aafe8c40960fe6623278089f146ca13c3e7e9480512e9d51863bd5464a1924aa5522b301245ee87a8d0c2bc411572bf442e410c35c8a452a928faa05a022fc4a452291534a10458c8fd4bbb90a9542a95021e6e90fb9fab0957104326954a493193fb1e8b0a30622a954ab1c08adcc7ac8d19527027954a99404ba58c2421f7afaa0963702127954ac5a06f6991dca9542a05032ce4be1597c084243ba954ea045dc8fd8a32610663c849a552290043ee57d00c1a27954ac5c0045de43eb5ac689b542ab5021e700087dc9f253ca049a5523248a568808331725f56273c99542aa5829b4ad16005b91fb12d5852a9540a9e4ac520f761e5841c90e1a9542a264507b9df13425236bfc5fc3eb9b3a889e2a652291b5499542a08b9fffad7dfc45b105296f8c2558aebf216f35b4217d2902176021549c89dfb57a3ae1c3ce4be23e55219acb31f68e3b926025fd358b702bbe5cb14e0e268e878a67e6fa10a41480c318e1140d33382a406ec13121f3e7c40d4ff17238930e73c8e76dd6e4ef7f972205135d62bfeda82389cec9c801d82985759c7e670328f943e5a839f5be8821bb1c89fc79a98d5fc9a7aa193136bdeaf379c9fc3233aeff630cacffbc67a94518c243bd5e584cf07f9f337f3a99fd005f7ddd2eb659fe8f9dc479f3cffe47c3ef7602e9f073d7f55bc8f3ec5c3e7f9edca30e7ca361863b3b99c27e37072496219a3123fde639638eb8c3d4f19ec7befbd53e06590e612e97784752bd639e79c732f427839d807c61559a9e5779db6ab5748a43e4594b692e15d646924f4e5aeb5147151ca0cd45fe674cc70369325c34ba2e16e9121cc19bee3080c13a5196e86f112d25c9703076ba391ebee9c0b8075ced5d862bec38a6421bdd21db0a24ca2279243fe425429d2c3ccd3fa49aa3ef1a59fd8c1d84f8b2b34412b632249be41585a20aac2159a7ae69a334f6f9bdee9c4576c680354ec3e6d6c5fccfbb559ea51a47419484aa2fb181de53e483f398e761005c50f6064fce4509470e91ee5a3a35ccac0a58b4b229c04ca478741191de6a49f60f9ba684d4322e5c991bc981713633cb5dee49b8659328805f738fae4a2c7330151a4bb0d42d4688a66b4d34a3297861c6fe2b40cbf5dd569b6059183353ae9938ffea620f5898a8e4112f31e176d8a1f654fe7e4ede4085ac1b59c7871998eee46d9d5a6677aa22abb594b20eae4f1ef0812dd8f89e827596c1304ddcff66ab667b3dd4be49e127dba5a8bf1040cb9459f7c73487294a8d143a1c4a3640fa74df1c60e777b37a8518c8cc947a29f888ec41763926d6f2647a993a44fa2f7e322a78be745187d925894c1279d6000fdd60fba6ac5b8a2c71c67033eca27a58dcfeb7f6e1fe6040ffaedb6169ff2ebd84d2ebac35e4287af725f55c77e491f740fb31a452fa7b5f890a0e06ea1ac8937c66b62b62a6f0fc9951f057e28b144102684f449c2b766ddbacdaaa361899ecbddb0eb68f49c984b95b2d26ad47a91b443423b35872b5f21c9f1148335bed8317aa4ddaedcf2f36e291dc3c31d62841042e8dc6d5102179ff9851b5b4380753959fe5dd67bc857c6b227d36cffb24fb6f5a232b8749333195e5ed24069d3a798655f92b224409627a57c85a54ff69bd3e2a6882c3dd6bd45b449aec87ff02671b2c418bec912b748f92ba2f417a2fa94fe10154f333d4b9f6664fa59d1894929319039575729581a83fb1660fbb6b3242a34b50b0809173eb686bd4418638c2ec5e332917e6f8bbea26b1ecda3696981280721842cd069efbd2f62bc287d485a9e0f1144104104112511646119b1177becd6662e2fd11a542248556bad25a078df3f5911198691df3dd91677b23cc51ebba5c4b21ab9b857dc89f10b969b48d945c9f6ce45fbcaa1a233c15b6b2dde82b4c42fe2176f08e9483db79aa31019da2fde102f7e017a974def64d067b6bdbccd8baebbc51cabf7475ad6abb351724bfe56f852da47ec45de73fb68fa0a294559ca4f3293cc5e2177517a1c10644fb3c8cf26db53cc05f6ad7ddbf4a95dac27bb5a83af5fb8186e9bcae39edc9adcdacbcbca9f64261912365b79ebf95c5049486472516c0156bfbe2971f4a3e92b3e1b96b46563a98cf1cdbbb9852b4f15307f449f9e0d84b1883cab47229c099a628c2d0e553fafcd379ef3de6e7885b5efba7eaff173fd36609bd23ef9680d7e3a144c9b7ab4d6030706b7bf91b47783246577bfe7f22009a266d47a2fc9696d829aa3f182db0f176fcff01f0f76616be1202db9fa3cac82c42fdc6d4c9aeec0967864fbe99c5b2bcd79ab74cebcd52965cc79ab2f11c289bdc0be39d8cbcbcfea29945ccfc53241b8abaaaaaa6a9e22117a2989d14d3e01934fc0411386fde4a2df975821f6021be032911b64ecb24550743b1dec27a54726638798e8a20a6f4462f066efb2f850467234e049766882d7a7a218e80ea266c9c5dbc51b89b43d4f2d4f161613155c8a9261495319cb033ebb4f2909f9781889a3eb86f8d3fdba042d255444a1052dcf6d334abead64b7a5884ceeeede8ca8d6d0bd25249236b38412da4feaeaba10e3be198852a24d7d7a3365e251d127256a7e6fe6cdf4913745a39e0f2cfc6698801ebc550ccfdbf79768d4bdeacd1e7e9685dffbe6662e4f572310618b172b9cdbc31b91211ec84fd40d8afc5e1dcc3103d2c4900ce573423ac7bb6f0f57975aeb2b4495bce20d3ba4d7abdf4a5f5233a517d57ff0f6b0c89f5fd3fd7870adb72fc940998313c3d6e7e1ab0c54732f1ce4cad4ba9d2f1403b13015f2e8df29c6576b4e422cfaf4ccc2466c63c11a4bc22431976d623aaa8b565685e978b17085bd38a75d1573a1df2aebd65ed70bc4746896f562afcb7af216bb2cd6a3880844e0b92ee9625516c8b2cf5a6bede773afca5e16e662257159b72517568239c0f33c1e8fc7e3ba7aac632ff5d62fa6c3e68a2de8baaa25ade7c2309799c4e73674dd8730075cec05f440201008e4ba7a40d88bf57910a6c366eb53e579311d165429a8fec5129269c596900d42f8479f4585ad2ef5bdd7ddf0ba60c478d46a638ca51d2edbbf4c2457df40108369ec85c2482239e073cf04ee8db2fa5645ccdeca96524af95cf5d8e3687b2812d98d48b6d9ca77dd5ef4a5e473cf4500fafddcf30b03aa24f6029a14e3f1dec45e2eada24c29f6f2a957cd1cf0b9e71506f3a9157bf1642fd7ed2d8cc755612f57c55e4c2886c4859da361e92df622cad81b235fd8bdc2c5b097976d3fcc41cb83fd587d63648721d1c41b235fb8c4c31252957858ae14ff02ff4e24c399b95c8af81e8844acb63cb80365facad9b06fcb829625b3bbf5783c1e8fc7632f05bc94f0287909bd644706bde4078e0cc2dbbdbb59fc67abb99aa04e2e2fbc9d64ce99a665e1ade6792b679a176594e2ed479ea30c5720a8a5186cdf76a5744e296384f0b997451d3c221e23b7c05e535768d8e27cade23a4c4681d6ee70edad1a2d8dbadeb3a230181f6d6a3bdcb8d2a68e35ce703717fb3d5bdeb5e66a64cbbeab5af156446b5de37dab9113b7e0a494fd5c4aa32ecc84c50e9ab6194bc05aef2591ae43d24972e1b70ae324e54822496c89ea4ec4d8986b6d52ecc565713787d3a35124688aa89320f652651c66b82e07b9ae8755dc329884c32dcd25fa54025aa24f37330183f4a9bede4baaaee50a6ff54855cdaaa25555abaaaa2aabaa6c555d55b5449f3c79893e6139f6e9ca4bf4c92ed1276b893e5555f5947858997eca583be88e6f48002543b7d63566f1035b8c3537346df113d77889a3a311b1fc551deae5e8deac2ca9702116c15442ccb678921f887780508cdbb4b1944f69ad1f8914e9b3d89a7336664da197a28afb51892f652642c3a3f4a4d652e84568b89be829f46578519f2a95b4adcc4a3cb697333d916c6926a970b74b1fc529ad3d4a29a592ca19011aab75f03df7dcf46c40b23ca4c92bad515ce211337d678ab70a64894bf44432c5b1f432cc14977810c94432916ce50a6e26e10aae8d13bf375ce7198275f6a3f569569665d12a4a29a594524a29a5949ec2bbf6407ef4c1791c4d63061f1ffc7b71a7b5075f77c3075f979e7b58476738bbfec03adbf1ee55767dea39e79c75ce39e7ac2cabf2743f366e7a827fb55610ce6ad609bb6977cda481771812f12e4338e77c7ccc6fede9e8dcb406a1549665e89813f37010ea9827831f17b405b7344f647b53ccec888c89f3e43e4e909c8cdec341e3f48d1ce223ce39e79c73ce39e79c73dedcf8e8d0c90837cecd9c82d3a636a351407c9ee44e7df3c343a1f998272ecd13b1332bf19833ce18b39981087de587cc41d39c1de38018cdff30bfd25398f371cae96294213767541149eb1364b92d45bcb86ca3bdcba05f201488ee45cade144f8accdaecfa28135d5ea3cc479f88ae151eaa09334cbab524d21d3622911e754e3ee7c9e15663b49247779d9247a351fc68343a3c818718122778341acd51761cddf0ba7df4e2baec2f4bcab697499034825f795cc12b3f5c056fbff04622e1edfe04890ff53de0ad62ecdad40310d88a3fdc15ecdac443c9e85836baed86304629e7a4b45629b097974fee4e5cf58c8e89808919688a150bacf845dc895f7c3e336bdf7d312d6ee227c5c921f622f3c99f9d38c002ce648a97d80bcc272f16705a7cdfc069f1f3e4969e2ce168c49fe0967134e2adacb5662cabd93d8c9ee0524af3c3749cd03967ee2aa5cc10d3711263cc515e1684306319ccb2bb3396759e2ef404f7e42f6ff565ecf3b6b614adc59f64a23ee2a34fa2202e25fe761f82c87cc87036e7cc46f7d1a7aaca22bcb5ccc754bc55939450e874e18de5335379df448f8329a59621df372a8f2af7a8dc44e5292a2fa95c86ca51464f8a96aca28374953c7a964156f66429592993d1374ec42cdb40cf3690cae3df913efd24bc0569898f3af18b98fbf27595eb39f0ddd2750c3bc87a50cec3534c9e02613677c05fd35858421fe16d47de460fd2924340427719f2108542a1504802197e93401e85422b18e647281412e1d17d64180a85b61d197edb91472526b7ee01d725cca6e8f0e430032f9f3cd432e5c9433fc97834f1c6c8f2f725c20ae3759269402587be81729f64a5247ef8ca617e087d05c33c79454c87cc4dd8e9aea311ca74bc31b20c1d8a545050e629ca290a8a499096100ed29251b06bcdf36972954b131c854089371e702c4d1203649c74192412892483f412a944ba2c09db97ec656641b6542a1dfede98cf5ffe7c6220a0377f81b0cf750c031dc3b08342a1961dd624e5a4f6604d6490f0490f3c588f490a8a086f1aeccface4a1cfe70f33e2e2f1398637d03f9f6ceb0d043117380abd31aa823b1fc25b8b057a35fa87aae08e461808e8d74118bbca2dc9b61d59e51173290569c91a783c4cf2a57287b9fc0fbbfeec878faa6aa93ee79c53e55685a6e05e1745c1d6b96ac9554624770c44f54d9b6277df748c0a4945a472a2a2a2a2a2a282dd7d3928b85bdfec8471a305ce1648b8c8e942c70b7ca9fcbd23ae2754a24f73e2d8da9b984694bd22d466a5873294770842f8e92094188f98452291e8988be8d01e5688c2f7e132f4397a58dc90f1ed21214b1932f469674866f08fa66b2086a24c056f2fab7c66a5d2ad2d95ec4b6fcca56445a23f119421e3a55b4f1692f764a1632e505e622eb095e8d3e37ff429869660a24f2a9f99fdc45c546edf7da2b5f83c35203390798887c41863ad357bb23a27a5347b324a299d73664f366bad52caecc964555531c6ecc9a2655910c2ecc9a0b5b6bbb3276b17dcd1af0b73191d257bd9333a0c9d02adc987feb0971f8e4624bd7df44902f193bb46addce4ae513f3ce540643173ae4d2b996bd3903e51ec0325ab322465d1d190f721c3997443c8cba059da10c4a2532b876eaf92b97c59d9244bc936523ec14ec46ce5f82786a45e913e89f02644466b6d09eecbd5cb552a6316047aa807363c5c9a5ce52a29efe10212fae8a1cfcf0c1a71f2d1b3ed073402ca900c7d23e5102e893ec25be925e4f28f1c22854821528814228548215288243acae82425f2245df410498412225d449281452878fb91476f8c2cfaa7ba7a90e2c1ce0f28eca08b1c4f81d8857d180fd2a70889d1432f6f8c7c22a52c89b08e37463ec14dbc316a7d94f69c50ca18a38470764bd1514e9e5144596c2d7487bd887e72293ad121fa090f11ae8e46e827b83a1ad91b23e380a14c9e946da2d3949fa47c946da1d0e1b1507612ca4eeeb006bc51b6857e82413537848548ec120349f90906725d0a91212c44e614ec5a53911033a2ba8cada9e07b2ef1d6436ccd620c306180c94b26d9e6815c9a2f954287a3d27ce8d0a4744f693ec4441ee1cd73213097b688372130f38079b887071ce1dff51c9648284b2e69096ec988974dfeb2c92706127ab8c4a3fabc9543a1832c24aa8342075507811e1ae18d481e1d66db7fe4394529708a308a0f1910fe04dbcf6c64627210086fa19b6ca19bdc9a645b43ebb017f893cf6cf49e70fefe2403127a15ddc48a2ec24042afb68985c81cc2a092ec66b97dfbe1c1aaea765a5616fb06662fa74fb1d63bfb860b9b5bbdbc1b12dccd21c91566cf3523927d4054c7547921693ec64c23f6014d2f957ff878a94870bba64f9bdba263fa24a53832850c153dd33ea0b102a6d639e729d02709692e4cf5d017d882a527b8b53a4adf9c2d258c3142283b77de02b155a8848dd594498e324523000000003314402028140c878462c17848a868b2f00d14800d94aa5278509968410e534619460c2802020000000200108020001a78140bee520af5581dee5db21bfcd3d98827048f65abb5465ee9bde899fbb727c931b5cea3f4b94ed903c675ee4bd95c1694096d3380f2e164e8c2d0089d0aba109ca7f810f7211fa5b1a37b53263bff1ac84e5b8f0f9be06d8fe174a1bfc1982a6f23dec9f74089d90082f4a669db3b6657311675e67b48920d600c238aa5613ae18761af7211ed37d717f4a98b28b884ddc1e5bca230ef25908dbee88905dd46f59d70bbe080970e5da68051b8988fd02fcce6cd81ec6e899f095ea51986de4babed7deb63f25b7c04131dad5ba0d9f83a5e33d92bbccf15247c7fec231f98ba3868b686e7c9b4dbf8e0bdaf5cdde63bc4ba1d7e0e5270d861f9f7681b3a8a084cc2f7166e9f3fc294f780543d526eb5b164c0c2d76d7a722e50571a94a045cf50d2491141998b653cdfb8a2ba719994cb852e3770fc3f2fdbdd6941a1db0a0f74c676d4d44ba34266a7ed213f2ebc256266bcad7992d9069463aa84041c6684fa9bbeee9db5f069693f79a331e6654325ef5b53d8ee00aeace8e2b1ec7100945a7b21c2f99929f9c6aa361b133cd7c6b7b821e89bc2e252a24307908a037245d2ab20daeec6496b18cd55f28387504d2cdc437cb4b231c92f34037cfd10d93bf921ef4cb76e5098102706e3632ddd79b7b57a189fa37630c67c5fecbbec6c0f4c9277ed75f6e67ef2b4823c44e4924c77c876944793ff2fcff50b9bfada00fbd5675cc603a64593af5016ec22e09fe7573070d19a2cd3d79403b870800d9327ac109e930a28aefd74bd7e9e78ce5f04ec1ccc0b2794b431dbbf7ae7efd9e4238b5cb563dadc3aa6b2ad8337514a909813ecdbc13b3f8ddd357afd02c706408dfe49b6412fd432ca3a30b211626928302328cc9fe7145a6c5040c014e2cf7ec2dcad00fc3c937555f21c340771af7eef7b82b099cb8293fb8b7b3123414805d95119cea848b4f719689bced6a958c791334f0baa4b00aa1ed980bb8c90a110720ecc4543ba0be450b66ac1fe92bf165fd8526a211f23cd137416101d2b58ce30e819a7dd9f65b58bd407f85c5502355d734e9a38fd53cd4f16a6c51de69356fc9651768791fef69163ed188216949df1a9869f50bd47a159a2c13bb344201bc627d210be03770417eed2a868dbd007a1520c0f8bb6acbdee4d1488b7a1c708a05c7d2280d1e3aa0469d1aa459d55eed6d72d5ef9675257cebf26dcbfab1c9e4be2f41754d9b4564573bec7135ae55b14f6cef8bb33af6b079aa4ff51f6b2089f646933a339d499293570fca3c1c6ceda5853b4511f7c7b1953c7affc9de652daa272715c9311b049be8da008a9217123b116831e31cee525cc408040599d14edba5bef7ab800a4b6ba816e0b8f3ccd2761630270037feeb461d23c4d057048df6f54548c910266e2cd4b931948d24ac8c893f7b1e2595624a19425733bad2c55008d04fef73c8b14617d83c2acc7e2262f05a5e4d554eed701f3ffdbca0341bda217bbb54a7f0bd2003f533f75e4dc4f98f3ed5573e8d06e3d86f8f236fc931f390f5a71f35589b15b3380ed6f2a765f3b9a2c10ddb6155f2ec0cde74f91e05759579f09266b2f8898b913b25053352b720ebccac91e385da16d016d4a35a574766b0b942853e0a534e7ab9e9f0272cf583a13f262093f401bed8f2a25a371ad18b9af47323ace535219e6949f22cd2f61bad79c271a6a6d340ba6220e34022d1a08cbae57bf0463b8624e67ad5babb7fd1d167873b641495715cdb8bccf3f68be32a6dcd44ee72c16a73aed13b700cdc2e78be2fd7df449f9291cc57ff34856d60b368d463b3939270a811165ffba86083eca7da0388e1fe73125634c0be386d32482896c82bfbbb014c00ccda94679de51b7623cda6304c4ecb569a8ee6df00f022bc1e29fd8f5b4a2198978a06e53f700b92d5ee372268c39c039e393e8a72585d11c876357e186b15407865d5121b8714db2338d93a7785cf3c97956a407d413a3b7a8c7c4529c46fe9b166ff2c6db3eef2c2e6484d1a800e3d65500726bb614e203687e49f15269e8bad259e7c68c6efa4549065a37b2ef6d64ee96f95c983ae17fe5c5a374e075056e82d1475300d632212b7659636abb42bea04ef23d5b867ebaefb770430f49016529399bad85beedeceb8533e46c81846ca70b8ad9685268174d7ec4253790f30bc0177f0bea4ca5fd331d9bf9a5397eeccb66f42af8bfd65712ebc86fb89b5b430c81636d4d2093c06f13302aca74f470c81c855f1acb887e81e0c201466b36c56aca436d4540a9cf8f13d904b5d7f9b2942b72ad289f11beb2b82e43ce51d40c7217bd0c00e8f8e67e9fd26e676f1ee4ef13c25c10fdbed69e65538667440473d9d3fab64be30c962916209a0812e10ce2fb619b86cc5f5ef7ae3a3f0a176d0e495b048c2122b0a495e230a639649b29be51adfd21e21637b3ce31c0e11ac827411bd5dad597eb013fa406fe69b2cd05937b41705fdbf9025762900548b8c2453c1a79018144ef9393ea571159f3155a80e205c9ddba1fde71b1a9a9a55ddc6b3877882326b1c42742e295b0b709c80b4e5e5d6322c65cc2a000deddd165255568f85fcfeba22a830806ce4d7cf67c92aece5e66f3189b8533cb156c23796a0cbaffa7840a6cc16ec4052eedc929762697f2e2efa6400a6ddb3e4845819c1f51718fe6e53a8c41b9dcee0582fad407c9332212329472e3429f59dabf60d94c1234a1d85834ae3425296fd704c5413f78c85f5d4ea3fa0c8ad51082c9f165389a3eba1b31ecaaa620044e196157219196e5a57a91a442687226e5c5460eae0c84115152184d1abb4d3f21bea9a94ef63cc2df20f804929c6329329af40ce0a8dffe9e282831091bb27125a7e130b2933d4a9a79226534b89619d115c1fa14bbc76333333c0aeb4ec10dc7b7b00865121c051d9041aadb4a3b0c32097b1aa583264f8bafcdff300050fb7b5ef81180a95fdc574a68b0a8c80dc2a0a1fe12530083706c8aadf02f601fbcba1649b4049fcda0d6801311920d9e32b9c4077931b4c20dc20bd170e68bd28008de60432524ce4fb66552a7b89878fd65c58b54d1f70fe0e55058ba35bd17f48048e4ce943761ba424c0727d6f4c59e887573872c7a8f0f20e9f2e1437ff32ea25b4516a4a735f1499c48d82fdf797c39d387168669a4aeabaa46fb1bfbd1df7aeb8f5d1410fb115f7c189068e87fb07bf5b4eccd72199c50557eee1260ddeec506d35b6a63e24d6789d46a82ca6a628c2dbf536dee0d0fcee9437bff9164f369343c299bcd4aa6e414c1222bf06ef2e8ee2f59c1af5936bba17346adec4906b0a66df6fb73a29ac2bca5cd90b5db636b149301f55361e3ae3e41575dce64060a9c8a8852dc8a25f422062005d09f9de3a4339362421304158f59ee85ddc26b2bf8e450b67c8b222d06e67782c772a5ec176a7def16eebd186ac7c4055d103ce8916441fee04779f7c78f6f6f7754538ee896285d967bb4287e43111b8fc258374c99b3c899cb19acf6be095466e0f83e231078cf22482051e2a094aaa482187be68b4ac3cd4a8e91ce554f70e7b81817fb8dd1d2fa4dda798feec910a15d55a47252b4187a22c949ad1d161ce42f894c59e75529bc606782e29b2e335ac9ccbe1580b8f5300361ee8249fb10d8d4a972199ae53d26380f6055d90b16ba00205bbe61f19c3e0e144bd738f102974524c1aa245aebea616d085309c839ea5343b44b8b037670574d98b41adb9b9b9b2094337a1a8fc49d9f357c19f9b47d5e24ee2ae911768f52759054d291f26125f4071f85458463484fca3e8fe36bba1b6baac2721d708b7bc248453e03ba81c2c5b51d98b4d52d036814f11eedbcaa83a8b4fe3e04f1dd86ab10f20116cd6b9f5eb9872e6b2724bf8248f45914e781a9c3742dd0e28ba4efc8cadcd5129be5cad1f28816995f396917aa67a01bf78b7b8dc919af54ebc40a484b8e9f286dec8e70fc17677cc8e32e1b6aeef2a6d8783e96409e783799b0056f9088fa3bbdd35e4827c4a7cc88fcae78b6f80eec5533f66ad9ecba7ed993ee2a691960b6073ce04788357cb5e179c1786b9d1ff5cd8a2dbcb857093feec2084c76791df9857cad6ff47dbc69b35e2b3e44ff5493ff3842d845ae90f5a5cf348dc3f08f8601dc218ec8d696713a84c96f9183c151b32a1b7fbd1b786db4d82eab2c0e6856da99ed7119462cb87765e09ffdcd472a57b9c2d7ff9322272cf670e292bb1c138fc46d210cc3241c4f3b671f3b9f88714f77c809a778c24e8b567727ecb0c846ad0e5dd328352316bbe868166629b4bff41495766eb7ba2c95fef091533e0c996fa28cb6dad621b782f844cb01fe25dcfbd167a6df08adb7d60f6125ab31f3c62599631bf624b1f3e083ac77c521a61551ded36f14f583f7238a8c278da5ad750f6036d381b2c0440491ba0a6a0916de9797728f5a45dbf1e73e8525943acabfd8c2ddff5f0b55969c618dec88fdbb9f1c0d778a83f06f4283046cfe434cc654db6649b78026da2a82148cb42c3d91af02de7b4add7a4b5b3d608629073284bc5f894a3a266ba9c5783bb56721ba487e07acb23175404838684f7060c809d98c66437560084d00634e36cfd92bad54bd091ef716bc648a06b5d047814b6442fb8ad54c638a6e5c27e164acf788262579a0b502a88dd48e236eae9009d317006256b4b098aa3dd05b09caec0fcba25b727468eb7c46d0edb8e674d08115d6dcba5ceba920ee55d80304f7d638c950081c043fd88d2dbb096757b7a8aa8f117461eb812f28cf45ee6da1b335f8648ac84cffb84c188962c0a7058e41070b882a1d2a41a899ac44664deed69a5a4761fa788dafade46697416e019b1d8b7c9150b3159c2fa527e262c30ccc2cfa69268ecc7e049756e86c76f64802d25c5aa50a43323c8d56108e4bebe857a1249155d29264e362a01d7011861cd95db7162e840fe9d3edca77933e79757ac1413b07f484e4caf39e75b89f8aeb8f095a912517f1fb0a4f4af60dd36b86764d7848be4752809acd85e2a380ec5848178d1003f9d7fe60bb2e3c1298cbc2a702ef84924fae3ac138f238fc0a387155a9a3004735a2481620bd53920855858695b11e6ff4b4c35b0930f14dafccd51f132cc4afb86bafa19911746cecd7aeee880575e24ac3bd745100a8c5caf34827b124fb476ed77dd5686b09d57b3cba4734324443ecbdc85116643ebe61618362d0202aeba576c96966c5bbbd1424f46bd0f718e28a0bc280232ef4b87c17007cffb1d56c1a3a4984ddee1ecb4e7066b63b173f90d22bd4a118aa79a32901b99a62466760aa675cfc9ad96dd9e2a8996d0c8b01b137f4aeedd5a38bf2cf0a51f5bbcef18869a0874202c47cb2e0760ae7234ed1d4f89327b8f55cbe952b5ec3f652a7f5e375844537853752798b549f91ee2552fa467a9f48f68a64f9d7ccfa8907b0b3006af785f90de05e24de50bacf72297e0480e6c46b9cf59df15ea15a3d69a72a6b66d59e45c051154c8e137ed28044a566d412f6a1362831edeb80a893fadf9179bb79779e8770f8fb9c49f5bb576a0b0f99a2b0cacc9a7592436dfdaaeb7dc3e8de4c66b63caf094e1bfce29ae98226ffe8d5c18c099929032c6b602ab0cd0799590fc5fc7128f1fe5489f2d7ea526466fbe92faae2a370df340a08b3fdc19866394b0af93be6ac4457151cde15aa9613051e53bf9ec063ae25d3eb90e665669dc2218cf75460c98e6b66dde60ac1ccb4bdd03cf549cacc5a27d5e05059957fb9333cdb8ebb6e842908e94c8e7b986eeab9032d3390597748bbec2610e69e0cf8c4070bdd50a53a6dcde693692968716e08e3c5ef1d797f402173c41afaf44afd5988b53bd9589b5b9f232d93576583e41d13a32845520886a130b63a27b8e280ffb82efb60c73ac626068d7398e50b0ab638eca58d5ccb71e2227e8fb85314a529aed69b725f62755b1c0c6b8dd1cf76ac2f7ff23a8e0a3c36efd9c5c5574f58f758fa127ea0930ea5b181f021387ef8b643215c076a8bf514dcced92d13637921183d3c38efa24ccb060edb58e8823edaf8a4ad2e01adc81ed819e871f314cb16a4f8c55dabb634c9aba3feec246774a4f274a45f79e08a7913b8442ad25709d19662a3a0e933b97e20b8f221d98031ae93c7a2fa04b09dcb3cdad222b30c0bc9bd0efff159271b605f14e6270193e9606c3199c50c6951500a4a98ec927c3a04321e0b84b08ad23b1d361fb9cf02520ed94de973cec7977557504f4d30919367b340913a60e1bc701eb24a6a9ec1f70bde67703f82f733d80f175c3cd2aa80c906041454589717023130f76d050eb4b326e6005b0dd0973d680fcd013633aca8245edfc8f44b5850ef6353c59c27d9698d1ae63cbdf4a88f6f39a7250fe1bcf4c4bc520affbb6a09cade971fce067bb110203e64a0501a14d42d628375b935f6888db81fef00d731dde02ab8ea09e89c35c534bebceab179ca8d094e815b66a033e3a64a116907907517b0f3872c2e41966e689f8d7e24ad91caf99227322844cf29e14d0b64974823159e092b29e06059802cc1b74475613df27397784692587c28dc9d6d16edfed901affa35e7ef3b69d95d6d1f827b980ea3d04aefc37bc7502d647891ede169557abfb35bd8298fff8aae927a396528129a2e536c7499ab0603338f394eaf734fe4227f68b1524cb42fb8db7653e85caaf6ebbb9ad67d88e71aaa016a0a7f492a4ea0a9bf0748d6a14068d77f3d742927862bbe1071144d8e7664b40b4c69bacc058868ba7170e75acbae4532fc16148adb84856c83c4d56e3a4a3b7ef52ccf6125fd8211c258abee710438327f3bc148589ff979ef07645ae2b8457509d40f4468fed0c080eb26f87c59d6e01526d682b92a6684422f4cef413e6527299dcbdabd12e2401b964a7a5a21d525086e33b7fdd42b3e0b4f247bdd1fce97a0943cc8c94df8d7e47ce995340a59ecd317f20d3f5a650edc0c9a98aff5fba32593cd21b3e1aadf5f47155da3bde6d4227a8adcb985af2a4939d410cf87f405e3652011e4e04cba679b337a0efdc858c30bb9b53ce8e5ccd28246b40811beec0095072750c44b4e8c5d0687c37c755caca3c252315e85d765f1ba4c225abcfaf78afaa57527440a2dce5d5dfb85dfe473a9af0236b2b0b2af2cc8077ab6b08e89899eb4e0eb0e65e04c74c57da52a964a2c416cd44bd0909019f129d01c6d0a7e8fd44d669c722b0a5a505ac14efc7748958d6735ee7656d3b985587bcd72379da24047de0e18b0fb4c342fb05f7b0a44fa270b35031b3852ae87346cf5a2375cca714b582de88119bc4f3a0dfd44377af92a39c7ef827fc298aebec9a62b98631b2e16d38a559481c9f2e661e89fb63a4b98c88c8cf94743be59a65c7b0943fe0312b84521c935e298aa4a89f6a46209dca38f8f9fb9ec2c48aba172c15fa2d67ea9b3413654159b127c10e43d6bb906242598ac7b88ec63158d7c8ac9406365582223fe600ffd6d0bbfd809003d2eb1b2ebaffc631373207ff6fc3d8a06535c2120c3ecda373851b22717da9b424c2a0237d4bc29e48b913ecad2797a1423784f607c53bbbe247c606508952c1e5db878da544a61312a5c789262c85de0c7ff94865389236f781998f6d61b9410fa81b1d7efcd71dd0662971daba86899a9cbc774c51a304b8c48b7c7a554695d0ecbba1266894e9af116afd6283bac029c44a38354f0f22d399d64eb1ddaf040d961f282d06cf6c3d4d6223e2ae1976f260f1a853ae0f63a795c94eaf0a983d99336dd5470ac49e761aa3c9ad7c8943f11c49f524e066d5c35909e87ca54257f1070af54ea1191b65cc9584ac306348269c56a6c7aeaa0c568aa00efff1e74c53bcf9b9e764828093ab995be505611cb90b8dd5a76e2a55e08853f710a09bbabdae97b9de456d02166418095db8e61723b0b99f7c4edb94f0b8c2cfce2aba5630f4606b03f4455f765fdeacf5fd8277bd195dc582acb63c153e2a5118b08b8b3686198740cfc539425549009d60d3508715cad67726575a9a02fa312d4a5a7f6dbc381981d329324ab8ea16690bf270fde3cc49d16a257fb1f04f46d62f485c616638a9ad7eba9e1ea74735f7782c9d807e926ef881e2aad137d19eaa44e77510f1b4e9d6b769acf708608e918104dcb634d46aa1695dab06dd901279bd2f92c487189a293fd4835102f0574b8fa7f5d8c3e61664a4ec745df66cf1e7feb84675cf141d64ae5b28d8804bcd994b6c13266af191dca1a0151044b1b7a640ebf00318539013d4e340abfca8ece5a829580c5330d2715c9e33564ceb40e75d984101660dd5dacd5a633a1ce1dfe009b2e36ac046a8f7d61e2b5dd00ddbaa2ca3a7b7d8fa317670083d741ed10a6982c27929368a4e75f0db320d6f909e07bc4d7e5f0f24526616a485bad10232ab77ad64ea259ba7b4687b22a783d5924032c7e3cab527116fc3de1a6e1661db0a589077a68cf5159ccab3d9f01ce51df6344bf8f372badfd4726885773cb24c643cde722d3aaec5d1bde41bd3e5b509e03388c0371a76a47bd40d289d1415035abbb0db1bb1c89deacc6f584b5bdbcf3b28d33956a2e1ee70f022ef2694e905829c9c1addb95ce1348fc830ee6903c17037fa5b30c48e46f1be8cfe7fc7c70f03351e3e07223d5d1cd96f18d12c62cc187f4cb8d2db0f5a03869b0dde6a6527f84362462b15255c67552fb5e5a86358f00fd735477527b3c33d8d8a4d4d85304c8194584a902214769b864309195553be39b86def7d80f800d8b65b17ad6afc6a278d29e1822b96b1688aa76abc493049d24f1af08a0f9ee62cca499668285e5187887f2194ed0603513d6bf5ccb6ecd3b4d9d49e90b582315b0a3a10abff21a9131e5511b6f5431a967e816e8080ed6cb10661f7629cc70cc7a8956a137389926d5ca90c992cc70b5bcd90ddfc389ad9b8898f0ac8609f0b4f4863ffec68112e1d6bdb532d15bfc77380da5a01436c69cc504750bb83c2fad664bfea999e0b4a32f76e6c4a9d04bf2de62fd97bdb6441c869b62b4108441c5db17c293691de59fa2fd625f31bd8e07df1fb12fb18daedfa1ae25e58bb65e7e66d76d8bfe484362f93d7821fb784695a4e3f0323c0eae51d8fe3444ffb2f3263725f7413d5cbf75235142e5aad2a87db298b0388c12c6313f625fe8a29aa1815848d1be750067d7109e878ecd22360b4808fb0fe6c4b902cbb121fea448a222eabd79d9b18822ce809a794674beb4639f417d4f3da01fe60632f17eaceaf235b3c71cba1e2c680a34ee7d6cdf4c8344632ae4d9929d42c3760247e43d40a10e09df7e1e471b4470ca074e37914606cac7bf34669156bc3fcea15f43d88ebfba25d1f681ae153c87f1f5aa5c8a1c94cd6f34a0212491b08fe9c3f540c61480e72755767a77252ba48cf168540ac457a8c1e8dd83508a88ecd80a472e4051b922412c6500a7ef7c3f6089f1454838e7be00ab1dc5b23619f80e8ffe2957f9c2a04ef1bfa799586dcdfd71571dddd6e76ffe4d4c8dab53b2e05703720ffc3b87c8617b4a5c32a7919bc53bcb8828c087cc1b4b8f8fe07cbaf66fb1ba988d3bb54547d986de0755d68d6895141e40968424887522655992ed212ff22c1612b5a691ba36ec2a28d2dbcfe2746facc08ca4cce9f2108a66e694a43e39bb1a2d0e195003ece6aa20241dbec1fe46248426828390d0a5ab90e8f88340d8976ce0d30d7f70ac4d50e84c2398670b31b56a31a53f0968c2d107be333b60efdba00af1a637fd51d49d6ad4aa90387c449c766d662848386197119fee5945ec466c5b2d7e19a139e4a583a959140e6f71bafa7fc17e3be2a8913349d027e69c8d7657664d272f451dd7ec4e13b6cb2595c4d1d020aad444aecdfc10443c08bf7c817921a347fdc789293677baabfffaa8f909503e133eb055ebb786933937dae8e1654b3609fc90f5e1a17c861fd7273590fd5a00cbf46f7bbc3380db5bdc7eba3f56e2c29d8d049113aa340c04282b8685bcad077abd0478b56120b2f818b5809c800dacbbe855dfe0993fe96d6965e3f72fa5181ad8e291fd6a69bfea2b09ddc0eed8e3787e53acc5f8c645dc64c0e9c32313d804598ee9bf6d35f227f4bfa4d48db36e110da7be147a56a228cfe810d35350175142471a3fc84988e10d1d7e3d2663ef1f2ffe34d946c9ed4bc1344dacd812bbb263339c560158360f53fa3b7ec1ca80254dc747124e44a8dd78ad31d48815e360e8a01062e9d07b813b7d15adc84242598c3718dcc1fb614ab9a746f212f4940c938857645751d5b422fa0c25859384923c354c481d0d776175b7f3be266e5325e8820ffa23493a0ae8d3ab8560e897b2495241a94fc748e1bed25eeddbc3e132137a2a4757a621216c8201c5795ae7cf3c4bbfac76084258b6d522558965d0e3de0e2bc590d7ccef658bbd1605b8e56517e494c43761a943cff59075f0e7555225b7baa85abfe1baebcb10627a9a15bc71e390c75a73fda15722f46a0319753cf95cfeed366a0c0bdcea7828fe69bced13def5ea3eaba10aedcc1ffa201194cc4059d0b23c4ac3e70a21037cbdcaeb67798f463a0d833e1f517728fb4a3fdea38aebc18e17c74710b2b2266b25f08392dc959e59efe0c30da77e4d735f91867f6faf33883fa90e93ce8d1b49a0756a3374812823d229fdedf67fe76abe2b8c6a4794e89af1c004517b518b0e98e9ce998b12b00c36ce54e3a87bf6859f3fbe7733c8bb21100142290dcbe1403832d2bb4df3784baccb428f1bc96a5c361736bb43721d2a3c8c02756e43d745c9023257b6fb4270365ea955e56d688841f9920b55e477fa229ec85f30feaa53a459bb3d774aafc087b2c9c504dd59906f3e6a044db91042e06686d7e48cc781c558d92027d1c05932920d3a1195a5a1338e0648980c327285b9fe6f9fa2bc5c6ce30dbc33613857b125f7bcac5ace3c764691f4f680a045bd5caacc95767bed98122828dee19d276548599e5d52d63d48921326140fd48e32561ebea499cd222cdf1015706e0fdc0549d609544390766186416832714c0872abb809be14d444f5255056f523c7566365126ba52e89e4a56b74f0a97bf328234aac6ce234cd25ce5586cbaaeb75855dfd727f8e60926b0e13dfde4c21e73e661bb5b0584f314fab9ffa405d425107eb764435e8e12eedc49afae4dce16ce8da4a0ca54c203427ddca0228c9be40be71e4fcf9807cfea9978bc9bc2266174d60d2643315dc65f1f557ae040037ed0654478a55adbc287edb46add9bc390020307ce4dc56932cedb5140a1a312bd81e7f7e804825143d6793f71cb6d6e758e2fefa6f0a840822b284a0c878954135f4cce72c02205f6a6ea3f8579d7dc88517c13603dba4f4b5961533ba9acb898cca59600bc8d58456f5069e4e49d41500f34450874d0b3490c6f44a492bf1712f54d358b809c8ce155f665e4b21f8854c5b509be2e1a81011025fe1875930f6c2a4e9ea74f503bb0cb968427e1a8dea41b9238f796780eaf977a896a2639524c4bad29001e7d99d9e3b1226fec8ab58c4cc9ceb25d59d0b040afde81d5645e32f975ce81083a114176f531e48703ce195fd2414ba32671a6e08563a668091a2d7e72a1ae90c9c4bbc42213514860cc93f9c516e47830e2c645753903c8019372d116595f7fb1a874af96901249de0858b0c00f72462535cde750df268bbf6bc2f8457db7bf944e09ecd7e98f41ec97a08174bad324f9dd91bc52d7a1a7b34b8ce7dd26ef26c0f2de5221e9352be25aea51384fd0ce8afdfe405d0833ec364f4673e033671eeeb809bdafcd17afabb0e19a3d67617ed776ad48ddcbb228d34bcef1c1d3b78acaba3285073f0bd3086af8b1c34d5950721b73b5cd3f684e586ee9af9f6500a95c1d47045bfafd2bf05330980482ccc21ccdf6472d0482a16cead666367657b477b0039da3f4e6ab0b220bae371f8b440b56b04f862eb25d30151e06988d9423b45f34f887d6483819eb355e254a742102bdc592956203b6a80464cf3c80d4df1af103af02dabcf873990e89e21ef3a65c8c9fb0992a25599b0197ba690c03dcf28fa7e672825d4d80e4416fe47a3f809d48a9cbb14eba567394fc6bfa43f7fd4f6504e1d60804605345094abbc35c73409cf69686dd7b0f13b5c9e45526daeb166137e8e8235e88cdc3235075e52e091fa23e989a3ae0f71189579565791c3a420077e04b59aa9fb0c53facfe40b75f49c2dd5e704030635eb974f37164da1a0900cc6d86469ff303b329c5dbd2138963a843534700fa952fb2b087386300078c83d0c67fa052284f7da739efef0419828feed0af210a21ee58b366bedb194a0560c6d503f17b12417b9ff2996d4d0858e30a0069d043f62cb02a1135b8702693698a5ae590b4c140c5391ceca3e587bac6648166fcab1494c227e225b6fb8a0f876fe7913d460209f79254fdcfc66b321bc0880b336111f2dcab1f31ca2fd692afcc1535b77ec43ca19fb8e6abe19adf05f18c791f4e38baa23933b81fac357486e70ec730d6e2b07c0b6796571993c11829df218f900657579723312382d433a830f0c8d3c658f5a117ccb7ce7ce8b42ad4d74855528a42bb4a9811f4c3e2f2fa9c4892b091d83126568b6c89e0cd40618731d6743570c0733848bfef2881689c48b744fda79ea0d3a0060585c4eaa26c1acd0591cdce9119953290430b5e2e2189930d37438e07afe0e501e90732528996ed9f0f81e0d0e4f8039eb63f1daf4146b149255ff98f4fe17edd290fa2ed8a11e443784625f1afdd95cb45dd27c789f6c44d52def87bb254cc3e57816b6b61ed657173dcb4c7d529aeec7980e69248d4b3b262b0645c2925a51259db13526576d02de3638d67596dff85cda7d0924a0e572fa5c82adde7efc055db61d62fb122129c133911ad851e24120f35caa7811dd10c5c7cc4aa0ef1b1bce548b77231c9ff6a5ac8f5f028ca1b92ecf9e53b66d4e1c58578ead4126a3d283747645598d36b163956d2d9d4689e13d75b8478a998d909571e44969c388b641a7ee6b819ff2893f4f1b0b67fd21575187e62593eb88323f90554036aa2bfecf9bb5e527e8136aeaea01bcb0097a24604decea75cb66524f9d91062fbfd594104788ae6c4c567668cf5c6670d7ea823fe26935771b9db16433663ed8ad19a7295c5f000afff0394a285846a1aa3cabf2ed62c8f30a85cefc8ebfaea5463adfe647e6c508b45fb2719dc0b4a52137bfb6288aa000c48a19ea63069b40b0e2bd75b52a9a5eda53a762c60592f2a5b52597edb37eb1d590506475a927721629370147ccc55dc913687cd11e35cf2c41e6134e6d20903f9e9e2a325cfbf517dac427a756ba9c6a61e7c2301caf622c73620126416132a8e53121fc5b14c2d043fe0a696134628ffc2037cba9e46cd8a36d9fc0b78c64c2e25445ef5b2338736e75c11207bef42e07fe33dcb5d4755a84a5aac80dd50ea40494aa3daf1bdf35901c4a5e2d1a1b303b375c0ffe850c26ec25677c3c3618144e6241d7ca0088b972c3f8ed26195016b4fe4103a07ac28bded07ea62975dc617f4451e11a490d34d80ae7126a70f64b8fd6e6e929d3dc4666d4d9ac99276e634edeb22703ede1e60ea3c411c813b646cc3c29458c228f05d1dda83652683cadcca4f0d4f8c45b4dd6da371cfd9506e3aae401c635f55bdbbe8a4288e9bc578b54020edd09d479fb99e5c4ae71c4e895af914e6d534a66b1d42b69f7d09ef9e04bcd586161e0540ced5a6e1f69023868025573d03fecbc5ff1d7b45a5f767530aff0deca38b8ded5081457c1ce4bbca5609f7c1be645a5a1656928fd61d6cdeda15dde2df3cd6890232a65710f614d266eaf9dba55ba99e22d3332e945b3dd3de6f5178c6d88b89fad1374d8421b7e3934ee404e048a8a65a53c7b9ea8c92c387ccb90ceba08bcbe0f10cd4dfb1789ba9a9af5f3c032daf021a56d5d48d5fbe5a39bba3b6436c8292657fbeb5565b949148d235c745e52e0ef07b7d6c5158f3a5cde4b50c15d1e504ac88212e9cb82189ccb9f6f045d47a7d6933b1b6ab4dbefe9c4ff1a96ba9198dc7587cc974f60beba9d94b531eccc4c6a98c08bd9b5a2025207fbf268f51dbd25a35d858f4441a266cee0a1c8b6a3013e2c754c619c9bd34c9c3fdfd05e4c6c12fb5c397f8110cbe142cc8ad2086ffa118aa5be04353d1af317b42a2094b78ca2bd3d8368ab496d664d314dd3eaaeceff61e65504c38ad9ab6cda7b1304af3aa6fd5647b9dcdf8879507335791c7be7d92f44b039ddc1abf82b5522575293d930b09b85593112dafca653ba69604f899d3291e06591c7fe269d6113792ae7cc302d78dd349633d539b8631dc1942589470dee35ba73267116ab5114711e0f5bb82c6c533df8353cc6fa8c92dacabfb6f20df3bcf26f1679ef6e9c30ffc642c3d1b71e6624f7eaa5983b2016f5ca87ceaf070b003a4fe064a1213bd78a2dad8d04bc00b8311976c275c7a6e885bf74d602ba31645aedfe26fee4c8b4e226a6c3330bca958ddc53a23cce11bc65e537e343e61fea5c44e402f8f460785b6c41e5d22cdb2112ff508037ac538e4e3649e20c5529fe63626026f534d0292a09475b965b5889bc67a43c732918108393dbfb957c728066d76772b74aeb5cb61af72b86d196616da3661adbc8cc6ef4716ee3b382a95e14a3e0902ee3e6ab708983fd5e0c9cdedcd3418087dfc4b29dc94717537cd0cdbe47d03a159d86c825f7ea7a370e56e6e04676880aa0a81727d1dacd9918f87366137ec9250062e89a1f08aa0bfa25f183e0ced10ae8198c356b11e40887a9d9db5fe16ec17104ef6ad086838a7affc85575b45477889df8dad1afbdc8301768a230e2813f48e9c2c585940d75ac0261c0a802cbea7aaf89668de4047b0512121e424e9fa032653e53fa089371e980bc3c246d65c6cb8a2766e8cd0caeb0e7d15e983f0d34683427cfe1d628abaa96dabaa086206a3c63776e02e8f81f20527df3a6c5267ed4f8a8ba5d08d952e8cb6024778ed830b7ddd7466767cef5a3508321bc64eb059d9e3bae3638f49dfcd4fc40861bd675459359d0984434cb5c8e7a36498694ba34c5cd6b2a3252cb24b7427ffb4af5b9e46dea52f1febe4a533303706e67a6b29fe65b2fd9ccbe21841fb9ce7dac7a7a3f7bb400f4e3367d94e0a1b2445d1b274914475d85a99a69aabfb966b75bbd53a04a04cc77e2b46a0234e937b6b111d3841852e93efcf48074ee8180148e591678e125f38b6b32b13fd3f81e68046bebe29fd93decb438af21c6f1d1a0ec4f9f9ce8ef0c65481a335d8e6f164bad060266627c9e49c464008fb8246964a78c85702ad8880261ecb2806866e3d0cfa1a530680220bb15fd2e1f756bd7ff0a2198b386fa292acc507e35a7d4a5eb8cfc84a00f077563a5712a063e45fdf7bb12bf23f6de3bcf3804cb9ba6bb319efb45ad2825cc00d383696cce225ad2869e686a809dc963151dd963b0a8c16f409280640c26786d4eed796b0605e82c29b11010c240ead06f7de4303397e19dc2f98ee61365f14f625ad7774f5720697241d7f689f19462d22abcaac56f17055493cd1d7747e8f51ea8e316efde158e9256bcd1eb7421dc9d96f733cadb24b80443e7e1de41a89f305bd29ca978eb2297e94951f16eebab6c5fb08ee1dabf4a295819b6e2aa0e058a59932f28394ccb9dedd40dc0bff4abd5b5c0b5333d99542b6bc1d73ec9f3a18ecbe25d65df6072f385d4f88db028cf80ccda5ca9f0ab7794fe9415e0b5a7b0e990dd53512e53462db2b00093aa1c5892cc5e0f9a410a67d81e5f91d0222c49a48d7950b14b0a4fe0b44a81c4892cd3b0e710f1f5abc92a2ccdb2fbcc90d6b169a08ba1de83334d188bdda38c800e154f5ee92b8262ca2cdadb33a836e6798a8b0689174bae0c04e0030718f731a2f7bb055f9d9a9917faa41f2d0479fcd88361e4976551bd000afb650028e8293c43687dc68e09b2b358e9c12d33bc2e7a73cb4ac1062828de453765f990d78b1a4ad6227bf9c0bb9727f74d0ca8c1269be06971c53be5c351c9c3ec72f9334f2fff085b71d5bc4291642b5347b32d1c1c6a7141e22d80975b9c55add74a65374995f9eb5261957c9061c3f9d9f04118b28d137b0fe543d1ca4b66c68dcb6a8f049b139f0db41041bb556eac3811d1a74a6b7ffa5213c73788c1fc80931c9455a3645f2d0b2d683d34f755cbaaf25ccf7d1bd3e880c2ccfdc67b978b38cb9e63c0f3cd6c7e995ae660c84c9b5992c78b3168e60900e6c676811214b877720176c8c7f9e84660a0856d689596381833919267046a314b847baa944d1bfdfc86f258f9c0221b57fd14adc6ec07c61f883cc208b719ad8a2a564656c139ba7aeec03dee260cc6dfbfa203dcebe5a5768069138674a89e63d247cdb7e13e17d80c3c1360c06d50a8a2228ab981feeb2ae8439677cdb3101e6dc563938a8fe07e7dfa9be1048d8c1113552c70a337759d92b22ed8a3bc5563cd0dcc9e469151f188081e72a8223b1e82df93a2a379479c9ca803ff643152f43893b6226000eaeb819982d657a2a91d56a20f4fe08e45cd3a9bee2c4af16a8fc7e5b5dc6965f3e41a9f0b3b763818813203b3ecb4912c476a50edc819e54cbe462136ad198152895976da10a9a467aabae02e2751d4a886d09d52f1eb04447a396977f3f01aa468a31d62658c589d12f4a2ac4dcbe08866c97a53b5e18fa61b854f0bc4924c5d6e2e2301844cdc184f7a4487e521e4ea46d775750540b602e298fd1f8d58d4e00882cc2fa8eca3e50189b8fdfdc0b643074caf77eea4e96fddca5ff1b6cf5e11a4678e3a016bb08c76358b6c0125dc2ad00841be696d92945966f08f07fdd86d2d3a855002ba6c34376508098cd89e79d0d2a819623c546690c1d11525e488a432c4c91cf9603318bb0acbb4a99fa3087672bdee85377651fd3785070b20e8d634885e8d190fb613a897a2ea61e0f082ebfcc6b68ad4b649def1c3c72f1c2abb8183ea4223b516c43f9481adc6e3e97ac5349897e3400056fd0d1452a2ab9dcba5d097452ddb95a5536c7a41196b4fa1898f51a488657782bcc11e712082a1788c0ebbca469b1f9c96461834a24c62266dfc973ce63b34e3cec6ec4f999bc0a5791eacf9b6797c5cad5d59422be610bbc9cf48bc97d29091c2870f0387391f0c5a39a39c2310b757706f9244e4e0d841413cb9b8c01e77e38b1ba4892f201f605fdacfe1c856931c9ea7b789434eca7eecbd214916d783d3b29a4b2049615ecebf33352d6c1e444dd7f5e5ad0139d9a5e4a1ab944b591518eb03970736d59b3b785c2b664c1c2b2b6749aa8fcdf967ca208c36f7242a97e0b39bec0048843122d28e13a3e880229833a26a25de0d4896b6257f7f0263c8f8bccc53dda7a7df935846b5d153962bd90e259ad0106e556a8c44400030a6993daed0c4e4f5eaf9fdb45bb4c01186ad9baf92c5c1987c2b56d510f8fb6a51e3c821c45c3f727af168666aa09c26b4e0b2ba9f5f12129edcce807e2fbbc6e214609b517a4b104484a1d37bcb3d76791acb57ac883e149d1dfaa0f48f29daf504da4a5243ddc9eb8dd9a02a43f760c947fc4ed34355b57ab9da242627ae8f8ae46708dc0efc158bc2bb31290b84bcf9328edd3b60992456a28e029c0005284ea1dd8fe24745b7c91705895adeff106efff5e4e1b32f6b52e045cacd9ad86e9f19bd58d2f099783cd978fcc0656e38d73d1006aaaf6dd8a9cce81813688bfa0457527cda7d2f5281c13cb453c9241403a9a408f660be474067cee364cbbd2e871296bc5f83821c2567f0a0b142e47ad02050a3da5a988ab6af3397bd539a6f49b921d6cf556883fe57381b857063861ea039c9cee1b84aa08088ab705518b52682e3b26327d4db960e98bd3fca49e49c5657d2276c337ea07b5e1ba6399043a549ccd96db531594f95d08fb31cc61c8de07ccfad90ccb7ce7e04bd88f3ee0d0969d172f38ff1daf888c41809651103dfbbddf27afc94cb515f389a01989e069df953d78b326c9a75d126984365c78c5d0e5ba378b96a45f836e7951448ea97dbe4d07d4c9f87ff828358a8d0ac1377a8e48ffbd743a7696fb4b706f5fe78dd68abccada020299cc48ea0c189122459195329441879137f6cc1ff37808d532e113410bf6ced4af57a79e88631fc124933f1756b1ce819b204d4ce5dcc9b45d00790bef3cf0e69dae219c1667983166dfc84e40808787a2160e010151c06a457d6946d35f09249e9e3946bc7705f75f06b71106121308bddcc953036a033aeb414a6f9e02d6ed374bc7b2903da2818dcd05733335981a5352bd25b797f67edd4d04e353f30c289418b638795f43707b75f000b86ea634a5f92921140bf964e18cf2eecc8122ac6968fc75236de6d23e82d6d64e665915f168bd5eef35e76006b71e2b75d3455ebb265a36133617bfd8711f37eb98889a03c60a75aa8acc79ce3f5ee70b15502fc1384d0cea884b8e9f143ff8b7439d4c76a40087a890040197d40300c6c254065e9629331fd491bab237b2f11b0507f599c05e83c44893a54ae536b8be432f11093ed5e72932c8b7f954524110dc33a0de309a5e4bf18880d7378ef95a9b92d32aea070d27b05006cd02d64fe6842b0d31145497d253bcea8d9b95ca62de4a6a6644894340be284f081b2507870aaaa85a1a068fef319623659a69a1c75c4bdeee3d63902969bd1b0d24f137816c1ae0da22cb1831fa4da86270ba6e228cb6e411ebc62d53562e09f7817b8e50d675a5086a6e71c73f3c369e2a929a6dee7eec2518387a6d89af9a24cc8c6b89f7451cfdffaf448974c5f62eff86f799642c90e98844d8fa90950833f05718e797d8d24bfe3c136aa683e85553d13069d9f85a99b04bb687c263eace7feb3e065278be18e6ec3224141e4c64e67075d6ade0e5232c81a3ce50a5bdb9fe150aafab6af9b1e5c94c5828369422300fa4d2da07ac418b4eeadd6dc0a7a7c63805e5641b4f1899e0e2c891d6f3087e2260cb7139cf02f2a3ec397403195c5cef67622b4c4f683e2df49b04d027bb93a6d60065d6e68914b500f99d1b60df17de3a4822b2f3e9750fdadba8b1408aa763f109d200952d0f3ad9886f932e431d33806d0e81e81051032810eb73575c230bad0b24e45867c2df7c919b044f8c4daf059f25445b4614be61732ef2b74375e10125b7e3badc9d73205fad31e38019a061f333569f6f47810a86a495123f648d0e0c2f29d6e8a257847f51e03691dd8de23c9bd1244baee08a8cca89a0c8d09050e1258c7a113422640d6258873ccce36f0b2653ace6603deb73103717e70c3e7921b8be8cd6634346b7474a76f59bfd83420497f576b829133a7bfd7f39012c89f0bfdc4db0a5022214da6b741d691a8df55cf26f760cdf766be1624adfc6100a3ff0d5a79a7c6961f21d9e9c6622b8899f63632a3ce66cc4c9620abd9cc401b95c54ff7c8f3a4089c6053d155f55e0e54b144657044c10a5cafe20be86dbb87b2d4ef3ca4c3d024928bda255b58a9aef436a0906598f1f245b08c626b8f48668a9356dd231f6295276a1aea4cbd3d012782b8132ce7f95b9ee08da287445579c9b0b55d32b76d01bf2577e2536ab95b5733176c3d8374b1e9b36fd5f437389cc9d6dea56163bbf8d167c0737c69b70eda40a080caf5bc323b0ec296830b815a99661064194f1bf5cda5202fad8fc1b8a802993513cf253e7d5994a4f51db19d925a10825b52e866e7e64c989e3900064fab21372ce704909fedda4263bb76da36d0bdbfd6d223cde630b32979c9beb55ee1d7dc63b600a9642762aef8c8ab36fa425c3f67fb121cf8dbecc6b4c77108292e321d89f4acf79c402d4cbf41699fd6af7d136756dbd5b7216519f03cb675259a91d29ad3074c47210b14f5130993ad873f52269a94859ed9a8fa2b0cc1d62389f3a65b58a2f18d1cbb31745c2aade65d3c3a66b4682429afb2b8808565a4c246871eefda29873e9b5fecf46cbe59212651893522553a88e460ce05296421da54abddd46179077aeb1d0a2f22530ed1a67a5cc71a2e6d875f31081afc6858f482dd46cd2cd9ac990e76ab6460d686b300d402918ffa22ccb0196ed644fcbcc17176887b6f150eea1a5dc5e5870244891150cc67513f156035d8b039d3e5560f553cb87091475cb4bd881254b5a87c10dd561bfb7a8759da49d457e3c3e8d7bce7647e41938fc9efadacbac1647012c7e87409e111313a82b6a27f513ece41a30cd6744f4511a08582ff03d8953b89fc84601e3adeac64b193281c2c194afba78656a831b57349420b8a2dd0d5a62240d8e6f696c52509bd3a402cba9408f1b9e6d8361e748fe82582e96342d76d780dea412d319a188fc3601c590b953c0bba055d7b7ca852061909f157e479a011396991e49024b41f62cb2ff79c704decead5222a4a10936b34d9ad33687b5186d1fefd5fe296c19c9ab73d53d4925f27daff7aa95485c8acd4490456a127ad10635e96d06340a9b600a5da21ff65fc0438268ded32b917a941f70c07900e19213ab7aef515d75f25b0790ab79b29eb2bedfed53061b8cd3c01bd16e33ec86030295242d1f064bb6542f0b96ecc61b1984dc05a4dbbf33afcc80ef8d25c3a9f5daa6dea60adb2fdc3d58807ab39fb15d036fc4faf425432580def9efbdd715b379036377b3f0fdaf1ed49234ee9e5948955916c48ec225dd9532dcdcd3579b8932bddf2e00b2955013a54dace679ca783130890f8d366d57d762f515eba34517bfe7a11bca100ed71d5bfcaeca06c8a1609def75797fc9786916e778805a30f75f416fce93e812f7b737c1cdcdd6bf7afc446f9be8625ca0fdfc47216cbf038a41c12ca5fc6d19a498f9f817e9e4721e11b4e16e29adf3d26b72e48045ddb182a6430771ff33892ec9111ef55c904e8f3dcb2b60db0862ece05e2bdd02eb220af22a13a1ec6839c998446ae425dbc86590040c08f12ad65b65815013baae803dd33046152012cec26fe09e84a1147883ca7b841affd4fc7df2219da3359afbd75c198a5bdbcb9d59b0bb3fcbc95f941d8b2a95a86ad0124ad2eb5f32e81f9131d8fff792b069a9a44b9494551fdac1415d0de85b79449ffa818889604de8a54ee49664c0ecd610be89694428d34d700bd09a4d1b38642a5c52d2d963ed57d63456f437c426929a6c4cb75561759b55f4443768cccbc70c72b73a805f05813cacd8557adaf165998c87cc62d9a273c46c030bfaa343996a48a04a8b4ca110e0116083a0f0c941ad960f63f6f08bf8d5fe25942d318cf1da762e1a1bef75403f0578c191e283e8c1bc1240a1b12028acb2e81fc81cb9f7890a596075c12e7b0ee25e44fdf3b38b6418e5d2db1b3a40764fa415c6cc3ed6a4402437e29e6ea277fe55807dc9fc93e9e1a1fdc6ea926cd00de9183a013ac83217eef76baeb0a4562cc9a5459cd6ed8375df9af2ac3be4c9437d55bbe6b629aacda7e80363a5424ee8afcc965f501aa07ecdf042bd0d841c410f7b23f3540d5bb9fcc73594aff8c27b309440a250e121bb0c21c930599c1030a945982a244d1e36f19e440e48d4404a81c99d7a93ab0ba8e03d53a4433eb9750eedf04cebc768509548e3c6ba0f581933bc22573fc858a964e1c793d0f7ff54e2a6bdc64283d6168dfd0e315aec463c181dfd691cf69b0813b624de7f3a304370f4ec45c3cbac7fff4e801dc4cd6baa65a9ed120cb7e967fa0a5facddb2bd15f1a3ea99d7e899ef62605cb26380a4ed1a679827b58f1409d04e66007d814c02a7a4fefa4a9fc06d8a7189821757a279bee3008fc83d4da039a27e879dfea4664934c5fc46ad922997921a89c4b4fa15f5969f569bd0c7465f9fd10724809f3e651ab7e3b3ddcc0d4322f4c7b78f0eec16ab1f896398593a5b08c931536cdc65eb38d487b4d83df87b1b18ecc5c76e2f17f1671f8099d417249e0db912612067076265cc5f9592550245971e806a1ff7acb7baa42b30a6bba5dad58675e40033f8a60d6f01873a6215945320f82f7c76239f6845956242026fee51f6fdb7f26ec7392c87c666eb8100c22520bacb2afd9c4907417200fc246a46668b1c059b3eb6cba7498cd7e716aa39a1e1c3773b986c624a30e69e093cbf0721c4b2f31a95ac11c91fe36d8fe5a32e5ab57af042e35b3e57f4063fdcb14e7c0e9319f09b073ef4a6c0711d620dea6cb520a72d2ce0200285297bd4fc141707c2736a74dd2418cc8ae5f74510ce8c47057bcbcb3f05806cedb79871634b5113ce007eaf7adbac6f92b0a9ea9c867b8a9a9d37ade8a5d0f7a687e1aec25bcd691281827607d928a281ea8d35b3d25b3860451644db979f053d2a1771b0b2e8ad61b56b80808e9ad9676bf90ef56daf4dd809e85075a471dbb5a414d49b85b6fcfb540bf5b429c6e9be477b3792f7bdf4d17ca1ef2e469248e916e321f00d482fb52839f322b18bfbb7d26273e816e3562c3da7459959066b463a2203041e0417e0002f3049a08b7e1087faaa16f430789462c7622ae00b1f2e640ebc35b1e363daef1c1e687d85e69bd523c9725b3ffc527a3e2cb7a0c231bf4bf2bc5aed02a34adb1bb9b97b0ffea90765565ec41b2b4d0b45a05b7bd82e36a52c0cc9b268c0e7c19583bb4c0faa7aeda537d0acedc1d4a91b7d85b3ee95ec8250e42d5c4eb18326a440ad1e16ba2745244ea4c55f49603620870bea6ac79d24b0d0438531a32fe7ed13354acb3b0a8da9d967ffb0414ad354f961318f69457c6f2827ada6283e8db2cac7b75652d944616567d63292f6dd3b883b3a49f3e1faa0d8e4e430e97d94e8895376db39f4b6d49c875cb5ce38f845319afd9cc9ec2fc6f59aa06ad2cf705dc7696e1060305e32bfbe31733f8c2c749d6391cca461d56027fe1ea2e489632da3a3e4e760f2a718e69dbe63c8edf399a16f15ca5f7c74bf5c800ab0f2bbac97cfa1c3e5f1c9cd7046d3b13165599af89355f51ac36e20e724656c5dae7996a8de4292d611a22742877c2551bf319bec3c0d1f24c821f1ae28ee33caa9c093b869aeb99bab27928b8a6b17274db7ecb69eaa6eb50fbcddc4a70d3ef00e208e17fc6f18faaf5eacf898526b4d0885eb4d161f4a7945dd9ddf32428a7e392af2245ff8a15bd68a21b0df4a253e8350572e5bb34440aabbb50c610068854070bb771bdb05ff613684da2abdec52a51e0ae519c5d0028c9ae9ddf50de5fb0cec03bcfc6ab277095e54331f102ed9845bd402fbcb60d8899c08b38104be3af4edf4518443ffa0b95771107e2affd653bd080392695ab371237dfff006e600113713d4e432d95f37b9e5d6be16e72d3dd6e71d79d723389d36d565599607c90b8256f6e4b4e50c8fb085480700a344d5654705a63ca739c319b82b1fc9bc34d41863ba341569a2340c9ce9c7b020edbd9c0cda13c4424deac268b4906e9129dc95e065e69047dcb46bbb55fd23b80d62a1ff5b36fdd81ee9f3d003dc7fab521d4b80963a73b0e04c740283942a704d7771a74b1fc272c6dfa5b8981264b4a916aa13eeb7d3c48897f2118ea913ead7679c2f2051028b8c250b96aaa802a68a566c248b3ad80973c09447e1b4c7df433dd2261b7fc8ca91bcadde19c400ecdba0ff4cb98f5fc7fc6e9a8873fa09272daf89fb1f7f40ff3a4fc7d497aed0400c084c90a8699bf3900667c8ecfca5aceb61a28182cbc1a63d6deaacfa21ce3c1c81538059eb0a231f502226e7a180426a16525c665662a8779a62c56abddd61c57d4ac4eb19bb3c9360798ba443b62faf8f8264db20e621d4700f6e43525f52611395ab18580c639b19bf31f5a7e5d7e636fdaa44c9b252acda5c58faa8da83100a7a1a2f06669e10f3e629331b272e302f3ba39ce49369bcd66638e5765dbfab42b63db01e0e46a01991d9e88e013a69d34cc0462e9944f3448d28b85646f6898473bc8f7a3bbff236d4634c659af7d9a10428a0951294d6e01175e046a11407e508b5cb30db588967ca845ab9c422d12a700b5282161a8457e872ccdff0a0bd4030ea5c3b45fdae07357d3fa9046fe823f711d771fe33a746b5e74da1c576b2357d7ed513df792d0ae1964ffc02a7e9baf880c6e90fdba6eb5695938fea410589823684b5ed780dba9f1f17ea60c93f4c87fa5a92c7b42c848402598e4933c5712a271b2626b3cb66c0d80b767cdd5c3ef4daae1032d86d985f94f79ee8503842a65320779b43e6b654c7adde6786427657ae7efe981bace36e5b05e826df8b6ad67b189ddfc85c20733fe82b655ccf8ec2c6ddf1b75e2193c2a242c02354dd783e747616bcfed5266a9cd9c416b33cfd35cd27473d5f019b2cfe1370865a1742e6fc8fa3dae222ad7d9406dd8ee1b97936f5f70b4c0b8d1fb9a0ceabd8ba598af753dc494ef8111425b8678615af037f85273104e49c240f65e4478059c04bf980f42cfe9c7f7d84fbcf34a5a60f670148b03d37e09bd9666fe8bdc870940c6ac35042a1ca767574f2b3b70f73dcf1452fe40d009bd8af139bc34b16e0d284d7a46f8672bf922504c4abac1f7c02b64afe29091747844dde987de1e2e365101f2ddca7ac33258e6453ee64564cfbfc54155c6df42e3224905ee4d0e960f2382f818d60d2cd5e49b2a39b58e10974ba336ce7f7d2460666eb22ab11944c535c2c30f78b105469d1504ed76da0ec3e2b608be36035d74d7a16db4ae00161577575aa87ee10fa66e6079f00566105f4605746247d531f2735a2a5e473437888ae8ca055bfa6fc8d0246718d3e61d20cda99d089ac561827b00500c1541b54e37f149b0452aa98fdeea3172e6b5c850d0880c2f93577027b031bd2a45a1d299f57ea9bfeb7bad02db40c73d30c85d8131c204d6ff2020e7045830ba5434f4b1718c9ec1a104edb28a746b80a0ddb1d833aadefd220a77e2d37013f55ce6e3506736a166276529e0a80d13312b8eed894db2d1b23e735d044cea34af26372d34aa3f1635346b01ad29249032fbfac82ffcd7a65ee20e6d85effdecd505ff51dda3ca861bdf811e3cc4cd225d4f5cd2c1e4e603ec07217b941541059df416a37f122274b38078170b496ea559b38431ececd1a5fb40ec9f9683a403739b65c123c7e06d1005c95cb3ef1cdf760b68d60a1ba57d1b38423a9766e4764637ca850ffb883197096aa0c67fc0739fa2caaead287474deb959f5efd824e8839a33d86b84a5e81f60e1cbd5031a29cae41d870ae535c9062a6976a76d65110b847ca001dd0a565378d27c6dffcadd5293fc7957f66697d1f755cd2c394d6e4b39388c143a111195101976ac36ff3af0c380cf3aa8128089443d0b4700626ed7799601d7b87171f1ede2df5f04d079570ff880162446dcda563ef1cddc41c0222b925f536a747b3e05b9e113ef9b681c79ead0ef0167c585de075770422ed7f87c842a64404a15fd3c0fed4caa1f0cace0a7d81fed8b3e2a1af2c407d36b09931d21bce240be5e8b846bec05719d8305f598f1a6857e076b5791f177b46ac8d95edc731cf8406e2ccb1a87541476735c50ba017f0b062300873e03c119d44647d6f74545e5ebfdf6b8801945362c0cdab2c52179ea3e60ab04bbb0b694748be80be36bb9fb1adae186b87269142d1c321ccc6f849e7c0ce63826ca71689d9e9b4132f4a170c07b8dd486002d9734cf8b94f89284d21cffb77e8559ca3112ea24c0a6184accf69494e2faa47fe297d35647bf5ca4a7e6d3e0f75be10b5b3fded97cb82e7456e2914ffd6eec6f013a06a314091407e43117050a866d939885ac5a0319674e80d2540a96b5024b77d5417e45e0d595e85ab297440e3e2854cb59f7249c771624d62b48d6bd89d4683da0240982ffdba8ac7106734bdf1b082027e2307079b90097ea93afdacd1e02d923c704259bc922e68c638a1179958bc62da8c7c5a0f62088890b52799822895fd4c22eda4dc07112cbba411125190e9112003f95f0987862936e3209a53345b0bb3ec4f213081a456e0d84df8c07a0d0399a0716e63fa5899bf741dcc91a06ac1055e81aaa7885ec42b5430211ac5c039a6972f5707cf776ada723d6be5db2d027f520246f8973b0ea48a448862bfdf894da0991b3ea36806a4a6007a5b49348acbcd8ec2e973b8e2f33a6a837881ec1066da2eb0a83b6246e140894185ff2407eb1c14df26152b2485227f5d67ce42642128c6ef749772acf22a1a60c4fc4f402fc66dffbcc89a569df220ea1de5f73fea746552553ef0f94768ed5832743e28751afc5088bb6e56219ce1adeb910ba4ee281fbc53be2cd6d2a2c8159dfa29096cf2542134f62e87f999a3c925d7b1abb4459b1cacaab5a6d852bb64a7a4843d34bd5d179de5977dafc83b501a986f4b121690573adfc1c40633b2ac2190aa6a1ce51834cfe28b2cc4b8d61c306b90e90855369c2259c5956688b3722f01293caeea430207e82512434da5a49a21f10186b6ef1c22bad053040cbad13eb6b5adf336746c069602020a068d70e3e126bec50aa8469c3cff4a9a9710544b0f4e27b43422df141e06ad3e850bf4fefed9a4f4ed73d76981e0b7341cfb75a1e15bf3a26961411a0adcd05741ba0372b1fa589d8896e3b0e7126ad41d3a567c89146ecef4ed86318ad83279b976a8466b3a98894ff9898d1d996fc7136b90b12d7bbdf515d978e0c6c9550c6c8f21b8c0e99e408dbd14f5167954359974eb7eeb2eb556938dc7c71ab457b7217a76e72c5b0f70a0d0b9160a28952db5dddfb9845308788b35b47c4fa403d939f049797e0505ede4915273392f41d5ad2972db41a009a5ab1c12b5dceb6c64cc8d7cd3ca15b7caa4fd5d4f100269dd741059731a5a1875aac3c7b5a2e42d43a5c0971e455716b7762b05c1ffeacc89c294a77bb55bce844402190c21eb748ba01bd30bfc0df5ef43e05a15c29b399f5b5d225ededa7fe1c3034a03f6f1ed99f4dc71f5b5314b1a9951618f7cdf59cdb4cfc6773c74f418d8d1367adb664fa951ea49122e188c43889e4e2b656ee4372967da267de3de9578e6d5198447ac5a3f8471187ea44f80076a8b826926dee7817030cf54107e1bdfd6eaa845f9610800cd5d19b1fbda9f7b33c258fd74c212fad52647eb24288de47dabcd724513d61dc29bb33f55b64c6cde3c0aeafc5ceced4a2eb0229d4695e8ec6787eddc2890584c2c149d7da1133e8f69083c69b4bd08d875980b831389dca655c275c1bd1f1107d9286b23e02c5f3c83de97caa20d833aeead26eba887f1a8a78435da0ae60d39a8dfa3214cf6692f9f97e8c8e8be08f762e0ce8d25527b3791724790bf95b39c35694852f6349d09188833345c16cace82661d865984858f4f91a55090ca808d7e3c4efb16d5f8e15727751dcba5cf26342ef389f7fe149b34904efd4295d2b5e5c8dfe70580f1c1cea7748ae78800833fd76b2f5374b1c2cc348976ba0988eedc46582d527132ea5e06e22a2ba302f374553dd251f7a700e2ec45b3aa6d1d71d2f1b8a0a8f987a609550e6d8451f15fa30ee40accf4099febbaa5214951494c3a14b578ceaa218483480e4eb52d374c627898088b4c5cb9d17f2b97d1a104160f81e25a7abdc3833fd6fd2d529153de0dd8149e045c5387d21876d178de75441bd2155899899de9d871dc17a08a929160950cd05d898dbb95a4082e4fb75e574c9beb85af5273edb5c096472241b9a2c393a0966c4240d2623e8d44d398a7169524574fa29fa41c6606f0c6ae910b42d33f5dffd08427e376cfbe02d498ba1d1789450050c874814213d00c842f3730bad7f92f6a5ed61602edbeff211a5d8acb2d0145b2aa19f4eeca659f5f727310382f50b721347251d661316cd6196af168697b866b16a34e8897b0d184b5afac080a775c44ff8f4653e0cc9d20b64d32e65443110619d0106cab77a06737f124ffde4633daf6a8dbbd13bfcc3c983d23f4fd9b27c7c9243e81eedebd1234d0c37fdda02724f668beaa827b211a5da13109a1213d8a4e88c64e9068494c690480ca463f30112f9b331f2dca01b903f0d5ef360f632455a1d05d6e0a5c7a5c81fde2d5354b5253371f5b07894bfe2bd155adee1d93958cfe2590696f98a3c51a22333137928d0211a597c3051b853745b16f3734a7dd44828f84c81358422b33412ff93959567bec8f39d82eb306ddb306f1661b4eaec09629915c38815fc263ac62646a96c9620eb4244480447ec939fe9467bd723623e32dad47f24107f9fe8c008cec9b4bd0722a8f9523a8622e9268cd5ce759044da8e7dc71184cee0871f494f72d7083316967bc8b6cd872fa588d6f30dad1550d03a05253d4c7c651c7d86283ca44a999d92cac6c6546840d3995410c037510e85d1647c35254d0b88d139b582a292d01a0bbe180093e93e278e7fcc154e45d501b7831a7b68f0c222be702c36a279c86d56ef938dcefc3d1665982f6d6fe02e2a193bd68eb5a51dded6ced2e948cbe14e8aa632316e81477ea7a53075214bc966cd74b04d998a76fb646429305161db490196eb5e84377d5f167d90046500a38336a7ba76bdd3f8c2c77b16e28d7440e2eda56cbd65872c09884231e2805e3f8a8c25c5a6c5826939da017972770b4663698eb518cbb290dd5096d15e84b75b012418cdace170aa47d5b8216be134c87d56dc251eb4124208b29230e2bf2523c0c4b705d7e462a4dc5c8f8b11b3547ad850f4e162cbacc56323f65850e4b1e2d80f25f2701a2cec0b65035c5e9d10a5dcc07514a084866332041acf43b7e22edb6dba4522d1f2840867294e67b3820e71c64aeb78d089446a2b51effff08c85c3f3f9dfe2bec4f8a9515c8fbcfddbb69ee9d7561f24969415b3e34d0afab225d2cd55619d41de710efbaaa929d3b986d29698c616e1f164eb89546dd024094414eee06ff2474b2bc3cf2b48a999005552ba1bcb0632424453d9a2b86b7bae0ead0615543eb0e6dd41a66642a440d1cbc63d830fb9c82fb97cc1e4a076461d2990ac44a00e91ea70c8b4dcf12389cb70dde222cabc5f28f921746d2fb1477483b7b4b45792209d29cd3c08c3b34a61a4eb58c64366b1d881c847a17b01db3d8b0b59fa8f7f0f81d5edc4da95e87739b6be1f869e8a03065331f1a24c28a28a616f4c3a430c1f850af9df9fc39f29cc8746570ddc2cc46bb0358353ab225e5b2da175ee4d74a32619b2586d3b9b333c2bc90de44436a2547b02425349fc897eb7705c1d679109b9201fc4af417bfb7d7d12e93d2e153d6b1f4d7efbb3bdbc5bf8a1fe7d719b91fe3141e8d6699eba21b387e090f37fb149ddbb7a5037fc9c82934491020073ff581a05007338f19a5ad5e6030199b160d8d98e003b8705f9e5251d5402a909620c5bda5770a46dba8be6aad01622027f3987fb841a3ca413bd7f9b6919bb213f864339fb175bfe926052ea3ffb6814488ebc4bfded1a8ff37e15572cdb4d7ae882c349f70bb0ad4d94c8a6931eca15e5df051ee2ea598a858686e4c45467480739f9301002a212eaf6f4a9ec39daee4584afb6f38d0633d494c329b4fec8b6d95aba32c710b3933c8a6fd2800e8dceab25590db4a1ced0bfc7630d20a24577a4716b7e3b2932251eae34019de8868b90fcd2dbc67706f81ed1be033b95c324297b1442d707466811c32aa3c6a19ee2f80a4b79c03bd3d018df3fc05eb0531fe290d6468797fe83c0c05179027466ef54f77ba64ab6a33a3e3d40ab88f4284ecf1526f6ce393c54384d8f4e5f1d99936ffaa092a16237030edde34c1a8efc43fb46220929dacf345fc9789ad721dd821dcb5d436a4d8819dd23fc08af841ad9b99338347881b05d5753076a9b2139ced56106cb657b0bdea98ad24a9ac4089294096627184525f557baf017ac49e1520041e92a68f09141a4333c3a0cf8778bccbf0f43ed031624003b6e8cfe82c1f285b8933e746881fa7fecff82247218b68a0aebac8a3fbc38683b26011d3d4f0ef566e71c844d403dc7e8912ea4e23c0c0dbc995a7ffbadfbe9d0fbd2984d23acfe7882e0ea8f7fe4abfe98cbb4ab3f46077ef547d69b577ffc4489fd32d2261f99524c9c13f0739134e758dabaaa5d0b11a4d245e9b470aa1fcbd456cee1c7f9e1d05f3488175a669f6535b6f92c8cc0c959f7085f198300e041e1c33bc4b989f2b9030c2481f0a2555907ae5c0b2912504eeacd7094797dab30cc700109fe372a2f58bfe557dbc660ec5e61bbe6c57757ac22dcf0361e4f46369b471261882798c8fd896e7d93ec3436b272ce5ec92a4d405651c93057d13d532fa65e92c30b59f217df334c7dd5c24b1d2b0b5659e9a8c422231610cf88eb82c1afa4e06654046df0c018c004b86b3f3f30f74dd9ac9eb7c2cec1415855b8a637aa5807659e5adc910559214d6e346be6cfc154e2eb40ddf2b135ae76d0c13be0f7f6a77b2464acccb4852954b83dd51443beda04f2ca0d04ad679235f3717feaad1632e5dbdaaf44e25eb37646cdfc633ca3aff2bd8912b6473c1dc1332a327059afd13c47b1e3d469a744efda053e029d12c1ab07581a3acf51022d1a6b772ee374a1c32b9b3541d2f55d7d08e49868a7657a2a090dd47a9c10a1d3e649d8c60eb436f61f366eed4077acdf742448b842f3733cea843b96c86d5e656719b71410bf5df3364688fe296549c12f419b3d66fce431f1e85ad1c01d002147df34848664c99c6248499267707b7afee90180d898062a9915218db1838c1a949a339df810dabd1f077209436c1c9fa358368835f0b81866589f6d0811928bb391ea4cc3d94689bd60422e8313e89df919c7ad51f53330c7fa6ed148fd05520b947eb6128fcd590e04aa61ef78c95d196bd704b5406cbcf56aba636f0731340f00e56c34ac0b461a5d64fbbbd5e49453445742c3e3fbf742e71b819bc2843808375162d9491e5f14638e3dd4e6257124d8afe238d7ac7451d8d45a449e89656a6c99d913009da1808597bb86ce73090ce32c0a6366610504633bcf4c295724e2aa9b6126877f533ae4b28732c1922682ffe1ce8232a80b0dce2bf2325479cdf9e3c8471e6414815fea11ab3cfae408b9d6f181c2b724c0f2d0d7b82aea1df3351efa658c57dac9949451799261ad4af2d270f72d3277d3e26bdd80d6fe6729958826366d886f3b01cb6a29ae0129a1b1f35cb77a33258a00984d39bf237659e75cf7eaf277cc6800e91513bc241b0856487917d8069a2a38e948d06f63c385f0c0b0d308bd920407d066bfc0ee8c3169a18d8c17b293dd096c7f3c9027159438e500237a04813e9a300dbd83771e126d35356cc8aea4c55aa8debf27b815f4e214a28272758649375a9fb89adb22fe6460c5f43b03aa4239c9a6dcd48c08c9bd6ba1ab01de59798994c01692118599eb34a44345b0a5c7050b9d7d1a5128ce7ef9720ddae49ac92eb81ce7dba8c0a2205d5eb7f69eefcc05506b5c8542a626d52dc4bcea719d1673390caeba82f545122ef42498d14ef32362d9303674de9f332800fcf0de2ff041d824a20a3d42e500d0f03ec8e4a82a407767015b985bdc0c8b22a84f219763caad38caceb2642d11716e48247124ea21818d5afbbeb05c57f7156e26c2f5a55ff86cebd0168601fdc856b0ff83f0280619917eec9dd25ed2860225cbdf69f18863a809586022cbed94dff82cbab0e73ab158814f4270b8294732716a57a163df22ef921b991e4bd091ca467a3844bb70d570f7ec9468f0ea81ae83a08e3ef23f3ae84417ede84017f4a17bcd03f3f59e1bac5953e2c91bfd60c7387e4e7e9c61b219465f48fed898cad860757014c05d8648824351085d981c78171913ea2aefc65d6ee4c8dca71a18a2ee3c5bee4d5874ca182796e7206be9f7bf2c74e8e1abf9ab2bf32c8d72142e4954fe176b0368f6154a5757fb34160dc71d382344d9c3adb18542ee7acc87487e4b74af5480413f500f133436fe8d4449f0c213bd8bdaa5297e95c14245632fecc3b41cb8105e83934ba7bae90a87d3d9e691a3279edc6c926ce5592320843d0d3728faf401e17970cdab8d04fb412ff40845fe755f741137530c8951ca0556b9f84ed19af725c337666c9593d07fe150df3b8a8ff650ef8a9b6f29467640cb3991c14b6e6a835cf2ca275bd7d7905b37540bebbef34a14ce48b5c483a9d42ad10e9e6cc91ff87d18a860494d20e61857dd99fc41cedb8cf46915fb9da981100f247fc080deac37c8fbd8254af58f884fff201b7ca5adabc850a8c3fbdb49cae5d95bb7a06b25650ae9817aea978dd304ae03c56c9dd5555b9d0eead87793373c8e796089d0f368a652043185a598f2f84669116dc464346eb3a14b28ad742596b2e4957a4638973d1967f9ebc209da616ed1c7f61b2de8d1841efa2e1e1a37b5801be6dff923eefea4b6afb169078ab08a871556c60167704159935900d98cb9b90c842d68ce122a64fbd27478122548470ad2946e5c4b1049c8f7b5c19c209461a2570808cd3d548fceb5a1fa42ff21f00795ad93a14b30122165c2d3f58c1bb2e1aced3657e2d0eb409a304db8633140cd38327e642b674d42a02a8048e88005f30e35c41483c2449a9310deca07760c6de4046925f526ebb41e90b9a492965c8a124b6ba9bbd666f566fa31619c055a3038e534fe7528e9ca5f8efd937ca184ae394d9ff9ff0b25dc55db85124af37000bd99980e9396997f236019bfb678c5a7782e796451007bc5fe1486f0c0482e16020df034033c66ff7b68f08037a7604fbb3df297da781be973e0cc8f674f08aaa7642cc7fb044b11bc77e516298b4aee50d45843792442f60e34a6051cc85aafbcb876c00e92119307cb3e80948988426f8bed2796b238b91097beddeb0523b582727744cfc7bea86fabb8f821f7076f70c9ce62a5ab5c7d052b57b5f2acdd9e8ead571924d9cb664070a914b8fde3b8390b73bb3beebbe526b7de8d8209dea73baca4967c2f6a02297f447fec4004ef7dd2f3aae6f145d14a4bc9621d8a23c11bc50913a70ef4acdf6b122716558af9ca380f0e9593882af72994ecba14ad2fa79fb3057ae6e6b09bea8b3049627ab3d14356582e8a6887b6cf2bf599d679db08f006d9477a906733c9177e68eefce83d8037f3a763a5b36b386b934719f07fd529964c6290a07581c28bd5e4bb3145205548bd23630d8b42a2aa4e17e51b3ed1bcbd4a1d6bd253a7c4fccfa7034edfd7be0f77d034c078e2ef42c1c640c2a92890d843c88e0522318678a4510ededc1c6bac5f626e1c0277d6229ef2cd34dda3826d11e0bcd8e63363c48a6d05cfc3b14f8dc6e8b807ec6e33cab7ad8126b92e2931e827a58b612d177f3dcfb137638a1d6cdac12db7a53c2a2a340cfdc9f98cd3dc72a49a44d6888c44a52eefb55ca35571ce65e6635a6c6d66f0d6a43790d38c08298d4984b45cbdea0609d67fa80a2019f123f23290c1e8bb06e0be5ad7e9b5c401d3aa7cc095b18b7f7701d5462077a7ba5acc390504e067de190af26b6f1996e592fab4b1d2c6f921c794690ac225092366500b1a6389ee2ecfbb27169e51819cc89e942357ba9a5dab65cd8bbe8d457ba121bdc068d3a2256b493f951a11b4935be5ef8485c8b128469d67435113d2f3831287543e3489f444d53d3d5b2801cef231c020feb239b129c06a4da5bb3f94465b2b562b189f571dec32bc9d3856c925ce46b6ecb0404e27f71339fbc7ec284b250fc66901072318b654e6b7f2a9b2452b10f5e898e401507bb0288f1c202d8976e2ce35e437fc710d29f64f97f002a5bf0c471ea49b79640a52bd1c1ba4897d3ee810755b865c2e79e638dce055498305156882a12b3ce5dac2492b723588acfb8f3de4d51f301db0ec4b74fe9d6891c98c7bfb4ca3820eb32ab087640c5b74a0fa637a15cdafd24f64910957e5bcd5fdcde25aa66412659edcbae44a4837f157928dd4adc2bbff1ef7ba46ba31486f9eaa8cc0d6ab0f5e5672916362486e1986dffb5fdfd47ca8beddbe510d274d5458b8c9551e004500cdb6714e5051ae49d4ecd41684eaabed679713585f65dd96b02b1a266bf558ac6a47efdf1a2acc4812b2309b5c686a42c96fb019c8091947d6c032b337326184862a111b6ee79ef26c20c8e4e5cd2adec473ef836082858ab5bbb9214ed5a6159d11814875e57b8948de29662556a627ee456cdca6fc1284efe3a010fa2f6c3a6d5a25845f1e757cd22d365fb523448045c0d9b0a7eacef95c424a69a8d539a55ad47ee4f82a82113cd66a73b2888187a6550c07a664376ec860de57caa9218972fd7eda5181cd5811a6daaeffb084e4f4eeb8910fd41e19db3065197ec64090ed2f1fb9bb93288c12e44f8e547794ae4e72c2d90bf44abf77ee52dcc02ecc61377e985b39f1eda254ceac9719d374c1317590b97222bce145e014c4bee08ae597381b9253f301c7011467bbee44bb699dc0c4127923319b5252511ecd32a0616e0a569771b4004536a37334096816d234dcbc1f17e3f746c2c40328e9b0979c09ba1ebf602d73b9f158e0b4aea98a99e4615d12fa721d7824b243b934a8b298aa04d38fcf8ee556ad741c4023ac685f3cd48484a844856273f68875768ab12789dd31a890bcb241078d3090827152b505a224fcc329d3303bf1ef542ed8a6a14398ed9c115a9ce4d4b4efac766aa6465d9450e4743083944da73e3e798ab011d6c4a4cf3aa69f3aa5571da26f9da4779da057ac1bf7a66e78ff7ce018ed22af1a3ac4eadc493c764aae093da78600b47e94c2d56da8a312efacbf81d4b81624755cf7ceeda3dde709dd29eee4fe3cbf988a0092b2875cc4983115c03ad7a72343843b69d0d04a4b35a55a75b4a4910f22eb97ef8e8e8db4cd59f9a0c5beb4d1684896bee504b42af5ec6eba782647f88818706bddec5b15703a92f04e59dc3155eca25053ab73b55c31ef47e4623a2500cc992ac5218d199857e0d50ada3bcdd38787947a57b6af234627155841fbba5f33ac4ea2c403948544cd8958518d2f8356b4c1411209113a3051413c38202f73ab5c40d28449fe2b0d6c2e48c5367f091699c38aae9c086cdc8d0870b653c0e5420b399a3948aa4f64c9880663faff1b4b90188c77735182334298f9d6365af59ec1994d0c2c6cc729c9933aa7e74c9772fe9fd3e7f88f801656d9cdf07c8e8aa38ddaa426b4975f50c81246cc8cf43299c78b21413310f792c56423c16c2fcd84050d315cc8888e2a11e178bda27ac49a58d7117be8343b55f21e02a70ff9f7e7d2272b674253929d1dfd6628b7db7e06306f7aa046a967201941324a5971cd99a956883ab832cd662e77a2928181e52a2d02335f999a3e326a428b413000c8dde35671ddb475222118f70cb224f112012cc39accd09ecd414bcc19fbc76b29381de00047db5c9aebbf546a74efa55a5e207a1aea495e000b226297b44a133545d3c683f4024a3866bcd4c28105861a9efba8ceab42e64e2d7ca236315517f111a72aeac4fd65d5a546c6018f4b354f141772bf096c2e6f1a7edf92055442a3346aba619216c7a4516b3cc6971a42ef6c0fa8f9132400f64cc357536e428727c2c80e78c1ab00040bb7b89b84389b011680f3681733964e33c52e2e29e6bbf97ca4227c9201186d9ec60e3f4edb684a53229aa749fb684b5f293a4090c45c0254266d860c88901618bbed3160eaa80124773b316c45f52736e2d27a136be58f511253bd05839475f1de8cfc552c58a2b39c494afe3b9fc8fd2ecfe33821f3ba0a134d9174717501998d3141e6e21996d5aeb795d9a796d64c82b4639582592836ece4c66212de59246463bef521c90bc3f6b8602cd153744aae528ef7921edb1b1d052649f91458d89284d19cc24e328470a667404a6a51c54d76c193143f3702c335576cc5a23093b3504ea06a7e1d04c5d29b892de3088f7e0819a1b4d74f3bdc3146128378b80ccee7837ff8ea47b0a7b0d17a459c0dbc05b90ea32a2d6ef72b3102884959afa1fc2e33f43e2458852399434b2e616aea4feac9296607794496e04830ffb2e8c305d1681c6a69507aff41933681e04c48773e8069550f892d9ee6383e52a2333a680a166c040c7d41a3ca3253c9b9fa7d8fd26dcc616ce340cc8de8ee6d9b2573496ce9a478da6e44405e715132d4fed14359fa733e90d5689f10ebee7ec5b78f36e211e1b55f416bffff44f3d545fb21b4b53b8898a9f2fd68707c4bd4e40ac37a4b6a3af03d241e546ffa0cd46feb4994bc3462b197353d55d5dcfa1ef4d51250d8ab50c454dafffda6f539e658036a599e06a1e4ec31a095414479c7d6640a674768f133f119f9e1e7107d2f6b3d77ea0d93979a199ba1bcae0d0ad61ebad48ad8d9d35b1d191100d89604cc9944fbe00274bc21c557412703c3e54315fb4407c7292879c7be9aba5322588eaa63d133d9f8eab42414bb31c49d7725b6689226f1a5cb4626d0415b7b5ff7af13bb55da3c2693a641cf4bc03071e34a27dfcf505ba18d7969b2d26076ef3ae7030f326379bdc17ad403d4ebff64af0ecc702e7a332d114e444339228e7ff37c1e5bed92aceaf7d9eda6e06db9334485c69776d47488dba75655f61d7632c9f289a59d31df8035a906742e9e29434441173115747728a217f2782e2acf1530e3812fe45cd3b7a0d1c153ab27634b124ca87630d54eb163e428340e9fc352d7e390a3483fe5ac35d31b30af88890a473aa6ae04aa70a497dcb348db37b69b952164016c832412fc85b06e274cde7470949ddfeef78ed6962ea9751b0f48bce7a3c940377610f7691b1775d8d9f01635f02052ddc151eb962ab68058bc8299e12b8696b8c189ec1214c0e5c62f70cd8d07d8aad6a08624c6caca68df5554ed8b2f84b9418847821fe4e8e31a0971d3e9d9f1a0a363da6dd51a4aca4c4255e75c07dc615736ecbb52375d395f1ce3bd3d1287f9e6f9dec193c91966de30854dd52d3922b23e60069f1cad998bcc61d447330d94838cc32fc567ef7ce226d94679ac3002866712a69cd8a4ac7efc72498205e8c4b35062dc773c0d850f39452263f224a1aaadb4886b9c69fe2fade8e729491ff9a8ea75413b3546afaec0605a48411d4586c38ab9ed10cb967aeb7f36c127b915c517d6208a1ca3b738b589018c8022e064988ea3cb0b8e1936ee850afbacf44324eb15094b1897842d72aa2a04ed94c820a18ffef21c9b2550481ffaa633a28f3ef14437be7842a56c44f13ff4515e2522848561cc29d0813e1678cf7e578633b4c74d9f657487ffac966150b5783dfffa45f064c2a403da715bddd8f29c9e5576712c339553e72b0b0cd882c6b94bf06a27e7b5441e9606366c4bf0bbc3da10ffb022a8b385a27188af9a5dd60faa1f0e2808082e5dcb89c2d2ea88ab88e79d70bd76872a171f1aa18e56ece027584d67bda7f42d4aa73568a9e71706760946bfcebc71112a160593daf373b52def9febb353cc247a54b1ccc100710e5d661cd5517fb47b80f4119b453ee52f6463dc1a1b3a9c5131f9ff82ee41551c408e3a1b5682fac638960d92b2d0abc6ca02dec3b5703392ffe3ad41a76dd3cbd093d7439b653d5a6bede0acc893dd43e7e086b9568f6c0d324ea3c04a48b2cbcf5df9a191ed8dcacc92892ba77d5366ee43be436068dbcf68a03f7aa485b70c14ccbe59877e4c5a010b30fb650a6684eec9b80e04b50e5e44a1ad25781de17d04d808d5e4f5ca78795c21a10a435a2fa5d023a5605fec32c6defee51a4260ad6f495322af1533b91e78b536d4c50a6da36df6dc3f88030fee5841e74da915dd1df53b597f530e1dae3b0029ee0333d114f1696ff4a8a29a93967319198218024658f4c228faead6b02622e22ea92a468a75e0f5d6eaff6c6ee9fd7d87a75fda4bbd2d7f5f6ae368ff52cd6e9b1362fa39b7bcfe97fd49f90438400d10015ae073b901f2c63ed6b9264bb8655f52af36a6764c698dd06d45d245d4e1713bed67079e5cb26ddb9b4a7638939faad27545efbce419bf53a651c2aa26762f4a74551512276478a6dbba976432e6d385ad5ebf56ff27eaaf62bb97161be1587753e15ea87b771c91ae4a6480381a71a14ba80b0398f61f64869ece92404cebd3a2c7bafe1679fd580362d3ac1aa0f18bfb6da5a5d0e98cece7d4eb5892a8c6547e25a1bca428cd497aec6c4d514f099c67493f6c5aa8f1e0b8a84b3205b3f80fb901ffb3e3913e9ef1eb7493bf11a8642ee7823042c516471fd49cea68c7d641dae148e3e3dbf611149e4bb8e59186b1da954c051cb6c31a2f5902130cf1893f61b62ba657f0ecd699c846d090b664b935854cfaadf6617329e62c07639cfb1ebd9aad480c2b5eec4802a26c4ff83b6a927e0d4113d440ea810efa8c6609cf2c27d888ce3a4dc497eeef59edb5c2bd4f3045f06c13ec0501b90b0daf32d9e5353bfa1ec2d5daa1118da9fa2894f06cba97a741b11f77235a3526b8fdf59855be413e949361f8a6eff637ed8b9ea4a4710613cf4429dc27314ed4f1afbc8c3439c1ce15f8ee243cc8eecb19f1cae6c9689879478ab58c353c3fb1bcf6bfc3a7dc916d442a4911367049f4f5d5becc7c4af4115db7d6f94ab4967bc2ed2b0de71840ff75329d305af096819dd742c226e1a5ae5b01118512d302284324bdd0650e7988bd0b0982bebd9a3ae19f8119ac3788d0405a0145b0cdb98316a551492244f5a7119ffb1ad802e52238872cc57f58119c4272f806952aa069057acbe6037d1facbdbcc74c7f1969a219bd397691d00e1cc2ae4b4511c988a0e64149da2a6262ba3b502757b37ad0f5dc9ab55094f844d6ee6ffbb93261d640bfeaaf335f11877ce474564e0f7b085322339c3795c7d4ee2d4b8bcb8f1663536f5d3b4d0ea53e1a47686636b61e1fd4818c804b4e9f1f7aedaa8c978086935e26c4e51284e7b65b9d08b789d2f02780c653416b3ee461db3327fcdba9f6aa3dc59cb09af179578a33f5ef6dc5695b4addb2310df0f6e1a28524f51ecd6e617ae35d2983147b2e60be50f0208c6248b068adc23682c93d7c29a620d165e9fbf22a7fa440fff14b1ab0664204bd50cfd4489d915207998d216171defa09c07231d3a8f503664cbad8f1e91de6252dcbd8fa5330c3ea35a4718ab3fff4a5077056bcb8aacf2198aa4a545991786d97bacf5a9ce0e9cfc2d775e7eda764746f4aad95cf66654c00a35bd364740deb530a9058030402ba622b1cf36372c1e49f8a27747fc4f187d772997b9123a4d09baa87cfb10a0350338fb81e43e9cce02c6de32fad0da4e266363fb57361a0b23da57df8ba3204298419feb01b643fa42ec3e530bc63e96248c21d3da7fa7e5f0e6c3110ef99d3714ee96ac2c09d76335f3dfe4dfa6e1ee51f23a432caa04daaaf3879e20061c709e87e59ffa64982249037114776f2e32b8a984ddd0156c0b8db0ba43f0c838db8cd910c58758bd3f8a5a5fbb4d5c21528a1a8be387d1b9167e1cdad5293f9c513d86d27a04af1f2a21efeca840c9c1a27991948755a0dc9dbdd5f5408c85cd71e15681d25959d13eb41c752623e71001232f399b5bff6b69a2bbd5d67e86c6c53e505f101e3553f8e9058979634412c02b40e749d561f7425e1f3aefec4f5b58535cdadc2e66e1d9da397a7df5ecc968dfa27d76f19428095a6f8afee9a5093bea1a11761b0e862f22dc36244f601990520c6f937bef5979448d4f5cb35ac1b04c195fc7095e56329fec483d75ed595aa8d6e5096e47d172d240d5e4658712dda816f74e70b7722dbfc572a205d6bfeafce3c983fb4a5906e76b8f7e75db74db385c426c23c3a43b204f40baffafe3e3e3bc9a3ffd8233aabffeec6a98a5251da45767803bcca9af03930abd02dfe44802c0e36fa45f5e663d1e1664f690995583225cfdb392d9db4295ad43bb7d06e56eb5e8df8583f3097079a62deb1cde12660bcd75575bd91cdaf87c95fc353faf3b412dfedcd40f36d88f13cffecbbe43649d9c2c798164841dcea55e37fd270cd469c46dd680e3c18093130e25e3c9b923f2ec9d441086f12c8022668d257f0c0c98a4a7c96ac2d9f0af66eec6f382573e17adcd78000ed6078fdf6568f4ca616efb278520cff83734aea9c90024a876a277dc8b55332b8326b40a38337566a7d2cef8d126cc68d5408e73d0f87ac6b27c69e334235e78753a7004f80acd1478588e94bc987b2f99604c401cfe1bd1293de1f5ba7aa3428e4d9db94d8eb7ec2fc4d5430f74ca668e6a0110ca3759e263db8bfa3c69e1c051b35271ba12c912e993872d2110f0f2d655c941f7891efb3843dc933dbc2585a5ddb9b2274907a306c3dfe63204262bb79fb9ca26d494507597e7d2303d9d7963f1401d84dba8a317606db8a986dd6a31f9e0726e15740d828a26694d0d56db418a4ff1c014462686953630fc28694d01a2de8a8fb0baf83d6efe2034d750df1df1b1c1021317b02a1dc150c4af48994c7a31f445593260e582bbc178e15ab30cfc9e0308bb2c6657eddb1118ca8e0292030cd1b8ac552ee37d44475a830b6526fae40f65d6ca88751e820465d4c799a29a9a6f6727651a5666615888f01ae97983f2af84f90f78a82f8b5cd287b2f54b5d8a75e0e20f67204fb5446b226306b6650bb44b610ba4632c7a5f755154963ebdd97ab6fc2bf992e057414d70f2a0171e48f8fbd30636f61516d1b04f27031cfca4c02867679a317da69c621831d648e1fc75792638ad51bf03dac1936091a7e893bbe49858aa84538065747a6e5eb2eec6aabc9e72b4e427b5d3e333701be6904a531004306d9e2904612d3c88a22d314d108d10c222cad897b8e59479e912a529562f50a62b10ec0e30af350eb5ff279193b1aea53a92143211f8ee3da2b628fe689b5e6476741a30f3dae90274c0a4bb6cfffde67ef1e3be92f1a45792d7811492e0f5809aef3f096a2ac9d673cb1c11526b79bf8b87035bf54ac8217717e1ade39f0209d4a55a8922a52e6a4902087e02e88093839208f7db7e6677c69d3e1476771a529cda435e3b9b96f5ceeed006a76713a2f80519646f58a91483150afce7b11acbbbeb729b6173ff7778af03c78255730b9d0bb7e76839af74e0c032b26c58a9f8d2bb4cc76232c3c22b352cedd1862ab6d05462757f0b3bbe9b0a5fc1efd3b23179145ee30f61efacd09c223503b8d8972e4b8d83273840bf856e96361ab7825f075876764564a96025a78389ea4af4076f4f7e7e861ab501a581bc09a600a63366700d8eb888c40ff36331643ccff835b3e48d36758d006455cd22799de9116f2ac3e317d23d6e2513ca5f4354eb4d0a191fc2ce31996004f8fdb5aa8d48829aa9a0ce7d4e60e811f782ce7be255f88eecf086d08bfa1e48c13b2de4763a9afb9cb1fdeb102682894f6f85028e10885857b824843e156fce2889c016fecf42681ac82a70aa5a5cac3d8e6a83ab955952d405f678b798c87cff30b662a9eef1795f7827a30d8f595e482dffa4474e0ab710b4caa1afa83c0704d9d617a7ce8f07c1ddead90b89fcf297000acc1624478e1cfca850b7736288cd403b384022edff9640c55e846228f96cfa71ee10444b997612958c26334e34dd9830b5f7321269977276b38750d1150ff3cac2109d0619576386071b966780cc552e371914146ce4cae82847232c200544449580f36c889d7e904a06dbc109e93f506268e8420d654cc8bbe4c0ba0264133159a91a2493a9aa1a25132a326e14fd8f9b466cec3034122563a65afea0144ee46c989c0df740a3926396a1cdd8dd8ddef7d70ad0f0e3458a9d398495ed4d71db6ac449fa106faeb9e632982059bb3872e805bee9d10e84da925cbde49e281bee615dd388ad8a39f31a4f0b136ae110fae0c04b30106a23e145c57d2f4e8f38ec70521cd753525ddfd5c30a8a51d972feea88b0e4ffb8598c59928675838134bc958fd5c0c76fb77d1cd7c8de897a4df81dcb6bd6799d1c9f76d3c719a7f928e9e46963426aa274eac3186aea59b31367f88aa24d216de4e7676e3859a3f074ae54dddc0606476689452ac012f057da8c985689c31d9a38faa0149aa171f28a5e8ead9986f1d76c82f3fd34b4870f5c8396563b7be4d87b0dc4bd8a80bb1f9d33e5d384575e80aaff6ba54792d434c449bb142f908f336c8f1e4783e7e26029f65d1bbfe21dfa850a421c9c45eed37f7132d40fd3082e3451bfbdff05b7109a8520ebae62566ff516b51e30ccda6019babcb7916d33d1ab7dae3f44fd59dbfe21a6b0233b1893cb2eb33ac113859adbc53385b93d85002098ac129527aafdd9018ff07fed8aa32f156adcb07ef7987baf4b56efcf1a36e9840094e6fe08e468d3787e0788de87ad8a51e1624fbe4fb8c59a936f2f60634d892ffa7bcc83fa6d7f19557a99e21660dc0c0a4f5aa25a9b69078147c7d9ae1d4da685a1802e2f5cc527605d9af646df9dfae63c9bfd411c4efd795e3885d3d626ecd059e1d5d2695d35e985198d0dbf5e675d6c33d775d7f0c5e57ed948abaab06ae26013e2077a4d4c6bb68b7be01186f99b313f1e7aa838a2591773f134f7d2b98b6e04f369a1682c2b1084051a606f57cd374bad7acb6596e05d3e0a11ccc7534dafd283e05d20cbc3f09746a44f295071fc9302c0d0083fbc0e0fac5ee7f92b532f18e5153cde6c6b5fc1ee7173e582c28384a542c4283d88633cb9ffc7c0ab6b875b561fa9b5e40549cd9e19dc77365360d9be91cbb0a330b2262099b053d45b437e58c06c937450365d8b8d11307336e604b8ba5b678281e3ac0459f41ea89890dfefadb434a3c72218fb93dae282c5da28941d78291ea8808eb367081ae8620041ddae831d9c7a66840561b1346015dbbf62cca31e5a449c311b4b91ec9ed1234c38608e3e43096036de787ced6cc73defa499ca9f8eda1d3d794f3f30643e2302498b3fcca264569130b6ef3d80ce2f767a2ae9e7e471d1082860fff5eb262bd3698fbbf06e850169d35c6dfb2f2a6e93c32af6b09765958ddd51368e784f32c728da23d2af9404d4c24a8db4c6f329d44f8871e4fe85969bbe2b9e140cf6ae2d0ac3454630c7f5a28a054a159589c1165c204e4b075dfe35cb34667303f98e5fb469ffb4de737506c08e69085a0808b7bfb4b4b8169c951cd375ba14797e10b321d1720fd333877a2d88fec84ba4d8ec1d9eee93f0db6bf5d9eb4da11266eca8e2ec1beb7b85dd5726a5cbf4763f91a98ea769534fd1935fe225b0ed395dc944a96359a5041df48084f4205803d7ce4e105c756a614a7604766fe71dcc2157db5668328bfa18237072cdec3a01c6edc0d7d50ff38f3baf48aa2a086ca463950c811446f8c494b9c81f02e341a12d617e98346207736d9d8258c5b68d7eff3fc3da7f378cb6dd92468d9398c5ca6c42db6536b22e6edd612a6e6b376dc3296e7c2a591e33dd2f86ccf037a361ba6542020554d07593303c0c5152007d02e36d14ba1c0d6fb1b38bda3c2cbc7ea641c956cb05a007c2b4860d60c9cc3d109de7bb6ce4f762c301b8bb06c16e5ca4dd790cc30686c30502f69bbadc9ddd6f696524a2965510ae909750a2b36f61472e6b464c2a8e394cd82c2a92f3a83bac18451ed604e957d44331acc31c9e8d1b447306753077fcc19540e248c7a0e5240ab324c9b414b293267c225314536bd3ab29f1fa1391316c1086dea60adcac2a017b026035c3267422531c0259bfa475465e10f0cfd11851f514873c181e10499336191229bfa8b20b42a0b715a682e6845e64c18a445919f2a43d558fcbc7e84e60c6a8928b4a99f6a2b4eb5ad428fdf923983129a30ea294e4b3675144e95a16e30675045268c3a7d514769140e4aa3706ec0bd1e39a72dad4717da9e47f325ecedcec49b1f56f1689e6e7eeff5cfe5957eeef9e591bbec1acf3866d1c6deb9689022851229f205022485122a5424a122df9c1c153358b1e2aec8f7ae9041ed8460d18ad916d9a2f96dfecab3eb2fdcb1f05a941c27b1dd18caa96318b840ce843b3482c2a009a345414864907c51a75dcd4712913d3c5288148bc8d79ce98c2061140a234808f296f07d757bdf4bd9e26939714909118d9f22dba5f560537fbd80b0c838ee6ed122db5017302859a777c3b409a3249fc14513469d3a78024bdff1646d7727a4b349aa1d1ada3f3e54a44e73e74c070509c3454ed05ad8162fd89d0b17b4641c77bf78f1e245122f6079361d966de8c62dd8380727017ef753a4e6bb1efa1a22840748b7842e0812769bd00de11bf9d6f9e0e7d5b08ce36eac612c70a1f1d84607f368fcb5d1b97834dedae8607834bedae86278349edae86478347edaa8f153beaef3f052bec00dbce41bf0652b6d4ee3a50d39b19eb03c03332eda70308ebb49dac2c8b6562be124680d0df7b231f20d1723dba0a04dbd8ba1828ce36e8b4446b64029f0c93bb6a7070a2a527fc9f6887d41c18581f9b131902aa3a971ea5887c6aa53af796b693b16888d65cb23f3e63772599e8dd2c80736f61b841306d117ce9c41d1240cff9833a81f0c84c687828668383f36cd41452183aa995043251fe5cf0c18dbba94af6dfda50c1759190d1f55d9add3f89a97f54542e9546964e3470da1a2c05ea322c545d5d3248dd2dc49eb16de595bec61121e1fb0ad774e6b3416058d8d9c3a6ac8ea3c1bed9d759854e0841936c636096944966d8ecdd9f4c3dbb5dd8894390f2c9d42d3679242a1a856decd6fc5659ea938cb65b20dde2b2a385cd2d15274b88485a22a720f8b5626a9302854821206a94225281dfe70e18f4c6d131e1b853a49e9716e93949f9884a670485824ecd9214f131f580a71c2206088530a71c220a7ccd596807aec8a7c255d5be275a31fa19f1f21d2765143504550348d2a627dbe0a4328c65a9aef8ad017f58fc8a64372f20c3aa54969738953e499dd367c00d46d4a602209449070848e2665ecde8cd053846f8eb8cd460f3d4062b1101622c21298366408df787584680cdbeb3ddcf03620295f68e9122aa37149a3af8e8cc6c75056e3a357a3695ae79b759b10a8acf7ca20dc5a29cf17e45d9d39736f306561d07c51a7711a9261530fc33065343ac4a9e18c551d9e6153b721ce0e0e2e5db73766de57653f9618b9bb4634b36672e307f6c8bbea73eb46978e36bb75a3ad9b1bdd3804db5229e279e9d4d7ceba172ed56bd0fa846f64adb5deea3a4965e77927f348bf43c3391a35ded1fcb441e3eb919ffafaa94115a802812f6d80255226913a9ae796ca3c120fbe161fa99b9bed91329c6f8eb7d6267d1454a4b5566bdd942d5ad8d96317844d695414d2f1c896d6e6b40988ae601cc1cece955ab86e459e6d1b10be51ed60defc70c52f6c582c2ccf6ae7120326f3d0683e3d3d305c6aa579cf060cbb61e4d98cf122eb762a4e7de1549d0a8445868d01e3cdefe28d441a797dc2d77917e3cd979be64936ee0e8de3dfa9e96a9e0eedd05aada852222a12552f95b2572f57ae7623279136d7d8efed5ebcf9d98dad0c188fe647db4bcca3798e731899043d973c831ecb373219434bd5697eb321692cbbf50cea589e95b4a522cde38af1c8ca68a8108e203a7cd3471ab4a9a57929615c4dca33abdf93c5783606df8869feda2071b4ea1d1a977987f6d4283d52698d26318d63fd83c922e4a3b1310cda412e1f7cd49529508abbddf72fc6f3728d47f3f6bdd68c9c4ba38de495078fe6ab8df94490006763cbd9d96992de7af08d486c3e1a491310cdf38a4ca92b99642bdbd4bdf160e593f80b1dd6a58ce3b7d52620da973253ebf5e9c226470e7677b7bd7bd679ad9d396e3c1cff1e0b715cd44d4c874c3976b3747dbb373ee0604be768bcc647558c4bed44dc830ed33a5a95a954df5761ec186d9a6f7cdfab2977036ebbfdb68ff7a5a9e9689dd3cec77b77dd35bf817c038e9e5e11e49bbb473f77cd4b1b348f978c70112eb25b6ed6074ffa05aa2cbcc11e49194cf363e4b9f4181a21aaacc669f8286b4541a249868bea8b8641793eb7f1efd4f8a534b41d0a849a00e65e4a02983cdbbc8b7930197b6ca33845455b8de18daac9320ebb834f96b1c7dcdd3d27c539f5107bfacdb7e7a6636232f61976f3cc90f16664ec327588a8569391c9d867b20ddd16175d9d10e7abb4f974d7fc04f2bc23473a1f8cbe1342c58ea71bd2435fd47f36f5eab3a96f5727c4d11943136cea333479869d26dbd0f97377bf43c3b7dfa971120df76a7c54e36110bd3a13463d0cdab5e6278d9726e886d0174fd711a15767ce743c90b0aec8e63a1fd0749b0ebe8ec68669d090a4d27519796675d4fa03101e5765342e5dd2fce499b48b2ff621880f79eae0f0eed72fa2625ade6347cb3199354723fc567272ca983cdb6855e6c917465922e4d9d4df0131f704bbcbe1e1ef84743f74341c50ff61ce78a5977b8f9d9bfcfbd1db9f87353a7e60e72376ce7afcb61c7cddc851ce63e427f750d955f9c19e6f7432f21a239a7c33f2937734f28df52b8229c5ec34f2cddda0d3c83a6611a39ced1135f9c66ed03bca43bea1387ba447ee83db28a724d8e0942dd979c8b3d11b41f788e479d6347906ea1af5fb70977e6ed3f3a0e1953c1fd9cd71b486eb6a689cf330cf382d3f974df39d908e072fa4853c3426b34d77c4c8473abc9f3ff2c4c14555d6d154db7191380ab15d52ecbc03800744be24ef7247fb5c0bd823c724acb1a5e20e8dee80b8baa3cd24341079e600e0faf521cf00e0752ebbda50f648cc73864d7dec306d246750b509a3dd8e05ecc842049182186dcb494f4a113bfe01761aca1776eaa81aaab6e93b2000f9e6b7e5044000010c60007936b76d7777c41eb9143b2df19201cc1f0690737858e800618dca687ca4c71e5e4d282888e66f109a182a528f0912aa6ddd7643dfc83a641784d0052160b78ef50d8f00b90615e9c5b42ac345f445394cf3e10f03e050918639318fca425a7d511fd118a9b31fe6509106f9ac8f21cea63821adcaae8e4e4813c253d5a007c833ebf7c31f54a4f4eab83e14fab01606b9a0220dda2201429cf0479863f16c9675b0e88210bab02deb6673eb9b7ed180aa00d9c51a20c50059f5443d407880fc7df37768fcd278605ba71122df8cb69d7b3e5eb2e1e0221c7cd41190b92e01a4119700afb439be40e499d5b6dbe199c052f6c00e248d3870c3e0056da5534609df6b533832749a41062a165d10821754b5ce5a6bad93ba1768ad9bcb5aab1e91382249f559379edb943e5aa25a6b155d9ab80c4f2eab8ce5295ee2dc73d673283d62b8941eb9aac157ff6389ec798d5a7d7b49c5c982392367121b45330d7c8302ca73134fa93cc539e89c9bbce39e73d37fd339ce5524079d7b92773ffad89d8e8ee503129b033980c42ee90eb436a759d979949cf35cd21c57d2a30fd041effc9afecb6e32a235f30ed0395dd2ac4efb80c4266916c97994bc7352c93b2f71268ef38f7bcef38f9d4bcf4b9e73fe4d9237824ed2a0cf076aaf9ce6e17949f35039d7c31b41ddc3dbdea7c71ede56a9383d9a7cde7da07f9dc941ffc0cec4a15028d4f77ddff76d503081a077a0e9471f289e4b8ef2f2fb3c37cd1bd0373d92c0cf3e20914b5d2d390f93775e3279e726efb49f3eaf51c1a7fb0359a0f3f8dce4ac9bcf4d6e2a69cf7d7827b4e4828e426147a1091985193303c6eb37c618bb94507802added539eb46e2ce0a8511b7d1cdb7cd47daabfed1a5b7da6aadb5d68eac73d6376badbd761bc24ff52ca9e42e5e62281547d896de22676eb82c89b339ac2dd9d24fd9d2f9a45e83e6964e4b2a8ec41ba2c8e91c4150910037320aab4729a4c39503031971dc26ba188d46238fb12e2946a3d1e436acada66d00c224fc852eaa9c85ec13278cbac7c136fc42452ac68873a645c2a8ffa860a20bd9427d34ab9139735dd209abfade698f102bd571f7757b2d9d4ed45509b6744b471c4dd993d35285f7c85d3e6754248cfae7c2b55429b2857afd21bddd7dae50856bc2a8db3af1ee70471a3dde2317756984a6856ca1558bb285eae0234d9b5343cefbeeb6f6ad1447f608d24b298eb4f42c6755d049d7275d44e92e2f3134356ee4983358969e93f955351797fb805a67ad9392b8bbbde872d55a81ac30375bf26c3797e862ce946a9ee2c47936e7cf3dba97fac8a7084625d2748103a7ce393b6ab96069e49674c3d7eee09b3ac7e67c556e7cad376d954147b3b7d2cf4e7cb5786b95913223b74ee74cc9eb7c44d956b6a98392fbb97108f266f2ce4a4a29e9e9b63466e26a9e8dbc9b399cb5ac23782a5b36aeda3c1bc9effba8846dcebd95e2e6f939e949716bd9fcab3250be36df36bff9c6a79cb534724ad277eb309df8622cbfc421c16d17dfe9d2a5b90975b2e59345bb336de974cee015d7d958cdc9a25a290960f7866e3d671ba84871add5efe394209b6f7aec218bb62d703ece209b3ac5da8bb05bcdb35ba48333d28318ecaa015964b22e5d2309c8cb79ddce25cc59f5c887f6c9e99dc5f5d66aab26015962d3c2a6850d68034282a4db7ec43d1bbb65c377fde6990d3a9db67bc1ea5d376987bd11fed55e75281d8732792a6d344ad9d551f8551bc5914c4a414ab5d64224f41502f9e09ba6ba6561c3c2760528beaf36e104140882a512f87352a327b510a8a4b34f684f80de668593b75501e5d5264c30cacaf315cece71df9749240a1402017f50210ae5cbb30d9fa43c6ce261b0dba2703242d950308a09c62b1414c628d6c6c22c95479360c79b579f4455e528ec276ea2d229ec27284f7de8a93c0b57e60d46a5a0a4a4641d756fe116a6e4196a1ef9a67f295fe559e81dc618a3505aba4035f1a1f028a636159cdaf009c94d2413c94432914c2493cc38b03ea145e1c327261885531f22d93e44e910680a1dcbab4ef846ceca36291b24aab295d75d1d7fddd5f3c01faf8615e833c9385a3b0ca202902acf9aca8a879fae4cf730083a07967e70e9e7878a53f8a6772c7f6292fa10f58f7d73bb39de50db09fc4ca50cfecca2f00b21100845dd630834a36e27121a0b9a42185b7bed0991095d9983272995d139e130293dc19e3e854f524a69b534565930299582b7379d92b2690a158d7ca38bdda2859491d593798a139f673d8b2fbe2e4d98156b8e6e75fefcd8705676adb5d65ab7287cd5efdcae7542275ddd8693426397fba4b54e84a17bbad3db566ba84ad936bad17b1d6b4f1b719ff8aafeb13a565e9f3c6cbdb6de2dfbc159dff0e6491470dedd71176397f60e5e1754d7690cfb28dd6a4ebe27b58a8a150dce6d6badb5dcdd36bf9b96f525e9157eb40004a404a5cd4006f3270613080ca47f52f84c73daa2a95a9db67429499b4a6badb5d65a597fb823402309f6a53ef6d5b6085b2b51372d476bc5b37e95932d555b22e61da6a45f087166d7b14ac99744fa02a8ecea50f9124353e386fc5c41c830ade2a0a1286dce39499dd7795d6ec137a26a1bf583aa89df7ac237770b88b95bd79b1f8bcf6fe572792ac541143f5951b93b8bf575e0835efa53cb41d055783ada1cbb219f836f72d48f436c14a8e304b242fff4c8da9172f00bf54daaf4b9dc43d4a8a81f519ee24f265e0a777c0eee30396afc342bd4372614e8253f816ef223ca5fe5269583fae42cde6d3303606ed0a4fadca4419fefd3cee232ef5039a879a8dca479a838e83eec06b50fbb57fca4e2df72506505d4a3b358255f954e4e4e4a7e02fec9e727d4898325fffc8472e2ab13074bfea1f4b83a69815e02534e748aaf521cfc147d3ae9b15bfdc9e7b7f2d3ca4fae023c812a1c7c42e873875ed2263e4bdef252aaf43c52ee6ab9cb5d2e97a74a3f0eb14b268d42e991dba793d3bca4af9389977ef461b7cb53f81786ee72971e531efe98f2d0bbf047ba3fef6acd3b6af8a6ef43f9e969be29394ad7a8dfc95778f83c52ae4d1ede94f44745139349f34879cb6bd093f661774abbfcbd4655f1df065f6ed7cbbde247dfef297e1c62bf7b79b662d1f22362bbc31dee40b47dd4dd729b6f52bbf5bd6f79263aaa861a6a790d2abed65efaf1db250f73b483a01e4bfede7d135fab15a4bfad1f891d06ed9f27fd2ee9ec7f46790682a81a8dc92dc409df101a1b51b44d0b8580a4ac83730bfe041e4077686a5e1814d6688ce3dca33194737af461471fd68a7ca391d7a0f4d4c3c78e7681a17c72ce51f4541a791038b223edc3eae0e10e77b8c3e65837251f7949fbd046d86c3797870869de87426c58f330880541b49e1f1ac31e5a223e5d111ac33a1412d2a848b7267c6347a3d1182784c6381e1a1b42634cf83ae7389adfa45379404447867e6a3e413d403c3556c4bc3a3ad8349773892e5056acd2e7342e5c5e68ece4d2636adcc831011ae3fc0605117d4212c7892d47195be6fc40657768cb198c0343cee01f1346714e7d51d0679ed115d4701a3cc8d387529c5ef32af99aa0844d9c897fb0697c54d9353ea6685c1a5ff3343f67def17bdec829ed2cc1c7f3f17c3ef4459d7e3e9fcfb70509a3fe6de1eb828451ffbaf07d41419673892e7248198ff31e52e6e4d887a0b19263f74163a0639f40a4cce7d8a712a1639f44a40ccab14f1f1a4b393671ec3348caac1cab1ca338f6b944cab01c3bc5a13115c74e7fd0d88a63a746a4cc8963a75290323067c6477a05191f29928d9dd2a80c1761da83690e9581b41998ead441ce8045c6798728a80cfc91f93893c47c9c4ac020674021181fa7187ea80cacbdf8388fc8f071022541ce804b62f83895b0f1c9c5c72964c3b0cf18c8995390173ece196cec1fa0b2538b0bec199033a7222d7c946ed827163e4aa117f61b3973129a30d147f9c4287ff60a77a1b253adbe52f8189d8e7e0a38cb57c05ffc04dce525e0b08780c3f808f8cc3fc05b18f0d85fc07b3c08fce52de032de01336c76c69d1e13185a036c63e002160041057e45815f4d40021180c0039e85e38067fdc830b25c82d9708fa73c3b94565f34ea9333ede929c5d8fe05de3c17381af054c2b03f8b7e4f8ad85d3e94227618af922276d8a74811fbccbb6cc19f1471cacdef14efb2e72f77b77d8bfda57c79a6e25d8985e761d36be7bc7d2f88c45d2a71a00743e3437c077c03efc339d0c3cc655ec579bc0756a8a410992a8d89884849d16a094e7db17280e8d0eaa682ff1b97f13446f4e0aebf31c417e1369fe229befa8c577199c7331fbebd8aea3ef3d6ca65d1a59b9ac9c403e4239140f0fbbeeffb4e43ac24a8590d1e4a3dac86546a4a29e3e8f66a08e753743fa278524fba9f7ad2fdd4936e3594f2b66789c1ecc005066c46c689cbc55579f6c2bbf9cdb8cc3398772aaff540ac7c00baedf5d63f97144dfa838a383332282c099ac37aa15743402810caca54e7099d949457d2729cfaaa0d11b58aa8e802033623a3d5235b50f0a54c22225fa9641c75ce21a5f5da2ff48a280e9fa4a28aa71f01cef209f0172f84bbfc011cf60570186f009f7902b800dcf50cf0d82fc07bfc07fce515e0327e007e5f0ac1806ff52ce05b34057c20010810e200062800019e85338067fdf881492000cfb315ef5e4e5aba0ef32b7bfb95bda24724762bcfb8136f7b154fd9f7e5ff6ac3f89d221ca6e7915a4411aef3cefca9af9f1904348766ad5643d97767d4d36767f6b8489e6ae3cd95e26d6f92e2aaa84815a58a686c7420077279325ec55fbec6f6d8db70d7dfb0f91d9ee27df019ff83cbfc8dcf7c0f0ee3691cf63377791afe8207d75fe33cbe034ec41be1dba3526e7c185ac306de03eee3a70d0efcdc99b3e6819f3c9346452a272de588f1950f807f10eee3a50d2e0767c43b10dfe1c30f373a7a768d212545ab2538ac1f19c7b655f0492acaf81efce5b70d8ffd0d777d75d9e7709bf7e1c6653ec5677ee6309e86c39ec65dbec65f3c7696afe1fa79f0ed4f5765680dde5ab91c6b35b4225a15e1e4641c77fb0fbff9d6925611518e6f0dddf816cdc6b77448de5ab9a1de450c25a122510d0d9a590f5f5d5aaf00b5cb666111bdff1d3ee870d9ff7093e3860dbf3b7ed0e1c34d8e1b36fcdb97a5c2f01679e6e22db28ddd2fbc932dbcfb31bebd4966680d45f8f87068d6b6ad6c2b57d2137c33bea5a445a4b38621162216a2971efe222545b661e1fdffb0bdc77bc061fec6633f73d7fbe0b2d7e143bc0fdfc017e11cf8d16d5ec5537c8acf78ec325f3dc6f7e0dc03c05b0f048ce7c1615fe32e5fc35f3ce73cde0827e23be0db9736e737c5758ae890e3860dbf0ec44214b4d2f2951f8484c4200629235b351f6e5c2787769d1bda756c68d7717db5eb6cda75b607586af05053b464d6c3ddb82d68af5a2b4956442b2546fcaaa803cfc2f1f1ac9c229e05647c964e8adae2cd4fc65bf28cf3966c63778cbc7d4c15619815d90ad046f13155b45ac34a0d12469d93f995925f15ad783c0b8795c302c2e2c0b368f51543af8652f07933beb5c4e6fdc7b786640bd52da2faa232ba556404b75368c7a1a24ae53ab285bee841c1b77db76f2bf62d5a984a91c2300cc3d08448c909cbaf869228295ac2c261fd80c1b0f0b61f6dfd477ca068fec0993833899cb33df7ef630817fa172004cb4fe00154a43da8483d06de30bec7af92d017ede1325ef46ac8a5c7d7d889a9052123e7d051370e1c1bf6ed5d7607c3fbaf2ee369fce56bbcc717e1305fc363bfddf5d7656fc353bc8acff81b2ef33df8ccd3f0173f7396c7dbdf1de377c6d139efa1880ebe03d7195a030fdb4caf868c7ca3abb6a9bb6a3436ba84b6d08d1ebe55b34187a25dc377e03a6b18e241b310b110adb0107dbaa688d5d02ac95549e136fcaa303079f6deb164dfaac916eadb13db11d7b760be0544b69040f0db80be0de8db80be0de8db804e3e7242583d9e9584be502f5c7e9504f62b2554a43ef3ab2219bf5a22633136965f258199f9152ef32d3ee35df8fd18977d0b8f3d0b87f997f7f80cf8cb8b2ee355f8f675c7f81d0d38cbef8c0ee3777a388f7722de8778dfc07b4b03ce69c0f5e82e3c1cd6c3fd8de0f60bbdc3c357b62334e6aab9d020c50da8ca58886020652e37c8574e95b95c45dc0e64cc450729529828baab54dfb7018da922217b74a01f0d7c2ba8b66a2ebe15c5b7805c6870d55a39af6fe1b010b9dce01a72d1c173eaae22cfa94b098389a2bb4af57d928568d3ec63aa6853179f154445ea197896107dd121a03db44ad2c2a55b3a295ab870fdca9696db7a3c37c32c78b0709d2a5b71dcf7e9e080ed15d1f68558f6ede9be32d88d61f95512fd2ba219af57432b991617312d5ee20a15295c2c315a157362928a095131312ea5cdfde56ebd5c79ac92e2d5379cc2fa910564535ffdc81a593c634b0dac1cd692160f5a46d8d4513fb270469692560c762b082d33ac8858518cad128cad158c2d1b8c2d2d582030141408c96c23fd4833389182cdabd600e9676fb4ae885643ab21233f293e242e40270fd8b089a13a617ba2065404b009897b2a0df7541aeea9b4114e13db18a4ac12ff0055edd1b09ddf275150a54b224bbb44db139f6b1c5d6ba59452dada44b5736e4ecc89691c1115690d5269b2ea50710557bc768439fc287b9fd837d929d348c4b69b7cdd8931c618638c31f7d206c618638c31c620c0b265c2dc6db5e95639aeb6cc1cc7a036b189c10b5e084318308e134e98a156869311ca8682514c305ea16cac8d85592a8c371432b480b0096d423408e2f9d8961b71d756df36af731e24e7bc2339e724adad5f7d012448935ac167c8676877b3542a31e173f26122753af930914ab9cca7547d13973915fa8427b673d9272ffb2464220c8930e13314a698483da7bb373121c284894f1f139321132652a99474cd0b853d528dd09fb94f45f6c927113d7dc6131ff9c9c44f3e5e9f3dbd7e273d7e9e7df44c27ffaacb3ec5ec93f6939774caf38f293fd16cf2ec2810cc7a74d9e389f6414925b71bd43c3e7044e9d1654f13ed835eed83eecf497ab4774f9f4ccc1993e6f13978f3691e25bf1b1ca5b40fbac3af343fed9389093b717efaca99bcfb465d6784dd3c4aeef77b93cf0fe5df9b4e2794d7a09f9bbcb31ec94b25f7debb4eda51f949e572e4e0ab9ea3af118eeb2352e9472e49ae1abd75bbb565c267d7a026d4e482aff3f6b649bf1cb74352f1e2d1cf7aafa5afeb32ef18625f1f628fd27dd88f0681e3dc3bb9a43527ada2af4ae2388ee348b204b64ba1316b33ca53e0364e9edda3b19267fb292abb44f6d32fc179c739b8815a7e5a3ed8f3712e77f69c6739df70ba6649b1cb5295d5ce3aaf590717a670da92f28ca4e5c7b9f6a13d8bedb61ca725be790747c559a37a1fbd452934e6c3eeedc3ce24769139e71c67478fd035ea0edb89273fb9cc254d44dd270f5d66d04ba56e9c36efe876694e2f957c26b1e5d92ce91189399ba727e9f1439733270c7d864e6791f0f4e3dc279f79d69da69e1efe1cff7493efa44cae6b50699dcb36d6b1efa4dc9472d473a94ac2976683541daac4dc3367cec83df54c629c49987c8e9cc67ee7e7270b82ee4df7f6d4e3ece1edcf3d3d5a9a6d78746ef7a779a03e5f814cf84e3e9ef468efc6a036398fceeffe4c48e8c9820923f9fcda618cb106bccd03bb759a6d24e63c159cd7a035a8ff8a0358b068c0bb4ad553652c1c164e0f0ba78785d3b3a9c3641cb0cdcad9bee0029345b125f68293b9b49e9513c3c261e1cc6871219369d989494a16a264b2cd62c04b1bdc0a0545f5238bc7e7c74bc0a2b596d0aa024b070a2d39e4d8800746504310922021560e0b878503450a9a02e8d4c142d7992a010850c281b3e7a5afc495728e6b049bd12d8d48d88cbce434df8cbc54848d173aca1310ea04501bdc95701ef9cc38889877b0917be4b473cee79c73ceb9c3647fde514a29a5b5d65a2da763adbdf75e8cf1b68df407943fa0ec1d293b989dcb3627074fa006330770aceccf418da3cb2eb3cdcafef27776c33678977a36f57c1bd9649bce3939f29973ce59b3cdb6bda1ea3344a9f5389da15aebcd36d76e47acbdf36ed9a6e211f310c1794846d986e46d59c7b6b7cd59dccee368936fb2a65eef48cae1f488dd066dab2d154300b47bdc1e908642b83db309283ce1f6dc1a546d90e847b9eb43ffbfeecf79156ab1a44c7e85e5ab0f1457a8504961d1a20655a18a044911ae0afd3b0151dc47f82eefa627bb92d7842cf4b0cdda71e1d8458ad72bc5cb3b17ff63892ac4855317b46e78e5e77e7dedd9a93c3cf587e6eae3535756a635a1290e73b4c5027a0a7413d057406781be02fd047414a89222087e5e3fb95b6cdb023fd06d9e9dbcbb24164a00017271f74a2227076f9e587f541c9c2d7ba8d7befd8a234041b5287c7e8ca438cc712a5229294f955071b45534252252829333aab54f8193034427c85b9ae5a92f52ad9958ba8fe55e9eadcc569a42e1d2e40445ae84582a6f250a5aa349723ead7cadd5286a925a3444a4a4281bf9f9e1ea1c50def6ad22d38aae4335eea5498b772dff63095a648583d487faac004fa90da354402ee5b472e14253203b3487d228aa169aa0c2bc338b5229146f7bd554328988b82d6562923ad9a4f0a9503bc5f6f814a1a2112a52a0a05a7d11f9390285cacfdde26710507dcda15a4d45c5f6d89e5ab33d36c70e28a6d356f116e8487dfd5422358a24443df7a4084a2d5aa5c814160b84e2c891154b45aaa4a47c467e7e58292b7245454562ee7de56d0f112ab6ee76b91495966cf5acace4992552c4a7c726296df12d117d515fbd2dc20a55f627b564098d8d960edb12a13875aba4888f8fca8a4bb73dad569e5922d6c7f6b0bce79d7adb6389d822f6878ad66712e9e93959a9351693afb53ac4fa9aa42ab138f54544455a97d4a225ae6e9bfc1c3279784653092040820879e2723ba555b098b0fca022cee4de7d7bbc515eaebe4681fa9d1cb10ea974adfde07a42889d202e505fd45df90154cc3aea6e61579e6d2952d89ebb5975e8c439146d7de48aae359b6453b749686cb44bec12294384c64e9cbaeda1b19553b73e27ab9b627e26ae22cf52189b60d41bc1d1c4c4702aae46a1c2e4775ebef23b295c7cdbf3d6e7ed4f7dd923160a2ab27e6785b242b4b142a57754f8dd59e1dd4bf41519c768a7b4145788a96f8655bcd79aeda9b51575c8456441c516f3c5997c8da20ea5e0f01261b016ecc424050b513018aabaddc0cff4a33d627b6c50370a4212243429f5f036aa43b546aa352848f5c81d21c142059085ae33cdafd2f9868f1377f52e66631cb8669b4d8f315de7ddf4e8571bb96da3d966a3185f6bedad98d26d44da36ce858ce2caa1cd49d962c71cbb47cca6ee4d324c9a0ce26edc9cc3573921b2ddbcb4798e3dc55d7774af47c57bc5d1a8eb669ea9549b839f77e0e69f3695dcdb4adbb661935793965ed29b1dd97cd359eca3f8424517acef6839df82208010a4caf975ceafd680c8719aa692eeedbc1987af7ab99e4e359736979bd5a429c822ce480f64208bf0ac41db9664769eac0a651c35a8e557fee2afc31ebbf89cd75a4d83146d20633496c4d491322fafd5faec152abcba0b1af397159757af21655ab656e7aa2ce6d53f1a52158dbd57df726685d713afddc9d71a92efc4c75a83747df91f4ba488fd8f143761b90f6eaf9c54a3a0310b052952239bba3d926403b9ffc2b91737ef2af7a277d65bbddc5d11b6ca0b8c53ef60fec71275088c9f2a0f0fcc09f51b7ef9eab3537beaab1ec9f5878a2816b879353544d8aef25548a5d1303ee5d946bd253637448a27cef2a0144f5c7f4a8a27fe8f22c593917c9db8144f54a478e2f424cc37bf4dbc230d61a758dc89c989a7f20cc53b134f084174744c4e7210940002e44455e249222767536fa9ec60f27682e85091ea58fd51715a2830bfffc257dfe2dbff9ff8cabb70158fe2fe2c9ce555aedfc455be85b3befa96e2775edcc5235bb83b844dfd0641c2e875a1572d5a3c5d428b8efc35727fa848ab97c7e4ef90db43944a5d9a6cf97ee02baa6ff64818d2fef2d49719240ce8d6aed00dba505c34ec11ebd23a4fc83ef940e5aaf88a4cad581748888a415ae2286a2a292bac2443434a32256a79f3736fe5990aef523c9097a7a5425f1a14971e39f2d158fa9aecc08787768b5c1e1aff8386c77440e329bf13d3dfd1fc8f25a81116faf3c3e21a6d333339986191910922e38243e86dcff23b31c72a1ae6c555501e1a15632a526cb0639ae6acc83b1407475461a5882d6fc68c1acc60e15e4c8c6f1fd3e2071fcb53a26bf1e61bbe93772bdef62a2f597ee7c55b8f75b0121808fe81718834ced12b300e36756c0309a36e8f5414e82f3f6b33a8be8226517d0dd586582c95ca5d145d5c5a8ed861bee1fb64b053fc4e4ce545df222293e9f2fc15d24345aa42e5a37d7d96c04ade4d1812868bcbc700091010ae5b85b964ef660c1903060c0d048a23475c60c8903262e4d9554245ba6d73fbae13f78b30d8b12a6536c718df8ddbfeaf90cb4345ad2f0d0e306274decd17f92243061ef27f975c221598c8a5d522459ad0841e3c041391329c919f9f7bef8d71af0c1809735f5ef2ec5ed1db1eff25ba4a6ed15d42c522d307634af3beb43adc1e22317d7968a3118ed17e7d7d966c9308ccece959b18219244685d068436279f2f0b8c0395309aa8223a8e8312a31ac1816d9abe09d179f419b411fb02344ec02b5aca3ee177ee11979b6c9c85c22ee45df8a8054d91542e5a5e1219b3a1e4263232eb28b481979955c221a6339f55ba4f23fe4387265f0cc4c9e61d79ac5659ee94de56fb0748d942b6406d35ca2ed57bcdc2a7ee7c553fc0e8cbb7e27e62a7f95601cfce3718ebf3807e3add88e0c7d8bea8bea4b4445990c9c442cb6125b8111ebab7669b5de7a55b07d79b820e363b20b155d62c430410c1a3060f8f6306a261c2ecdc545e52f76f1154b5f1e1e58fad2e0f0cd1a302a5fbddc92c6f48884ca24f5e32572a32802ebe0203827a594bd6ebc4429bb0ad5201aab1be5b649c348b00114a549bb1b47bab7bb1549972b3621f1822a600d9d748d297036a592b6c9396d1bbeba512436140a2ad220de1d886f39009ef300fc8ac7fc758a8407073a1cf891b20df848d9103d5246048f94f1102263363195193d8cb220020004006252686019c020d00d601297d7985718afa012197bf1ea530929ebe1350564731c5e9dca99063c8b8ecdbc7aa84a71199bf1ea2e1993e1153b05a2224592f3610a0545327e0cffd1f214b88d25389fbd701fdc76efe165543e85fbe0f6a5413c9b3aa84363db112ae280fa0654cb20651c0c2497535f49688c0b02ba41c6b81d489106a1479818003d8a0e841e5d05003daa62f4f881344e08a8a4fb01b2a9cbdebcebaae71f84cfdb6ddef502a26fa8746bd84bab182a452300000000008315000020100c860483e1689e269a9adb0314801279a85e624a98c8c328c6519052481963000000000022000223a31900e02c1b44e43c52cad13353ce618f0e8fee067f89a8863363832aaf9b57dd7be8ed6e104645838e982b9d372179127bafd169b176811bde0de2f39a39d7d9475adb8fde2f97381ff2eae5046c2c5f6f30e9bb9ce477fc30327f97b428be5e89fc739169cff216d59b5aa43af80d359779947ea2428599c3c4870d137566e52dbc19f0c823455cd5083c93a69f05e492b80d7d5df62670a4cf63e13609ea55253e21bd8724bc1cf369f197ab21e1089bc7594986d1e6dfffdcd9324b2d18a3d2e6682d59ad271637c4da0b12e28b8e5d02c2dc1dc9f5c30080c8913c9d950296a94e52bcd09e1b9011d41c65d58335b5f3b859ab4e7c5fd0910488a303de47869c2179c9d54d36afe0c611571cb147c9408334c8c8a21753fb1324c1f34deedb7be74aa1e2b3e000fa4c07e2138e224bdd7a8b031cd053c59e63395b9695165a56d24c1c7a1274eb7ebc590fabd42d0e3e713d4c0e235a43f4af119a9a7370e140de5f5dd6c32161092198d77d0e5500c0e0464a81db7dacb757ea09d6610e5e3e8083ea5334b314f3fed100e3e1c70e7629982135972a7c20c9d31acc81bacb5c9fa457050d462febf88e3b6044171d52489a4878ff7faa4510ab06b0201a44cbbb2698392da8849d6aa41f53129df8b1bac0a2e484a1054c97a241eca3a233e0b1880ec818c8a95fcfba53a709561c4001a7f581bcf00e5199285a222c9c44785ab63571ce64c9b32fa38e44f2e6f31beda919901c966257d98f26108e5865e2ae446d6c04eee1cf58a528fe719500d6a6f31ea8b98baa77e06b723f70109a7fd98294bc20773c57b703949038bf2b6411d6c35b32120c0c4ae3178dfb0dd15c0744c401f7915198d4ac84db0cbbe61f908973cb6e186062db0d39a4512a34fd682c8c0f2617955c03b32cf63ed39657197e764553e9f84f9704425b43ff2bf21cab48d651f73b3061af86957f7476b20331de92ad17d4f1a5b50499a0f0b99426238a1c07f48134227565c27857b0587606db12bf1d2a8fa135616fee545537ae671b8e658d515c0b994e470937c1bfd133a4c4847e68bdffb46363c43640e6b6b44da351504fcd99d8c191e880b8ebf7ce20e2d686bda464395e67981d7b8086b9a2765a135cb48697341d65a08815e71cc55b911d35046ab236c0bc7d6d6209b25f0f0768db3ba5ccdc48688b1812c5a3286167305285ea0b7e33e2e563622e5f9b627d69e304fccab2aceff3118a47714183bafd8cb54965b206749a958cea15adae442ed9af373337a9003c90ee81c8cdb7aca75b50d750a4a6b796e7d61ded02785adeb6a0f96303aa3030b8ba183638df357865768553509a107e6b433685c8b36b5f4fd158ceb0bec6835134e93ddd609c09b3ff107d1f7a101ca5f8feec41ef6c5fc519d1549e9a06839f5cef6b601fcb636b5c0f7fd75aa8262c225ff92600cf5e86a1e731251daf4ac54d4d755ae25e8f632b26639e6ca995a08d76829b903597a3c5a591e851ec4781be86ae56a1b199b6d89b04130c896aee556989c2b8adc50c736a29be43c969efe16c18818e7e7d4bff4a177994b47c7bbcb61967add2764fbb8cfa7ecc9cb2696068251991b4cccc156ce1899d203ce9ad00dd56ec03a7dc070fd54a6caa781417623a2fb6e6015b0f5f0bf56d089ed1e03a41a016126ab1ceeeab8cec0591ed09cdd43eca05a78e3ba67e026e9d1c3c7675f460f7ac7e0b7efafbce06a185fd2d4bee64e8b174e2f22fd126e5d9cde82cc863a36b0604cafc1d82c443804dc396d4fdc5dce144ca1fe18a87c0db851122508be296ceeefc421185cdee89fb8413012d08d61cac82307e87403cf24aad87c52b748dfb538e2d771ce505562e8a47f1ca85bccd28df9cbe4b8ba0bebc6d2e541f2ee4bdd2fa8f2df836a1500912b97a4cc4f452f75f281e6ece7474ea134859069a01bf56ce3519e8d4a6c0a0e43654d964b8447e56f3bcbfba494541721112a27a6e226bd1ebd00b20f40713947e3dd020aa23727f5933766f23be007b281b418e9cb17b3bcf445de0fdb71244228eed98fef96ec3dba1e6bdcf1e0fab0ee56e2ec3213b2d8181660ddf6b6adefa61d87b24702f66a4861548a2b260655ac22f7bbca037600f9bb0393e901d4abeb95854761a0f3d940e7c88623f52bced2a536b729b3edaf7402afbae9687601078020ea4f7325ada6e967480caba0b231e9473353e610a407f0a2d863adbeb533538bbc7008d36ceb0add1b6efdcc63bec3cd9e25edaa6c18a7068e3b1b29b699fdd967046cdbe9342f3c3aa6d1a5e94aa4128ac2c5e87f9383aa7623e4517c82e51211506e42c7314b1e82d6acca3ae067814b4d71c2982fcfb0165d04de34850aa3ac7777e67ddfd5d297b9d4d706ad4132c252bbe46e1234e96d8b5c0563335275992fd358c02c8bffab879fef51c4b11e2d512d405d00878144a7154a414f95e4ceee6235c09a7b78f4e6faa968495840478b0a560028c2df10c8693070f8d3dc40468e887c4ecab469e0349959e47a1a3e0b0c6eca0967f4039654d0d252e548c382ed88fd6936f5bf93f0170c6b2dfbe1244378e1d18694383f9afcf622736c58f11c77457d75053984f8125350274c769dd421a2d25d032f818898a29081470e180077b1997cca697a060b289d46055dc72e4cad6d22f6a80e5091785cee41cee22b01780bfca82477b0fede27d40f51c914164aa971def71f69c1d4800db592fd27cb954243eec63e64b75f5e0fbcd96d8ccb6d16a6e9944b45504da0e7c20a1cb280c9cb914f87464252198fa80ec1c8183149ae07cb10a4d23d8e587dce8575444c5a79ae3944437428f904d2739e8eb2c08975d365c0fd13638ef875d1136142b1d2e8f49e82808e10562bd8ec639448b3546fd5c1fddbd216355a87c89f4cf89d49279c823dd10c809d1a29d52230510be9110f0d27cda570b4bb750cad784379cc20bd8abee3c27935aa17bdf1f370dad1afb01392cb8616e70475b98a9046d72cd914c99af35c4f2146c4ce7e787da47ab17c3416eb60d41a1b9b838f54257aeca36dd3909d6f9343fc6217eb3181c5e1b78ab51d8870d5d0f215ba1107748b5c90a1f6922d04440f4c960775f1e4d04a5f7fdc0fdfa942a4bfd1855500fa42b0b744a8acd647516ae1b44f0d8b12c947ee586bb011c05d2f63285e92734529e8671902e6b52281044763427d8788e66cfc759495a7736c2a918c79ddac3acca664693c651a05d915c6a38b8e175b0e4d7b34b29e6b32d5bbc875b553d7ba59491c0c227070fd06227211eafcf32a15804564f57404049670aad79f513a6f14c2130d15e301a2e6cac6030d7d17140363e6b04be601fcfd7ab4b94407cef735959bd3a4f39067058b02f61bd195994990f5bdb7d7c47870560907620b3d849b50a4cd6941a8c069dbc0c132a657b87128f8b4728608f3847b11cad45cd1d82e68034aa11b3cd190b353928210144e04b674b6f35261acd6fcd017175a29f2535dc4280a3e662d2a6091f8a982a762cfaf9b2c7ee6831a72734de6b61f53408c8d6fa1aaf998061ac52e6c478cd54f4c0a50b18bbe74dca6ccc0a5df5422da49db54b176aa760576f17798f8087ee1de503ba91185e96ce2c8ec59144bb7aa7a8a565337b326091c61e15e04bae358dd2656cec00e2c5316d8fbe026c9c76cdf7c46c1014ea01dce4e7c237b9ce68ce2d334242723cfafca454695dc663a0f431ca6bc6e565908026be6aedbb35271ebbeffab63b826364790a2876e85f3d82d9ce2b4375f32a6533eb39b9c4f27c3ab9b79f03dea3660762ec664cb7510e59733553a5a24cbe6bf12a57b3a2bee94b7ffd95cfd5f08b8a1281ba563fa5b7125f8002234c583cfa424b9a3bff0e222c92d59cf7e591e01f1388294ac7110621c4ee7a75514fcd830640cd5632dda8c339923b7c42a818082cc02663a02623268942f1b31ee5f0fb517a831819156b63dc76e74a36b1a99befe56d8c724e76eb4033a0ad4c1e008edd97b43d2be2288be7f9b1fee9601a63a25e5569a4414bb1f8cb9c2822310ae3db337b792803843e3954b3e863a38159ca122e4b7179ebaa1ee075e766c22aaa41fe50faf2d67629ff0da21bf74b8b2bff9f2886294381822df51cbc8a6fa57be34e1b05050539aaee642cb14744c28e5b87257db8e16fceff09c801052447e779400e5a1f13d7fe8d02fa82c3f846786efbce5e645f0970bc5345831d62546c20476d44ed442b9edd6ffa25568527474e705d01e9f7bf81b5c4f72e224efa7faddb00e618a8a66ebb177f9e650c09e41de2474c163ce106aef497e7a20ba74bafcc55c420bb34d9639f521d4863fc6d0b6eead4a0f22e48d885808ec8bfc15875a09c7411731d6c36d956a0b2ba933b8cb603771eaecd40d10d513fd47fb35bebd306613cc945b33e45123362af6105fd4f570d13b813f5be40c8f12a92ec65b1409f14408bbf9e4bb83cc808659dfa926a897ed1c4a90cc64bec99ad9e701edf5433dd1186adf4fd2920de3322880f6acae0f3f3ca75d7fb7f680eb24d96f3168a9a6303ea257a239206462250aed8007c1538fe57f713f377114a7cd396542027e2914bf414e1ca1830ec29730991eb333dc63bfd5463df11eaf3c10cae05033b72bb408e48b59fb8381064cc4ccdcbd53347a359f2aa9f5741ed49c5ef70f6880e3c1300935d9f4c78f64755331814ec622af403917e1367b2d80fc41686bf888a405ef9e1a182cd113643d7b6e8f51470c12d1df0ba391ad2554ac4853987a2b6cfc6b684216834c1a75f573c898a27d57875fe9d72fb219d05f959d0c6121193ebef7671b0f96c444287087d9a3400e463f1de8fec138e7d390717a5cab27d6d5025df2cf92a2dadc7232aa3af7109fdd4ad61d7f7c4136aeaeaf86940b014563fec449cc02a682efa1b6c9965474413629080268110357925dc6e4c86069135c309022d93887e38b50e117f766fca9ca7736e4d416ab05025b7e9f2223a81d5a88bc9606a3a4f3ac328566359ad1b4f916ba48dd05f10650fa24232e898e2f7d84d5299ac61463158eb4ae7f72a5a0a825a941a268cea2c5438ae37c27527e621f33e940343e1fd07ef448ab8365c5ddb839847c0a48e021ff1fa27fc3c36a5aecf4d7ff7c6ae1d1800bd84d629d020cce5f179160a287b8d1c111681775684c3fd526d54b5e5bcdb2ec0ba67dddf470d351187ef036015164c2752d3a411c5dc9d5474edffc0dbb211815b271c29f62427e1037c3cf4d01c061aca55fab389265ad10b92a283e80335984472f295306a5f19d957340f2ce8efc74ee7214867d31c36111be0c9cc7ea263cfb24deb40414a7fe12808cc5eb893a5647eb02226d4ddfe297ced716257bc3f5e58c7164164b00492edecd68a9c9c4ca343db61d2b48abd51eba063d64dcab352ad93b29bb8e038e2e9117b22869f79809d33429fe80b10c25b7e51a042f4f3129b0175742fc2a36ee29940f74a4e0f93780cc84b596bcd9867e937800927527c50ba206af230c5c7805c946b6dba5baa2460dacbc8c68831d020545fcbd64fc3682c037b43712484a4cf35619200bb7f88ce10784b836f440e4eb6b6859efba9b1a2bb0122d45d6838d8380945ac4056e3d17c1a051cd5e832aa9cd840c516d1f203d77984b1d4ce8cdb554140fa588a40b0ae87e8268676b9b38e3becbb251f45d9debd4c22b1f8d545a67aaa55f75523e2c0d3d691eeac510e3fbb39b4f6add697c19c393dc40283dfbb77553be17e665014f17a463322a2eb07bc6d681abfddfc6047e2b047e2935a47ff875538bb1fde98cf5a59893a957130d0692e3e197132a50ee8251c2268f52471f39192320c89a3a9690f95cc39017de13efd6bca1460386fa686c5d13fdcf2c853271fca91d8c3595c98743bebf387128deceae8d3c6d6187324dbbe773d746b6cd4b47f2f2b8900d84b160773a203dc382ef2109e85bf8a15f74610d954b8ecd39979cec396f4c9d0fb70f27d3a566c2194fc930dfaa25c86008f6006a735893e321c74885891d5d04401af0e8894d7b30532ce1609f800e69c8fe51f2517d131fb58c004f8c989118668e3b72a8cb4fb0d315d63324d2b458b228d26c1b8173dc80152057366cd1b6800cbe70a45f7a7fc16f9c7f5bf2220e651eb12449b50c30779f7bf8df5de089fe010e54976cb149e488626b7152d1a736783af8b68dde670b5180f70452d2252e997c670cd0a9ecac31a2e52d46d2db53ce62844d983e36ce7c86aa6e9b17b5690cb7cd6707d5ba5bcf8807d73c5d621b7627125930bf4293168055e30c1d51d4e61234ff592c5351de0932087979022e81c6efb2629010f2ae2650e95a0565c89e8991e8a020bc147712e426d598450498a2aa5de05070909591dcc8d99d796e47be53a3ad12463e99f8210caa777cde9078b25507a9c7024d278579c5e3f5b049913da42a1e56a61371ee26c16fa95336e8bf088a901199867c66707df3c23446952796b5eb723222eb2137ac9998704664ba219a421daee864834bf524a4d8d7d972e812e8848158a89c31b216092a6cba144ad8a0b1115a8011be61e8df156c13b014ff7fb40986eba34989b2e327922c95601d48dd707f7fbdcdfc5db29911f8947893816f710777f22f413cb4336b8467d52867ae2bbc1e38e5115d3c124c9d84998f66d5cc28434259c06bc61aadb3a23602e9c47a61ec106eb06d9816cf877cdf2de2bd7d043331910c4e6f38565c34ca105794c667fa31e03d04274e81837a08b12b164dded0c45bb9ddbb49d96e8b138e379462fed745e8f1b9488f6b6fa130e31e31470a000098ca8796e50ab050353c0776ea8eba39d0cee490f42a7eedbd66512ff74221764ec39e60075a2e2759f8ee33751487ab4072616d2d58a841b12df28bb136e5b8e687d96db98fb2cc0fd8f94b12cc1a5d91f21c34a6cc42c0bcc33f6110315667b720c80cfda899c11eee583250c312d8fcc33f88f429330fadc7446b613fabf946b0e789c7ca369f036b111de29ed72e2c6e8f757445c8c84b5d65726cd4db9ee9783027483baed09f23dd9df73eddbda6fa68d15522831af2cc2a0b05be33c5d8b714889cb06d0b0c9bec590e3df4a91635def754b948ea384380889e60546f42a9d40b993489319493b1883542c16496c0cbd66de080fba0bca2938873b0f1739b6926c83a93d5681ef3ed8092de763745520949eae0dd0e198a781445072bec9ff98905e9440ad767e3477d66d12922f7a6641306bfaaa38a9b378034c10587ef7c7196b69ae0c7493a75a99477248146f007a3036e976dc386e9d6ebad150cda57fa14167e78de7ee72db1a910db77238c01b8fdae2dab22295e5c9f0dadb665f8cba83fe7177d8adb1d90661dc329f056565e9f633c5820c5239a79747cb3301f6999955dd7d5aa0859b7155de7f298193eea3d97c30a6037298a43f7e7ff88d9c61aa4b6ecad9a51fa2610e76e0d0b84de06d95a284dbe2cc0eb712f61cab97844aa28c279785bd24f02d84a6345f943c46d72c785bfcad742e6b13dc76fb8cb7c692e52f45ef1065f59dacbe93e5f4c2b46e7e5cecd9695f4198facf602c4a4c63a12b7308b2537e6b893859c40def7d9deca26263417e7055613a32278c4bc001a76911eb7c36cb2d28974cc5b4fb63c8f2e5b02ac0da649c364c320216f204770207642923a7e92803268ac44eca483f57c93563367d0722a5ecc5d1be19704d9363a529703400ce7eb22d3c103136dc9fd28386353de899872047a75c9259b3903719bd5656be9a7ba42c1955b5505d407c20771f6371f04242ff087e82930923e5f43fe0143f1ada00b219a6fbf0fff2533726d0786fc727e888da4fb5f5505f88885411371a6ab679d128cac6fa40618d4dcbc948323922495019faacab8cba980af177c0af643ff60196a8f545bf8c41e1e6fc83b49ac8385acd6b9f0c1a333b3cac407dc2e3648d73bc5fc9e752494b7216cda6953371e42b0b51d33b46bbe49e071d00f2770f7beefbcfa27909f331e74f3b27c54ee372fd44a17828ff21148206310409e07defea18b10118b5cb78b49117e673ef44309ec4975588d0a67ffd85984b41c03d032d8a09dee7405281dacdb174647766adea4b7362989c76cce81dbe0c80906f3d0555343661311d8349fc82067fb743c6ac67101a360172b11c4ff5a7554ba249840f281c155b901a6ef441fe74b983bce4741ec85320854c5e3e63fb58f8a06ed2261ff5a3b8834466dc8b4af270440109d62afa092f61197b01e98387b9ec0386013d8d8b4667e6713c821f85a88f7641ca5e01cd711d8ebca18acb7779766c7d455db8eaac9f4176ed9ae4ed6a395f99d6ba516cd0679fbf14e87617fa4d88ae49a3df146993fcc04ab7a47ed3ba0191ac67a62b52ff96be3b85585c6a4eda2433eb43c85cdc5fc6b4430126953d36e4a0991f9de39a515a94b88a53e70797cf22100d7b84137d2ea0a5b8a0756df572939f1815532eefad0c54580502655eaef4c026617a50275a64bece4cf64739d874db05e9300b206dccd88f6603e3a3758cc5728d0a69cb17dce22e9a0729be60aa76e4b464641239afd7bb9b73a387d458a2c59073d23345e0c909372a55798e9d30608ed62e8acac7abbad8bc54d95d8ead554e3a7b74535a39293c2ff1ddacbe3fa633cc808b40651fc2e6a7cfa36ae3051740507c646349d2b0ec2f839930d3e62ca050827d965edf0cf50d17ea197bc2d183271ba60210a4a9ff5ce41c9609189aac4f4d1a160ae6d494da7885a962c67f46702e3628feeb3e6561f8a752bc065d1c84c1226c5a605c297062c81862ea5c87114f48367e189f1b610414028e8cb970914c560add627a8ded837cb7e8976bc8af57971f865053059af19a2a9ae88975f3b99764a1602d06047e5330210af285ad2a9edc0cc0f0896584f581417ca8f6ae9adbc1964f00883dc3665c2d1d24414a6a307f7b34ccc0ce846204d933e02ae15a2ff746c05d064bf3b93cc4606eb9a632a2c75a1e6798596a27058ec62c4b89e5cafedbfd31b4c692ae4051af6d55ceb2ee28bcb8ad08ef1e10feb811c0f283b534ccbcee2f4499d15578947b41b442660b4239028667fef8e7a1045770177cbee4509954821f9fc93d3e846609bbc601074776f9caf76f2252775264c428df9c09df4b155babec08a727688efe536b2a9d84944b52f4504feaa3d0bb42f8acf8e0d52b7409d10969e2c11116d1d445498abedd40e4024806048c2c600aa04a1b3b776e07a83a61e3b1a3cc4b9345063ced69a6e0e24addae76540e56904f0684384b05386b61969a4aea3fea68a28a5a547101d0a75406ac1554f474aeea61f14a798dc0d75351c651ea7cfa3824121f90eee58141824aef404e4b78d5ad902635f36f0a587f19263268b20a837a25e57b27f0b6acfb25afef7abb1917d070a5b71633ff83ac6c3394da98e298dc9e3599c930c52b92ffec4518d50348dabd37e21852ffc5545b2a441e9bbfe4676eb4d8c03c981b516f2c1c342c4031c32d310ed17e24f82489703ec8ab02da69fc506ec2bcc0d5bb2f25cba4408b56b1827cd35b2a198ecc7c1baccb647f1ccc23520a85b8663e19dd350dd8587f7655b020c45f3d65e9fadcbce0faccb9f64b31174ac5b1128fe1db2b586bde13fce54e8d7b6358943bc060940a2b53b0260eedf651e64f04f64fda7338946236b20a0fa72ff161f60ec9ee8d3d93d93ea20789e854923bfbb1923beb0b07cbece392167532b8c362c9441686f1927d8c327107cb1e53dc2a34fa686119020478e0becd1b4b8236effe17d7ac529f75e6433e7192e1e59d4a690beda2823ffd07e75bf843c2171398ca3bd2a6eb47d54b3e54ec455975fce46ee17c05d29bc1459413891bc14808cfd085eb69a68eac231ed6c16e524351107ebda9ec2b3638e7b38c575af23f5843db337bd25b5f5301c46cb6b895fd54e5d6f98965350374b75c577896a2e6a7fa772d1d7963a24b0b4a3d24c4319a707a4c419e621348d6059d282ce65e7f6a0ce83365f6198360cf10ed3192c1d760ebff9741a15f75f4cc4b7ec025d98d695fa4c5e3f07d58de16e9630b81d31f281736a34c12d289001eb7a9349cfb2af054487a150800abebd6d1ec0b6e87b34a6c8c5abeeb35052f5d9f6583dce301bb060e47b5b0c584ca217ca236a0d124675363686a09017106f117720cfa60a8dff8b51a84d2f134c7809e2f659a56931b630cd1cb13352e69629a0e9aa0ab4b19fadf19c0e0d7ba05e5f957984edff3c69dd8ae6f1ac658d2ef9678827a4634efecf56dbe14fcfffa7038a50180a647440aeec8c841fe12d752ee7d5373af0a66d7776dd4be43b6bebbad1be9ea17bf895091f301de9d4a4590b2997d679e1d399e161e0c7f0bd845b09aa5a8ef81cb05b5a4d54c0c590e781b26ce91806a19b28199ecd6557203f4363e546f44e4e6c77a5b2af43adfe188e896e04f2392914cbc81cf78e80c87a89519aabbcc0d64f1b3e2bb99c6fde40919d397ee23827111cdd9d9134a03b1b4ae02c72d08dd8073ac34f99ac0cecf39ccbc1387af34e34c207dda31cdd04bcdec90622c868e8b905e135255ceae17894133c730391671120625d94dc32269badb32a8f345b7013dfab7a7513d85436c17ef20b91250b31a305d2e201c28c11edf7a48ba1b48e6de5bbd8712360164e818b3e909783c8c1598c8455cbdf8421cd47b234bba62ab1b3c778c6eb213cd593e00340d8ec6c3437266fad7d06193a69ee3eb4e85a0ad349c8fec0631721fe69e80007bc392769f5cc430a239ce08aafdb7c8d3f7d4b63ecf72cdf608c909f70283dd2c901c649eb605098110f426e8447a3ef41022f4b7b983356822deb078ae53b6538964655bc2389abdd2f087165a28bf11ee9ff00876bde17473e7e4225afdd1715bdaacadd19a4787bc334c869fc595b0b45ee234ed9701504bd2bbc45d968bb8380ba2f53939f8f888ba7e220430750accc41b8a832307aff81440c321cbcea26d6c33dca393663052f063db9e1f0deac7c3a7ea32a49aed2f21d85c9f7e5956533b72b0e3179483faf1e893cfc9eb0c28071da267f41ef9f3e2c4ee377c8b4c1788e20a6d0c2ba6297c948b12b22886871d0755878ccfc32a937418ba5bda0356de7dc90236ac50b91dc340ef04f472dba29e800ed59da35e20cae1480fc0e7fb55f9e7d04bd49e588aa23d04a47144cede7cba2eb5656fb6e3c81fa35af84757cec247101546a1cabd7733837a0b65ac466cecebb0ede81cd96fccdedec6ca4553e2e54a76e37b30e34e1eeec7a3f39d46e5aad57645d5efd70261d715b995d9e70b1735ab575b91ad3fffb8b8727913e18a9895d5f68aaaefd732c2ae15b92bb3e70b376a5657db235bffed7186e27286c1f961e8fe5310b0b2b2bd22f4fd5b44876b3527b27b26dc851c2e2703b810b362b55551f5f8b544d865454e647a17aacb5b9c9f179c8f47e33b8dca95abad88d2fb817111674e837121bc7a453b32f5721ee396436aed2d371c44af0da574071ed93e7a1fd3c95fe442e9d3b9961772394888af18f7a9b578c0cdfe15938e3988db22846991e48598912b1e8b182a698606b92830e478a4bca007c62066e9ecb3c794432fb1210201b860594b76a694afd7cdfc1f5f7fcf90b6010299d663cd57cd68b98bdb3b3531e96b4b167f789fb2b6bc5705f6380440b22b842d8aa02ede577f0d87d8eb7c3b21e570f16c01250d53029591f3dca04c43ae282310cf54151f1dc8f14bddd9c08f9c8abc298d773a58c4b2eb90ef4a371d65ee7aa85ed4d34ac501c33c8bc8a247db1da6582d2bac75ed35c1682dea093a20b7d96fa6c48c27bf66e223d53ebb2494ae1ace0a62df3c10fac4dbe7793185d8bd9d7ebaa0637d23ac8a4728a8279a81b2dde4579b38049989fae2f38cd78f0f884dbcfb5f42d8a53911057aa33b8966b3220e40aff32bfb8dfb4d2147770935164d4e32cf04cfdac1baca185d03035c099803ecb0c4786023d485740bad48b9a51e2d04890ff410b659831670bd75248bfd8a38901d7aaf79fad599681331187ffb18654661ebfbd8a2651385289457a69ed6630948a9233b9e4cb379afbf8e69a54faa5501574dbe4429b35c2b12e961c1c511aea51b9372e515079e8cabba9bb364e7e76001e6210fa3f9706664dad82d54a62c2c24ba4fb80237e513d2ba923ebed383916d322fcf4bf5080c19cd9dbcee0c2c8d23ad40477f87180bab3a7c78102752a2ebfa1584f4bd9a7997e130a5bab305ad633a70ecebc3c460b9716a1c676777080337b8199f893dda186c0f4300df24de696ebfa9b9cdb86b6f02029638505b90765ba6cd4882e937e7086ce57c3fbf8556fadcbac81495a3be9184f74b0dcdfc0767f8c5c5219bf6860e5b841c496470622074c061ba380e2d3eec8fb58922bd917c52bdc665ffdfcda78f292a758eeb8277098e914c0dc04515ed59dfb6e02a88224bc56f8b0692be3d421d69895be51c75667200b772cbf9b9ac6026cd1a6945239225471b250ac098494b9208aebd88f469369cadd39b1cab06da799f5f2d09b56f7e29d7406f90120b49b0a523f92ba288f0ce785865ab54f74ed625f450fad64647aaa48f111750c1d3303f14452b931add57d1905647bebdbf455d83938806ad284c3e921753494e5adc91d5b19ca7ac6f00e5e801db05d22e32853d9f708b033c90cd97b81417fc85a760bb4cd9bba7b8d42040652acb1fc12f8362900cd333800843da8f86383019fae1a9ca6863aa405578b2c344e105263fb1f76cf5e3f785b2b435df790adac43b94e20440341218d1c58a31c897c19b786c3d79208b7d1584a6a4f31b28bef913f0313578ab975e05c4fbe464f049b1a544a98b1f0a0e876913ee95243bdbc33524434e5d71bb8f089ca6d6d354040dd76b9adc2876131eeda1c25fe50e6086286b79729ba44ecb7d19c15e230a3769d0181549d842e501e064b61cdc45254a25d6f8291376a13f2971c4c8b908e72346e269249512561e442b8ab988b2f62d070b041a32da9183811ca55eda95bde40414d7aa05db3f0d47f934870cd37b22205ee8e691cbbbaa4008a045f1ddce92d00da20d9bde0757c171807e96371b76d22b053fe9b80b00a553e3722fd32c40c4e5dcaf1bb2bb25caf008767612a90262d397a264d6761a6ed1a214febe4106a7bb47b287bb5f5b4cbef36c42858fb970d4fcc3cb5b5d8b2e8e7d2c00a782c18c168d13086877e7ddaeacf2a4ac71f714dad46d088c1a45ab2736225709118b5e575b21f4ce34c7d206d5afc62b92790c0d278a5e918926b8833f60083260a497ccc2e2cc350c2d9002502a29754e8f9e7fc183eb3bdb37a4a5cfb3a13d73749ae4c553ce01877e5cc0b13d4af68bbd47bbb3e35b0946e25f4662422bcc0c24096df9056aeb999ce2a4d636508e5230ef42472094678a580ada02d87ec634245596ac89a5675b7ed3473bf61bc00639f8c6780da38091b4bd5ae08c19cbb91171b04aa2b5ce5b0c7dcfed61e27fdd31302a5b6e09958e410b80aa12acb07f6000d44b98ebab7b1bd38122eebca2a556250eb2d7a80e65393e7193edb45413009104c007957bfb40a5101387b2605d3ee498f214f93d74c6e83a28e267832664aabcaad85079ee8e19769d0962a9f9c1fdf22a53574c426ae5040fe6b13db69f458631c0f70c5dfd7214a4b01bccdf1392cb8418b3c18125bff5e91edd84fe006269e2b345e4b1f21e663bdc375ad0118449e868ddf8e379b7c68e32f429d4537255f311455fcfaa83c20638d580eb0ab3ea00f26fef415de0079f809a1b3e7b762a223db5b073c2fd51b6935587fffde6c1ceec13507bf9670aa5699ea6dae3b22ff98c643c944d196060c039d644545da945c062763139d59d8e9f9fbc133efe23ae0f627cd8b306c86f69f013dde0214c524bfc5bed1fe52d0eb048d8acc1aad95ab34206492489e8b522c64c35dc4b3c30d0d152f1876f5468710e857267f760026321224bfefd0ebefca5036501f61dd10251f88579e5577ffe20b2283e85e2d0e68406e373ba8ec4ff4653a2d79c795e243f7816d84ae43a0819d86a621a78c92793695abc3564451de95ba0cbe7089d969961a02ec300d4195a21ce591993556f6b5633734d8a92328bc876fd95e1dca56b1aac531556cdd453250052593f42558639e096ed4196b1cbb24f0d7bf315b47114553e991cf655a3f178bbfc0ab52aa779913c8a48a89387446e2d66e57311af25bf2131b6cd5beb6c327eb781886daf7be7e1e8b4a289615b559c21573f41dcb7e9ff297333dbc57c514452b5225271cbc62800a07fc49119eaff13a32a35f07007ac395590e827a5a5059dea5c1f48e365ebe3ac1ca0663626830670959ffef9a7425a536af1ad28feefab711d9d2e13d6b9c035bb668677d4c7a0fbc0706e4a0489fbe222cfee1423cb1cb139579583e31412a6702b682f23cf1a21aa2ecc49237622aa5d8839948823144e9b59ba66aa1baf115e20104cbb3babf78d75a57a991e04d8aba795514672af0ff6c627cf8cf4cd705d325c5b98ec0a087805c1194bf67a380fe8ab2d409889787f3bc6ca394c48c58731fddcc0c339d001acf462120c85c52cb75bbf303cf406d3fab3252a7f62546ff2d3dac78b766c145b160746a4d3cf26e6df997b1e8c87c0b8ed05223b27997a531b529dc3f790a4f01c235b0c5a2026e06eafe36a33540b7777d47b61c0840cb8b343f9d76e463ad389cd0c6ed7cf9b995f35c606b48ba02b76b40043ee3f7b9429f6fcd5a86e04f464e03cdb430326c4e0d4338637c62ea302727e5e0ff58902a777bbb2f322b5de61c1981264583c9d0ea331f097b412e3b5ba2eed4b272fd4ab97388c614668d133649d713ffb1113b37a814a5badffc237fc42d8371dcc8061583aaa70f72e651c71a8ba2bc69bc43eb6f7843c9322028b3072c9d3e535a3fed3754974a9deb0b1d00f4395127ffd7fe26dcbadf99d1acfabceb5f9696061938f91c353f24a9548c152c1ec9eee3c12b89a9ef1a23180c2c8efefdab1431795ecf14d2c9a7c9b102799ddd70504480e0e28d85e3b7df6a2ab7f7073bcc6fc44632e9b60743a98ada1a081ad20f86627b99d2a799520de0d1a7bd7cf4c454c3ad36221c82d103617001546205a4d3480201600b79f3fcb139faa72c972e025eb841f82e9f90f08015fff68b9b2da8e745811146aac0792c307f9e16b3e05aa218f2d6e8d3dafb7b8f414303cf060dd733a44ea77d39eacfb46f1a78f9fb63e1e25f51469f80ddce8a2570ef74733bc2a8c468b4972c0863899f0365dbc15a4f3cfad2282bf178bfee1afa27452584f5f0c76a0db78e9a78af03bef9c08d5223077a35754498af97438cf73bd7bed9c7ff40545a6e562ef0c71b55bdf06741d353814d0b4e0bf9b6caf190553b26067ee7d239c28b6e940a2481524c42ed5e59e55629ae2e900c980694c7e8d7fdce3e0f8a22e2b3ca012d958a84ea49ff477ae508fa8d75a0cc8a3e5c4b08d66f6dcfd10c33943dce09a01e8ab39cfd7b184fc23147608f39403eba0dc4f251f8653a7e94e95949fefac7689f39e55c2ec8c8bcd0e7c6f521a6c97627c6184973c2491cc2d6ba0cfa6b1813df9b962c9cb35370b0e971887f0d29756deac2105c681605dd1c66f925e4ac5915f4b60013477173a2b9710dc7d85a958e0d987f85485009f741fbaebc3430a7d81dc3ab95304ae1484bf1a4627fe937b134366f685d0ce3ad140da91dfe0220933075f6348098524733565a73187e07bc6506f2a16ccd889acaee7a3616286ec0838297f221083ca751025c52e6e2971543f416df4399315a344d861ec5d34918109026aa1da290383b259e1df04c8c8d25ddde7f408073d89e4bf09ee8dce157cfdabcbf56af4356a4cbcd242abf8c8f8cbf6bf84ac3b561357eff15f2f2239cd232f60407cba551863c30a8e31f6e200857725812cd511f1dea96f1955fd899be54f3603845c73ae3678447f68d98d0f7e8198c12fab14b3417029cfc0750e5aebb994ba53d4401aef918a7be2bb3267400805b695de1932dd135c5362f6ca97be267f23fc5ec400fce49090da886386f1e42f14f0ee140acc0249181eae8f1f72285d836899099463a44fd3be702645fa3c64192693af79adfcbbeae4ce1b68b0bab3c18c8b9c514c302f74a7c429b81f5e6477b6a85394ac663a4659cbd7655424232744f47b0a5531a17476f707268aba12754108e0da509ec74f6aa3541920303e5d46024791ef0f7ab04caa8b7d2a91cf63c312022c344fc5f6087eafb5526a8f8d23ae4a8aeb0d8d6f2485cb02cab100d2cddcbd6c23a070de5a3392fda1e3dff0ff29f609804bbabfa736ad86409768c5dcb1ac8b612bdaa134065bb2e828a981f76db8c4389240e9c3c17af807560c16ac1097a77eb32f8d415e736606a144958076b9702cf29f276a3390b94288236b4776aba54e9840900e7c072c89c8f2211707c1a0931d06a4db349c7a262c195d112e6bb0a753ee920b3065cfdde2b331c07c3779a60620f9b4ca50aa1cf3759ae721ce1540933f40e14cdb3ef07645022e6bb78b148282720b222dad77da9952884149d9be4fb349a3612c2987dc709c9f642882aa3d0b9333ecf069236ffb9341513940827310fba6cee9c425b11f58aa6ff35a4400f7733eac41a72f26b181aa75e2e84216fa973887fab2a9e3401fef7639b2157f1d11985c80d25b0554edc1bf4ac9ca256b53503f78714b124d5b37ed037c09d8cd846e27c19f73736b6d3bdc9a189872ffd4a10d867a2230402ba77e82d9fd9a30cf690dcb67d7aec038052bbc1caf97fabbecbe827fe40d6ebf593445c84c26cf02cb77ddbd6491ff04429793805dcb777ea62c52ae7fc115f097160db7bcb9785b2d4dea2f948a29ed5b8256e89c16a34d7af9b09c36303d5170f770d3c6277790d0ed84417ac6404eeb04342c3f5a99040ceb6d70d41352aa7fffb039e36a4a20563cb84f83becdd394fb0543ac7b50b75c5561b3313f9630d63ddcea52e37e697f2cd86c52c1bf13f6375e30b31f09cd373532be8974c28991c75c168226e07a6bd3bc918ac8a31a7dec1ebae94d3f3c7b1b86ac366addba3b49a0fb75aab5c79a77eb692dadc77e14df8b51339f40abbb19659224e94029480b5879730c0e6bb7d213054270dde4b1fe30f78afd108b6127b2f450afeaf06531332d2c5f63fe93b5f38fea9f33a8c251e0d114ea87bc1e5a0f662858f518a39fbcf0d8bb876686d6e16c9dcdc1b29a93db9bf7d5f358018c64fb8b84b5f84c82740eaca0749c451c11b2805d336e862e40a0bc1dee079fa93bbc87f7d02b9d4b1b611d08f1bcc59962391a389455a81680cf938e1583609124972b4ec839dcf4e54d6c78daa1083ccfa2d25552aa1c64ceadcb9a43b7c546adf93ee5d4616bd7cefb550fad7884c16f362da51f7c87f770544b2131cac37ba064b995767e1f4d78e03168a0aa6d29329c9c28750cde03b1838347e682ba7ec7ccdb53fb8f41b0663964cbc65d1ae278f01e72bcb45438483cbc10e8b0041034a6a1517593d69565124013f1e89c20e72cf0a262323bb6c64e3c849e9690c11a53245311c3a883c96bc8dee31a0be22f5392a91ec9e33d1c85dae474b572c22b7d71ac877b6374335032b0830eac36ae7967f244ef1b0e94ba5767a73984e4322b58f6a0555a9b61c9dc67ae5c57b1b1ac2cf0372993f7d06d0cd8365a8d7a1a81062d163a235c0c5d8c25adc507d45827cf8330c1efac12c59ba1b3c22880b108d847148016813a95711fe4960afa0c0161fd6813bc32e7c3addb43deab3deae93e1dd5068acc88df91427e2594e0f24c34aa5bff2ba81450ca55c5b1a5382a636c098b6dd3391faed2a950e27bcf0551c717ce391f74ead1b2832aa5072555ac4013c3fb416114b9412c77ee5063358371d546f4aa1aa22d4b7f16d397bf65bd365860748b743eb4a19cce54b4d31f5fc63db41eb36c9be5a1418dfaa7f0ba5c1417f127b1f2ec16294de91be947e3887de407e41e0579a8e3ac23e8c3e383e0d05318006e139b14161b142849558bc8770a348a688e1c41ed6a65adde10612cccb029b219da3238805a1440472157e5c126706c6d13167e51ac988e545357d8454543ffcf439c5f8386ea3712d34be5818f3f190169227eeeba7ff72cf49bcb14cce5434a4a1ff0ba31d20c1bdf4ec5ff98febd28ecd7a28a2976bd28bf7f2cb00d3f4e568cf12e1f0ef9764fdbd5d6ee44c9588addd8e537f3b9cc14b93778323059113be909884618009ef3c7c4f617206337568c3d85f96015ceade4e67b1786f07ded397ff4c74c4e05297967cea9b80afd52733ce7ab2b4df8a3caf56fa504ed9fee4d32c9943171fcedbee42a36749af550713e192278cebfdbdc943c3c46ab71c1edaf9cff592e7cbc687ca0147cc16b7728b8600497bd9ad4eb39f1c799ac39d01c1cce4687bfa4e78d2e1a7ba76607ae02e142e44f45b8e25a90528394c23f37e435b30c22c9d8332a1b9f6c17622bbd99808b5523a1089547729205a935d991245c429ace1735e2bef41d4cad390d909bd893c6ea69d1fb5d82bd2bce0ec7b63706b652e8d017024b744ac417b37947abb50f262c82273b421e9aee4db099b7e387a73c3ca654f1bf93d023062b82d43331cb7f9a466f4015c76e384ab2a5f4506aaa9a2f61630713645e1d9828c82afa59b4f955879655e86a01a08e9d314d805f9e9ebbda4f976386abf601d26cd40b2985e1653fee8e17a4cc6293e4fa8f7bdda03ed96d262ddbe0d73514260bf767143dee55db78adf299734b1e981a680d6d13744651d729d6587aebef28bbe78b41a27c92949f44f040d30000f7ef7d9e2a5da04083bf213d89980b9a80fbfd7d28f8aa7fe21e32fe7fb54da42ecc8a150517627d175aa34aea252a2dd92d01047e37406cbb57dc2428102173fae335d5a8882f3f4129cd1dcf733b32a4f0ce86180723988a4cdc1d94d9c168ff2740d3027d051b6cc7d3f32db42cc1f08547b86999e3ad1a4dae55f96ccee428506c7bbada6eb5a5bf85091f3c8ea352f9a14618de35d1c37c2e01728915389287114cf18540700608d7ab641eda6923b6405a664037bd9a0c2c7e91a4802eae4c6c1388890f3598372db8cc187a8f42acd0d127a83848db786478d0eda824498a5eee94c95788c49f5b6b09d11116ef9224b73e7303733ffda37243a261cfafb1fc6ac690a47bec03f8e96c899530449888dd3b262b616c606c813e7e3d72427c95fe6f42fe18f0173bb4faa4e73822a43a7aa0213825accf36004eb7551ccb8016316ec575f85386882b499f0db02ef2e467bd03a78b5eb567bf884f96a79de36a110e1c8a8e3a817d416b2a488c42a08de1339d4647c9932e265f6985a133ca59ab53fcaa0127240a4bd786f16b7035a817fb866994be6dd0d172d85dd532db216d9600404ba483816b2b10960456526f9ee1c1dc9d9672c04a9d761b4e9c86ba7e530b6ec9287c8e77a73f1a3038a826752c5723d7c49f035d7d9e68803719424461716a9b4e17560e7540f6eafb4597971d806e755088e7b24880e8acf6cabdf3d9ca32108634102ef913a885eabec0a47f1fa10b82be6eb1b6b8a0afa8b3c9a9c87f2a8f83fcb580aff66d76714365a333b226c4e8b355ab2e47e3d5c5df0647f5fd805eb79d17cb5faf5f7d0910d3301ec8d937666902d1d3c7f43adb08c97057326ae5b179071a927ef095c78cbce5aaf4b23884568805f997818227854caebc8231e1699a10e845290a8450ee5d492542a28e71c47672e183ed2c8d064c06220e5159b28750a36800695c779c1cfc6d0c94b388f252bc528d8cb6e4b6254d7c54335045adafa8da2b7cd6c4f6ae78d4e861d75e824d0a6b7c49d96a481ef4cfa2ed0cd4a966785d039ce414a66141ff50757fa058ef07fd0c4a743debcb150402d9ca4ee3a96580c38d11cb543cadc68f5083d4990d42cf17ce1006050aa866d3f693f6a617855090cadc0ab01dc3a4716a513e532abf4aedcb14635c7bee73c31aa11a6914c892e15c558e194068dc37e27048c892321f9e1ef403142546d093285be1f37247846ae118d7eab427c723911f563d4fd90a5716f443f55b9c770bec62e29b5ca2a2965098c25d534054fbb0b21a4b7ec927c9ca556bb3760998b9c665b2f689515fa2e9d71ec1fbf14e36fe27a639f91170a38499ec71bd7e2850e48296c474fac6fb08016d19805a6a2c0cdacefe00efb899713211a1573a0e535814f4f730f7412d8b5fcb2827aa0d829b71c980e97159c753bb655f5f9798653b2452e04d0580afd4d2bc6bae104925a400925ce7adc82d8e642e2374930c37240663467d0d1249582043629180c6fe5674f02a398bb26e4e190f108e43f2b577b13d4c60d416c1a3cdac7781ea5858a62a2ff4d10d078d966782d5e0718002f2355427ee941a80d4bb669d1e048408cc6b2df8bd8be8cd2ac10514defd2220fdbb231afb69efe21a20b110bdeb8786e26acc99d3aa29adbb97bf35ed77505392bfcbd9d3b0e1c1453de1d0af948b2e2798748a44c02af3749d1fe639151d09c30844434a39aee6c5551212fcdf7a71b09eacf4546344572b792642a7eacb55184928b6cddfacd15922094cdf31dfc00ddee5931cdaa78005b516a71633afb291dac404223eedbd7a8406542eeeb8e8c626b1c9dfc2bccfff0bf46459e9fe00024e5b7b3cfd271a4383fff8af4c1004d52573734188160fcf7629856adb3bcda9fb875cfcd1482d80b1cbd42655465265a3ca899b5b2d81472c0b3b84190b28049a976760b3ec7e5272c13f6a6e40e3c730f07eea5eb474ca5157752044fff717f3171ecdf5f3150819edfdc8197a773d0bda2be841f66200370b583293d7ec8a0dad96028260ed80816b90dd581fabeea001906f29e1b6d80be2e3a4152d9ca304f0109334e620172748dac07c75bc544c036acca5d44abde2f17b4b842bd3ad23ec44dc5726d9a4b420a347acf7fe143d2f02d27c02e5c21d9d35b65cf6d90cd9221098bcedc59f778cb1986c371dd6288c4774fcf8b2349de387239529ba0590485f2df5b6e32920d6af3c72492122846a96ba779099f63db8760d58a287d3c1edcabdb32ef3d88d1a659d86a8da5bbcac931035ae8630e6768b92caeb18bd209c77409dcfb374e2d82ff995199c0b5cb4de4e0b33b4e70a9564930767ef92e22a70fe6619651eaf1458dd0e324c4df7261e77316e3581f8d1f9fa6b55e75bc14483507556891fa140dd2266f02f8aaada0b1ee1f7469895fdbb888260778fa0fa48d643d8f85ef9b754e9e674721ce523b72eddf99b9d46d8549628ec8b63fe02b57cc238ecd80ad43f369ade4a36c95d9d2cafb3a28797a369c24fba8b1a1c701d4ce9ef88a7e75590ffa3b3026e6eae400a2d550c0426edb705d1e3f01efe082ec2061095c9dab772c63f79e39d6cfbf365c58872fa8b23942e4a6fa3020048034b0dfdd0389ac0307a5aaa51ee2164156e801a099134eda5459443c5e539a835f10db43db56f5377799d1ea1de04ac0f17b8a56250b87828b6f654296c546569fcd77ce3a702fa98922b9201d4ca2694091901eb5f5c9906384085763d06cbc89ef884235fc58d22f704645df1c9a53d7f7f0cd9e036872dbe5a2698e83e6873f821fca411931a7d615d45b2203a99595c266988fbcfe6c7c98403409ec01c21044fa29effce3899d5fd068bf2aedc4ab502f027d1b2cf2b8225bec08a88bf00764c453825f86de6916ee014464ac8ff391623c74f75fe4275b05e6a204ba82ae9aeabd0b19176866e53d8ea1bd5181f23296e7a6344098f57c0dec9452b92fae62654da0508e2666929c7b86bdf1cdad8c89bb4ebe204506cc0dfc2c79fc12ceeb9e9f2be0a7b7754db9be489df65a82c79e1d04e6a4e0ba2490a1adabb9a3d1958fa93e32c1b71f40922263f2da94b2ed301e03fae411014ecee9aa584388a56fc0dca84fc1db2e708aaf5d2867e9c844f4ab34587ee8c144f8bf3a285ee21795c629ecfddc2dd3f635c0f30c85df7e7552a3909dd805d36f41a22f24d12e3a0e2e73574b4b48451870d345f67c03726c1c7bb00e7f5f0fb7ce125b6d6369a1bcf6f49fdb055bc4daccdb37b4ee806f96b9b0cc8a6a6fc41dd3195bcb9b27010953316bdab0e1b0457dbb5829105c9df65d5af5705ee0ea2d5b8bf5f2201f9b7904d65f918305a7af4f50ac7decca28fc55e1b9decc9af16d85e73dfcf4313945259ccc649bef8405f7f5a00aac85637864077b2026db6555044edb011f67d5c70d8acc010ca639a35c0ebb1f675467d282f914da301d9bf42f38b43beaf247eda570379cea384bfa220d764081145649aafdcaf92b5e062db12f4c1be4b1abe5fadcef94b742b8873e809f10398d77d0de0bae03f4dcb83a9a2279f5d3b50bdde4e93fa3fa308a896b9d663f65806286c74ead55328763344f993860795e7bfd70231820d304559c10a20361d236c1be989c468295837c52d9c665ee10029195d4aac396360094098d96200b48a39ecfece451b359c94f8ffd3cab08b30bfaa2b175ab1bd0bf97b05b71f5b587fd04f90f0cf82e18ad56c90c8a3767fe73f7a9d5b34ae9f201bf8ced374a5b173bee62a1017ad16a0db1a9c5c85974d6a7a1686dc4b762348877e129738c6bb46ce30c38511017255a62f99e9d9ba0045b6aa18c1394d8b17db76848e0a434e0878d1140b402ce12c7d79a2928f8bd3dea6702cffb82cc702b74e12a4d033f57b3373593da4c46ba0051482b539800a25de8b2bdb576138eecbf0fa188a315568b15d2b6b85a1c7021e1e9528312b68b0b5e5010c37152d3466aa03056d7f9b06ba10d9ce5bf55f681101bfc063ef764f87522da37bcf38d4d67bd91f96a8a6dc7f886400cfbdc8f3057435e17f38a0d35c004bb1301b49b3cc1c07d8b9ed997840736ee60462a8d7d510190e0bcebd18039e0f0d21cbffe8a470815f96d612ce4b38b3d81d4980af9f02096031d455367b87de92d92f4541ba846bbc6cebe2672f11cc4aaf2e09091c12539a1cdf0392153778a0a6d243a6035a6f41446ad75f436999c86f3503a631e862932c55230392cfc8a554c9002e43fe3e1d938e95871008a2b53a582fb90ad35d66e4cb5447ee5702272e8162e700188aaecd1c49e05342fea1a329897f76eb35d6f187e86a6e8fa34954a61646f0b8f3730cf2191fafe19b7762db63d391cdb06fa60e99bc140c8b76634cb9e6c6c1e52529fed9ffbd9696c9516c95124f9c633769a782516742c57014715e4bbfbea2d89cc66819463a749629f76d62bfb6e25a2666d66d8e7a45fe86a80c4b0686a1209e0ab5db76b6a8c441f9de1fc289551b0b513c0dad12756a6fcf96df6f688cd0fcaa476e48edfb330b49dfa647fdc6ffe1c5bf83f9c873890ad28727db3ffddbefb1e398bda6b1d644e7ae156e4b10ebdb42db3f6d86eba06c93b3ebf50bbcff754a8a4b3e487c7c4da0c9379c5480588e035f81e179e6e444879344e6833240885f83fb2759c31abc65262014cd5acf38135f9266161849bccc9a60dc60da61563b168747eb3a82038d4bd174a05b5edaaf6e9ebb3744dd6344e06458789480f482f5620646e62ebd5f61d6385e29069138dc6babfbb587b2f3c7527631cb77b79e86ef850473cbca7205071b0090ff2da16725b3447ab5cf296f2e9b2fd3f5c5bd9edcb1fcf5616750ca2eeff1fd5fdf674c50e1b8cf5e67f8d5a3dce236f7083d966dae129b13d9accaa457ecf869995e33a49532a991ff5b74c729056756e3e681183d632a37415a6a0d0a565941c2cc170c64ad0430c66273475427d45a1deb0d6fe1c87a820ef3eccf7da8b6b65aaec294be9dbc429accb261ce7027676aecd810eb535e9342026a690f4a0384e221cd8533ca84bf3c9755b677e2a31c8b77acebb9e12de3f32b28c7fe224647d8375ed3bf271aae6c08fd24c904f1b2da472146cfe5c268856960c896a70c44c3164f62dd2c86ff1a3a819574a9692e2dd0f5c59a04207e98bdae65c26d4d28641c41081e79a0a03a165053ff23f824673648934d25336c214e8ee98197a0611f3a40b195a61d14ff16d741386c65fddeb28575a803e52893511b8f13b87ad6e30f5b19fc7adf8086ad6220ae54cc2a7a0d6d38567f8449850ce601e65ae16c8cf7b1b0810855575198855bba1a5d227cb0f0f7815a2ff44406555101519cfa01722e68cb7d48ea10775315d92582b6964cfa525fc742790644d21c279f3d7130b23e6cc906011ac49762a7efaea93d34cd74cd2c9075182c65f1e261b9e37b65a5ac018709880c9f2139b98002940998ce8aa775efffb075cffa36efc00b0b9d4c0354e68302294e9757d28f9c38cd73d63c7257186b751ca54e224cddc43acf9d452e151c46df04c4943d448d8dc2b92463a180e5d3270001969c9228ae9b5c2c81427a2c71f134fcce3c633807933a1e79d8e4f88474f05328d37fd86baae0a203b4119d74b4d300b0b46550ed462b3d0c5219dbe1e9d989b537e428f0fac1a5ea229846ea0f67ac427d177999707b470bb4ae1d81d574c82cce400ae6b888299e267524078ab7dc2f333eed980a95a2e9eb16e27b74b135602a6f346c1b307adb19413e669f7866fed40394ea4a9a9f3299265c5728d70b7dccbbc89a81d457bf8a18ea76a5341110e922f4f3525d8add4150bf492862d30fbc997843a94e204c3d9823715f3538958fa9f5948520a4dd3a523849eaf2b41860dcad0646800e99c387c8ea0290b7aa60f23c1a770b2ad51776a78ab5249a5c28f4ec4c96227a9e96eeb8b01da5f8b041a22bbc1801bdee371b7b29950a62d534ffb38dc6a251082b6de6049169e4f4131e425ae96033d17cc2289541e92600abf0450f4e9b345fafbbc1213beeca0f17c892566f0553d70237256dc062a81ac5b25d4187cd1fa787827468c6701fdefb74b9a56ff420ecf13c738cc45238e64c37d831f10116267941645d6d05b80337b270fe9ccef4f6979964aadaf5a0f143a1031ae3d4de2b12af1081e9b64ccdd18cd0080638cbda19f94a3800c8b937190c25436699413bb1f055b50ea9180ec238d082bb8f89f12bcd284db0859442b4c34c60aed1240367523c16bee1dc00263f5628c46705d9e901a6e41b068c568acb1e3ec21f0b04be30910c094a42d8ff9e08f620d30a5923b8544cbdfc48b51ad0c9c7ce7e6056c29bac408e98b0d6166c0ce557ebd93d7a7ba2c90d8db4e8328b662f02744e93211e123853c1f4dead404098059e46a65d2c29b4381319b898c28c0fd3ebe65e6a9f84bbfca90c4c294b926119b62819b2a9f1342d8b217206b2f750eeea2ba09950f6378496fa09597fe842b60e647baff3ebb220bd84a8ee0499906d49ecfccd9d413e56f17dd64850ddf992fd163d9d5fd9683443af48963176d828502050449da4b7b78973ffa35843d6d0c5ccf9c5b19293e5380006047cbb5a003e2dfad029a284d7c19870f1237f865b4a4c82c876df161976307a26fab5d27d2f52a50dbf79c9c122ce9672a11303dc4f2bc7224c70cdf68af4713510fd759bd3aecee3abf0fb2547717f49c217886ebbbc0a0a9594ff788ba29c5edaebd4f057601fd9a250be2895cfa6e835cb65b3e0d6a5c68e8ae79697b6c673b4477cdf48482167699130bbd5672ef8dab7d0931390fcab8083b4551f418868a1af44e6419236790a7041d9b3bd48b165ff4a3c11503791150df23bc16f371b51534a1597c9ac4fb747579e80c56129a8c19cb71cd56843489a968a5b7a5c1b9e22471f0f0808da4d897d4da80dc0d9bb9260f856dd3b2f892338af4959095eb1a3aeb637653453f264c382184c40973b6bb6679e4d51979f1b7153b327df954e1e700caabc43849cbddc80a987ce6aa546acbba63622d8832b97cfa001e60baf4aaaadef1a4ad863bb17ab6e5c2902c0ec62c48e6fa867f44ae21cc093f3f24851289cb1832ada415ae4e8ef8f25a51c7617f90e20759854961bddd48b2a37ab35f57a6bb451d53cf287f11b4134d27c26a66a6769b7ba9c174b7e23ed1bb1beb94a89ac1ba2cb4aa39340690c4b02f73838de62a2f2e01dedc16044db0a11aacc3f3801f960067fa9e9ca655a3f9ce088d343ec543ce3ced79c21a6229fd96dc91d3f32b3223604c8fc790e6f5d0b8cc00f08488a6e19c24798b2f70027d32c8143ce646094db3d33ccf3af61c90d5bdc51e4010ac59d4177698b614bbc0ae8f76706ff1bbb017f4ca903512e1810995e1d31d0542a071f897b196d143a7be8b2db5b2d1ee60329572f5f861f1bb77303f03a228d15635ecac960573cd57c7dba77c0d96f8071b4a094f958eabb9e5af72d6d36514ab79787130ccc6dc6da8a601fe80c01245f35283404412103a957f7acc08c564c462677b5aee232fd85ed61db3b5e1715cf2f591327ef974ae5d9cadc83599e6e5e783483786015a043803a5c2da6ecb78554b7262bee55fab171d45d4dafa0f6bfbb48c34f6d8c23ad99005d8033512d665c23b3aa44c4007518d43da0b29c9416029116259e5aa13653d2741fa3f93655ebb667b5beedf196477ba4ea70cd89a065d19433b5d0dc1133b10bd7fd06d13b2e23ff0271f719f03cb6641f4e88eeac1a5f8b60ea9b315ca98fa181067e7b466a95ba5269c71f2735ed195833a69633d5b8b8b8fed8461ab5528d56d5dce6ded5bdb2275e72e8c30ddc13118bcc7121b9e515e9de62c456ffca0b915ef72604d1460c869d49e0898bf01a5039a3af626bef3e3ee594a5330339935a59c5a06ef058bb6189c3cacc0e4a0d57f36a90f9c469a88e3a480e746a31de53c0ef6d88a9309448ce9a874b8f20f0742b3ab8ccd80638c48a2b39c49b4c9f1035556bc3c32c720c9f9d68a3eddbef7874bf0a220d6319af498b214c23e16d9d76a116d8413759f63808f2949b3609dfdb5790c443b903a24c30f703ac9ca9474155c4710c02b42b9e44a649507be87ac2c58c4021439f4f03c1eaa62298b163b48c25bc38df2064e1003514f41809a88870135f915044358768b4331561a085837a65ebc2f8554db420354903a4e08e65a6edad87aea02a48ea4036f38fb4002728364202f149b663b46c3c8a5d887694c7a3d9c9a01c1fec233c19afce1c8e034a8bc1235047d4b8f6ceb61143df7b2899afdeff0fd545a27eb306ceff97f461847ff8799d6643a812a66b881e143488ce90e308d05626f4f04cac27732a16f50601d945a93d77f307724d782cc45db03afb810fe8dbe7157968a2e43b15232034c6e44a85bb31c77d2fcbf518697b35af483d9f64cd6c6a125eb7c4ae0b6e193866b80b89873eae009e7ddf27b6258751b78506f9624cb974cde48ae2a6d90a17a336542178fa69d8cc4f94feddceaa66d386d02f6c4137daba8832a7fcead65c4dccf5a212f65eee2b42669583133e3c3b4bc02ad0a9a3cf147d2e2b65c3720661a040dee0d521e82c116a4783362fa90d51e1bfbdfa977bdf5d91038137b17c32d3e1074341d72066cc41da62b9f35b6ff3f6cf39f8c02e66b309c56c0cb053f3954bae6a03bbca8c5e34bc44e466285c305af8cee4fa4027c84c63bab9e638ddbd58e489ec08478bc15eb58645ca5f26d4aa9e9f036c7310a806994ef7a0fbcc31590eb6882d784f6a178f112477682785eb4652bb51e29723ea6415232ee2a08ae5673f03704c0e1145227b844aa1a4bd4e26d42a56bbf809a38b5006b8423476c5a54cc90a1e4e17fd892c5473365205c53dca0773394e3bb4c58922cf5aa33ffdc6dd4c4e799c83b3830f813d964bd7383c9e1746c372f13f680607f68da1a25f902425ad05e49d17f7d8210140287c00fc507d9ba31250bf125939c7dd697e1b8ff108f194bd3c9133554194ab954d89c7c40404ae30732397956264c13eb359b7edba67a0be80ada0adef515375918a903efcb844fd29798a707d6e20d8378b4351f3fcecead8c0123c36f1c5c7bf43188f5582173d4d8bdcbef80ad435cdd998a9615089965b132a93748501b85a4b60153e9ce5534d91abe86695a5f9c96882c0fbc3282975419b4255b021222365429f49bd53d022a77a37e1b672b01671dc91d0524e3a0f3cf7473f3af9c5673082abaf52a6c58b6d35289014d60e6044f475418d10271094c28b54a91c124d9b613ff83a3e526de885421c1a297c9053edda2868c53cccf0ee1c12839cb1cf6a3fbd66f2c5f20a7217e61698f191beeacf257fd5bdb789ae6164f74124ba8c633829131fe86d5ad9e99aed36a24b7411d2788e9b53446abfc03cd012c97f7e120a8a3a7d54a6ea925e54e9477fed4aa6e08ff285873052ec4acd29445742c7e20588618a2877168c94f91c12023295c82f3f8fc8e5d32d63836539a6c8603f13dd2c212284f7b5e61c132f84a05af6a39e618afa1b8ebda82abf66cec07a687443e7d34d5a68bfeddfb4d14ed90454e137b846a826129c422aa619f0def30104d5535933bddd3473804b1101c65656cef4616347567bd0e04df3735815a2ef52a12d2823014e745c4d85d0bd10b01f1bbe01a88d59849489d38edd2e6cb8e3db9ab0d4123ac55bcfca1f029853eb9e72819c22ed46c4d022739f5af70b7c77ad032b44c46626c27d7df1870616b556dd1b448a41789f5b0c5f95f485ea7f514a8ba3af6f051bcd0bf9d8de576062fb8cc5beac7533293c08a94dd372694acdb0be6b5df3f987382c0c9dd45ee4a89755d4a2109608339eb44f16d5a0eae9324bb365a63c440e13c5435d23bd87b78548b9001dcf58cc369e8b84ca70b25e7e5dc61ba7abb064f54e386b6927a8e805ad4dd13136132a3f3e014a833d7c0503aa480e7957301c4d750e9980e4a26efd268682d49171245b6aaeddc92bce7459892a91203b8439786f4482380b560070388991a9ae3280fef556ed3c879b5dd7967449bf2e49d725fd24fddf49db65d1b66d973d44242864e5962277a5077d0747072727a8e828648eceef478e28631b83167b4a12d27ba3460a2a7a4db7bb5cc35036f66c46bf63ad868aae22b6e3f591d44115dba9828a6ecbd7a6d7b3a1a2dff2fe893ca49c4bc38edb97bf7717c48c34446feeaecc82f9e5154a1d65b0dcd1b36bb14f090c67220f2947e4d19188d062bfada039d157d01bb079e3e2e4dfbc78f9e2a0522f8b2f2f23f4f1a1dc816541ccea8042e4b9b8f20ae54f99059147eb4859c8918585869252c3e19e07edb876aa9c21b65d2ef0009d30f284bf21b09c842150250b6fe3efa681f91ee00281c012087bd1e6359c892530dfc23087ba125802f5ca8532d85e2194e116a5d64973c02cf61aa58e7066862094e1520be60d2e300194418b5d37f2b420958216d7f8b1216586120c25300be9755d09d423a952026f1e7530061a6863da58d4286f5787a0100d59d1c71785ace85a0ba1068a17178634d231e92b8c95cde2b2b2d232fe9843aee288a325d75a461c0952ad81c01f9094e3859443d229456096896276920e2947761d292727df441e5cae668a14688e949322e5c0224fa9a664d38b6116f75acf219174b04d9553d61414079128d4200afb4592542bbabcf8527af90c73c2a0fb06e71af7295099ddde11c798a3e2a775da12b45bed353437ba69d37e4b392cf8eaa006a2225c90af08b704661886398761ce61bee2cd39e79caf68820b5a2f0e96b1ec286aad43f18ee24892492c018f4ba83104b20a363c4e3cc1e3c48a67398b573df7da5bfcf618ffc2f1133f1be04c00021190400fb7182827304c562b58e45aa87c6208aec1c769259e47bb140568bd5cb61112919a0acf134e38f1048c99cfc4f8176e93b15c254505fe5aec221c6c2377306b83d0464221647df946f264d96d231106f36df3b2cc07dbb6cd1a42db562264318d659dc5aaf3546ed5a5d216ab2e55ad22dfc619ed4c7ce693f52b70e9733d03fcf50d70d92fc0475e012ef20870924f80d7fe000f70da3be004c51760009a2268ed031ca0eed4199546a5a1f2541bbd1a93bf2839c278ecbbc1385916e3714e96fd7ee86c6696e7a9a62840ebe51a2111a9b164a34ae65b959b6728c55685d0dcca4d54e43c470f598ba26468879ed1c8c3638fa0440502ef834f60d5c3ffe012789d931fd2e33e959e95aa6783e3fbb5fec57111780aacbcf63627f99b8b3c8c8ffc8acb5e857c109515cbcb85be7878e4e084ca324d43a150281412a9acdc6ca8d6976f46dde51d7a3638a8bafba0c16159f7542a4db349ddc14e371d71149a93b979d39a87684e24f7e263b868cca8342236782bd9aaee7a780914dba8eaea24ffbdb7e365998e7a7d54576964d64b4d59d51a592b5b551ad7005cf601f091cfc1451e004ef23878cd85c9dfe0fe0470daebe05b88dd06c0054d1104f8978e0efffaa93bccaa332a8d4ae3559e6a43edb978b5e6869797a8a30bcdedd3497eebc57216c9dfc0f0f5ee64d9a33757e7025f3ceb43bd63b8ebe66419fefd60e5c9134282a7446a938678423c219e10cf48c2c83fc5581fad130fdb741ef420cce5e45b47f9184f7995d75ec5491ec645dee6237f73198bbb7ec57b781f5c025f01279fb452d11481038109fcb5b93d18f023bcd8e3e5c5c7f0fd2d5c7fced567e1ac5fe114f830e6a502ef383ec4b43b9d70c6b2b2e2d9e8d5a8bb926f71dae3dc3fbbc9bbf8c9bf38caabf0941fbdf62b27799b8bbc8a8f3c8ccb5ee5afdbec6f60f8ffcd0e307cabc61d58523b1a5ecfc67778efbddb701e666970be9265341aede028b87253c1f0545eb5a1f6305be33aff2022f2d735e46c7d8c97fc8b0a37f9d605d7c252754cabe225899ecbaaa3b1ac7bcaa7fab46e5312174173232e82de20b63217395f7c0c273f944253042b85aaea9086d3b8af24d8035f1134c12d5b571e43732a8fa13788b2b3f5ad9764f77f89c053c021f03bf8041ec6e828aff2d9aba4fc26f91517f99b8f3c8bcbdee63d7c055c02ef837bb42cf585af9704ae85a56a0ff2b4abbafb69b1c77eb04d175b438bbd257cf9bcb8b80fb7baaf65f5b9fb545fc817f279b0ddadd0507959e5e6054aa5c9b25d057ca0004e96b5d02d0909c9cccd91ff9b1831524e3c1b255e3e553df15422d40fa8332a8d4a43ede1d59e6aa3e2a8be09bcfa2399adea6e64f63731fcff06869fbcf350de6df82e9cc5f01d63751a9a1d0363f55e96994c5e32d3d1a6ff4be7f5e3192141e2916c94188d46a3d1a85443a3ee6646486cf44a4a642edaa561e3f2782623ae132096d0ea99a5dcbc98a1c12c8681a2ee5c50565cdca8788182ea8059941429505a9fbde4599cf62deeafe2268ff3ff15cabf78cadbbcf637973d8cbf7e74d7abfc856e677ff3e2856f185b2f09ef81fb688a58e161f1a83c3c24ccaaee3e763faf9fd70b5c12bd1616ef81fb8aa05959d555afeacef6ea8cca4ab5c951965f5e4373ad970f4be66a8a93502077fc5f392f1c9e10123c25d210c913227942244f88e4098544aedb38ad0dd9ab3b7546a55169609617d266af57676ab58779caaf8ef2217ef2acbff8186ef2204efb0f2ff9d8ec6f78f0d7dfbc7092bfd9c17b7897c07b04de21f0aec3836f1edcf5c24760b8c80ece7a21762b5b6f60b8fa42ec76757207db3e76180aa1ed8388902579f2cd831989f0f66144c8cbb70f1b6cfbe861167f2441633d95923c2d3ef178f8574f7ef984fcebe715fc20e263f7d1f3e087111f341f497cf43ce8410f7ad0831e3cf1d49d3ae3ebcbf7013abdce10db736db9c95564d7a72df575325a9397686ea542b94992682ee5a8d3eb6e7bba4d9c7cdfab8372ddcd7173a076707b4adbd37ba0bd3bf976af2f87c9b1df26c21d261578cb58e2063fa9ee2ad1faee0d25c296f0dc371f4e9291676827415c041ef3e124b9ce90b1419e09d23f9e09adb5a3da345fe44bb5872de9bbd4a4d66b4903816d23c72e63c6388e7c1ca93220df0e5af72a84d8b6d7f7f7c6bd9707ef843b76801802dbeefefbc3ac0c6c0bdbbbf7baaf4f873b80903103443ac8cdfd40c8d0671ecfebc3b6df693cdbd267601b9981f61ca23d4b9741ba2edc01840aec81faf5557c333565b6a36e825019d1644f0781501c72b9d720f679a2a589f7f619bbf570dc81d6f47bbe10b8dddb379a33dbf24badfedb8e0e04b689622b03db402e6e1372eb908e91b0e2cbc8b719b88665ddc31d6b482f1086d724cc30a62b6551a3211c09da1e2f676af67a383939747470748ecea175d293042e0e23cb6c76d09fa147f697ec3a47d6c08ca3fd6e10eec5c5e55f1ef7de8e18448e1f080543c1100ef9847cd2138434ece909d214a429487b692fedb5388b9adca5797aa0696844129554a8d48ad532a53a2d2c3f7fb96e0a5c51d39fdbcea65253b34941c17122caa195889e9889802423a21f919d8cad09f900b189e180ada39c11153ed5c9b7d4d792eab0a43a2df634c7c58daa10d2b057e1082df614b8b7ba624f7f2eae84e396feecf24de4d9ed6a2eaef4abd5947a2928372e0d9fa43e13dfced76217d1442522d14c2422118d8844223f24928cc4924821241208e983448a8d4654b8296cd5a5a3f5870af8f573fd7ee57953124d49aaece6470b6d617e0ad6d509716767b501833521eae8c050108be510736227b86510df8f313b0edee655c421fec41f08089a131d24879c2116751d836b2bf52e8b9bd0ba094c0871a31b9752cd0c5ad2eedaf00077c072072c421b02422bba19986f2ca12ce4e110803a6443fef2a05016f2f245e12ce4e79b4236e4e9ab4236e4e6ab846ca815ca42a39016fa6843b336e4bab2272496e52d8d3cbbe881518834a2377c2ee60e0a2c1b61a1c50e02c2d32d8be64467d11b702b33c244c396ec04b6895a032fed09ed841037fe2e0dbbcea1a1d0624f3d52f4cbe059ea288137c0117176e1ec07b33e257b71e60742daf8338900b21995d518191919a131424282e6b293a037e0767493e444b58e6e227d73f7e3537a7cb963a74c43b986f20b41cc48b3f0790709490966303fc6982427cceb187376c2bc1863969c309f634cda09f338c6343961fec6a41061e004e584f4201de6c39870bc24684e5cc573fc8d3a634e49f9e212a28d6883ea26703038b14666d350b127d246606243e4992622f01177b9a7878648731202149413d53bf986d319d8e69d1d680e066b68eede9b9fb40466d1502fa7d4d339173702ea1c1747dae99d7c2301713d9c1ece0898d3e21c2d769d256c38d8268a663e339af32f67d01872537c124ee8494b88ae23d9d888bf94c7fa437fe7cf2cf7aa4ba53ae7206e6bb30409c704cd85d630cdb44c135599dc448e1a9a75c67083c8d34c510fd228742a895228558b65436f18db16eb4b1d3bca2b94c012a8aeab14eae75efaa94ea552af742355eaa14a37446b69b7db95c0d3e9e425bf2e8afc8a4ca792c8af9b4aa23238fa5247b983d4d392826d1b4265b0d451ee28af90a21e3a52d40647b941a41da9865443ee5557fe0047a39fac75305339715ffe6019f650868267878e6e6f36ed2816adba0edc959595c01248aae197061f349cc10c25108a329021d58dbf12f8938994c05f09d4c05f4dcd187a52318421e5a911192981e3ceeff7c3816f38dc2af26419769ceb4a67bbe25691e7ba795fe401434fe4b95a873b74ce98fc42aa2bf5da9ec8d38a54b8b7520fe782167b8905f7865b49397ed7189072bc40ca1921d96776d0dfbce03efb7070727e3b0320d1c5153482484d8ea3abc01c1849d0984712993932cb414847902ecbb2741558e4a5a99b2a3c9a9de823f6884111888a3cb87d7a90e6082a530fdd3cffc6c5c3e5c54ddcdf1817bccbbdd10719c57d1883ee355d492da42508543a483b480341a0f6d59e9f97d07bcd363657a3b9f3080d2cbbd06220667504d116af56af215e17c8d2d78de6343bae6430bd3ea23933240b21d57e53dc7be8bcefce69b366d3681008f4e9e9f90089e513f7678cc62a2ba4a99393c3b3b313fb80dd4e96f3a6620ada7b9fe8872deecb987d8373f3e5e24ebf2e9a7e4f3f87484fb3dc201e481c1d9647dc833c4edc6f5f0edddfa70ec956f49b4356f4165c08425f3beec998163487fb31464c99c0f9e31a512f0c4f44ebe9728a47a4baf1877b1d73fe0dce3d56bc437fbdc1615e96d160d607e9f8c33692d48157b4456e33175212a9243ec94b25d34d37498ee7e966e8c47d8e41c5ec9141e4165292dce31ae2399adba5d3740a718f635091d4422a8a6e0af15e2aaeac84d6b63867dc9234131237e6fc4cdc6b1da48fbf9c5e20b0c6c5372447931312f7b2d2536a20f9a0b604661401e011de690b22c511f720512b7a09dcae2b83edd640eda668ea976f451f5d804465d27103a3e83b8cc1fd081a7f3b40e80d0635b957d00909688e59c4ddfde232eafc7a31f8f548bf5bf16f5e5c5f9e30cb4ec61fa42763e6000e1e7b195f791c9ce55d784bce4b7e85d3de05c6ff5f5cc8908c3e484566e1c51e2cfce6ad27c08bc5cd4106071700f857d0d78b7d2105cc8b4b6e853ad343f9159e52fb185779160efbecb6d8e37ce5659ce559dee23253e17fe27ab5702f572b04f772b5425430c2b2252e58c4b42f328736e0000019172c62da17c992c864b4d37f0000c0c16d9fc3ab7db5a17db5344e965150d01ccd51429453ffcdc90f913aafacb3dee10a8b0da6524b19c9d9c8c8c8c9e99f838adacbb80a00dc861b9de5b39ffc8a0078cbbb52f8ecd5bed66fb55cb7a17da58059f9fce456b4346e24af58bc563b7133a5c5b20353199dac699b1e49969558ed64239172b26273b55862af592f9c6115df5681f9f2d9944ca69a17944aa552a974ea8102d513dc0185cf8fba53676c3593ff2132e07367767777695cd70c1964fb2c2b8bb398fcfa373a7f07e2538248f19de2638a3b8bcaa4f8981292e22f2939a5059549596b2a6e56b2ac057581d996dce22f9a63b969b3ad9cfed951dec553608f63f9cab370965fe12dffe2b3cffdeb13d7abf572b568266d68ad3041bcb884b8cdd220abbba03977f3667bcd60ffc2a9a5cc683dbf5af9a0fcea2754214ff2faab1d2e0fb2f223aeff567b36e5431ce53f4e5613d7d34a5eb31609c988888c0db1c02ab803b6be7ad7632c9adb6eca5cf98684a42fab1ef605f51a8c4a8adbfaab1dab9e7515fc40da8ac852b0295e295027538a1229458a57669179cc897eaf98030923996659cc4537666376403e2c48774867c94d029dc3e6649ee8220c44e38835dec934f7de7bef156dac8c344cc619fd03052fdbe08540f4869b6f3009518bbd8c9ba0432d923e901319b493c7eb811209341ab4d6e27863bc9b04e20e402036a478ef9dd806238c30810944306c227611bb043423ad492711a43dc8e3983f150551cc591445511445719f208b2bada8c5951a88259f42aadb9bb5f7288aa45e77ef665197cc9d6f246339e79cb328668c4912549a27eab149581a29e9ba582c0341ab4fab3311f79a71360b74f906319644af17c8be5624793dd829d829d82bd82bc8a2887378851c98cd9a082151bcd74cd391f6d138865cb78f685bb0b468b56a7fa7d309058d44fa53ad6897a79a9e49b261d7d834f60bb60b4623910e66b328076643a1539f1e7a9360b7608fe07442a13e0332b4c8f46d6e739bdbdce62ef146a2530abd3bd32904dab522de78030502ad720f3c007dd0fb003a88ae8ea0e85d5646ac9c838b91d6a493a9e4a63574122aa3bdb48a466e4273231fb550c76cf65b23258deec85b688ee4a6eadc35ab159a2395469a541a6993674737ba511445d9dc48452651e94b4e98d6d2cede91462391489483908a442a7a03abd5a9dcde60be9d3cfbf5d19e1dcf601ac7344a5f7aa2042ce9c06cf65289677434f541aaf5e3ab75284492a7bdfb1169b486981579a0a7e95392429b7dbf0e3bf1ba9c45ad474dc2af2c8ca328ea710c912171f4327511784cc8cb726f264a0f3d13a3876b1751d7a37bace1e8e859ba89e6cab21451997115b59725688fa011243a4805de2fb6a2488e5a44b1ee81296ed7b1ba541b0bd931fb15b5488e0f68f3e8e11d425c7f103dfb1dc58be6e0819de22850ad3548d42ed0b2347d6ccb1224def36a2b80f61652ac2d6c50e6008dcc39291a4b926f440f3d6ba0c53aa4e53063f1c66083b01736881cfd92ba1d37186e39de3b96f78eed25491d29e8662af8589665399220bd17b0b787e2102c2b553a4b7b679a3bee300d431e79244127aa5d450e5d0f15a6e9a659fe6d41e835cdf3baacdc1a498d059e587c82984f9d8a22899e621e4950696af477f869db6263c1676fd0066d0f8c984d02eba20dee6e1c6730a2b706f63198f7de7c7316af98af0e1558dfdc82d5175fdc896d66d902f2ed39672de290d51e6ee6b0dd1e18cda16f8aa1b9869724c78ce6cec7214dfb689620adb5d6dbcd917452c457d43afcabf3db902c08f75d3716b628e622945ea4d1d8dc7b1c6b1c0b6409db344bcc396bcf7ad43e3930cdd4a8ef4bef6e13f0157d5a0cc399f69c039ba30bc49207c578c7bb4330def1ee997b3711f7661d38c61b04e1fe40b877580a381c1ddf28701b521dabbdae862d619b532cbb9e4f36a4a1ebce1a69e86218865809586c4d3f642de6ac473263f29918731eb3e72b93d71a5aeb2c8a3b6618bba62815a521d1cd019748a234a402e33027ccb94b2c61824db1241691eaee12b9abc41229130ae526944e557ed315ca5b2d3f5fee25cc611ebefac7fc49df1a159b01840cec333ae95b27a305814c27579d3a80d337e977d5a9e62ab3c9eb201dc8d57b49dfa76aae32e3ead735c84d1e3e7a38f9da55e3e8e1a48fabe89792eb0c51e5e17bfdc1c3c7f587986f10e901731d7313ca770ce6bef2bdead6ff7bdd4bf7d25fd781b6bc25e91a54fabe4ebaf67555fa7edc92a055b7f219b92d5d27ee57b9be5ebeffa57d6bbd7de5da5d5b6f976fd3ef8afa5d5519945f2fdbf387d35b66cb5b286fb5fcd4c968efb882f4559d344dbf280e286f7988ca98de5a75a79badd79d6eba69be0e0f208ff7d3f63a483bcbcdffe1f4d345c771fde174542b95da5691239b71b8114d657d85f29ad9604568541abc90c4f5ea0ceefde441dce443660f23718db444642abbfa10908f184c5567445eebcba7ee5c64c4b5834c0643e63222c145e5c50643aa33342958abba5341320223c286c0c0a8522698120906266c572a9a15c020075d7082e78916ec70cad3072d1679461a36a7fc953a98c5b65227fef2addcd1c1b612b884d0566621eb30737ae9f83cbddcc9b7b204625b596621b495c13b825086ddfc6b447882bd0ce69b4996953ed87677985d4368bb44846c3699b92a68b15f1e56c16e926f261234a01dc808d00b5aec1a64ee40e66ed3e89dd67b976fb81462efb00d875a5f23c2db3982f3824eb3247d40d3badabbcba9549ae61d3e9403137387433e73d7e274b731c8087914712e61adb50d4e8b5b90a8cdfcb72d7144ad0267b20be9cdeb0d675abcf792e4bda90fec6024b598c9518b2b089831fe81fe470e7b92fb6b7fb9d69209d65aa95e6908c8074b9589c07ec66e47eea8d729253dccb313e4687533e27924c6b231d6cd91d248266f8b8dfd72cb844bee5a4b2f9a7eb73e5d7d49753a43764cdd3bfab025b95635e72cea52c4068fa7475346838666244f36cfe4dd6ef4efe487e8ecf00075fc727260f6c7c7279b4699843aa54a51a82a6bc53dad154a754a85807ce0484dad952a04e483a5ca444699843aa5423073d53aa948a89369e7940a554fe4e0092c994aad952a0484843aa5461935ad54a34c429d52ad35074dd924017111fe8d208fc393d145a33c6691699457232334d8a6c7923edca6bf01f13c02315d286e4f0fca34caa5284ca35c8a42fdb035b556aa10908f5126a14e29d6df564476318bf50112a232b55624d40987da848e0e2b474ece25ef252f199af2cb7743c4e1cac14bde4b5e3244b56a994699843a95a2488dbfdf78c97bc94b92dcf7bf4aa6d64afcdd1bd7e73b995a2b55c8289350a9d39a7d48a6120f46d9547a52699d21c3547a39f9639bfa50f55907ebfa14cbb118ebbaee8aa139919b1f1fa6bc7212ea946a4571529d541b04cd954c79f4426c97959511359ab2e96f586ffd4dccf7fb783127cb749a607da54a818038e9c34feb0d889beccf30218694d630248405817c0a02f20112338d7206d246a234dd4ef03c718a2bd6e1046916310e77d7665d23e79407a0750c65a27b04d166bf32d643af3a9c89ae225e16e79bb1a8b18602e7e280746c85163b768c936f3edae41b76bd5e51ff40d42e2c6a2626c02d9062d8b2df8595ca5924c58fb98fa5b205add45cc296ec5acc23b95ef4667a78ff6cd97c33d75a5803010e4cbab3c09b4c99b02e58e410b66417ccae64c74790f792175496aa90130bf2f16ac15c28d6fa0e723a9d4e3115b552858484a842d657338eca880412e590c88be6522ad66815ce52371065f7acae72ce7eefca84e6526e9ece1ad4f47a27144a031b3c1e2ae58143838626f6fa60adefaa152fcfe49d4be57ff2d693f8c7cbfcf522be7ecaff51cefa115fc5602e10350a950c758a81a8aad5ca056bbd3e58eb7b8bb55a43542b95e7c3510790a5ba56417f7d84b0d657552bdfbcf485f3fa58b50d4b5dadda86b5beabaa958aa5e29c130e4fb2c362e1c51ea4af1ed4e6d38ae6522cd54a5d85acac57552b1b084bb55affd767fdfdf1f151592cd54a5ded10c45617acf5faf0075157ab98ffca5255ab57eb631f6162f24738b1b37372b2f29ad0d1b9e4bde425fdeff510d6aaaa56e426b7ff06c125ef252fe9bf7ea851b056638e9c9cf192f7929784c2e7e7e2b8bf7d046b7d55b5f2cd2be2de50b93e15dfdeb5c1e30d81595f61adac5656966aa5b2b0ceb2a0b9d4fabf7e88ea51a858beda39b8d0d9ebfffa2c5225d7ff88c158ebfbcba5aa56adec1783543e15a63eeab0542b75b541c052add4d506014af561ea3a2a5f5464400e5e1e8077b5fc865bb1b174204000047083a9d4527c7d9a49490bca896bf66269392ec6d281000110c04d3c5fafc368eed31c51dc44b3bb7992296e864cff317cfd09f8ec7b70da4bc04b1e026ef211f096e7c15d15709594a780a3acb458622f54cd864ad53210281d2abcd8e3e404cdb14a50351bea74ba5a39bbbf18b2d9d7a7652f7956c8666f790f67390dd9fc3ba4dc44b556985ca5444ea7906a065341a1d2d50ca6924a89d4b3f639b7fd8a594fa9542a954aa71e2850aa1de8155a35e2326b24b3c261cfc26d2b8f4be1250fe3b457e1b31357ebf572b5d647bd5c2d1529605e502b7028b485892335ad4f3329694179cdfc75b26273b55862af994a8d6652d282f2b09bd27c4573266edeb405c54dd8397b132f7994fd0258dbd7fffdb93eeb6e878282e2230a8a876d8ba7d05ccb1aa6281e82d282e2282ba681694c4c4c4ca88c8989872dcd4b688eb686a9897f98d04c5654c664c536783c5c837b30d87afebb9facd85c2d96d86b0653a9a5cc6826252d285b05eea3bb8f6b584265dcc9ec1eb6ab93d0dcba86a93b88af0e43657cbd50c0d0dbe36aadff9a651b29ac256b67ebaa0705e93f037cfd06f8ec17e0b45780973c02dce413e02d7f002f80c3fe85aba4bc031ce5e5800c3480010b50400210700003640e14e07138cbb5776d9056884bb33093b5e469af996ce7025f1fb6aed6fa37d7e71b01396daf19ac467e5e477c2581ad3ff33d3372a23ccb533e050072089f52a8940b9d296aa8d00c000000000473170000180c06044302491426699e4f791480165b8e72564e99c9c4c1248861184621648c218610420018223042404326000db8d5d6f9f67656607b416ca7a32052c84d35f7a34daf93ef6d18a4cb36c5327ae7ebcf67400c79715e366a7ddb093ac34b01fcee31e8ea8022cd4839121a519b812aae1beb67c303c4cecbcd12f5fc8c29d4f3e763fe4b8353db88e6fdedfbc8a22422f37cbdbe6af63243bd76b3b0a6e9698870e4d4750c41acab75cd931d4c23c7525c4c9821f4f92a7d41745df1f219f0eef3391cde352658ae678dd3cd55e4f8fb0953cedb48559080bbc070d8a58ede4223d6ffa188e1c01741dae8bd14ee4dcf9fc3783775ed3fb1e7175999ce91f9ac6bb3bab0729014fdd88386c11e8b7efe339485aad891db17599b7654758203e144142642ded4da6739c1271781ef8555bfb5a51e153e7be5413c6f2303fbf4858a35c31acfe3110abdc0c074db9bb83cebcd3d38683e723d4334f7b5421578cf759fd3e59365a6a4a40c4411fe77ff151c13fd26fb1e46ffccb7c401801738a2c58d7a93855f608ef65c858ab3186a8e106796d54bc59313da50caad66097654891e249769d1cdaa1b2cbd9e5039a86ea95db98f458dde43147cbfa0e1403ffc4844894ff0777fb31a62716810e201d40e01ba73adda153832424177a7436e27a1507f7819b34aeebd140d62f7c1577563a8ac0c474a02cad4f2f6161d7a893618796459a22d4077d3b131e477cf4e663d07e6f37512d33e078277f90e1b4732a39cc9084312a81a95c902ea0593c72608244443433f389874b01fb5b05423a21199472432d2af5fb4dabc71264610becf0b1c0d6b85a0eabbab40b03d91877e302484de4e29fdfdea1e3d1f396817ffcae7585c74cfff5d23a662cf76ebd6f04be9f3c518aa1ae8dd9ecdc0d00e32a1ebb3732eb04a372739dd6c91711bdc2ec12fe3edf37dc17e69c6c90fa5008a30996c5b57d7afa209fb65e2c1299536267a410479253aa51f6811bb0af30efaf989a5650503d081458bca46a98486d7d6d2e12e4a41ad0f3303909effb1c67ea94cc001e4af20e84095e2e624cc3fe800f29180608823265d0b2fcc0f3e99fdee0e607e3ea478ffe06b790e60b2f0480f4873dc5e6faad69077ff74cf750760ec2fd001548c2e51a302c01a710e202e346000ca50cc95fda59c03dc24502cac83b7c03c5c749ce0750e303d064469fceb4b9559c7b95c0d58af2c886d1d8633ffeae80007139c3a8035815477c590b0583dad734bf8f0f34e72836148f200b41673e9b6925649c333ffa5f301d48110ac02900000848b2fac7a7bbe60ac4ce7fa5765d09be8f90024526e916a7e9d50b8e22f85140763c87a95ea0d45629520bbd1763c0e51640fa0c06f8cf6052df4de3073020244cb0e3aef0fb93fb7eb3c9a72bd8ab4ec6d0c245ba6bb689cee87b081e804891319f3c461bfaee6ae4b2722ff013a5fc0098d1355e17cc524c10e04106816af160f30b27302c1dbbd1b98c7a820c066abd533ca9b9b65d0a8080142788a0d02ec6643726b254f07c3dc8ea65373181f420071de06c231270420088e2664257c485a7c4a0a04a2a19b2f35a32d497bc88cd03774bffc43001dbe364c12a23ac8f832597c818b08a03edd8665b5f088ebad1f5b9f0063f49608980b2f065d14010abfdbbb11140193d4a3056fe1abe0b5ef04cd637e4580f5fbd6a52e0206430cd437371701d36705fed3b7d383f728643b5784205a62ec689241b7b4d96e20a5edf293f36d20fc198eb184d4c8997b0488269710672b5419c73f7590b87a04bc8f9589e0e7b3c038edf19000a28bc46a24205adcd6e336d47ac118b3662400a70a5c433b4b13930410b62de849b4c0e8b2cb60075ac656f492f8b3d09bfeab51acf2c842227fb75cead22b3242837012400a45d143ec88807ab2da819bd24455369077f422ff2754cb12304307ddc42cdaca65435230292eaa1fa21a8b240a69cad6e82c01fca4f59e7c2b6cfdc0367133d42ab5e95ba3bd04f093d6f6f22d24eb17dae464f59e3623c4ff3d3d972e0240b5beba3c2660cbe049a3ccb4bf4f866bbfaf40879835a742c15f4cc9d0918f3f9882612bb81ddbb49821dfdfe5748150e96c2c0fcc315a59421ba009f0eb3ce0f167c4750166c9b2c382876ac40e71ff2e8ecb225eb42bd526c0fc1cd629c46b556c0065eb88eb1804b288398a9f25154ada5227e9750a8c64b89c0063e7d86b7cde72028881bc60bf75024ea79d77f0f10d7b02a0e18ab1f1fd0464824afe8da5fa4001c4e16a274201041ad04d3914405d2fc65ce5786a788beab63fef7f92862fc50b172a31afc431dcad46012173a01552c0fc3f294d0a58f1fa783638ce3cc8f77b44c7f73dbfd2a8a8000b0fd8db0b7c88d327c6a2021058c2fb83fe313339706736734f4e05d8e013c29e7e049a006c3c15e08cd8f11c668e06bc98b5ec04386d6ec11af0ca2115b00af0dea181d448d7bc94c7c7781ed43c60b29ae1005d1eaeeef77024016e8ad772f7af987b388dbda042eabc9bc004e18aa99988aa8e974cb7e8fbe9b074ed56c0e689393ea8544bd8866aaafd890826d1153075bc356589c545a72b60943cc4442781ea733c27c8dc757f239b23af2d546fb2e0bb9ef810352346a05e015200d26b5dca46aea7cf34bc0012fb82bd00ddaf23a34cea1720e7d9ba2964f52c2cdc351258e80a05276feba53e6d9b80c65f0a3c04d5b167cc199c5ff7a57dd935e7e0273ced8646ed8f7e1a432a98d2c94cfe59150160372b3aa3123105820ec6b76d30af6ec606caba25dd81ed2fdd06a3188e8c926280b464835aaf7db0b36fa02b90a9796a76d26ecdd9382545a9c20bcb8d4614419b77d06a4b41346e3c8236d6bcaf7fbc145ad686d37cc2de696b72f37e919241ed72dbe604d1f60077ad29b460214459a1a670777bab3dc5000a734df5738a5a3b5a5371cb836786d2aa5a9c62136351cab26da0b748718c1d765823f6a1ad25a917b54bc781d075c61aa900f7b0ae26a95d4e00f1b76835ba9af3851f95697692f01a81c543c352bb3437a7d7ccc37edba38b2156c75ab9ce832eb007e949261eeb3b923cbabc6099c32a846e630c7be50961e016e9d09699f63ebbae8110aed54eca663f0ce4e7205ff2df56c9f8be22fd9a34d20ef93e645ab14b9bfaf99fa23969bc5352bc4965d28c7a2495c8d98f617cf321c9c0b6c87b02a14cdf2962ce92b021ed5dd6f509fe78b39c95305ebbc4d93f616f551322e676374567ed72094ab1089d3c9a2705312940743c25ffeb984e4a4ae49a112807f0ea2354d8502d1577403a1e267ba873e50248d8b07319a546affc17da22050c5497e953a5daec86a0485c16ba76e91ea3a5ee717bba0d934c1f3a7dac583caae27b9218cb5a5f775b1e8ae6fde2ee1be2610b7fe1a81c6988011de2216643675355cdc34077b4bf63454ecba5e96b3acc96b9a593621026242ca1c2680efb0f5e3693572e4ea9bda024eeff8141fc6ab5fe718bfd3f4fbe39624a4de8b0c5e18c2e785a8e91cb65428a2a03465829e8b6398153a95072bbf9ff89205ce9838f679a4c2c9b6678227dded18fd99c45c7f8ffdf8dfc76fdfff7a64e893bff2ae5ec57fcb15562dbcbcdcf43fc00c05201844545dd8dbdb94181725100a0060f00c9e70fb5e74019b1e5c1d19d5ebc9621e39e3f3c00e8d3b9850064f259931ee3259e6b2d1521527343baa9cd58442a068a34962ede22dc13baec0f5aa9cd98f8c69054ca9e2d00fa57130c3d27d40d7eb6476ae14d20d0f2173860bb9a06c0a32ef227bc03a07c44cf1cf569a5c46b7987350e7ec42d818f90e95a57146500a08f635cb59b9b3f40d57510f5d0f0b20a955a03a0b6ce1d5f7000f4a1d7d3826c1eb24c07dfb6d0150e007aaa96e1c2a2c60e005da0ef6af597e61f4ae4efa773bc8943765c3e9e1db7744abe34830dfe8c5b97752901a0ffd8395063e8e036c9428ade3701181d2ff7adfbf968fd223d51eaf5612efa082800040263079d824f0168d7c0491710a254c6ae2d422b00b686b4583519269f05a0c98fbd930d85b4fe355e699b057ea9fb9ff102de4ca5215e2c59da2ff0a834b223cd7d998a034236039ffbc6b1d49868002cb4199e38cf9435008bc0cd6a080488759e380046a30a5df85b28b346078064342c0feba00a6c118184464080904d77e395af713789ac9489a3b2164d3d43ec29d9815cff3c002d7735f30110021aa4af5c19b0490028a205177053db3fa40d6c610ba58c76c41fa5a2e04b8a96288c15840092f01c27471a345aadeec2de2fb0cb96e64400d4f81ea32f051a554f77a0d62fb412c09a36ed8c50efe7f452540f482be18c561ac46dacb659444700e8091beb3a2c31c49879c55148e62967cb065b8d6785bd9fdb71915f64542561a520d84900fbf60100913a40725b6c7b77be9f8c15f07e6f3717c204c01fb2c3276cb5e353b7fff9ba634148def5a42309051ed9ffca4af69e913824b845d10980c41f5c380f85fd7aed33275f5df69d00f27adae54c8c058c2f9ec31a2880fccb198d02201c444f370540e9ac659b42cb6ca2ffbdb8eb97d08262e7d619cd0c54df2bd0620d8d512359006f38b5008493a7c0e20280a77ba110f82e80094349d917c002a78f89d0a644cf4c1ad481cc258900a39bac9b015065c5c33b8085d8deb36801711c50769b1b894b390de49706807ed36426c07300e3168ff035fd2001df49895cc89d29f3e3c90c68563282b23ae91506d7001e348e710a5791f03a7bd1531ea4edb072ae449038fc1b0079f6625b9cd168e200c64d9fcaa967419813b92bdd9d2c824cfbc558be82af690a8d9ffa7200b60a3af737cf202c07501c02750073b90d413004089abe953b02ecc00b230158367d4666287be640f7cbb4ebea430930266d80b87dd2549949000afcac4b53006c6357ba08e70b8a59d64069ed42138684197318c6208f152f2f45836b5f736dd79c096084e1a17d0f020815df4c80157850a1635d868587700c678f1923846dd4e42a184e828809d28010c7c81e71e5280640c0ce23a772007ca1015865a88eb6ebd3e5001ffe4a510ee06a62906321498f2f00dfe18464278cdd60327a8e65f07fcdc6359d4266199d49079a5fc40a90f62ffe165d83c01d73cb36627d83ea6a1ca2673a4e49a1669a11424abecb5d2102d4b64b486a2924baab81e2a3a1b3dd46a6fa9b811c03688f7de64ea32102d44dc65ac404cf0da4a8b4db5e829e94c8df87317e23401f7197d61408f549d67f89dd5b9a9096a4dfc3841d91cb405fabe83793005776dd78c2a48a306f3e8f63e3941c1380e651219e858d25252543e97488f7d03754639dc68ef40cf2eda1245960060e9771f07b0be8788ca530b54d42578b629013c02ae249abb3822bd11cbe106aa70e9e00e905aea08a22a1eff13866d03c9aa7a57d8ba00856e4a4d83263d8c31ecc1360856692ec6c146b0f0aeadb290d7e027c94b0c81f6f09bd86565426aa50806d07a8c51df5b8405c72466bb715cba200ffe95ba89fe2f0768686fe82536e1aa68fd095f14e0cff916e6f97a770718a12f61c687e42cab570e172b2e1a1003dac09c952365de7b5b65c72cde4da40bc2e444dfb39e0433e85b679b663f028586e51ae079d155e3051ad4e4d99865e584ea52895c10592a596e51de5b2d3c6526a0617980f5acad6923822bbe98f08bcec651b40a5307304297e2bd47a121d8c40b541060bff55a88a8a8838a2f5d214ddaf9e6ddcb0b302686f746104be15ea1184c0f50a800f170e4fb56dff004a4d3513261da4c1375e0e13e58a852473220bc0e9aedf10e90958d87df4327145bc5ea703fd21e3bde69a28641a995c24d466133dc9160d91831ce3dc41b0a4c8ec43b183a4c159d08a65505d3f52e4ed5a928a582ab5585839c400ecf66300f061de8a3200e38f8c843079f6e118e1647fe6cd00fae52bbae444bb07257f68ca429e02d08cad40037037b08651ff474781d83f8102e01d0e52987ca6deb941b2cdd80076b0ab9bbd045213b001c8fa963155baf79ce9b1759fcd920c366c00ad6e27e1addb00d04f7648eb0e93c94d9513f208d7aece008cd0ca37122a6f0023bb8811b5aab5dae541991028e73a00ec8cb01da451d920363e214bc9185965fc8d0515599333234bf1e0c81a6e20998a6f4906c127251e651502e5f22b7762403d536430aaa08053772cc00a0cddc6df1c808882feeadd83f7ce346c95aad00d157d8aa25e5875057627bd427faee4cccc01705bdf5358dbf9bcd2131c6cd57ff84cd20180509647e362252ebf66f782f88cb8adc92c43fbecdbc15a26c0090584dc87cfd2cc27b1358231cd533ebb8179276628b265c56f88eb8e07f031d64629bbcda18838f900e8073c8d5da6a873e54847a6a5c06a50dd49730ac50f1b710a281e1522913c4713f1cd74743250efe70388eb59de8e16448aa5a5ca9091c4713a63cd3a82b4492b099ad3e75624377d2c7f00f5a4e677de09cf4377df73e3c01fc0fe8cf18f3f80a0541808d71f809a61c2e43af3383b71f2d250265f8973a9532e488ca20c1b5bb7f9cca7ddfe00a82226d4bb6c923baa5566325ceb8cbe0e890587773a88030c023c3a8026b3350e1cfbdb988800bda427144038c7aa2a007ed56aa6b33b8dff2c2d9ffed9629d04934dc5e20dfc1292e6c04200b3b2a795de21fa4e9e0ac95c87002d8775fe09206e0703fc6b19e8a5c91ea33ba346ce2e180c493e6cd9201748d60e8f46e1e0a13467f9e004e9994aac9b2bb11a8e3e77b612330288481e089909d17262aaa94fb3b47f828e2f9cb78f4e27572bec8136a583afad22fad686a3a4d48e075bfe94fa11921ceeb50bf0d624aa5ddbe1c51157b7ec68e49f41a91379223e701ed85278dacc71d10fa2c637d6a678c327e87d72f521a3e8466602e5a3ca2177588c00aa39823af08cb1e4c1b1022cfa551f990310c605634907b0dc85d8cad6d8543e0fd049f10140d7486f5cf4bbdd78ca39c3e591e5cd3bd1acc77b09c368c8f001f07e673cfd99e7dae9fa83b658bebab890acd6f5677909f155fe85f991779b14d5d1646653b1b35f52d4dec93c05a3d964e37ecd49c6100102807b22eb06896b6fa60beaaf30e5387bfc5e8fe3e7119531b7a414c649415ad00628c81f664c891818554e114fe9a56b640830a0a13ba3c7359314e81e0011fa63f85ab2082180bb43ea78298818f7fe67ba792ea3e71bd4f494003f9cfd68d46fde5895107b118e94c27dbbe771fe725bd3a61316dea24004cf2e8f5c086074c1f35620d163224050695e6d1624f02d0224237c5f2f1bc4d42aedcc4cdccef725c0e7798c9f63e2a5a50e9111e055f6940d5dd14b2d9064763df4485632186af2f84889d5b09f66c2da5f8d2bedf34d0eab7f9a02048544ba56d6f89d01c4e9e237c52140649a1c35144d00bad079b24c854501e87f84a500f64f97bc9f2a942b94a15f552d7e720a504335d6b7f048599319c398c3dac7b2515cc17f09b3774b6d9d78e03cb7dc38cc670d63aec8e7f28fc8b8c2e4a9f9cd4c0e8b415680e923dc30a65fafaae26be0ef622632e4a40db17434737f2d41a1aecdd0e261bf62bfc5618c4a930d944a3258ad6c80756f8f06cd0a8e888292a2f9f9b467050cac57a2ebfa76e25add0e8b0b22f6f11ed37d16200ded8e7b36c1eb5515975e4aec5502e502a44c20bc95d206575d00fe656bc20bb0aea509bf7c60e7a438edc1e64e99ca0af8a37a8d8265972fd523619bdd324e3114d72bb1bfae079c18a37b0a0797c6479f12b8fc0be29a199ea234152187885188d19cc937e87b800a1940f81f07bd12d98aaf855c32bd51de7c765508818d6a04035ba9ef5280a00d441b4c8fed89311ac34cfcdedf14c5e5a452f82f5458f3e84714327618706452a9e46000a52bb85e52263b12e832eaf923370ec5e4e67dbd4d98a045df52d78b58a4ce05426b656135dfe7e4da0cd2558cd1102a50f47bca98aaf09da3898d251b2a0fc34a38b5d00e753d069866085f32407b90596e02f4d618b97de6b05d0618ed38dc98d7853aad26efcc0368005aa16846c14533801b6403d9b112c87b092079a8fa11ac95536bba8e099e1c635d97c5241f33fbd20044479bbdf2dbccdecb2335f0d75da801486846da98f59c8e82e113d8810236c02a1a99cca3ba71ea15847d4e7aeea717afeabd4b82fdb4ae6d3e4fe8bf83f84c0b70359de7d1bdf1c757fdf3bd669127a5a1062db57bfb6c52078455a6efa0bbba3eaf3502392bf1556fabc29166113b44841cec326b65346763a3b612a1398881887567c23f6ae50f5e6449cd7f9b5ac637b2a47e766a0517a9793f6dab297659c45fc0676b3ceb2d20f0284baa1749ab48073377049dfa13fba904e2db6b42e018c780e6617e4c874f10d195ccff98861c7c8c2d0b4c0e24c86d3578cce10012a7138a5830253e82e95d9351a9696f15b9186d041e23e3d7f12698669e9ddb59e08856089a5a9ed827056dc5b8ba4a0df04de6a43faa3f4fe378f8d8070215dddaf3077f91d6c06ef0b15a55fb207d67d2567ec4cc6dfc54b80a647006bc4f45484399647c4219467f0547124b7028d34b32de923490f97cec10ca826f4cf9b3254a06854b5451ad2e11d9fd298e26a409e600f2617b18614853c3cdbc80f790b78834e22f172be76709e575d63bfcc4a3c4a1559bf1f7b2e694174dd14d94e90f7376c69adda952d7bb05c1d8318fb746b80b95a4e4149d1b37ea833d6e26f49fc36beeaf4ec0599e8ed64a77b19cb264424d46e9962b2f4f11613c9c54e0a03be238b780ea3ee282d48c3a13f8a0e802879700740eb62833a73dc33383a5757d978f978efdaea85aaf1fdacc787e1bd0558bbad57aca56a927a1cd647ba4fee85f582cdcebe058aec1c1a49b92baa71e67bca6fb321b6e65d6667668cd3e750f2f813de46c3304c6695d52c0aa4cd862550930b9178545afb470cec4e9357da8f92391d7683cc115f93b19989bb9fe5202afc2673324bf8665b366d22c39e15367ff577910aa2ccef356f3c56e5a9811708eb15382f5a423d0b998f1dea5669f6cd7b4059d30fc5e81ed85c6969375dbbf7837309d3166e63330813ac9a77bce13e4987e9fc68c49bd40033b8c403b9100778d02c1b9fb2cb41fcfcdb246b37592b2d8a1cbd33ea51ff71b526110dd72b1056900e6c0466786b794c7ba71f0e185ad7be28033db9075b9d65b4437d1660ad793cea0299f647d046b8eb29819d4a019b3cc41516c198e54651df3bc07db6fea1bb2280ad1f9843b9830babb4631ed77191d75b46b05e85d73952743ae774d57298f0f24719672a1b36a00e65b7519b222d8f58a44b0730ed8cd8cc3918ff93ae942b48edccc54959f30ad2dadbbe027d2ddc8e5765f1ea0c331c508194f9c9924a0215620b014fa49c2d8f3a49a34c660a8db4fc019b10dec77ed9a05a9d727aeb9b74137a0dacf97d1701ec391774103019cb3242b9284c2f6bb86f4d52f6e872fc32a1efe45231123d59761a947d438b949b6c2ceba42bd6217d58ff8909f701acee2a79acc416146f37ba06c7dcdd52c1516d36b701466c898114d45e8d10e509801aec3eeafb9d871faac75d275ab71c0641e418c8c593f77a5bcc5448d03723bccb4f03a285c84e7afeff5c498d17ea931ea672e023e2ad75f18fdd74c0f6c6a8fd39a31ee5142076ccccc5445a39199f13ce69bb9f83e363cebb4e18a2364fe944ef2e2fa7c6918e69c93302b0531a36bd26a63da90811900ad76625e0d7571b221d5e7b2c1a64d825e4c4fdfe401274e970df62e16a267ecd9342f385da597223a35b605145b67899b97aa395f8ee7f6054fe90eda4b524990ea9b6289d58ed63a0cddc772b8ff793bce4a7b9cf8100b5fc8649c69036c19ca8cd7ff8302c33b72b80e1da04328b5c13ce5da30d94a6e0efdddf313048d3a60f1f3dfb345104930c25acc199b4788e8f5fda6c9cc232b0b8568c3d6a9e7eea0e759b4b518c7f6ca074c19f025af71dffb125a47fc47b8d08e431895bf9671feff0da0160d5374f1ae470a0ab03444c63d400b6f37aab89abcc898ead754b5b73b6c142c7e99b2589a8a572306bc84f51234f6dba88bb6f750b7e1099b33b76026f321661b58e4fb164a94a0f2b9c5cdd816b3982faee4ff005368768b711351a41e1a1d600b5db298bc943b305466e568fad69bf85a779de7d160ed3f0c5cbaa001d92ee54e632c93b84309ee5bf4d77032fdd26f413b155f18a049621a01bcbebd952683bd74acd593d9de0617bd39122e1c2618594fb65fad6aafc205daad8634315cb090de27ed35b8ddb235c250ca1717ef1e2eaec38b4060c261730a2556888c0b79b6e60a6624329072e382233af7a1622bcc42c3b9aed1a69affb312d4d57ea00933ce372b2a404360ea037ad1ec4eb940f8a672e9ada597cd51cd857c9c93c46c02692c046f2e48e92b86df12f5092909adde75c1cf85d0da03ec3b21f2de347386188b2051185a5c2a646e47175a357bab87e011b1fcbad0ca42d11ed57c67633e3172a54e843c6cd851946a5521953dffc1adc10b5617038d7fe57398215d684140418efae0bfba581789067e695d8447057b190c4c3f3192df495fd775713f32e3adc1d50a5bea0dd10f50a671d9a0c2caa6af3ec2f84154f7b39eb623fb09c4948807a1591b8bbe6322f930cdb3d460d545e3ebafd0d8897b897b089e6935c727f0cf12f4b4ddb33a0f7a3e6027aae7ddc2768408a20d8b3d6b9eeb06dc7bb99add8580f15252f8d8e8ea1f56811850cc766b57b195f09c20ad58e52f1a1bfb11db496574c42ea47ac765404bbeafe6b7e40861e078244e1b79ea09ff1ac8e0cc1b92c7620147f6a3c2c4aafa491cbc72ee889da68b1650d97ef65242db6b08874bd81419d1fd087a6c97b54d8ddd7ff37be79da27076a3909012543190a94fc9cb5a6d97b77c3606c4edc2b651f5b313c5f90454137d1e240ca857c2501d3374a2f8192b8af563da9016397cbf00a459d8a7f9518d45b6f68fac2fa74f68ac4585dcf544d5f1824aee65061014ad8be3ecbaa8de6c403f5c5dd54c026434bf0b01ef984fef42c858d49a9cbc4588dc9b08957377eb67de318d67b86bb3d0a3b7a22b596c5a8e61c276d11ecedcddb68bbcaf363b9692319aafb0b14cdfd6e7ffab1963a7b4467a0c265e18d27a71587e8b634d3e4fbb1f00e9102c6186187c09ba29a1428942f4e78c767b9419eca23fd1d2da0671124c8fdc8eb54c5e6cf42a5d9a6eef1109558d69b7dfccadeb2f12a3295ae11fb5458260ce8bcd933bbc1fed8b56f2ab0858a727c5b0c3a9cfb09f379bc00ef8fc047502e8a6ea0be534e4bac90e16ae4a83e46d469a301195f86e3fdd85b6ae6aaf77110dc0f373c8eb04dffc17a44b71304463c5c26dc973752290791fe3605cff352fec129e2716d4b568fd4b96a4279dd2d467bfe6c557e03fcfa4b290c63fa963835c6ed0c482dbafc9178b50cc5a5af57baa0c747f25ac42f2794a75e1bc1808483292fe3f74b3a00b83cd4a21a921dcbaf5e219d4e168f60cb70954d3675805817f94118961c2409c88228be00ff867cdf74c91423e06b9e95d50f742dd0c0db7ec013dee324449cca240e8ce096b0be52f7d899f31f07f8dd144efef7c213d2881b9ad76beb87b8e7bfc5f74bb3271dc77d2208c456686be98c4371314f6e23c1240420d8ebc9389fbe263997e58f92014fb8f82256dc29d4e53885f8094e6d4e261e70b6ae4ebaa413931119318a9e05a269e2c9c84618014b5fff541a8653b3f368f506eae4cc002dc796d0648b556fb3bc2e9cd233fd0b18a0ec29a43e80d6d0f97a0b7e3fe920613ea6f410d6ee604dc18731e5e8f4e4dbf7e2e0260f592a4492a1c4a60a10ba2187844d34308baf1bfd28f2ec665a0a527a30b76fb2786ef2e0e7427a27c89556a9dc8d14451d0e23d85c9cacfb7afd06a70795464e56cc21f4a45a856e24ef975da429ee5792a9287ec278a36aee84a1abd354215f9646456b97ba9dc95514e08417a9de3b4ce97a6b681e47ad6c0a2b71137d5c4b52c90d00a64ee9fee00a6e00830006e4744a9150cb77cb89c7fc28290ff20c3fc5eb4bd8e1d6fbcc6bd8fc9e0a27df858f9814b74dc4ca0f6f776280cdc3ed4a601566e3e4ade6d5f745705bd634193e0f6cd75e5d9cd510d27526535702447a1d61b9b4832808796cd10ef55d9bdd6d5e0c81157552ba59870910e12a3c391c78a08c4b601cd44cc2e2d3c1d5a82794278a0796288ead8559438d5c6fdafe2a5a576ccef93c0486fefa657738cdb52e7abb729bbc991594b7448a0076cec4939a2c63ed0cd27269768508c2c21196f2a89ca1cb9a94bb6dba8a8bf62ccffe6d8871afa20a194dce6d3438899217e63b4b94295d979a8b3a993d1f2baaa78e5f7162f32dd85d6acfda5c09e399e571f835b0a58aa6ab115b8594b6c1f97ad6415fe43c2da72b248b3510d4bfca5ae7339dab4781154824a8a2ab447deb048c630ba5961f671ea5ed071c7faab6aa4725f644090e873f6f524ac875146251e2a9c9f29312b8ff1c97265bd94f8002cb342badff7006e5959b87924a6327da24b8dd29930e5d4b1164d3bf40dd89ad7ef72d8af0bead097a825de7e435f91c05b6356429059619fa42a911019fa9b29c5c95cded5080f425effe5d2b0de14c8d057ed9facc59cc3874cb2fd4564c51e065e26a611c127e9c77ea94b622ab3124d398b67ed7f6621bb244fbb06a44ceec1ec93e1dc3492c34ebfb669a5e3d697056f9d9d7e4f65565ed2c4ee308f79a92188b0a14b02831210c0bcccc1320828780ea529b3820829395599b823232ea375032805f79148b51f18853c7f8eb11f18ad7717666b1752e17e3924fd2cb2517c13d4a5cc0a49611c38eeec2b21769ba11ab37fccaec7322b03516863959485cb206ab4214914d8a6c9955959b2f4243b64c96fa3c3bf2c926765bccc0a75858600650467628ec26599930c1029ef1207bb67c1b5c522e71527cb658b94b9fb2ae8c11cad0842a599439459913991ee2af07d3d200d2bb1ee0342e13029048d63f0d454bdf33dd66f99deae8c64e2cd6109a2e439a4e3bfd6d6aaf86d1930a851f2626211a44e975949ea1a8fdd0c67b80642d93b2688d0e54a1c1a6a71b4cc0ab7cac3a93d664566ed4cc839e2c8981531123094e031bc54584c0614cff937abb54a4d56743ff12895b016c731991539877f18a9ff21d832bd364a6dd60dec8296ed020a55367f1deadf708159044b065c189cb08f27c70cc8d53b18a044a8477d332b5a8679060e50813cd3abd53d6ce3d28b23080a17744c174f55e6f69095c0034235b8e414be665f83b26e4ea475ff67783b1c6e2edfc7f5c5d8949209898f7bf41f455c446364535f7c50a508c726f662899e492cbbd88674865b890b2f61ae4abc7f8d6ed1ce9601f3b32cbc794d2ea28e0cc213f98206fa59cdc3cd20d3ed000b13ec4f10013771fe495718cd3a5cb392cc4087fac7a9a2eb5bd4c9faff45e8624a30bdee4456ca7aaa78ce196b45fca0814e8aafe1f3af8192b8cb5dd035f834e2f87b71b33610277b620130b8d984111c185481d3a1c1f6e1b1f176cfcaf5c45d65017b56c29989c8e9b61f3a79dcff47768d5971bdb97bf9166d44effed160f6d1c3f3c151498a77b3f83030e79fa015ad736440b4c873e84002bcf68b10aae6f83212d6d0ca28220a0309b829328997f0b0646322139951b2b62f89692b6513916d9da2a73cfe40ed53059591516c11242a86097b54460a617dc364b5886a2191e429a87aaa0d554b68c8f9a823cfba9dc2eff73d44719451cef931710196be15dac09e29f75790758c6ed71e25a51b828a3583128c15f3ca0f8dbf36624ac98bee82aa87af1ddac2f604d946949ab4a00a37fdddf0f0b84f6ec61aadb4f8db508d9ea62086e7e990727efb8b0829114d1b724336fd6b3d75c65ec99a2225245331dd630b22b1da0985b69522ef31384d40ba1607bd126ee3038b7dfdafdfb8bf0d7d669c54bf7142324932dc91b0a390cf7464743cc5f585e997c728b53b92a802ffcce239035991079de6be437996a6fe2cd257da11ab684f62b26b83250d1bca315076f75661b1d1f50356910bf2b59fbeac4486c0601cc48bf4fe7c56aabce6485d29b1a25d906cba4d68c882c455375e9b121ffca82c0eb1faf141ebbdbd591489638b1bb1974e8917a3536a6cb44ba7c426299043f179b3cd80551202eed8607db2424aa77cfd4d51e5b0eb974e01fbd40c7a503aaa5d3383abfe33893df0d3f1bdddfaea6f7ad988b902a14ed9fe04ab153c3f3601fc2c8798766788ac70a4d8c151a748b439e543a08017b571aae33f397d335a5883d94940f5f6fa425c42a8504432be5b506574a989621532e66cdcf5032326d894285761206526191232c0488d98a90f92b1db112cdefed77e097d9c0f2c88b56b7a3de8e187c2a7dc244100ddac7c4e28f2188cfdfc49a00848cb3cd34db3077685851ace8935e1f8a18a3ff0df43003f49940bde9c26858472307c708152084b7962aee8be53046a5c59a68c71d9790a8a8db2bcdf62efba2afd033fc1eac0936b5c056629be0ccaca7492e1139e0a3a55c1ce8e8e25ae04d500d7de76ad505f613e4a00e44b792c0f94f0322cf2529e4e8cca371fca7ca7b40d4dea6b0af13ab3aeec2e4f8a545ee85162ddd7cfd95753e40627b565b33207bfbc946d828a980394a42039aae069dc64e0dada210396b20b7ca4c69e927d46b20b8aa8de63a6bd30506a5b3a644f9f702e08a23ef84e19cbd56f1560b11c73f1044e9d51288a9ff296d25f5b485308a723a78c2b6106d6789d652e3dee12f6ba6b4a8c87ad02df67c2af7b092170d02ef07d4ce875c704048abf51bf5230509a9e47497e38af441454d3168821adfb21ca174db839888109d1f8aaf5e9632946859afa8124beb068d3965b511148eaa6e746ed29270aafd41c29b288dc0345f830c9318f1b8349da9b91712661693e7fd9db379883fe258de6ca1a166f64715cac020f302029656b7a0bb63019c32c37e115f7f9cd2922fd908e71bb7f4369f202e6c8b5ad5883bb604a664793b56d88934ec139e25c84a2eae2363b93312e352fdf33a071a149ed23667f5395cf48fe5c77b4b451d3eff0d0cc66b63b422f3415b017bcbb2ce65bc8377c1d5a2f71b89ff1bfe148576918421ff716a9241a9dc4d94c689df0545a8fdd8f238f473977a0cb0058ca55c7acfd1ebbda20a30360f7c09d80338517206e8e7d58053d41d237c2704264809e46f019266799391b1ae14f9e152138054c198b66a6f9e013f95f8069759c4e3acd763f40588895b7eb74ad47c3582e94ecc464e7ed8728ac8872d697f17f86e06b7f8f0d305aa4fb3bc9fc8fe6a1b2e251086d60156ac14dd3f0bd4f4aa0a31c8e6e41824432320fc57337f9153448897693fbea0909f5bcfb7a3d4c0d33b6c63e802a3e246791aca3146ff5a09fc6fa24a4b035ab8017a4a794ac1ba1e799e9d3e0f505a53813fd08dfb9d43aa808baddb4c0a371b09476d13da5fe91fdb625bcb6a051c0aad322135101466251f4b2d3dc7c92be8f642c33e0fec34372c8ed21d3acfc8c3d9b580c4f8bfb47d151bd7d4f75e4d4794aa7d9dc519e75165bdd3063fd808de1ba13bb23e64f496ef7634e024ac2a52b988d808c937e2503ce3eab6722ac70c97f002a6888364c7ad616e1caf79fdcf7f730442a4d3f5439ab55ab18813327ef5a407d5c58689a3396701af9a05c2197d2b196713e36f828f964a3d133955e540f1cdd4233320d8ea0512ed52a745aaba9834a2143ad6f9702dedc385236c84a85214713202575c594651f697db672f22f7f09dd1cdf3f5e249dd118e08d31c697b9485611b5708056a1375d85ac307b13debd12178cf1b8c0d9b45f8d98ffde139938414da36347205167831497de8025acdcea269e1ddb7755332ab1b4a1244705195a3312adc1304bbc4b2115bb189c0b0bf38cc88214b3f83bfb30b482ee114960dbeb13c3f09e73d351e9558c4b53bd89431bf7400be6294b428a31246426084c8b4b5612d2a4a37021ecf8276f4668260486bd20853ae7d9985bdcc2ad3cf072c0a6c94631f52d3df725a4b8ababc2c3189e9e76832b4c7c1f39db298fb167b596c30b24dfaa4e9840428a89bee8ac4e2cc32fb2b3c603f1a75dc0c2b04d51866fc70351453e02e2bddb5676edfd823e7cb32f3b81bf2ec44ca6bc03facc2968a4a866d81633990d65dfa5ef72e83183a474b13ec3728e27a3c59130b7aa3f5d2eee594720ef188b335e854100c1fa0b43ca36dc1a54ea46b247780117fd015465a41076a0330936fa39aba864a4321987a4b0b5097d3b2445c806f84d1ce3f21d971d52054cdeea29ab12052579dce2d5fe1f4b73c67d17357da094ad9f72f824d21f5e6a258b2d48929eda87091c69c87b45425c87a47ce9037fa0dfbee0600522a046528a1eb39f22bc874f7fb847a31651db7d05eb66c0c8c166ca16e08ac14b6153f3f1c1330873c781120838c0e2a65a350c4c4e0c4d212f5d1f80f88da788f4543c3e12015a550d4d59f2edcb643627e2bd2ff2f2f89e9eafd824d8d8f9ccee3934e7818b05da86117c7a1cc9889053dc58a33f89789450018a32f268490a8b82d6ea8fe1b44dead70005b8a239d17e7c494ac4eac51564848289ff460bf538b1bf296a2c41232bbe60e48cf6b3f52a426609b86ac067529c8deaf71ca03205544fde17d2d1d046683d795276ad27785041f6e74939ef09fa750555833619152591ee555e289c2765f2212e3e1b75d02ba2858c3c29488a550c0299aaddbf2b01c8f94e7e237d3bec5ce5fa1188525a5948f2ea31bb89432360babb4788524c7e0260304daf479442be2249ce7523549642dbc4527629a57fef7f7cab122deb1b318df51d30048f3eb0da54bc401c60c9f633f0fd7c29655b43cd6d4cb89422319c9a184a4307dc2547a0bb5811ed617962d38fc015842d591629a47f6a4bd0d2a594121960c5323038f84dcc3a9752120734c8f4bb54062ea5cc349ab9571020d1a0bfe127de544a0f96499f47c61be85bae60fe1e7bde55b2551881a86fd456c98dbac8a769d87200b1e18c0e8016135a4cc9f023ff7d3c14796b1aab4c2b109f48fd6292550a876c746630cd4c14b48a3913cbf18d4ebe6999a2b56e99b04a6113fbd7fc9748dd9c554a939d2527b4d00e9aff4d5629837a9cb8bb86b24a015f1901c9d937f3b7a9c13d412fb8df29dd718a8b2863afbd22942f97dc079e859e3ca30587f94f9652d0041aa97452ea8382ebaffcae4150e302ab148ce4a5295a84c8053629fd053a0912bff428e5158d66592e412c13e2821c6a66ac226089c424559ad33bc9d651418138460320733816dddf0b8f20b2adcd938f14abfccf2892539a4969081ab72cd34c41a8506851503755d9f659ce53860d27e517d10cfd521d2fd4a19d3a68374eff898da57b193c270511e486172718d8a8b3b5c18340b6761ff204abc74780879c4b6287b0e1388b1309894cddd6e42c4e47700e773413bf00236fbcca48ffe6de8a7de09d8a2a6c4ef2c85d69ca433725312df472a12fb12f3fe8f46dfc2630cfecf24685f9024afb2990384974a42ca2c52e13fa25b6e50f1dacef6b524aba2072514795b09337cf564e6be2242b346d8bf72171e7d355724df581a36b21fd010eef9b5263ef8b78fe78a0a1267b03b4c3c5d80deac3468944e1fb4f74c5dba650a6391c7be1c49e352b489b2fe559986855fbbe96236717a76cb3b498ef31b1f408007cf449635dc2b08d4cfdd73838c72f2a4bc95ff4dcfbac78db26a422adc8836be6989c0f4c68930c84c5da3a9ffdbec061848035d2d6d0f16bdcdca0655caa66d3122f29a2042c5e5289831d57f4f640e09ee2b08b287187e88b7a3b17a2a8a2e11f3dcbc043a9a17d66c0bb5e85adb427eceb87af5fff1b7c3b603f04064bfec84c6df6b1533a224663c4e9dea2be3934b10fb6d5d8abf0eec888e34c89d365262956adcd02a97acbfce1c83488d8b536a3112a9a509262236ef180061ebab1fc3b3ead0201acfcba641b92866c64073fc62cab90dc1891818d44813ac1e251ac0b0143553e4fabaa33d3e2b73c208756889b4996183224748411ac2d8447872066c242b09737bbf9a0bd86285f45d11ff8d95ed7e8d94ae854f36b9ccc8b14f8080d4023a9de35afb4600594a84aa9d9678db44e542f461a7744c1caa7c9982367c564025bb936441be59f1f0d482e980622cf658db5b6f628e8e4389ee217fe9365268032455cf42a619b637aba17ba4c91bc50a6847d7161a5ba66713b878a45b1bf135bbaf3453657e0001119f0dbdfeece2a0bc5c9c5bc88d5f2e8184984d22069762de20a887f2a820a55c01db741d0e85fae82639507ace0a5091f214facb4ec2e21339ee474eb4a7a5f3275b224a60b6b24163d73bdd6bd116d3d8e1b92c44a427b85c19cda984bae5bf32e44aa2eb16417d9a596ab0fc76ffbfa57d515d3f4b291b668469f52587702bbee9d43df4e0c1e959782f4082a145c89c7c6b5f6df057a3dc3a33daa439435101520d010af439030eb6552512f60eb625db4e359eb4f5d604d897a55bb0f5cbe9721d08e4563f6118956cfa08bd08e93b0c665783fc6e17c46f8e226fa6e62f8322dac9b2cbf2558b0129fa22671710a52edc5c7501473c283e10274a1a2790f6ef28808c38a1903baa10b392923548154246bdd2e7d014ca2a3554567af056986fc04e6c77e771170a77f769e27338d973262e216c7de5bedb24e5cd9538143d72ddac51122602e8142c65229ac02ecff9634579236f7430112cf5c1c9fb2615e078a9a63258692ec063eab10ac68a0478b6025d12b8e22b582cdf92058310f45dd7c2dc13acc704e27c8ea2fcb22d25c17498a687b1f1e17cdd5de2e40bb11410c070cde31a0fd757ceae11d9e61270ddd37ac2086391ddd47418686df331cac8df695a734d2390b87dfc6005618b03389c24ad5d8bc152798011a43b4f092b9730fb16ae179b6c524fb2993770cc3d9b5382021d797aa0dae244ee57effd32cd4e9d1af8240c737f022984617d936763636425d58a9913e0ecbb05441ae64bfb0d2c9943bf528cc5937bafbf98595ea44be91e2593e3ac27e1d6b85eefc0382e10e01a8144d06e0df266c18407dc41a181f3d166b8457dd9b1f0b86d9d94ed89dd2db25b213b6a58a9110defb5b45ea39b314ed810c1f9bf7dc037486bc16745b513645ac20104e77e9acc7c4c7e6ca834ffb9537053cf08e2297ab4f2f5b6285fc2686e921372e114408ae20baf58b64a6890c86721811b4202b0e24ebcaea18619718415e45b31f6c8303ad20c72f02d8b73e8d442077a98760e50b704496686ae71a0304afe3310628b0bdf099b696379cdcb0f10cb56b99319a86e06c30da2285ab72c999aaaba4903edbb2e16e09c7da6deb418e9b129ecbd2cc058678aa426811a57ab78d3660d79fafe88117640dc8e2aa82dafa2bf76454c0e4e812124da85b2f321d112cd094e4d41ca3e97a36d04363e9206b29d21c8ad17d8f0015658a971a9a13f1668acdf97377110f0da49e6e007054a0a521294c055c22f4e88d35f1cb5617f7de928e12c601bad2f387391a02bf97b1b112759d3aa93244a2763669418f12f428e9436b108165f9f590c894b0516beb612e7339e828e4399804c7527081cb93d2ae5d809db104e9947aac975a2821a739c762aa479207e828cae9648fa20059792c6ee914981fc89da1ed58181b35905620afc7eebcfb16ef65075cdcadd8a3f3bedceb93e66a6e7055d40cc7dd67808624debaa5eb40a2243522254651c7e6f6cb4732810498efde42ce38b693c63ca19a951eff94e89d9a05f82aa0010c37f81dd380d54d904590fa917878c42d1e388423e8adec4a662f0ba2df98e1e32fb8b95c94b570b2249a54bf1ef7a81facf34916183f2c9405534da01d61340a0b0ba4bdf715e50e6931f2c2dd248916ad65865718069aa2ce2a5a4b6cb206e9d60eda190ec968c7053002541549f04c92eae2506945532130982abf9aef577bed8f28d9e29f9305b01d2cc46237d839d64d667aec51fb646c35ceb105493558d8b49ceb1dd33851fa44779ad85edc9ffc1f88a3a9c44072276cbe28a5b0b9146b95859651446a1844234119827cf7ebf2dc2d5a888212ffb51c80944bcd37ee306d3123322c0295efdb449502fd1c5860620bd3a1a1e85d1e3e930c1d0089641cd1569595c37593f4cdd7321f2cb31d2c3a3689986191eaf22881d2ff5acaf13d1cdd09ca66a3112f52d90322b634bb712b0231cd33ab6521196d111901ee752432af475d14a38654a299ad36b379cc0aec1ec66d5bc6e926f262750e37baeb84886c04838bdabba9bdac042ba4e1e93c706174128ca4324c90891c4a92007af759d6144235c74bd9f972f04c3f1f72c321b98d935ba226c104cd7c3d900826257bdd2b3d65ffaf733b796bb61d1a2857a06c2fe065ffaceb82a2eb95559e4c63b3809d8acde324112033c759d3383ca5190768524cb27447b5e0a6dc0d2a36564d37657965079741a7123c32e94da02c58ba03c523d8b1b1a4df851af744c9964e7374c77c8f556667b57731b2a6ccaaae1bba23ff8702842052cc3415c60fc808fbca334534a568a293e08b150002fa152c30160b39d7b62c64d373e8faacf3872ec2f14a23fae88b67a8007d7a57367a4fb738f5004d90747e834f1dd68bf07d1b388002a06364bb1c97c81ccb1d8e1133838e2ca724586ffdec0e59097b7e80e27abf4c92de55804f98988d3566b1d0e57be630ff2b8a28996fa1b062227f81750fe2039a957baee792bf091ea74545f380b4009296b05ec40404dcf2ccf9a4eb15b27f4ee4a6be718d30e04dfb94d1463d7f0bba2cab925bf3576297000a9fe1e8285fe2d500c5f77be32ca8fe8082ec8e6b979c024d5b19a08f5cb93ddcdeefe69bc06284e4a349de8f6e8af5340c4c8898a2ee8ba97ce34c8e6dd37197c1e2f89738bc7ea938afc9f538683b6c605637bf5670dba6c314985afcba45cb28f7088e7beb40f2b39015a0951411a2b4f2cebdbefa816b42d073dedc44b374d028028181683ed273debe094629ad7142984f2334b5b45867a438972da94bac1c89a394f538e80f9a8125a49bf2733092f6695ca67d6ffbe8b4906e7ba0a15695ae586cde45f2fe40178418078df08d8e967346b9aaa64c484ef99b626bdecd8748848abc4c1a67bca873b253cf9e6fe58b892525033d05ee6fcea362e3c6069eb4fb7f88d0de5ceb07bc6af7d843d749039f2ab07d92d1e73bd2a4310ab5be612d1be922290594e39f626cd71e3bedd84f8d0625cfa1ce745abad835f430e5ae12653f0a3b586c1b45e2ff84bd4767e748acc89a9954fbdda97d4a590c1ed3b35d03286e033dca2c259942c2300fd6aee4792bad42f03633923e3f2d76e8477a36856779293b8382b292ece3b4f6750f529c5fdb7d86112594b35cf162347e3d50e3bf33e1df8c675f449c485a89a55f31a1091d59452d1ba7b194032660fe3da7a6231d4fb44777f90d515a215aa4980a9de2d7e61107fee1b845a9c20e71cf6743ef03c6c88e7ac6b7e53a27362bf43affeeeb1c8c86ff378b45b621efbe401cb2d348fc450d0435865dd5230e1b16073b6e50ede3241ff7fbc98e6136d21321c620125ec224abb25e759c00466521fac6db45b8a04a99809bc735de345019eed0e7adf8b316387b2d52cbb708204e1ac737a979ebeae9bb93c5a2cf48a1bd206c7daebc8a870eaccefe0834c719a3bb5894e205502a2ee2d85c4446e91e6d7a28beee55f52de6672c838afaf143f78788f9bdc6ba064600c3047cf42281073cf6de51b92636ca51e1ae627eae2d37ad3fdebd996b6e53013f780eacc8bd350878efaf7285b0ca5d00623f9299cb6353f3bb0b9aeeb110a68dd667b4638f16c4837197abd758a0070c8590e7d12c9ec0347512b89528af75f9210b8a4140a705b2bc20007e08d282f8a3a580465095e245cc0602d55dd14e2eb66da9de052931195e5db3b49048a19f177389521c3e7b098c2d18bedc3a79c08141e0b6e9b8d9864127e443a84fbc5cb16e7c5a3aa6c9828d7329361a597822024b6b4b016ec60951dcc16f07af427600bd2a8901b177a6f1d4d401970fc6d4e0a2f7355d7041c4599152db74dcdaff985a40d63290c1292853b9a7817997f493d8cd9911c9dfd07dc3abbf9ef54017d11f7d3718dd9dad04507bf515d907e3beb482fd01fc95100151e48c6ee0e32d42ea3e7019e5f61061b9a1e761e0679c04807cd70ed071bfaaec27d9a81c3ac011c73876e3ac18cd474d8a69d4049e757588a1fbbe2601fce792fea892f7f81f1e76dccf20f85dd5b1d73f57f143c5f4410656fa9ba43a1977667effec9f10a06b3d58d2d3c0a1eb4ced1254576bb15f1b2b3d7011c9fadadf957f8a7c77e8e860f933d5b9a8bea503efcefc00f9cd9aaceb71de7b8b038bdc813c0d2eacec69d4bcfd96c8395cd663a672b5a099955816a3376833d86dc90fc8c2cd3b64b8989254a920532511ce93f4b443abf6ac8b27f69381038a19a7bb24e2e5c4aef6a5d8d60f686333dfcb8dc2eae16eac3c1cca2a3bb3f12b046149ebe110950024706a35024ec24b65bbec707db166b3a014e9d5aabf979ddc1d7395b9e17622f8abc9d5a39a202a79cb6815986439957802cddaf4c27eafece34e9fa4984fe56945267771e2f18a4bee48fd9294cdc53697f405f64ffdf072f40eb0df6617b6c7b23c9df02028428bd37188036182ab969c08962dfd69132639ca62bc81713df1a4dd0582490ec8214ee5df21515a5eeb28fd04c50bd47f65e77bc4e5f340ca2082eeb373dd27eb98b0ed51060372e936c9c06d268966e03d330a0d3c5d1ab46ae08ebba556408e19a6893677111136e7405053640920ec19e2403af4dd5a5467612c8518aa40fc42cf53b2559a96f171b74d876b29d803828ec8ef8c51d625bc02f17a2764a8641e74b406142cbb34160a9110c4bdade2752249e3b835eb383f40dc8c6131501df621f727257178fdcb2422d39f0cbf161006a532c4a7a4465b95b670e1a2208cd92066e8e47f5ac2b8ec598d82e456496b65232822c49a268f213655c3b69984f212ba137b8897d68185bc64bf08b9a9428484fd82f5a7cb67050b5742cb51d315b8fa2d0667a1be06860adf09eafab53abc1cf820c1afe7bfe02a486fab43ddd3f5fab03f8303db91ee9d205024841d159854eba0514d0b9b0fbd135f66fb2def9323ee0c56921048004a6008b96802ebf2bd5e267d3dadcd66bab5db04f5edc73d7aea156ee3503a50c76305ae38e856f1efa3034104cc8ddd821c2bf169649fd45c77898c424c4ccba6200db67e9e33b6f3da6c50ef766f160f29f090144236f989bb9a44fabc88e9d8859b82179ca30eabc330b765570e89d2143431ce69df1404261caa6fbe81daa6202aeb66723c6ba36200355281b20597824e09de2ed8686674cd8f0033975fbb38de74e8c02ea951ae7728280b6a9c168d2a02ff7756c992eddfaeaa84d1e5538848182d12bc85b7c68e5df05a0fd7d578086d9625a427180558f9884908e5562bcd497fa1eb6aa179c4b0059665cf5533f431062fb0fd76aecdf3ffaf1d1f3fa0f14cc58b78018998bf403f10d6831b57c313ef6b325f76aebfe3429767fcb329c96240986177b0d393df5b1d1e02da7d2e931964c3d6488bbebcfa2b2e38b1c1a28069f533584012100ef1ede2d1956ded9e034531d3c809208d095351c8489ffd171be1916c416c85e81bd4d5d92e8c47048a8effbd5610380a6d3af595cf05fe046f7ad2488b04bbc1f00e969e904ffab62dc1a87d0d461a5f0dd64525103226ba49d53da0f09eac594dbc8db7ff424cff7e0a8226a59c2047479aa0d1c712027f5ad2f6de7befbda59452ca500b9b0bef0a64b9852ca96ba5cfdc65ae039bd2f11d3ff18e832510d29174b6cdbf7208f9e4cc67ee9546b34dcd215a598ae0852a0f99d3dce6d4696ea3d19cd6fa39db48bdb3737ca6c31d93f90f3b9bb94d5b4b7766b31cb7e95829735a06f9b21e67d3c0224cfaf531091e61c676e81eb2b71cafa5d10e8d560e11aa4094dcb90a44852a10dd49f6769ddc9708c908423507924d9bb907949e24f7599f9247eee33ce92678249bef90469832a74fbb363df330dc71997e1c7ddedf71b008338895d15ce6337d2afd4cd32f7d2c774d48f5d281542f5de9497d22a1f646da9c96d4959eea24fbb62d54816432ff71677a67c7744ece36cd4bb481c55d93fe3d7b80314b23d13db0bad0af0f513294f4d122d93fee484ba559b98fdc9fc9b4e9b4cc551e323f87fe246d4295876c93a5979e1bfa4a235a6a7a2ad199d621b529f39c69fa90d5c9dca42625239bcd487246b75005229ddcc0ea647ebd0056a7e397fc6222959e6b3924bf5f07a1f4bb879e52bf1e8211ab2349bf5ba802915ac7a996b9689ae6b8cd699aee133f8ea69fa36d4e2b81e4d81c47d7a7e91da7fef56d74c771f48ed36c3ac7a9a6f995d1f4e83a3217aa3ce8cb7c479f4943ffc3520d3ae8c50441d3043d1673198f93a1efb83b8ecf709d9aeb944e7aa9654e358dac81f0c1752217ebefcc4997e913c92784e6b46673729fb521395e3afd7dd66c3b48493a7d244f5d96e330aa6936a739a49743662ef332670799b9cc675bb669e599e3e3cc73b9417d1c27f559ba6cc3a6ccd269fef2f1ab6507f565331c277db6a9bf9c9643705cb691707cb6916a399aeab3dc49f67136b537775acd9d745b06a96d6c6fbecfa44bee73c6a6f6a6e3d8de74f699e4b534003540e83b1e522f7d2c4393a4792923a9d3bc0c77dcdc71923a4db64f7307249d923c3b9bc74d1e2735cf3eeb9732a72425dd74ea32484aca7012f4e2652cb66b41402f4ff16548328f518fb9cc632ed3339acf944aa7954647ec53073d16731990d9ae79a969fa24e1693b3bfbc45f7a8edb34b5b79c7d26d93f3d70dbb46933c6cf3c741da75697e3250d87a6615ed347dcce9092ec871b04f5a9e3782e835821a0c73cb64f9953d7b32174e6a5ce719a3ef1d33c67ffb834bf71aaedcf9ce2e0b8fdd9469239e849f6653b466afa31f36f344c9f487ef49cd2c87cb1f9a4fa20e82efd81262252079dd42054224498d44f1a06c807f676cbb22cfd965b037ba3f8455d1ff40fac0eff752220585dfd91d21bf51ffbc78964030d3e14f2653db8bd0da5fdea4d2deefa2552eac1042e3a3079492383103b015c6192a1092586a0418bddf511ae93300214e649b5fe3e751e2bb4f5a23d9882b48bbbd7f1bddf235dd2bba4add5de7baf63272b7decf90f8bbdabf3eec58f7bec0dffcdf79eb69a905a13f2f9c1223206808dea39bb8fbde15aad03c0cf9cb39fb7c78e94fd96f3bff9ebf38ccfaecf3c9fcbcf3b9f6d9fc7cfb537fd14dd4f1d989fa10671fca47dfe3ecf3e7b9f69f889f3397f967dce67ecf3fd1a7ecaf8ec96ee003dc74fd8cde79cdda43b743ceff3e6d7c79bce65bf595da68f6f9abeb5446699eb766bd2ce1e5cd4d39369f6864ff2cf221f4a952bcadb666fd8412ea6f51a3d34b6f6193c3bb69a4e0e6d8693a9551699cede67d8e79f977695d9c9ec63ce0e7e5ec661154c9ad46936d0bf71038bc31a7c313d3f7b3cc6b8ba609e3d1e3bbd7ddee3d39d461e24ab189ae4dd1b6afc30763c62da15f33ab5ba4bbce2d0a9cef5b23a0fa438d041ab2b8fc03f42c2838f7d2c2bbd898ef54982fca257ac417d56a3d1c750db27b58b9e1bb8f93a86e12ee94ff5b3035f71787ae02cbfd25bf5fc3231bd4de428cd6d349abb8de634b71bdbdba5dd6c3729d8ee1817b20aaa1da2726b465bab0623a5f76ed0de7407805c204ec0586ea828972b2a1acae58a8a8672b9a1a28c73453634193b733d67eee6537489406cda2a33376475f87a35e9c57e419046a3b5c98a252e2b2c21568dd5abed6bf5b6591d2361d629b4c80c3d748feed39f52ece1a6d44d7bbba0a6d9dbf5d3f6d77bbca5b5a856a744348ab35eab836401949eee5a900ee0bacf1e9f77527e2e3248894cec568875ac0405435a0e25f378db5ab718c12966756a345a8d94776d03fa9f673f6b8d036a9d96df86096126e5b7fbcc0e82fac3665d4d1807d0e6a9e79e9e9643ca23f54170a4b6915afa5a0e793dddf628fc3bbe80d811cc20c638c4f75ed7f9812bdad17522f95a90a7a20d2b1d3d17254b5aefabdad2e84809fe547a5c1e555aadeb883a7e8be90ff5ebc162588591627ca55c4c7f6650b235840ac548fd56d3058bc5843b7e4129ad350b7ac5a5428a2b61900089a094d67a25cb53c0a45b57a41e0ce91515d87bc5eba25802a9e0bd595c816281186ba5f5a6896aab8555d96bef104f019366fdcd72a97cece28b4b320d0bfe049d467dccde70de817e4fc67befd40d1fd3532e4ca590c131bc918bcf4c48c5f77d374d1683c330048fd436b77e51a5897bb5121fcb5fd01f1a84058371a2039848b504dac58924be7e754bb37b9a09ef3ccffa0373a7f4f47a2d88f8771f793d9487f749f7bd1757355ea73d4c3e666fe00c9e1d5b4d278736c391c564dcc0cc97ab244731043f2fe36b6906ccf24fd231d62d40f1c6545ab37cccdeaa4c0119ad135da9c6ead5128144d3c7ec8dd28bbd78adc119e72ebe780a984fb1d056acf898f7791ff562858aa78049b9784f0a51098cf1076e4176013dcf03c3b2cac76a2886a2166ffd5221a3c4511c9f7ab1b2c309ba66281aab124da3542fb84086f4c75e4d019366f1d6ed532f55ba3c054c8ac553ff9e7ab1f2c29ff86d4877d0f1a9172b277cccdec6d288ea85251fb3b723f86df4879625100d9664d5402825b508264d834b0c23ed8dda5bf8d4cb5418d65c029b9a5a814d3e61a43de7bd18678c2d686f93db94e4b600bbe069796dae87952fd5db9cb3a7953d4c7a5a23c0a2e85e1b4a24ba75ef0b110c3f17de357f2f862078431462ae8e74cd775ac75f67ff1194031aca39dafd8f1919fcd878766ee0c0e5f0f15b4d486728e768f73f8e1c6311878fa4cd47b1bc6980f36807f84d13f11b9a018ed30a701c7a019e437f00826790f3a09a8e4c4604b49582b276cadea668b52e9feb23e326f603149341ea20c0c6b37303072e47ed268bcd06e0cd643762b1178ed08c0c643273e6e3423332c0c181fde8eb407a28c783b42701add91d9ae5783736edc3737a781ea4af0be921cf51e4371fafe90ce9f0ece08ca1338483538349688706cf0d9f511ae1c8e1e44de3709c16da8f6367c92a6162ca91a3270793a6261c3870e0c0e1f46f78ac34bab1a989c3378e1b38669441706ceb64868d626f4ff6c97d06b9a36deee3b9202021a1db179bcd66b3397d1e97511af16c6ada9c868dc7e66510dbae6c5ca7a6c4de6e4d68d79cd81bee6fbbc6b433c46fda007e4317c0719a03c7a185780e1dc4858034109fa10fe019d4747a80f4d4f8a1511ae5ecf47cda564347ef1c070fce06046cd4202de03b95aa4e4ddd00400209cdf8a99547d792dca0c1b383c336460fcf8e8f6d0c1e0ea47de434f0707856ccead323ebafe9a31e5503022cf1d81180cfe947eff00c340f9fa1af0f21ed790e3de438b4ce715ac74de7388f2ef21d1fafe9e8dc08a03374fb82c3fdc070376e6440dab491ff681f1ad4747478768cc6d080003a39e77a4141a5d10d0f2a81e0bff94883ac6a0308ca01cd90f2bedbcef18ed41c69d31af88feee119681d3e8300ae733ca7af8f1e12d2a0e720f21b3a007eabe9e8f0ec683006017474d4c02130e77a3e3972e4f0f151c885ac6600795f2e28bfcfae2d09f9782e084828839fa12f39667c99ba9121e369879b9b9b9b9b9b98137b63e251d2c4c449c74fd08eae2a6162d2b92dc74e114f91ad0887cee13aefa0fee110d0161082824004bcefc677718e2b8d703d70012883e4d83d02f0c303ab010c20c7a6afffe80078067a87cfd03a86749e4313f94d0bc079b4e73b3e351d9d1b38c6b001565048010c1d765449082f926c4589e1c21547ec28ad64ead522428c0d6ac61e7643e121baa34e31a5eef6469d9ad4e91223115234f131db486d0e7ccff4ac97b18354744af3b8f769e6eba42e3950f2f28fa47c4f709ad669526ebec23c4d33468bc1ac622ec618638c31c618635cef4b0736652ed11dd6e9e764ad17d7d630dd868d1e7bb3366cd4b8dd6ef7760380df4e1b1b8c814d98b79e13ff69bb76090b2d00a8a012583c3b5ee3461633613d346a362812514c91929145d695d5172a1a9ab6d68c3c7a5f814ef606de404543d3d61a2a2a2a2a2a50ab0906dbd137577a93c93a33d36241d414169c1c1795187b736575a38f138bbb5e7d9cc4914ce5516295595697d32acf505d8e8bd92ec9fcf552eb12e5b65c2ca04441555c51972848ca3565751d5cb9b0505d075200e1e4ec52cb455562d14a2c271fa2a038a9010be8e6146afb1015fdb9242e812851d28473068fe8e008ab2f53515559221e5cc63c291254a84c59229e90b4c1439490a78b73e2646f4c9a94086112b244c3e65b27a1a135136d6763f3f4b80d212b50202392bc90125a6822457f2e7886a7c7c647631f2d5991b1ba443c579768070bac02432a916a6cb2b7eb640dcde35befb8d6ee638f4ed2a3b7d710835545ce827a929af2c1b240014c697d8402cda1020d2a81ea6052d2e4f424f6eca3252a1f627c60f9a822fb10f3d77d6409004a004f029012c094cf47166cfbc8227d648159def691e5f9c812c0d44b71253af91005c5490d5824aceeb0f261457f82a8ac2efb0eac1d593bac768ce34892a68e313ab07454a1638c8e2c1d94ee4927a59ba29bd281a5a30a1d593a28dd934e4a374547968e2c1d593ab27464e9c8d24dd958b2a1e4afdb58b2c16475d949b22c6332992ce6234cbba09bb40cda05eda49fd0561a4b57e1a4b36262f63e9996413be927b495c6d2556827eda49db49376d24e3a4bccb17db4c4e3320d35c3bd1598e70ed654945493134f92bfbeb3c5b3546eb96ab8cb05db81cd704250cc5f6e4b88102149842cd11f2127fcf599144e088af984f168698b8d25e251f3d775b2745cae972c663a95ed2eb6d67481b334c4d4172366e013a88363e5145415d31d90e520aa29cca325ab8b25b13a4fdcb2ba9c965db37489725b384350a2a02a38539728480ae78bd57570856304d57520450ecd7170965c67e32ce158e5b800729c106c9afaeba78fd3510914e8faa78f4ea03f4af49193bd39b1b7a7a88b9392eda325fa03c533c3c9294aeae912d9a22e51ada9c9344b23999b3248bd9d725a15c8cb6d05550992eae0aa03294250cc5f10d55650950ea4c86d817b4bcc6de5b6b6725b415414d7e4d3447faca86ce8a329a98b8b8af2d4a38f9c60fa8849d311d3514eabf2382ae1e804ada3259e2f9768c7ca8aea6d5397a8d6d4e41415e641269547075715e8fa0d920a9a124485a301d794dbcaadf9609e8f931acdc116076c64747095affefa4b73f074134485a301ca1a2756c7410d58407f0651914154b020aa31882a88ca4a1095299595959525e3cb94de60a8acf840654b8b2fe013145251b4cd04bbd91c4855fd75215257c894102aabcb6e9640c29461acceb3443c500eb53d561a795752d0db755c53ae4d6e2b2888848da6c55b52b0f92babe3000c7abb4e75a33988c2355d220eb4e4da4ce5b62e11073e044de12148caea384881165099bf0ec3358db8265c93c535150106d7f4d7dcd1474b1777bd863e62bab8d7e6402a88caa587a834fdb2537e39022716254a9425e2d17b1f25395a7272b23acf8978fcfa48aba1531b6de4d63caef50caf8182dd8ec64b4bbba53f7d9cb498cc1fa64b74b4758f962ed18e5f3f625afaf3a7e92f65f3a09f9408257f7dc4357af4d1d291121afaa8a9a68f9c8e98a48858a22255958507df190f8e8c27c663796c0d41fa79b4ade94eefb8efcce0e1d9b1d5b068760255e38847ec75c423f6917c650b8a4e8ee33886ee1ac7d273e191fb30ff615de410d1c7a10ff7e972d911769a2e7f695a6ed0de6a285481c24dbf7d7e356b76820a16a5784829b44e73954768efdfd0e95b7d52aacfbd23f7c37dd623a5ff7c1caf8739dba388ee33749be479d7f37b8fdc330cc330f490f436767127d917df8b911e0f2f2ff5697e99ab3c5edbc33d7011de67e9382c4b8cbf12f473080b0955a0d24bcf7bbdbc57f597f77abd5e94aac25e2fcff45ce551dddc3fae577aaf98e72ed76b27d90ffdc4b0d74eb21fdba707944e193ba9bedfecd3dc2fa1ca4314aa40a5907b42152896b79012ac7a50d46f3deeb75b8f7bcfcd6fa0ad32cf9c59cd0b6292ac58469c000bacb3d829087edf0756fc79b57ad6398c31d643d5f3b267a38aad83d96b0c4030a6ad3ef6561d748149ddac9eab2d8cb4877c1afa385ab29675537cad2af9814a7c319142cf7ffa87df58e65aee53e9735a5617823fdc3f6ede319aed3acd66751ec5d98a3ece4215084cc2f4bcc6c02f3e5874f2cffaa7500522f738fa0855a0eab41c77ae0261a7a5d190fc476e9b36a250e571e62de46df0824d23fd31bd7f11cbe67cae7b1e5827f2c3fa06367bb3f9b4a0e70daafe61a990beba7f9cf4f643830dacce33edd7fed3b5701f7928fa58646f5674bcb30be659546475e1d6c0deecb7a146b7fe630477cff61b888449475a76ec60e5619768f6669a619267fde9333b8edd4d0bc3c4f2c2504aa9ae5e6f2e8daa8f43f6463d3a641deb5c05da546868c87a15e78cf1d09fd693ec537a7a4a4830cd51c7f5bee739fdaa4f4a453d1a0ebdf53ccf7370dcd4356ccaf4f6cd404ea4bbb15b17aa3c3ecfb3b7852a50c6fbac7eb7d058f1174c6b39e4dbd4a3e5902fc992608db0b4eaf859bd5eaf7e1d097f18db30c6fe6910634bc39f67ff61bdef73ece397fd87fd4cd2de6ace1bfc2b3c92eec0a0531e6f73d0dc252a80c5dda794470815c87aeeed10eb05b021541e21052222a238ebaf3fe911f4c7fa4963f0957ccaa3267910cca0e77d2b8f0274407facd724efe12dfc94fed0abc75e9394598d7982ff7992ca54e6ab5712ac2e63bae3ab15ac35ac55ac75ac95acb5acd555eb08fa969e1fa13a4a45303202dd51fddb2755f356e663ddf6bce84fee121a31d21f133b6975559733ceb52015bc365a75108b69fd8c91661573846b2f107c2d4837cddeb077312fb60e2619690726e512c6bac7254cd38fafd144ca5eb7591352c9135fc77e4b21d63db7a590117cfeba231fc963d6d8b1dd60aef604a3e8b4e7cc5a1f52a61a7a75ba447417be6e74b5bb974ef2c23e5ea29ae837aeb4f34897e14a3b8fe209d416f02a81cb5f4d97a8b6801b37dddc2528fdc6e92ef4eae48402b59aa95bd4303e74f012ddecda07a5dff8cd4672e3a52bedbcda072e7ff96b2379b9cb95769edfe8f1a5457d52ad0f49a84b98d6ebaa05b944721a93eee8eea5e9eec7dde012c13c740f3e2032e6acae7ee843f72a2ca23be8879e33f14b83f7f10acc227487fdd06b12abb31e7a65b2baeb21f5d06b93d5550fe9960f7d0294885e4acb7c183aa5148c0f7d0c4b229f9b2f1717003a0c8f188d2912a12dc0bc388fdc1f942e632381dd6c24af9de465fa8b24fdc67c7ad16df9c18dc3c20f5e6e6e2422e433a688fd86d446ea132d7548d9299921d48acfbbc8dec2217b0b9d8e3b676fa18fd88c19b388d5891e7a08a1ffb0b7d07119938acc5da21e8b0b3df4b3e843a8975fa2d72e72bb4422dc22f616fa15a19f144b873d740dac2e7be82ecfab293abd6118d29e702365ad51cc786f07f05bb7b5dab2220981dca79b489579f3266271d641d03469209ce49ff4cb0697c8c7e272e4b64ef113e6d5f4e95f31684e3a08c63c4d0ac22602ba808619c799e72a8fd267e7d0d3729ff5cb21e393fb5502d1f1b0e6e4e4387517499d46a3954e69fb54aa4f6d361e2f69b58d647372c88e53af5ed2da909d7dda27bdb64f3bf4e5c9b3abcd6d4ef32d54814ab7d5767ce63203904148a733ea25a5d565aea35f25109a53178da4d1ca4a739236964633db8e6d762d92b2a4a72cc7654ef35ce5413aade84f5999b391a897434a277de632a7f9e8e78e87e13e875ee6b69c9d641f897ae9343f7776927db2745a69fab4ed9c7de297d976ca4d7aae02c9dcf5cc6b3a5a47a8f2a064e9365b57615630e99fd6eaabe321cc336fd9ac7ba540bbc5f4b7e99596cefbf4d548cb1819fe3ab656f62ab6f4e0d3b69807356394a73e46eae94e8ae9c6ebd55e9cbd0f246f48de4bde91ece2a4845a6b254b114cba66f4e2de7b4b170e968bcc3967d76b06e6fbbeef65d24081498661189a30d1098c1cc77184dd74b9a1c90d5996657923e3c6c9ebf57ac98875710288180983c16031998c942143860c194e185d6e40412693c970666174b181cd8cbcba8b0d5ae458ba704c20499224abde3fee4be9e57abdfc87259db42e577579b5d5a5492224499224f9d244acee86c8cd8dd1cdeb5537117bab2f72cbdcd4504cbe93f9387351973ebe3e8f74b95c2ed7a6f646c4554319fe7297cbcfd05d995a22999fa2c3fcbc1e7397cb92ae978e3de9fe087397b893ee633f932ee9371a3665de9d641f5331d5f1e38d24de93ccfbc6cf70df90e4b89144c7f9316c27d937c54a6e25ef7239a83f77694bce74cc4b2d8a3e3aa9c17d924f922eea4cceb4cc4b3d7a88453dc6fcc71d2b09e290341cd2631ac76547e21e7148d04750c734b638d045f0ba42eba1b60feaebdf266202ac7463cb14c080524d90eed33ab6f6833dcd3fec8bd21fea5d8e94b2e88e5ab755dfa6cc1ebbc8deae5bb77f0efd75f04ccf35e2650fe7bc29fd81faee7ff7abd3aad3eaa07d61a43b34c1b47ed23e66926075f003e9068df4f8eab42619418f82365f7c5eaf20193699f7acb5fa899f3ceb26ed2dd718bc425187a2a8cfa44b29c638c4d4b3ae4c15c873ac4fcff3ec79f7fb7bf1bd15dcdea7b1e739fe3cb0561c566f4b7d6b2da80334c18ca1e8260a18198ae8493e38a3dade563244c1bc854e02b37e187e18f33bf34bb3b98dc76b3bd7b1df7cafefac602977f3197a5b962eea33e9c52ad6648ef7591be2f2ebf493ce9a6c07715decf493be7a9561bf434a17fd7ace59b683949b6e5a1d479f228f973c7e376cea55de92077bb979fc6e241e2f37d28e5f711b219f27eff878776c396efadd674d47c7cc715a8ed372724cec59f4efe698fe5d2ceed30ceb6ce6e66c9f35e79bf375d3f3cdf792007be8157b2cd4629849ed9aa1a9c595fbc49fab671caffa34428a1a0438c4186b7108c65bf47a9241aa979bdaa3ba4931ccdb087969d908f920a8a4be691f30cc9d243c92177db29fb71bbeb8ded26bc619b4ef93b3ba71cc497fb3081a8594deb297af63bb636faccc78eb193c2582cc970f4307ab53d749aad3ac0ef4cf411d7ad5524e109742ae87e116354ccafc9c7ee8542ed0f46b10b096e1f73912e8d7c7ef3f6d6910ec954370073e4b81b027d19ed21f9afdca20f74f13fcf739f87d9e047e783fd4f6c87efec3d23e4cdbb5aff6ed23f5b177a03ef60d55dd9eb1b70e92260d2aa3602b5c221ae1e2ae6315ccef31147fb10e4071d7cffcd4ab07f4e73a8652c1041f04efb626cd8451a2dcc5ddebb9eb33abd3b47ae2e13ff780669a679ff7ec4f6a85bfedf4071ff98758d728f676bd3e85b7365d0324f1c3095649b009e28bddf511427045932556565869622385c3e8f4b8a74aaa3e732580dff4d4995c85a1de812f9fe4290d974cea4ab7da14e8ada2cee4c7577670f471acb696f5550ea9ee2a81c8befab9c5ba4b6ef5b234aa9f93a551dee328732a03f6f231bc1609c64f15f431bb28ea6090867749e521ce70b8cf7dda07fd3279b90168d501f3ae853f2e91934ef39cbacf20988ae2a9e3178b346ff32696e9a9b3937009243b12ddd8c54cc99dabe3b02a0cf316af4562b16ed3d39fd771ced9f175ba34142f13a7becfcbe4af6952ba6bc641aa2edba2535a69166f28bb4d15283b580291b9e857579fe9d17174e9595fd97519dbbe5c39e7ec7281eecae1f5bb24d31dba88e485d96d29c473eaf2ecda35ea3ae7246bc9fce8a526c3120875a470930e96432e8db6cfa44cef128b6575637ed07b500406c82eeeb39e49d6f3f4493efdbcef920a7429a5365b325697dd62dd2595c765f258631a1416eb32a9b45e264f788fedcb9f83f09f7be4e99f68a391207c766ff780f02775233dd74b4fecb1193a35f2a1cd4044518417dd089117f7f9391def17926308640c12eed3c86737127bebd4484cb47786588e1a8eb822767bd0aaa29bad67da63adb5d9de2a668159a91dc2f696dde23288b117850e629abd10dcb54751ceea42af3e6475a08b9e07026fdf723d211493ef46c71b6adcd4e2409c4dcc82d1b43d2608f0237d5f6edf8c30762623558049abb0a0f2b6aa0bab7b0360d2621f10a156a6ccf5fa4890ca3c95fe2b40ee1215dd8bbd87d5d5bf8e5d034b4477a097ff24c197393ffe5c035de9495dfb5ce94310a1dcb520a6f65c9a74992e63b83482a25d0f887c606fb756a75e498e3a9ee321f8897e3d7015116187701dec629ee65f975b5d2d48be9e6bd9953edb1ba6ed2217876b41cc9763d365321dc275d34d2f626f5804ab33f799df740c734a75b21d82a945c86ffa49b11ec9dc45e87f11f3d2b47971a6d332482dc855fa9a10bcb4f4d9f3467a6d289ae3a5a5a75fc4d2f6099afb04b1b562ba362d31f672d728af46a94eecedc9de9c7064c41cdfb87971454210c14886cd7064c46e4cea2fed325d3dcf9f8b120c624c7872450d554ea0c50e3b09974849ca15112c4091a68b0a7ed8612f72899452f002154d566a00e3ccd48e96a9a18a98279440f1e2053beca395f1e62e3265561e768d92b9192566d2623b06e3c1dedc856538be710c73ec55c90897c8838bc38e2f11edeabee9218820e30616d355c90817876fe89bfabe07e66bbb5c1bb437700cf3041f3be8b50f725ccaf51c57dae9e89a0734a76d24754773a59d0e418b60c4deb0d3f40817873d479370eb5265b237ec6248bf0482dfdb45c029136307ab98668dd91b2b4031ccead63a08eab09f9f8360f5362db2d7c39ee7e0c6fe9ee7797ecbd1ec1814047bf480f919f42edcbbf4bbfccc79912ed275c6de457b97cbefcd86f9bbcb41f0345dfba49535e76bb65e5df67a71c11798a7cffbdc1f1a6c602ba63aeb18a426f83f2c78898cacb4288e5a6d511cfd258aa3464a30511cb5b2b5c600d71feb58abc578d78eace521d39a770d6f6abfc230827447a577db74200ed38277534cd7985529d73b84174bb4e7ac4f36ba838e2378b5e856fe687954ff6623f0437d92e03daf16d4a7920846ecad2aa94cbe7af5ca94f5d545b03a7c3794e8d5895ca20dc4fde5cada5ba55fbe8a082b353c7902892a4ed8552faaeeb7fa84a7d05b8f6f0086518d1459a7596b4d20526b55529554162a1311129e56254d2c7db5568b6071d5c76bc475fcd49051a211468fd11da4a9a9cdd682609876844b54a96a54b94f9a6b9f661d3d974621640d526166ff71c7518b606fd547900af3ac525f3dacf4c79e267865fb20bc2ad6c55507cd4aa54f09bc7ed12b56cd95665149dc20d85b2d626ff504a32a16b865562c7b56325f6dd117b1b76a034b160b6ce8620a0b40ecaa9bd56976e965c32b2379c92b922278af83f78aa3488e64288a1e8a65f9e3929edf6bed593fd77a04c97bfe0db97f8e8e441e8d4e7631ab6ba4d2ab27b155c9ba4fa4eb60f5d10b82247a58450fabe8b4243dafa5e89e46227d14bd0c9d96d74b7dbd6a105b4db3b71af3ea7b1717f4bccdb534fa7206b339c4f3bccfeca317c4cbee6924af96d98d90aee7c6a5318fe3ced394e2ac45f2d71bb2b79db75313049915c03039c500b5c3b540f582254a5270c418b830bc88a2cb941a1864e149b2644916537cd89284aab6195d7e95bcad59a2f8486d986239e4e5d267fdd3e5b0b0f2f8dc2341d3c1729ff5cb21e383bbb200fae8461e2d666f36b334f2acf732ed0d3ff9b549ccd966f97104c798625552561628ae2c541e395b07adf5ea7bb9b250812a0b6155425fd59b62088d0d6104f6565ddca7cd3a6d3d3e678f1296de73ec5595c0c5841c4c00e384165425a1414a4ae90a1054beb8228c17787842072c4d402a26332f8cc1c20c182cd051876ae3898e8b165030c61863fc3dd9feecc9c2841a5940699dc0452b8a1c9e281a28c248e9c1cb97342adc0ba58a97718c1c840803cd0c5d54711971006bfc199be24c3ca18d66a68c71021b159a687aba320307a43091d58588263098e2444b9553ed86da448232336c51a6043669aad89db48f8a35072a460e60912b9e4cf0824986aa2a369446e2d67f35609a4519a9157c3063a684247667eec78ac31820142d3aa0a0459625b448d989226cef70aa343c2901802638c67431d546ca164b4cf164aacdcd085280c6c90e4f4a78d8018f33944638891e1cc2f01c6cd89243992d4f534c3e708c1a249eb0b4c08b1aac7522440b4a41fc8035830952543871461465c0454fb84802872d4b4c6a45c369e831cb0ae5f7d5ba23868a6383c493229a4c5cbf2ac414d2c3186318a6e079614c32650b282f5c68d3e604f5862a51e89818d86011b5841a2ba4b8e06488194a96c68b2f9631ef79636dc1b4a2614c064e2db0304eb900b361eccd5e7ddfb842ac090c1e3fa661e9b157a6efcbfd68a681c1aa0aa3d7146a132dff7d5e51f860b70829565a2a38628b3418dbf03808288fb1077eb012c30620acc088da612c7e303c26298d706c4c0f1324a29821aa6a862c4d6a78cfeb093f9c3041ab492a082a4dd41a5aa0424942184d20d1c395345786f8c6af9a50c58485c755258c80c5c8728247bf308aeef8f2b8c825ca57d57d72ff7abd9c3afdeb5f4eb3badbbf1c7c39b568c6303efeecf1a12f93c65334417f5235944d92b332f16a141e50e0040f6ca4a820458a1e9caa7a3883a58828aa5820c6922a292754a8f2418aaa1f7ea89ac2c27bae14e5b9096a094aa317fea2260ad60d3ffc80d50275c2c264660534436449593383942822a157be806191041e5ca23c5573ce59392b6fe5ad2a359585d0f239e74cc36ce531fb08537cb619679bdd2737e445327cee61eb21859bcf99ea33fdf2395b34564d19d147f0058bf88be822c0f9cbc5552fc9d72c37fcc7e53f2701fc823ffce5f310e08f084b0e3eb08879ec2030b1d063ff40be8a394183f6a882e63dc7de96a92c4bb6583143b5e54a15ef795269e4e12be60c93250f74006b8a5a51068617a09c101175c24783112ef8cef88042123a4019f3050a44f1c808a5d137e673760e60fc83a649172a8059620618be265039e8c9d6132d4b69b4a0601437f0b9064aa36f4bedb31bc9f51533a3040b175a9a5cf86277e67e8622ac00291722a8c0228a0f2540e902638c91ce2d41d4f0397b06f0eb83272f4cd1a604a9184cb1d88a9589114f79c7872815c06005142080d8bdaeaec62d0206c000a143065b80b07aec17c00ab882aa4c145b4124816577e668b4c717635c65788c316692468a0e4d6ca0628aa61dde946adca7b7448b76393729482d501a61d143a862e933d4e54f1a46cc7b1e55e3f32765b3e3f9599938a9513ca767a5f29ed59f35cb7b6ec57b9e8326cd6f3933ef79d18f0d3cf0e18bf79c4811a8f75c84117c78cf49906ac1d20f5998b4dea35b7ce0e23daf4e4f3f401135458a14d37b5ba82cf19e5780ca730b4c8cb1b84f6f89022cd8e1b3e3ec13f05c7d04c1a4cc9b16d9d283188fb14ba07a1fd09ba921c6312cac59214b941a2d98cc7b1e019cafae5c6e73b98feb5d4eb1dee52e97cba2d95ae2ca16850697272f36708182868b0e55ef390472441968ed3c07e1014597c85a89184fe110daab30b956073461fba21b834b0e4c3cf606881907344488b1020c4a9864a875499525ae8f181b96e0b0822aca9ca08adb5e6d306f22a591c7058727bf44f9ea042fbe56aeaac4acf0580c138f7d01b42b5472a498e284024c6b734c15a103bbe108aaa71c8090c204859241143d3cc60e4a81c263ffc0b4160b0e3a013da0a80184628bc78e0093ae91a23565cbca1160d41a4313b3f7aea89043175fa48049937c659a5a529cb882a5093c80891580c7ee41ad4110211b72c5a403506769e29a358de162c414d413033c5106470102e085155e9a8cf1839422f695a7d807aa98fc5006862ece3c21840ac7c1145419e409a7db06f9bbf8062145ce0784c79f3127849c18f3d88f681f0969b26c81f102124b56b0564d42bc40e904532fb8b046871d9e60b3f33c2ecc336f656cd404148f3570314d1a2d3b4c81440c3b2c610c03962494a88cf9a18814547041cbd6cef344d313fda48ddf0b8d6b9fe0b84f53dc278d00a59167b32c9169b56c8f3dcc0a7c84c97aecb426b43cf69d2bc5b0459a295400450e67b078c18ad6d4181b7e9802062598a17a26a878af88f71c34697efb914b000cb09400c6842c5ad0820b56b6e098c04b9313605c60e2ca0a8c63b61e1c4b78010513490840690826bca8008b262c6061b98145cdebb18318bb8f188e3f7dd00429f1a44a89ad258c78cf7be4945230039329a2f870058c999c9574710208d78d21b4a89c7952c396285790315b8f1510443cb276b8018c165548696209c618d71684c882a6c4d6145ed6503901d40b2a1883ab9a147ffad0fe1c724193312ee0020923aa90884155125baaac9ebce73bf277f135abf490f39e8318eb0280f711521e7b3942cd632fca5fad59be8855a26a4417458f5d571ad12d62bcc0ca126bcaa430c6c51777a58c8eb28c114f8cc87aec434b5f73b6e2038cdec003450f98a627c05c51040a55454cf19ee7a811841a99509884982d445439e1c5861dbc6cf10589f73c287f329c80668a8833554a72b8f8b23045a6e6ba614b0e534c818317349ec5d85bc5ca7ee6ab7c9577c65aca1951b5e671148fbb34f19888a7c70e44cb5869bcb8e10b29ca248942caee34df7b10acce7b8cf10a8fabacf018b7a009307058c3a60a0537ecb017c958594cb65619e02b19635e7ffabc57b56589f7968852c5850d0c555568def39fdc55c632ab4efbe54f7b84cdb2546c162597c95fb74e5647b564d1f4d74febe4ad164b5f54d0420c1eac3cb13bed530a4b94b8d20a33030a76a78dda6293244cbd12f3977a7982c4f76725738bba028a8c95272a4eb03b6b96120a585549a05192022ca2d89d55cb5a55591d519f6a94bf5ea354f8eb67e541853f2bd5089448c1851a96b8212a88dd599710628a0b37bc200b1bd8ecce3af5d769f5b32a392b139a757d842a7fffa46a685daad7e2ee94c5d5a227fefed9e36f0a4f9b98a284172872b8220b18764e8830810b1b5890028c1d94bf8e51c84981165a4ea8208621a0ec6ed3164e4b8e00a2042dbbd3fc1c7571350a893f6347fc69b3fdd99346ea469a28b088c242cd7bee738bb2f6e97b8ec3b2b14436cb6ea581e147fda3df288dc62626ed0265e96d18f2d1747951745c69249a23d0135b967663175a543bcf6fa6984ce6eb1918fcd7c47f0e80d2e8136de0236c0e7346ca67c75677e3b3d70049f23f4c896e4b4b4b26502d2ded3ca75457b59696def31e324bf52933691e0f3d761aa511b6ba4479cbb3564ed5c319c20afaad026b65365687b7b76b41c40fc7679e63bb1604df383649f7762d88e7a38ffb2cdd73a517f799e33457fabeef4a1445abffbefc093b5fa28f9ea3cfec9fd3f4888383838343358523359b39cdc7d96c16f595467ba2e9fa33ec34ab9f85b5b4a5f5350bebea6bfd18cc65f80883c1ac64c890f14586ae0fa3bab8d7abe96f5c2eccf4e6f87abda26030d8134cd77f395d5cadefba4daf17d3dfa58bab2f1f5d2e97dd7abd5e56ab665d5c298ae2d48fe395bab82ae69cc37d66a6effbf292e7e12d1a3468d0d858ebe26a7d4fd7b74a98dacae91259ab0a258831aa58c145155438ed4ef3bd24598680bd40852b24b09c4143c5cedbe1d5cc103372a89ce4f0444a0a2c00e3842b2e705999620933546858614d18ca63e6c90e686d103dd06ab5dd7c192a4ffc35d3c25faf9949505a908a020a0c499c665871227bcfc15a77e8d42c2a726e80c2c3153880a9a24d35214b14371058210a356d6e589202175aeb0e5acd52727d769554e054a50557a2a8a14ad3eecc89f7cefe9600e68bbfae8179ab7680ca228589154d9c76f75e590d1a4689005027feec71d22a2acfab78e23d304f64bad4608599f73c57b4430cc0784fcb1547bce7b1d2c8e352c506d15b9251450a6e34151e9488e20c0c667861f70191ef6f5dfacb258b95bfb40928a618625881932625ecae17c917f6d4cb9fb1a13f6def393d7d06f0e7d07b6cfef69e8366142d549c79cff35b0eef69818199f7dc2c02428b326cb29c49019918b4f172c2094a3d44cd00858b26587458533d0f9bb25e543dfeba6b6646c48af27fbdcc5a7e60c27bcfc1cf9b84c1378124ce48715212440c53358a50a2cc5b97c866d15dbd5c7da55687c6ea3c17f18efc02194011444d51c1972eb85431c9e6cc8829a100a4a021092d301801e609f10c155c9c6660e3c4971d0cd9bfd2284f91e66dfc750fcb10e6144ffee6ad122c3d6d39a382102bb042c7b012c37bef9d49f30220986e50034375c16679366b69cdfeebd866c9c8d2431554564c49b276a769b39c9a42cce07acfc1227447186dafb09fd6caca5e2931f3960bee550a543c89e242eb0414c46077d2decba14a0b4c9490841628761fb8e72014d9e012e5ad8baba018ef7991d551363acaa50821de7b4f0c1354aa40d14209a99de7b74ba4b4021d6cf8a20a19a83452ecbc7d1aa1599fb70da5a4a8d4cbd7aa939832643312000400b315002020100a86c442a1601ac65918af0f1400107da25a5e4c1949c320477210851033c410630801636004608666d80070f80385393daa396097752fd2caa80910369a97d54ec2892dcba45afddf6ca604ac9f1d17166df8771fd2b6d10c80a6c8d3c40b93516c6f1962bb116812a08dffd5f89b2fb17d76e8365fa65189c300a9562fde4f8b50222dc5f02d0c933a5539a3006f5497bb183f66a5883b0af4741d48e09350e76b0d288a9585d7edf38c18a2c7b0102b8dff251f0e84aa8b7ed394479d74e8dec44af3d4721f4508a0a09b32e6162043106d35dae983d8e43c455f32769530fb78f06da5c2f80b8f0d93226b927015a9c54707bf790c2965ace22010422b7960caefaa4eb86551e21aa67ee077e5549d95c57180b62efac3c5e41a6a3224a5d4642a3fc697877bb24b8dc18b0afadf1577ff94aa3503f3a897e684338d4bd85df81122f03b8938770187ff3b5a08fa6eed6550fb9c9b93dcb9157d0249c8e9439a9ea862696e2e534e15d98d7333d5f8fbecf5809a0c63701185fd1d6355df06ad49549cbd644f3bd9f463a63d39d4199f2379bf7eaaa7a653c0d3feb131038e3a06a99ca847114d292af51f7529ad048cb8d6c93864e172ad2dedb5dc42fda2d243e4c0688f9885d68a00981006d4313d21f3262f4c2b606285c83060c2b9c71ddff6fcbab54d9073331edeff3b3370bfada79a2569950707995c8b776dd0f47d72c9607c1e9f712f61b3627d303555273761f8bb347b5caeffff560f0c7566d0c6a8ffdde41ec1bfa5fcb199e174e6d1c3dd6bb1a9687c43ea3944b6aa0d5c5c0c46f9d850e712d168c1b388fe00b590ef2e9502094d5cd6861c9f0e1c1ac50b89e4d2a27bd24f6539c4f6b125d0eee50f1c5815c6ae13d88652fe7c4fac7700e721a8996506d53848822b0072cf1bde59961d3e9fc409c2af358c43c50ff566b71beb1d416c10c17b6bad2921139a9eae64eb1e944d6c446c8912df3b22b6296e092472dd682b7f0649507c9721376abdf4e3625460cff73da3a615e658564aa9d7b7aa140b9674a7f474ea8e5d4cee5d753297a26129462ac0d61ceb7f3cc13f0c343f4728ba1c7aa68150130c0d165bcac95c68bc5227590886f0ce2be5b1dbcda4ae8d538746b7a883634cb94284322ccdd96e9d4660af234573f80cf19b7b8c003753708cad5239a219fad01674710c6bbe3508282a36948aeb78814db1440b75a51fe169e8d56e7b6617a802cd09450ed82b7cf754dce7c22339d8643612634812368f8a9c1bc4ae53614576132643146c44027dfe3cc5d9e3557071163fe6ce38ab81d15bd97a36021014a4748ac77d79b1d52baaea3be9e8c7eb2b15dd2c56c5768f240cae22c6a3283e8e0c4bcde54fe28f4cf5cc3cc373ccd4f3df4b107fffb60895380d8c95d7aa8c99bbef2067c67e60298960dd0213aea3cde800112e9a00dd3e7ab77f7b07ef4bbcd1997babee952e6c242ca1d433bfc5d8f2a31b210f9ea09834e66bf8e9b29b2789506ee4fdcc94ebb5af1c9b29dc7bbc60361e371ecf9d4705b88d34444989ee7009265678c7095c9fd6b79264dde8cab94687f040adb890e6a72a4e8e77c4807ce1b1bb21060fc4e7177466e52e33b7f6932c623d7a5dcd8f60f7ee8f413edc8d4e6c47218990c0a6a0d9211364b93574674c43924a97a59f7627d7ee0d6d0dfab086298803002efcbccd26d22530b67ddaa1970980fe903d72f1050f2980f5067bd0529442299041709871ab622b27bd0d2e75915efb614c8b2e7f56c0abd71a3cf8880704e93fa8c853c3163e0f1ce085bc38ef56207ffd79f9cad1d920233ebf3ff3c367021871c25c137acb805243c0450f207d31e648a0b418416a0fd990007b730274a1f7aa23dc88b33ded06eabca25d0fe5b5db9d2250589e022813e055e05d30426826ee26a7a64d7eac98f067521ad1553653f90380aeba0d4ca5b819cdfc580f244c4e94720443d91250153181c6885afb3e9f3fc45960534b259b07e0e670fd01dcd1afc6d232ccbc37a0b3174b20b125d22ec66a126ef7355de909f3103020c7143f13c7df55dbd7a4c8f94dcc88d4f66b341ebd22fe9352b48b323f819d68ad41c2212fc806563126139beddd8fe411f54dd61535bd8cbcf2503b78e20e542905bd99e79368f6d39c25fa3c9ee7c9328706961e24953653a60b2c8f88ceb50050e6550e6e34fa6c188580a7cff91288d62910b95363d07c4592dae01d43d58f8fd48152d265c2447d2d4913e41d8ed26478568c247a0311fcff948ae0e01282d0d1a7490a83e6f463ce1de73836e85f38702a110764ba79067bd2b4250f4cb7366719605b7abb5a2e44d628c1a555d033e640abd03412002680b74e8c0251d59999a1a204a7158b04b473b809f51c7a7fb0a509aa0539cb49978be3303c5bee5e1fbfa3c10ed14b8ab4e302c21b40856360f6a6b38b4458cfac23245f2614abff46d350e8883217ff5215cfe5b66060378d70b0528182c06fa33f36a63395127d191075ba51b2569de746d13cd9fad600b9431253729e3e6fa5319e13ded75583802cbdc1b328fb4a738d9d6092121acec9199d4a9f31e28454d37c1f675d59b57e146d9a1f7a9351f807a92a441ea4c6a75cb8a02053c641f595d6094a7da44024708da59cc8145a70b0c4bb8e90c02bf15e4a282620ea8614d704c91df1933ab863ba783b8fb47347a8237708f89f7c772af00729580c31830388759639ac34c3968fe5628c121896233cd57c821717789d94e1f6758cf11619bc7f1081a5cc9f290498822597590cb2a2c89cbccafaa8ec7784e5365531751dfc60fa9576b00f443c8c82c1ca5f60b3680705aba64ef0c8012bcde779fc03c3a3bd4c5e0ca13157ad2ddc610253a881a83e489ea328be499ac8ca34ba720bfa7df9051199dee4bfb0b299898470d42eb1073f9cc6dab604e35a0c13176f83323ecb5a7b774d89c6430b7c9fd60479674d30894d7e1a65e42da33782e0f072a8a0a4e5dbb59437a281eb37edc28e659a77ce7ff5eec290e2fb246f3020d2480a7e218284e2d524651dde27f9a29c81ab92a70294a3987d860b3d6a27a56bc83999d7b006db17acd4dc911c74bbd08bc027cc46f1067b5a363222696e02164f47ffe0b4eb5c77277ceb72517b1829822c3cb5abb52e7f5adb110ab097b32608ac6ea37e457941bea26b3be5ce9e10fcc24ea5f7052bd50906220eb18270047641b33445516c494708d6cd2b1c4882a657996c413468999789030103e6ff1b08e103c516873ed055663633e30ffdb4c535bc70be6a370aac05a68426d780ab347ae54e6067a7d1eab6a5d87dd49ae1b990adad39af3f8c5dbfdfbbea93215392bd7bcd0e90ac5507954dd2775cd92b15582c6613b2ef649cbaac3f47fe257c24af1345862aa1967a64bf25a1da9078553ade9a596ffe8d4fa034f5788e4e1a250edb77cdf2beb17dc4299dc8e99de2e754e2ef32a6840877de100f6b77e4c3be489e3bb1518dbdd536775626e7d76d40e92f6e92a52e31173cb530c1558fdc77f2e2721eea1cdac9164ba26bea356a2cdf2021e14e90be2b8b7803472a2951566c6f01a1143ac92631c478d92f70132ab248a82737d6d2ebaf25b5f62777b9e922ba0270a9155e84856b3dada5436a1d09ef958d57fd5ebee03e3a15da59629ce146c2bccdac87e266570fe32b50d186f2f152d01170274719be90e03e15502279e4513fd7b753a57bec4a4927c10ab6a15cd89afcb19d6b03c2b252400fc52f588293c48d81dfd24fcca82497ab8fad91e0cb8b96f46de072e00d6b997078b9ef982f4bb8a7e6606139b8858841b95983d71cd87ac27cd6e6f4e162e396bb5312f089df5fae0e1153681443022c823d8317912e15d5232ea6e7046cf6b16588c56a7ae686b07428301b2308ef58a5040796edc63903af35df8a893dc1a3257a7f447a5f9e0055363a554a1d309b77aa4a3e5dccd21739b833a76176529f4afbc70f150be3fa9d2cd6adc447d8c30680014b52d44380a89153abe83147fd226dc358b5133c7c6e3350704d7be277fd2b4103181e2f7bb982ca4dde1d79773fe51e61c7d07f6ef43336064fa5d934faa8fcf4c04f0b0b1ab63e25af7e3df8c5ecf0841600ffdacdffede3fb1774dc2d4150d5c0179773606133c49ee3875a3aea4a3051e09a7d66f599f4ba3a13f1d75631b2e5517adc69b07cf82e90935e61d33e664f8a3b005769b2a3aaf563f84929c66d59e3e605395db1523775fe4855a131517bf2b14701db11be80ab58bd6862e71455fccb8ed6f6fb911e19a4a05f8c8705af711e359473d2b85d48938804da2d463389cf4c2e722b3c35028e7a9d687b76f07ec66aceb137cf1765afc10c426d00aa713d46f57d2ba51e7667fd2a486d40c99751aa1f99102454edd1002ab6b9848c6d83b1eb9679318a206f512cccf3969fc7abe18f2b7c35b89fe11a8f6454180f40d591904c602fc480b30fdbc7e1bce92b8991b99c33eed39955aa73e4eed349939f7bf18b190881b583918acf6392faedc0562a2e44f0b33f92d8c62cf9c16c5dbc8ed11ba2da500fab1b54fdc78b504f97c1fe4797b0d99cb681a89e8c6b701b5c9185034ec61971330c1e0eb8e0691135554c563bfd80efe3553245dd325968e58684fdbe140bf3174af4c73233d49fc57fba23cc2084bf3d14d3cda4fd6d01419d345673d28703da7b78f830ea2cdc72ceb5703266839195f4081ed071533ef03756229f6d2a75fbf596a0b37fa31956b0c2b1255e19d833b9477dd4213abb53063ccc9baf2fd3dfb4611fe8e8b24d3fca9db1029b46e7d98206b2498182d2e60412cc6cc22e765c0a57f86adfe18d4710567746efd0d7a3d1680af8597268c5a69c0c8778ad7cc829415ab9c3fe6b2c143c36407a2460f2ece8ec9bcced8fb1c1b57f0281296a41277408279db0c7c5616fa573a20c6c11b584c3b5f3c464f6bd0d09d284135db126f7ee1e052d9fa9ad6197bebb10da80f29558bc8ac54eccbed99c4395d1a4f63f40bce8bd225b070a6f68f763799da10112e3f70657a520bb6b1f416bfd16155c5f4ab908aa146ea8bf4fc32309c175c7a286a783d4cb20c888b6714066b215213dedf07dd23b5a4c79778fa7554167df6538578a0977e1a11c9c29c49b117159ba1e23fc6a018a29c32952b45a35c32d76e682609b437f8d934c250340be301d8264719125080b1d38b58930513559018c4ada82018c871c2849c297ed114751560ba9ad617b860fb4405cbe680e23fb375c40d7eb4435cad8113054b86a4cea9042941561140ca687b61e9d15063a13cedf8e32a076c8d4dab2be2cd5cbef15a14b28bc33a63061bfe796eaa384044b37e9550efb65ec3f0ff6d726f6753b0d1033ab2439b21d6058c590800086a1336b961767a9180bb650be608ad509fd4861086689bed70db65ef86c8fa8738eaa899bb0f34649bef7dd14b26d50d7ad9304c19122af1ac424604c8f905a22c569cdc5bced71235ef40c9901ebb86e03e367575f28b2b252b4d0ee861d371d4a7b0416878b11890810a0d266cd7d6e06d3d51dc96bfdb9836973e405dd018223c4a404f5435aac13cf722ce9a044010f3564fd126e2c8e46de5d9a1ab29da9949155534b8480627ebf179df791a1dd8f3db92d444dee63e24254a6c280e0a9a572d38f7144c39b5f826dd564ebb05b4d847a2eca9ec3cd043fab26a6d88e11570f955936274ac18acf8c9e864a9a36d974c2da8f7eaa508c08816dbf173fb6285ec56c81b1885532f072d3e5efe4e3170753532a781779f704a01cda5be7a4bcf5c02c550774b4611388ea150a0f708efb06e5484af4492a9687abba9e6d40a3c4acbba5500d42108c0e511d516776e808e40b275229aa46be4527063422d8ddfbddba18d4841bc3b2e765666b351c32217919a66fbf6ae3fa01644c85a8e07fc39beea9f5f130a4b39cb1b1c900e2759a1f58003257a6ea4ef1657e8a49a7a908365f0cc12cda38614620054833944864471cefcdcbf8f0a557958bd5c2849862a786838be480df61c9e33cf203b670bfdcc0f26e4298f35f80850b95ba0414aae469479dd89b21ba612a6dd0a98743db1246d76f64d27047814e781a3117cd522b063500ababe9e77457dee60ae1235b9d327ff4988c85480398cbb295a109c04c63736eebea8b0617d46c257dcc5086f4fe4052bfde23b7280eebcecb463dd60617a2aecbbf51b8a8899feeeb95e87ed0462bd3f70c700a2a53fa4d469520223d385a22201429638a74285dc416aca7051f7e5c668d240b1f0868c1bb18eab82c8c2ede018ab7b4ec26f8721842c165bc2e230fefc5fb519eca6b407e803187488b1af48ab24b7e7fa62d487d99454c7e838b90690dd702e795b881069814c957e8f3a789041a1f074ce7b5dcf1c2859097881bd0028bf293179043608ba238e9e29c7814722a97baa8b815af73e674f5de833466bd979ee79a04d25099c62f735afb32240de17a967d94fadbf92b98fbd07286b4d6c6f77f2a37ed1f7e3689b553944ebae4c041d379c933c0377dd8ac70e0d498dea435c18cfaa6656b653946797812309131095533a6ebf689c8bc4cee61faf34c64418a8f9af9a6a0bb3d3b1647bbfd3b5f73bf099a70aff368caeadafcd443ce6f32407f53a1019171fa713c25e8e23607182c438f8179f702216c964ae6f8d6cf7f9f2cb872a93edba365968d8d65505461291f5238f70c069d21a6326edef7bedcd7beddf7db87c17db0ce31fb7236b1443b588b4cf1e695f2c8ad450644adbfa042161343468ab68c17346e2a4c6432c5127fa131a83ba56ea43b53b387a40f75baf8bd1b47ae48fcc3929d86425c48a869cfe91faba83959871017026dfa73fb035db2a2c848895e5072d158840f11357da0bb2110840c0d86389112d3bed33f96f642ae23c48d40991ede9d8a0a21650da2fc489469bd61fe525c4c876914c9438c4c5723e8bf47049306adf83987905e36c648958903ce4230cc81654a708aa719b3916c82538c152007433d09dc76dffae53d88d0517ae61f34ebd534c55503ef99b087d32132fed8163e6ab738790fdf088c4047d9cc907393337783a6312a029886be0b37500dfa64b8e4e5ed21a551e128bf3011313415fca35116f9534a3a2cb03e2801def1149408d1f3872e4bb46b45d293457ffaed1657215233fc1c45c1b1589c89591826adfef6a8318e2440defc6f5ed97ae5a48fa137c2c643443b7b209f44f1166449c3f8b7cd895750786a3b86b25fde661938872523671b66a5b30e1f4e90d17696c9306c6f4f3f87943d9b0a091cca2a29a4e490e2585a2b2ea42aaa94609bc9b782cbb4ae8b2328336faba86be5e2ab2f1ef6c60ac6a3b124b4351718ecabafc497883fdca09fa20a6c9ad2066506fb90125455afe28e61075f120fafa2dc38711160ac26dab44dcb6088f15aa822904c4801f75882885a32988f8db392bd94dc1011753f0228f34cd23e736c4aaea7ee17f2b302f6626c2d84585bd5c628c14cc32fa6cb28581d29a9b7765eb231a4a63dde9b7eb33d212f6220e7758ae19f5b30fd8a33e99053f6116c03ef1902b77317fca6e837d367db3d2fb2c285408ec237799f51cbbc2afacb4e0cca73a7d268cd2ad295bb21a914d2d613c2a2e7734552687bb773e503a742f0106e8ed78b37595cfb7f245a46260142b2780615e1d9a03701c21d15a09e0cb18989e97546e54d60404eed1bd40e4185b02d7c01b840124c7e87f6192e0343f74aa080e7d458f28719b12a3ac2d56705cf70d3dcb6791e945f108f92c1c307c6cbd2f899e41753330613c527dddd0fc97bd30eaf9160f20001ee72bdf45dce64482d9f1b3839ae08d7f4cd94e4c9ae47b4bda613a90994ccc54e9e142d847e0522b2aed31622d70c6fdae4309703c16a5cd15dc02e65cc37236012c1151854187b44dcdbc35a596e204e42bfd51c16ea7fe39a76ba4cc8d26997671289b60232d4b69c34a909a72097d5a7fe7e30893cdc7776e69e22b7d0ac279773872343ff42d34dcdef8d57da6a37bad8df8af49e9719146b6cb4bdd7f061bac750cd962c3bd10fce18edf8416f3d690085eee8a273092f7357725b97b046ad809197829896fe7b240da38944212591d3624b4b0c26ef3b3a16c506ac33af20aa59920851fdc838dc4c2e5f7c21955b2bf5c48795b707d16ae06be63cfdbfb92c49567424b8da21b319ea51e13d183720483ec1b8d67ed501afc2185287548176c4a6e93d347d95edefa5a6974686a1a58cb59468fb4797c42bfc9d551ba2fb83bc2b63be6cba896845cc81cc2366d9756bb4e89c28493f016082c862c0b50f1a62c32d85b96844a5e405cc1a29d325e88beb4b96afdbe438fd6ccb602f1b419c0f84811c3253839d84230cc444e0ace0b4faae7d80e4401c736c2c2b6ea9aca9f372b052f5a7c1e612ca4fc2060320cb16d685cce6ba7b35701467bf4dd8213cbbf01a2c73a03cf064d32f9a96008f524b7c3774b425916c4ac95bc8559139baaa1c98c98c552a4c592399da176013925b33ada245c2549b3920140565b6850348e399ab69f29c3761a4dd14c8ae62a448e6d0def5ca65b1deeb7e4ea7f7511209164c942d766948310f7e94f6f23e314133b567fdb2c9a4b9b7753bbb8baae68a3619359dc3f7584918c8f2b283100d0e0c8dc9d1ebe3dd822b5599f8a196a324c7f2eb1619f86326724680488a1e831c2a31dfb8ab25a4b0e0abe2d26e86d07de89e6eb01557384d6f70a4ffd4cc9e4cb37a7c02e7c0e7a1c9a51c0a48c4f89212af7c86d5863148d3c0dc497ba1c76cda43d742b19306d9f5c093d2f400b7073ab888d8edaccaf8a0063e691966d3898c4275089753f0494d17065acdcb2763c63a5ebe7f973002240307fa248a211a11dcb9ef0c62c7a74f9a7b45e7894fea7be35f2a1e094d6f9fc070b3ddec981225c04b0b8bb7b34a68d31c454ba9af365e601c49f5bb19c374d4693669b81bf979936c4ea2d8d8dac7de6ef25f7392f1fd9ea33989742380d5252ec0d099db9c8cac26d37a3eef126a6b6aedd6b989af5cb872c8143317c715420ca22c06bc0482e8dba55d948741dc372c7d487612486b6b012f1debeafad90169ad984f4376ace5e1c2cad7a51480aa7f7a4e099a9370273a38279fb0d222af73523c55cb22df9d938005d77d8d060ce9a0317d3719ac13ca91a14b9f8c1691c0ac5850da9fa670c75778474ef0176f36bd2f0f4787d2d890002dce26836b042512e5e80458c2a2a45e396e1cbfe82097866de20507c65580226294aed47fe01a44cd2c1a9a2885c6b7f0922ef8651cdb0e82db0d1c8646295392098633425a898cd2a06a385c2227a74b2d00033ecb33e5a49850e7a277d6393a16257e15a02783a91744e93e4c39b51bf03acf078a408cb4631eaba739074184b84154309e8d773c3846c11c7c0dda78318caac272f2f7f8649df2d6f75bd2ea4119bac9073b455281cfb757a4b9c66190834c5636164fa71c6dec805412ec92319e615d9921b0d3e09460e356203d0504a571c340e39365b3f62d136892dd53afccc7f3e3ce7983356d4a9f4a25fcf04f229122cf0c8cb8dee42cedc9e8724dc25e5c1620e57cb2611b963d17f29cb26a5cd81dc28444c3ecacf864d6c15b1cdab08301097345ef3f997534a65287d1624377a9b379974998758a40e204a4e03db17f21a48aad6100a9ea8f79e40fc5234377ba8d68fd744646cf156d5c5d0450ccbc63b819cec2f0d0baf2de4220d3040fe93375609f693291c75fa86ad3fd7366c34162d4d36e4a424a94a223cb5c3c2b3960510fc80e0339cf9229a9d669b20c3461549385fa26986409db783f7258199ae0651a5a41d3de2009f0c7bc3557653d9599739a1ad45879bca68df57ea3b0bb6d8c0f90f1acb78c259f0a5b6fc110c4e9edb0e6787ed020ed61adb72a43359ed55b0d8ef8f0ce54a6ff5c13c38819903c2435b073168cea6572ad8caacdc8792f43b5d2e4e544e815c90e89a2ef826615203e57df700b740b851987fca4dc62cfeaac25e6f1a9318727197b4748028220542932fd39bc7bd6aa48d95c234c9349a44e5a64d6fe6681806b83cafb8c8b478a5262fce823427179553bee36078986cdb5057392fcd6ab076d8b12ba09f68703d33590e2187073e80648d5889f9990e8431546ccd8be583abcf365f0480ad5d88dc66a3b1ec54c8caebb89b3d34f0632d458c9a49c3aa0f855fb335ae59cc46c6b8b13ffeaa2822ac4084df5af67c1c6a9c29c4d799d23f9f79a993cb0ab2082db33beff597d5396dce71f8485f3c21fe2dd0fdda0cf6e0c3e05297897fb0e68f9c3e94b957d84491fcc0ec3c2ea2d0795e39f68d9c1f41444bc82af8f46432d8cadfdd0d24ceef12cfb1ac0cee37edd77456c8c98fee179ca990a153ab971643d6a578177d0a0469529ace186986f971e0e69e337f6694a738135292774983fa56fbc997e29379213bf12a1f61ba88f0fe72d2005924672b4cc02a0a2445dcd95ddd99500fb29928ee515ee7ea86fcd8e35bf31a2f369ecd5d230d50300d2341ada573fc827cf1a92da7564da642a50d18dc71beef3261efd185b6091a120e67ee4b9a6c1f714b92ecb04dc2aaaa390d03c01e2b00049e8ae1f7f47a76ed61bcb6189ed853868e3f8b6d6ce61e88349a472db802f30761796ab73c46fca4619d7267be5b08006a66fbc3766e3a5c642a5bc62227d81edcb5cd2fc717f12680b90424bcd70b1072c0e1a726e59464687d9dbe0ea07629d2cd7ef0237b9f86d3826b5202f9f4faab4aee016f6ef776eb5abb1e2651a3e2dbbfacf458c8f464d5d48cf9cfe1977a223f8f87b03258805f0f716c0dbb9e5c22785e58846742673ff76342cc7eec50f8fd95723cfd4db7867ced730eb57152c505220798ab9ae1ad045568d9db800da9a6071e42c270abd1c357175a2a962fa5bf47c28b4a22d76360eb1b392ecb538835c89a5e556b00d350d429cd81d1d0fb4d4888e633fdf2fd4c3b8431825230a8135d5f7771f35243d42055e273dc0dd4d768dc1ba0e02521e403e4bcb355f1f6dfa686f52c6cfc5bcfef2b53e459b85119ec0e3930c7d344567dcda3d525611df2396eecfd343125562715c3c0cbe014bb940d50d589af523c43f39c153956c796ecb95d1b148abc9a885dbeac426371069d4c1a56a00f50e433fb194cb2dcc3d39524ecc133716afe614c5d9b4f664283246b8f3108dfa1d181f5cab825160fd28a59460f2014d15836a9bf50303f61f3fc0c0eca2c9e278b403e4b214c7955de6eb48c00c7b4bac63a6a398c83156139944cde19d0604dc6c446513a751f07f6eb08a34b5535436a52d0aa78aba6e5479c4de0bb8cad1bcc01c50a5f0392b0cd482092c7f34999d5b653d1f15d4e14c189ca324f38d3e64821168e25c9e068ab66a2ea425afe5bd3b319a9c34bc5d4d10ad5a6dbcb3dfa6f7d27a3cc7b1d121fe288f67797dd6e6f5e783326bca3cafe44e1f3ec13d820d1d7f0e026fee4612e13ac187c05b82931f8cb75844b97564f1d0530f0893880613fc20c0c429499c2e0f8e78f930aa1db8255e02cbe4f2de447f3df2dcd292c8f6c9dd797f3fb3a245c02c5a94be847634f4e89dddadd494f9b45eb5987e7890255e782cf6a9e72abc30196f4cf382e5423f5d680624a77aa271c0800d4c77aa83c6af2e07a5d77f2b033399d8dfe60bb0db38cfbeaa2d04563d54d57f9cb491174037a20651c6b93199633829142a50368027df0c35fee899cb7710bde538fe294dd7181c25c96614a55526bb4c4319bc843c42f3468f2ef95422c13ee26a107a8e179e3e6e0094dd57ea4cc8eed49941029e25b340b9c08723d89b8779e066dde43d7cc4975bd98b00127da42323d1eeec6b50b15d72245aabb49101da5cb7ee105655e73fbe0b3196520d2c1e4e908e20b165290474d1b89a0f229903793bd4c40b79413ffb99d9bc23d7dbc50c1967f5ffa8d3475223a34dadd25bab543e0d9eab03ec520e0825392585bbdf98c7b0ea8c18fa2db1432b27d1ce44ae52527fef4e81cb4dc0e94e83cab9c3b44a368eb47f18179801833a114ae267774e8f1e8c3cecf03310de6087be8ec01fb02218ae72d38adf4481d4c667a99a53bb42052cd154e288556429dbb00905aaabcf9eec4f2d54a8109ba47984d8041caef5a66e23306f56597094ce35abf3f690340107a1a1f012856410ac4be93639a88de41aebb6ec345003afd223a85002b805375515934a877a549cc74ffa7c7a7928f36df2b2d232903adc64afba42859914e5d1c112d4e79a5c2311e694af94b6727584b92c3593009e18ae5582239cac671cbcb1c2204039cc0e8053ca201c2e0b40c54823dfb56853391fd2295ae036bed003a9d7b73061cd35b8eb0c9fd50c2587314659548295cad178e1a39afcfa07eb9b1ae40d0ca17a41919935ff30f83b8647107542103b0dd175f2f3cb78485027731741e34eb99dcdbc1e3aab994f915da379409f85056db862bd4dbe0e03ec3a0bf28e33d2d3f007a7a7bcdd5396bb34247145cc93eccc51764108f93a87c3eab198685ec5ba43013ed93c7d7f1dec058425ea337829eb185f9d1cfd17b3b94ea61d9200dcc5067880340174b2d3e2d425f2f10618694297f9939f5b4cbe627d78b0f6c15c68dcccbddf88c27addba34f4df2c9063d2cd0be7fbcda9cfcd5426cb1ce0e842142132263eb42c2bf60ad2adb97576437fee5ebc8b1c672690a1231cb57425624fcc6d00d366c0599e1922322d4e595b1dd97bd3a2b48b5b46abf3872dc0620a787b9d9c89a8a59c3c7506d8b2b28f3cfd1d2ba4cf97ec3b8efd9f65599d8f62625d3d156c5cf21ac38e94971ee69b3830fa13a0c135fe25ecf1d8c8e1245e33c07dc487712268352d8d3df02c429c6d80b04825076b4bc4a973769033498a6cfe8d514d1358c3fbde2b66054413c2833fe58a119749fb5344a281daaaf08c6042a1314d2623b2db85ac24f0355c7f2b8fd700aaf2dc6ad2117997c4cd936486b1d2af7c2a616802ad6797666d4790861156383e7ab5dca2c0c4376811346f0bf92efa3a548a1bce1c460e7b537cbcb7dfe151c1d28624aeb508b47577a395cee21245c9c8db9cfc9b302cf9aa613ca306651ffa48f8e06db95d82937a0a5946a95e314475155afc7af953370a6c749b3242bca69f765e081f5ee06aecb9953b93fc8214013392e846ff3ff7ca4beaf1ab6d83747f80649e26ba2e64ffc7b3b4da7c3eae96f46485b343149d69543144009c510828f140219c7f4167619af904d796d643ae80de78b0c7100381a6c99ebc9b3c1a4e6088c9053ee663a2246cc021403afe30fe75d329ea609013b12c8f42a624cbae0d62cb03ae1ff4e782c3061e6c4d46e5b0e354ce6e0ae54a1212d56edd1d087b75e950ffaea18e9ac418a03be139021791f29fbebef1067d96a1f9518158e2c73562242cf1a5a6d6f85e7d71f4e30f851e0fab3c67e545dd080fb4646c40967a745219a944d56af50a16d7df46dbce0c43e08349f64909ca10fc841987f1d30fefc26aefa4d83e3ef356c678be90108ddfb0e5d4b52d197e45825faae6992c793cdab5afa1a4211cd3df79b0e29b4ffd2226f6eedeb614cd7fdab91c64d9667f758e28c42fb40ac317f28e03fefb34aba05e46e0999a9704fba5e4c458afba4588c1de566fdfed93e705de961c08fd2175c90264e00131b1cef12b89b1ffeaac33128d8303b00d4f7b349a9e2cf1703bcf391ef86deb16a721ee457bc37228529ce48bc9255d6fbf257577ee9c05d56d4066f1e074b415daa8c45b80a98c38d26d21da424cb29ec0b88d8285654e8514d460dd585a713b799a94586be21edcc4d5fc6acdde15ad1345043e9e49ab3f3993cb3760e0a34d5043d9c47beeeac51a5fd0c5dc04023661712d4aa29d2b83758c868322683531ebf750d229f490462695edd08a387f37046c0bf828934fc0e41779c84d647fecdc84caed3f1954847ae59efcd9c59e4ddb8c080ed0a7b21d5f5bb6d27378786f0bf0cecb3d7202a0a77aac42e4e1f8ab9f6fb6e2767ee4e23b3f369268c6da125fa10a6257b7309a0c26d3cf25fa447b45ddef3b46ec49c376ab8edc7fe00a6ff1e9ff884f8116cee01271d9a3b37be86921719e5a7973b2afc6978a22379427420168917143338f9ea353087ae0239c7bbb943a71c1490bf6a5847db8d67670e3a82c19caaeb53b2eac2c536cf7d5820b2e04d1d425c86fb736ea07622db8a1d50a57c828de9dd064d5b55bac131d7ddfaf98d4796a1828a1fa606db4d4f57d520caba82c24c4e76d6eb827d5d1e13bdeaee0d9c2cac640d01ac08b28d3534208ec2cc56f18f6e9a6a869e5bc26195335c6c932e1de51273a6df367c6d6e444cddc0b6dd6a15cc764f7ebb29c0dd2999713fb305bc82d97c8f6dce2259c173756b2af02071991993bf813fad1260f8ea9bed61c4d34444cea500e649e7e4344d26266f8c2de9bdc5e61a3ef0e4bd460b16ef169bad8b758821976c6a754b1b2dc86933d16a6d4c0ab2b1d2b004d44c1ec44b4c7c378be4afcc58759efb38a750d261e82dabec665061080504484442ab143d7ac65d84f3c4821c127323f26651dabec063165af86002d42314cfd995286f8552d17a19487deb4fc6790b2c9603ecaffb01e25e9f78ef23447293d56e9db664ed883196cd6144a688868d99dc9e86551da9e285b5a24511e3e5c4fd87b8fec945299780df90701d5024ffe6277c05d7ca2e873cc734b101794c05f6b028abb66f681d66d37537c9b426a00cde40afade188ff70175a918d4b73083436bd0549d8680ff632e860d96f54c3b72a83f20bafc4712f65b93f29320a8daa70abac7e038a8c530a0bb664afc03a2b2673f23b476d654525954779cfd627fe39e08756302ff3385d3ba0981b5d9d77935242e132f3d1bfa1a378e9b925c66f077fa0ec637a709091fadb7a7054366b92cfca89ba8436ccf555f790ce12c08cc41a5b48df22e25fc803783a150fabedb540cd8881aceaba0929f4fea2d35e66120f2d34d3705c45c05f199859cf770619de395cbad0a8f2d049bf6a967a2d42ed9c176686aa30d8352d312f37cae8014eec06fde292c4b1c89a12d1e73cd9ee964a27ce6d3389b1745a975b6dc0fd8ace645ff7273cd267732d9d96dfc0d4183c27e6615e9314c629b7994b993def6354c12771a36eb39926192614b59c450fd97596494018534a9657b82a25bcda45cb863cfe8394e45a0245a0fb9898e8b1970ec19ac23d4725c606e9766233fee7c288fd2a8ed2d71c41f3cc6207a587b1341a0327943c0a0d25dd3a787a2914d428eda7e4092317599272a2c29dea07d18b7aed82835cfa441627b455a4b8c546cb69874fec0863fabce6feb8072c8cae5dc83b90a36441f85fb09442c575078d165166b70250ec7bcebab391b3ef157d15cc6831cb7b6514ecbb1f82014284761853c90ec3ac957fce69f21a293f0d841ddf0defcbb245593b522f1c3a920f3e1823188a3f9b340850dd1d6d15b8bb702f7203d6a27ad3d8100e9a810a2a1ab8056aa1305e1928f7fb5c2a42c88c26d6f2e4761430d5b0eac278211e53e7ec9826bbae349d46cade10e885302d6d9d6f471ec23558d0459a2a8f0f52e8fbd1cab9e3427a28be221b8e21eb00a3ee5c2f9188cb1e9f3519cec765e4e89182a55f83210d9fc38e4ef65b79c48a6bb821e4712d0ef34f51b8bd9111c403932312fdc046916f27c2794d739b9819a2165ab835a39b90d41c78981a41194c2ad2327a0c97dd9833fc4d26518c9e6489c886f98a710cac19b93848a4f32c882c5c5d95503f8a37385fcd0401a89c17b06280d0056f3b62b03c21cb003718a5047ccdc225bd15ecd18711b2470f01e31334204689ae31479474cbea7aed14032b5763af136d21a2c2a682756e156834550ecadcbcd57aa88f5cf2a5dad7f0cc21ea564cda31d1ffa795454aa787171001827657d0d10676a9f1551029da858aef4fb27dc0920afb09250ac42f7005e4f52c375d8485ac372c2dc70c86dcd7e295ae1dd0f7d196fc5813dfb13c0270abf0790f4221143ff33e04b45f8c180012d4275192226f3405d486bf11ac30977153a1e96713ac0c73cc9b0a08e4e283c0f100e8d8722e04f95698f66e0c084e8076dcf3e1da66d0971530a98f655450a847e06fbba8ece3033620192d41c936e157a2292782010d16c6e00be0cf062573674663bec0b960d390860cb54d9e06d4214d0ac9e464026687c08386854899c5c06945e34e06e28c14530d9f27fd53e1fe92946c144a114b136631438e91ac91a54015901f22081deb315b3e18a36eac926e0c0b58f6cf10ff968aa94a9b985b0021629f1245ad6946a6f5976887a2aa72224593a3228c33beb43186e97d46f6196c64cea6b889615655cadf036ece2224ea7aabfedb45a92a9505e944b11eead967d99c5b482c86101f48e67df3b521ea9c1ec5c4402c1d6c921a93f7a658ef63c1a9e6595bf4c2539344c4c90d01b454282182faffb1932e23cd20a20a60a61a0bbe3044e95246cc3cd641d1cf9adf7de343a5441cd816ec347555daf0009a4ac719418413fbbc657f115231d19650b98a149c2c02edb47eb291baa2b9bc029fff209621a30672c1c8b285a0c61b215dc2d8cc0811772a6e78ae0930332629e8e84e324aed0a5a4414314bb15ab86140e4d37c627b86ca259e6c4a72fd36529011a2ec1eb7801b5dc19a10f9cd38bc5c13892e2766b7e39fe622f1190bf435beaf18af2ae1f0888acdfd26ae7430a3c238a20767fe740495b73dba6504d3fa892562ca7513643dceb130ed4eeb6901b3fe45a7bb2d6271fa5f30ac3c85f2aa4642294d0bb1b741cac41a1f755f0c853bd6e4f72419fd89aceb6266aba016453999b3345f2f81e6e080eee1215ce7b88270b4856b854c4ee6a7abaf9424a33c6b44a4b992bc248ddfc0bfde627ac9b7b7ead095aaf5a36b15135d38842b54ddd5cbd2b909efc815c304f6ea24af2e6ab0d677ae75553acad95257f0636baa0a89010eedf055dd225f2e6a4395b2151376c8571408fb91fc491ab5c50c2e8d5db3727623af13019b82bde20a509ed830c82cdacb0b7b0f98316bf395856019b7e5ba9edae60e3355f33f838af9c0a73495b63a21fdb6a9e2cf4fd57832ea30488aafb08285ad06f072442083c1d38276831e6864b4e8c5171e0b50616c3ada0cd75f564c9e1b20c0322114099464c83e7da9e2f07586f7ab5db06e0ea72829deb1f98f7328cd1e191f93e929be4b4478b6c18e7500331d4941bcefd5e28590c0f29839570c365ce37d2101e33419353e455208a9f0f1e61899c7be9670868e6c79a08ca76bfccb9841ac17e9b73a59739b77902ee4788eb38bd61ca13973947159d24c02944b989b6c788f2041b75dcc563cac1f40ed290a03ccc0da072fe406ecd7c2817807b81ceac713fc381fc3584009d5b6c0fa5daf449e6a74f29cdc4394000e89c631d65c20c4bc348ea88c20705b535a180a0104777296675013a5710c5f3746b04153f8477740eae8c5919fa4095d30f51c602db00d978928019a31d9dff6e3a57c692612971217a53ec35ee89f2f4fb2d1b053f368283a3b708e5e22cbe9d8071125bcd1af36884c44ef6bc7474ee311e592c2eec062428b09a6fd24421333d3465a3a90ace541eef449322e636b4721711e1a00a129365a910aa0d116a3887856d58a9b03ec8ecc080648d2b671121d3b78477d329683fc05e44340ecafcb9dd0e292238a15cf33cd8447283dee358954aa711bf560d488b6983ea08cb6338361872e4f743eaf10ec68056410c770628b6020b68213d6fd844e1f49f83f118e421aea2e6770d1bc5208cff0ef1025f0491725e2477250ea8688e8d0194728b770ee2cd876a3b110cb61484c485e7df7e312188f6253d23a06f1bac47873479cfa66a29181e839073e0a629cfff6aed6ec3a640a167515888caead934497d8aa199a78c5b7012ec74ca7343911d33d0cf476908f0d40b7d73ebfcdaec3fc5f737dedcaa3b90c7ef680e8587033b26005b0af56dc9aa4527e50a81e0b8f89c7b2cd26ad6014f481672829c19cbbb59ce020c03ecbb32fe64ac016dfc86c7ca5ac3432e6a4802ad866c09c054472e67215143a2d84c262e03a09a91781815f1b7f963c3ae8f62cc88c0ce52cfd1154030523bc0f684a44616662ce458c1c1bfd4f3ed9a6762b65c6129c9e121c202e47180006948664b3d5773cce71885096e8432f49631adfea9589f89a8fe0d55a51340bfb9b0e7f8d02b7c08a5c4466097423cb78dd3d973f64dbe57604f9770979d28927401de57a181c100562a019e91a247aad36a461fa18ceb0062ec5bec817fc64d0eb03a59608302f22d4503f0e7b078a6bb903eb6b24416e7d2b702bc7e5c365a06aaa844efb3a9fe2be6da44d15ddb2a488aa7233917732f883a0f0c169f6ba163864baeaa3e4e76e5f2b930d50551b75645dcb53b7c4331d2105cd3337d1596bb53d3c13b6cf139a7529582826e08215444b02c3e2732ebb88edf87f6c6a09428e93be93a1dfa338cc5e7b6ee8288ec7b33e05d017773dbdda15ad6150801c0a8effe83a06fb050edc36a3cc40a384a7b6ae7652585ee5a769c82e53738cfd900f133baaa8f3ff42b50acb650699f0f2404d90df202d1430fb0b6621563236f5d450ee5e6f0baab4ef0a8a460727a3e97b3cf2fc09e3fec35b1e0a222e10f968b981f2e8ebadb7445b4cf59645eb67cfe9f53ce88f6f913eef3e3b964689f7707f5d4fbbcc11d8d0f0ca58ebc4e7a8a1621cc01008ec51a84d91d000c85398d214fad830e6820c65c9420dd3a2ecf2f0b962b53645bec875038bf99c9bb055bd0bba62ca2a23ebadbfce34b8fedcae3c9339e238099a05f7b7ac75b283bafc70ba509b88f779621e15ef598304264394a6991e585794495efe768156997a73f0e8dc6e2008d54bc00d8fa7eae87f077574a0a7b3c737ea68d987a0572336ed52c77ac6539ea7ab6ef7596d4427a84c4ade0bd490274b57f0efe8d71e98f21426e513679fbfc9dc2b67f9e4a3b393f041bac763b3b0dc5dbbddb6c17314a87c8f89729c1b7d671a3c5c2ab8c567807e8e6b61b8e0abac9f68047a259e0de5234e71ad9f09d30e99f7770d9d9aa39618b30e2ecfec9490ecbfee131d7d6e742e02e7fe6c95489850be113b2f2f808e72895a327c6dc007f716cdbde39d6ce41253bffe6892f5700585e4668a03d30a17d225a48ef6c45d118f308ac3e98ab113d72f844e20d2703d2fecf9f1060d64d48ca00ccfacf132bc048d5fd4b1f0176f44058d46e335b6da2486fb83af074fef124824ed5386aeddd4b51d275a89f47465a4b69b5b23ef5bfa083aa70e16698ddcfeb61edb877f4a10b7d7ad7875085764d6dbb4862f773c4a546cbdb7d0432a1d91f70d43e8dca31cc154178e576b7efeb8e150c65705fdce0823f349561070f6352d409b404b20a6ab2cd54649de1a70afca12676abe4dcb02dbc760827900dcf89d184120d26e41a926fab630462c21625e057ff4735668926293f592d774015db0c640fff079e25892dac024ff8124bcfc1beb7874c5f98596ab2ca87cbfe4ea806964ab75c4ac596345706e6074f7a9e69e86184ad2a62a4c6ac6590bc9182a19d348517be2e2999ef35928c4f0420deb63d2c293246d646980ed692c0f6a6fcdb826fe4ba5c4b5b3f86aa5aeff9c20399be210412aa9c42889af478b2e08203fcfc0e795d2ce0d2c6a5da1f28916fc46559943c4e4af5b8dc496b100022d18bc1ce1edbb9e17b3d90e9c1a3c00af06dc03c452d38efc6232782eddb56017ebbba3edd4b46ce456022f242bec4c55eecbb164a29a5447f31e79f51e0ad7c24330a40ba0f4f8ca502639c4d15b944e40420877ecd159d2601204924a7642aab04fa9468b03d46e69f12ba381a2c52bd827a72f6567331b5d266082cc74f5fb48fb6816c3546c0c47caf9f77a740f62b2b6a43b120a30a9c82aa568a180464e50dba2b0b00bd63002a87d10747e5eba04dbb43a2390d78d4006996df2351742c765a0bb2e3dc1e1ab2ff4712223e1d32808aa18c6d284bed799ffbed981e4d267b42d195d1c46461384912e8b4ae0c13148e3638c22c55af43598f507264f3cb31e804f4326fc7010bb72ec834fc9361feace9d2e50619b565f6c336d150ee8830c6da910624a2f8b5411c9a364d62395531ab767c5678d93d0dc46a7a83ac3bf40db2eeaf28e16d04f2a5d7dc88710f420107198e647e724b914234e84368b318853b810174f74476c09ff1f75f7d5b1b130d29b6b9d15983ea3751901dbe72b5dcbda407af8d2487c74eac0dcd3c0e1364c794e23ed5cde8830c7063e7ce3d8236287b0814e310ef7adfc049c8078bdb05959e2b45f311ef6c5b922afa344854eaf2b38baff55ab37177f961d008aa67debd55962b7ea88a506277500b83b4d942dcda764f79830bc98176510c2a3c83e48647552b0371293e606e042f5d1779b561e7e627a7c1b22b75bac8d94160128868617f6dfd22f7f4329bd6610000408ede41138e310db872d26b04942f3b4bf2ea39d51e036b52b6fd5fdfa52e8f8852e9ca0184cbfc611f591a8840f6caf5a3d3bb69c096dfe8cad2c4d07efea54882ce229f7e8a5bc1611b0771b8e7cb7451f04b0658221f0a1f7d41b39702ee6553cbacdf9444ab0152112029453a3dae721ed282742ed3a034dab6364953887f0e12b1f31914d439d77bec58d764d1a4055e2a172845a24d7bba37e7d093bec0e5af4cad49a52885e5bf1a73400a161a875535882d316c93291d6815806da56f5d1b07fa92d235f1d5a6f0a1241e20d0b3e90b1cf72f9650c58036d1adff22d6e6017e6be598e453fb70b6f2541dce026117132828438aeb72ef31d2137a85ad1558724cc85576e52295b1053a189a38e089c52c84ade17becfa791bd70460012e499502045e59d85f343a53c1b6c32851d77894293236295b8cf818051c5230859bf15fdf48943e8c3668b912e061e93d43a41e6e4cc50eb9842b663f92f008fb556c99f0871856f88faccb5d34c67aee5319d6493077c379755e9cbb370b3acd7e75238239076b61ccb60b3100634f0fb55537ec211aba6b9b7c9ada3caf14f27bc219202a7d1d80b13f4951b992d5797220eac4c5b8d9166b620a308431ca369a16d8c127d24447ae23742a28402892613441ff4744b0e22a7b99d63e438671b38b0657276b801ae50055610bd2c2cdd152525680fa7bb7f4b7157408ddbae917f70c9982992e32ea63b8a8849b0250e27158214738d4529e3d8c02dad3b3faa80f51434e7088c4c4a517d68fd6063d5340612ead585037b1c57698d3268c16d873ce53a042cf174559168da8b425081b7b3e64e1e810ddf30d3dd7299f5b57d953095a82ca1a4111d8117d87e532e6a95380b34b1a7490e105e0842c9a118d2ce388d93cc82ae2652ebf6b1aecf4b6900d4930f12eb3b2007e10e693e6efd66208a1c9028b6a1f3d8b37040638d93aefcd6226b1e26798f2ca411ec74afea925b802034c3947777079e171cebf4a5860809e6e23f088ccb4ccd7ec3a30806e3dbf90153147f5702ddddc28ce05035051e6a5f3a443ca17456da928ea3195a141067bf0f2fb8553ef994f3d06075d4fd10d1a52ed783ec890b567e9b921d6ebbfa6a7ceab25264d4164cabcf580728da77026d587113261b209538cf2dced86624c47e3e41fb78ab523f711a884cc446b1296998b71daf3ba60e4fcdeb890e2bfc052abfb4f7c8428960e554209afa177ea3e87323db1c23a793fa7b40285c6d8b1f13299513c2312e41a3a920c3f91249901338db1e2343508150fa1758da1b349a8945ad58ace5adbc4d18a9e55fea3231229fedf92808bbcb66316ef6e7dad7bbd69158d7a3c940b098e0f0b88d1c9748323fbbd3f2c58738d1640f5b4213b5e75564fbddfb512fd4666d24e5b8e8c1ccba81c65b9319ff3d0054ac8ecdc63d161075171431aa15c5361cf8e08453a49066f004de0dfc6e2349ea4f3f1481462dc3671328c0c09be125ee4e0087b822032d6ba93c4ac8d0ad00d1841e17746d31688356f595be6d520b07bc8b7dda89dab9680986fdde1e02275004b4807df0288aa95b5b575053e6c0d592f78cf2e7f8377cd38d251801ec9aac967e2b704afaba3c57e22780f932c2ec21202be4ec034dabf3c9ad18de0c942d523c8d79cfcfbffcedea7cf28fb75aedac2224d91359a4b2ec24d21b8cab1d91196393166c59c4dd73b9fc875215f71ebfdb31f3f69ac82f3098d39443a4b0bb09f0ad1dfaa229848a4a9647504e14162c8a71f12739f2208feadd576496b86b0aa207d6c1bd913b651326f7e81fce73fad91541ae781785f44684b2e074b848e56b35bfdc8e536830f74f7edd13c7ff42667bbedc16fe05d5fd66c5ffaa034d32b474aca325d0a0f1893bfac96ce5e55eaf1eec142833e7ada9f5dc3fa7e8b0473babac6dfb3315949982295402ec3959404390953c010b31d3f8c6a40268ee42df7bc43e59d721fa777de6387b1c70cd9ddbf4e2ada0be9a40ea1576d6198884a8ac88c89d7741e6708afb701cce96bfe40eb0bce807e78d1fc43745e601d75dca1faa6a260414f8b76637d5ed78a883ef81b0fd7a136450db2ca52ed82282865ab35b1c844582cd9f05c4be30e90626a235a17678454394299dfa632946cf5aad160b97b2074645511437113f84e787dcac2aa29e1576a88a2b8f5fe1785b617a22099cae4c419d6365a6440f0916fce4f6c612db4236999ec0921a775dba4be7003e2b11cacab6df39e4840373bcd1cef5a96b5a4e43a73406d3ac9ab1cdad5d0a4857ac40d7f497934b0034635d98b96da84b72e9a66e5075d0f4da9a069239c5ba708e9ad08d612042a28d3e6a0b94aee942b4f5959a567f868dded96e78cfe6855ff05dc7d94e75aa96088137f4e361fc6372736ce638a68b5a4cf5fbf25df96c2009fff8b1a7a01460f90b317fe05e58f71b6010a7bf402a0b926547ebd4ffb11846b8c3dd5ee8d386b1cabd8961ddbb7c50366cb4307e121e574c39c70c7f9de59a932228355c6d96ebe5d1a79a3b3f120fa8d757900f72e725d12c89fbf0d22541812e6e775e49864489be191b8a7bffcbae1d8a1469a726ebcb8169d9fa69eb224d545b6774d2f6daac65e9be87d52f12b793ad729e3809a5008b56222389483c04a6180889708c95c5c907443131d6140a82a1df01dae2683384706c6b86d6595f7706753bf9bb94a658513491cf40e809df747db23bd94dd5ace8124c99554e15c6f888f2d72cb912beac5ed6da85d589c3eaca442807a3d4ff8370257dd4d7f61abd705bcbe078c5d06124196c6f0ded3886e1dc354c8a0b5c663ef13351220e0c79e91b6049fdaa1135bc18a29264451edd363754d4e4318c88356bf3747a03d9d9440adf79b43cb6ad58f6d26497760d7174fe20fd453c648569118518bfa1a201324fc6725f0887c059e7374f57ef34d4e012bbd59262dc69f76c94d145897e16ee0e41e77b59db0abbf275a59d207d8df7d1ffb1ad62a4aa5ccbddf1be86877984716908d224654ba42435591dcb1bb87cc824e12f92ba66db4e6f5229a9c4564b19327bd1b83092e4b59bd47635eed8407dc8b121490545376221fb857ddf0fe832d487727c0585f79d0f6ce32acfbe1bdd420a3bfb2b61b38c80f56db98fa2ddb53cdfe615c00f79e7784e2767d7e88c96c1f968ef045edef09a55458c977041fc5b496feb0fc9ad5d2671ae89a85cfa3e7d3b275c38a01e0a052fd6117362eae49636f73dd19032aff40911a88ac03fc4eba462b89346a397026ddb45672e9b3cc5fb98bee3e243220c4b6c4b91fbb44c2cde805e953c703b08aecbf7a8a7290b8bb10a998550ef9dfe18979f31fe492aa1c854dd63a1d202720453d24fcaf04baa19e732e3a766fa7da26e5a4581428bde1f41d04c0982806e7350c08bf0656d213a3ea0f8d47a26a8d3f845c96fdb88e262c8052d48517679d927d93407aad21f2bd887837ce9d90af180950161f71a5530811154ea1b98879938d708db7d76af1363635506ec9d4a8dc3f68adcacdffc40d1cc47c745029c458e444f231c9aaae80a43b56b046a1edacb4c2339078e157e844be52b49ff8583d1fc1938cd77372ac2429d348886495e4841f866f85b4f48d4fa24b33033f8358956c29ea4004960d550528b3dfccce64059a144ae58e90f9d9db8d73203fa72259fb480dd063f7355c22d6ca5e574a0b28b1418e23dfe28be6008a0f64b2ee04281d88625e83c9c12e35bb32541db6a44970c658ca0d1b8e2ef089b68b636c3b48c44743c9f90077f03d484c980865f229d2bdb2d42871d356ea0e1f728b6deacb204fd3c5281a6ddc48b57c30ad48d47b244cf788593a8815c16eaecd8240850ce0ecce35222f7a565690fbdb0cee35ce92d31cd6441d0a6027411a22c9e3f867784485d893e67d3cac94c82dd6c82ac2b9186e634a54aa6f1f841c2fa18f9637cfea5f14308876d9c10aecdf2451ff1a362ef5cf49542b4193d1332365f688a72adb8bb2ed764881b1a56c1b99e31091275dd7ecd62c2445954573ba783eb01c1151942a4507ac70d5e5284e138b76c131a42afd42dc1a4bc9bce41099a9cbc155f3d6b74f3c528d32e0060c5c5561b5f06dd22057e0613d6714497473a4b9318bd964d772ce1f366d5f8cf086e3739172ed208d7d183c035b4e56e97cbf38bef56bf77abf200ccebf66cfd708afd65ce514f2cd44c9baf0a11dba987037318c7fb84b4e329e0a495872d8a158aa772f46e5d81394d9e0d799414733cace0f87b224ed8dcd9e90c1747f1b6e76f63911b6b0d5db56e9a69341ba4fdaee4657d7db2375784774910fedeeae81dfad29cc93c8745adf0bef34ff5014ca666e300ad6feb2682caef7bea92ae86075f9bbd523da339be81f3b4ec2d930501083f2d7e12f4e926609a5621c03a75aad8a0274b97fd8d411817438215bddff2af23771eb08fa45d4b7875dbd295ed85f70b28a91de39ecdbb6cdf22dfdf7a69b6bdd7b33939aa476179c747207d2c2ec9fb1073cdd6c969947dd08e49972b04869a3883ac5e152f9e08c9d210d94012a6d144fdbf694dd987608e2b8e22a743909339811b7bab1ab9dfd76e1eb0ae23d08c81add99b9aef8d19ee43d004ed0c34704d44a8d44bac1bc247488344cdc97bf57d2c02b79ba83fdadf2eeb338b8555191497574a07270af276e2bb70c5516579ae7f2558de1644dee426a5c7a33c800fc19b8c7593d52ba959b28581e5272c603e50f8b4c2839e3d1811a2abd2e61dba3159700ba3c571ce1e8d32d5f3ed3452da8b797060cc6271a1850e8f983cfa99f38eaec076ae88532c2d6ccd634de4da866fbc9d851ec5fb775021182fc8beb4a616c66356e5a8aa40960b350f6ab59d202f9b0ccd187eac108c00dffd7c68f6c969c4ca6688495791edd170202d747c03585ac990b6bcb61631ae787c8c6ce59d963b32f3460b988b73d9ee0bd2b8e941030dced6373aab431908600b45f3adaf4d8bc8aea18e845f0ee1cbbf9eff7b4e096d735c3628e2ed2835f845e6873aa42ea79414e41afcefff0999226ba23c5d4074793039c188c0c5b9c704c747adceb8bd09c6df3eb8ea302f9b01dcec2f35a4614067d1024ec779841b5bcf7fd7fd9867a3509a1c3e38615d4cf756a0f92ddc0b926a9d1840ee97b299c2cf81462466c3c4651db66d2680b4fc229361246b81dec78a40570d6c610a11a5ca4b4d3cafeb98b41027d35c5493df78f6ddbfc6756202031c6e81058fe0d0291dd6e44b98078228b70023cb508d4ae94b7441b3241240a866b7e28b56f138f86c90cdc982e0f84ec5b14f8f47aedeb7ca9e43334eb05d82826ae03ce256af4e838b5dc7c80de03b5c4fffbdd8ac9cd0352d47acdbb4c1abe04b2451871d68128100bdd26e3fab3a9958bdafda53f35a25bcd601d760a86cf20dcaa3c829fd0730d39196ae95d2df98e0bbbf0a97c3ea77c6cf4df3827fd2ada609e4633249fb058cb316066167de55ec7e758fc35cd7b6b01dbc2bd7d210cbb470fd272cae33e12e84197251a72afdae760eda0408cebcd7c83a1644fff5ed3d35f7346b7941183e62e8e4629917ba4c7e44f41cc5e30139cc0148a234e90934c5d83667aa8fc1db6bcf0a0e5607d4c827f9139a40fd2965decb9aba62a226bb3f402e70177ea09f0211948aa082e7d32e3b16ce6daebd24c6b4bd3bd25b81c2f04a2ef8f26724db266e920d6785f249a684c958e7a42ddf7739fb6a9ce8a814c2a286d03c289fb34d859581ac44e37f82f7b9f00c5f91145334b43765976e4b73a31b37493edb24243c8e4302fc75bfacfc7e312664458e39316b443304e4137103d8fea3a010d81315c809b2da308e5af9fa0135c5a20620c3337e19c54a8e3c34c0baf9c6ab1002e89050bda70c53dc9c482bd0c2ed169cfb4bf3660820b55e2874ce193345fdcb4ee176378a44e31ee0c40f68ae8eebb5584b6b4244408b09444012e26f68db15c43c0f2904f017e20d8b34cc3a6a94a31427757b0900f5d1a78044e2560a901ced32c096a7c6c2673ddb5621c9b3656fc65c613101f11f1424aa9250e87cd4340637fef93fd3c2bfc3a2a5c3f0f26e7fe3420d361ce4bcd607a36a4b0e1b083b20d3b48357366c2b87de55782a868b096e5c84d11ae9f6f5afcf6996162958001658af0660bb3ec8958ccae17fc7f447224f95806837fa87cea306b17ec63a514c917997a7b0d7bd9c52b09d282161b65aba21a245f54dc7d456ff44586072408cd268c0a9ebcc8923451d07743ae70a6b6152921520f5dd3ed8b6ef4d9d57989f7a288f5ba8fe232c081851132bc63302ff12ddbb14ebacf5b71e4e48ec3f01a05abd442646f0692bde88bd63566df29dbb6d9e4638b651130ff66bda161274c4e2ac21dec330323c805addc20d32f177698982142ecfcd08a6ec27b8a0738ed22f4532208e2b12df68903915a84090f0eaf2aae6457b80ec2708fa1909b847c284264aa9d6af60a128afc69af4404f0d45ddf0089dd07c6641b8801753b173cdb58626cd2552d27e51de8d771625d0f554a7702d49650fc383005806d7b51dda7108c3c79acde3e95b5a43d744d7b317b4b9d572c1c773f1ff01a17af953b8a85da13a0bbd21a19a3601d19f56d33f7a55c436f16c8fb6522efbb7cd6b0654c8f8b620e8279b9097d20c573c8e8fab9dd3f72bb2a1af1779c5ebb7788f056b6ac0e24ea4a8e88d18e8d20184afb3d0e8720784c43e57447a59703534e545d34504d37ac4348908044bdd5ad5372cb2705f2afe4764a4e6d15fcfe80fce816bb378b7ed508080b3c4998a11dc42e2e9494cc8a7c8cbed7dbcd4434db235998e028f811ac5f3c865c354471f615651d590aa9cae011cc97a22519cd48b5ba272cce6885ef486f3aa8177bc06cf73ed51f19a5199caa8895467a8eccfb15087c4d369dc3650b65c1c911d2a86134ebd19619622771f6ea7e1e384a5fcaaab0c106d3be0242c322e49c4e29287ef54eeb000434938990863e8a6db8a59ec8d784a8719254b6cfedf971017ed1621ae985d16e8c9513568fbe79b67ff07397183ddf42da571045af739c4d420ec4ea110741865dcac4a29464de9553237775f0816aa826df2f4aff91252c285f89055d3f519234315f1808d9f1b565c9824baac69f8c4356d57c700f8219e1324d5bc928f4a76379ab9250d8f250ea7717618549e413b3d0b591034140e290c010207d12ad6db3f2a9c782d1a2cb8701f61c457fcd4ed17b54d5b7e1302484815952d4ba16cc513f564d0b9bad3a6721422f4b318a9f82995f84213a4b520be9510502fdea5b40be4072c5428042ad668cd65792e569d5976a99c5a6380a8d0fb4f73ee9e81e859dd1161a34430c6d625f48474bea33a46650713238e1c8b5d2d594a24a5d3d173d46df143e141822bccc4a0b5305dc147d63d22fff9cc1231059017b2f5570d5b7387c69ed55884c0eefbf803ca63fc502a965c10512c90dcb83582517156e7c1608b3c0afc8c029ad502b23dd4b34ac96c744720fd3646be97e14fc273e856afce14ec6093488b9fd76c3b34fb1632e6f501f1fb16189f7255557fa875730c014c0a29196f5b261313a62f2f95fbd368504a159d4ed85d49a7000bdf94ab9c740bd5d407bc34419bffa4d167a2e6a5f560ecc470d11b9eac71d34cbe39b72cb18622d40fe8c707081b51c3f654e9a7caca7e7831067b8a325a37e9c171cd885b22a72ae8dca1bc187b8613e92651ba19473f69f944ffadadd2abd42ca2e6c09c96e413544a307c0db6c7737614a3badf1de590b7e78c7b86743429beb0939108c2288d92ec6e5bcbd4c3eae80a704eb6277ae8303e6b695f65a03a7bbdc2d9a3a84ede089685119984575bb112d55b13d905158e7bf81ce5131ff4a00758179b15881cddcffd6c7dded3e6e55129ac3501f0709348e89eb616e6e7e4eeea0f90fe17bac79412d855e428dd30f17bcecad29a2db3277dcc05e681ec13ef8151da015786802d6b1d62f7f6c21e457be56402ff3784143e0eb06770dc5ce2bc2292ecd98aa8c60843bbfcc2971b60e54ec560310c0df0162252d778997db3d40be8125f95518dc27b675184db88f9fcc63b0c1540faf3ea3b04d172badd09f842445bc33fea7c28476b902004a392981c80263e92529a3b5f901221fd91516038eb22d54029aec57014c5a5036e4d9ae02963580a1c1064e2dd6c3a6c65dca83b44b8d24f46b4f9efab9521ba31bb9a111d02491e637b7f7373eccb367858894c14dc152b31e190ab590b781afd79a968537a11d3028b85fc92a08b614b5ea50a96efe6b87aca0855faf7b825780043853a2495db5956ca4206276a0a784b922c23f5d819a8abc03e314a8db3e6c437125057cce544e55653cd223977921aef8ec270d5a05811cf97c9ea104e5dfcc7d9f0642690dec4b41e682ffcb8352eb2ffa5bdac8ee349872e1794512d2773961a1f3841042ef31d52c506a5feee1e9771ac95a3584be1ded52f1be067fcf694bb6a9d1501a2738b56347a2c5b2b1909fc5af119e1e8371f8c70cb40d12b3c505085068e4179865b5afc462b80a64914a69444e3054fc0696efa7ce77f4bf25184309c2c8860096f622aad9dc0d882ea1c299d84b1aa69af4d02795da81e9df4b3d8875521791866fb4c6093b4703d8a06ae48642d61c557d919c962d38fae0daf716fcfb5ac850ae28c74ca8c126eb6839b2d46ffb913ae5b85bd3242c5d4f2879415e2c9f64c314f97f2acb39cabc544340e592c7cd33e701f7e9983d5251044064d8741b1b591232b7d205d9b3858e650e205a619bf86c148834f2bbe41ecb9f0b579945b12c717d329def68c5e28028bf97b74830d458a83020402972180da58ea2a2cc216a141c8b4239a7a828731405450ea2a2e05034ca39448d127328792852aec007f67d1ce96f2e4a410789142b643276ec42c01f6c10d39e9b8bba37664cc72d634fcbc07e2303755fb9ba17a9820afd7cd56372dc0760a57ccaa0c80e59d9efa2a05c6097feac0cb8e207aaa41595c3eb1b7691030d15e376de2f7a25cb27351b2a6f38f957bdd443a8bed9523f580640ce0c94fc6c248ac2f97b4cb6f07fecfba7938d4570c604bb75bf30ddbb76add7c9393f9831e3e5fa67459bbbc8ffdd0f7d850d0d7b2763b81f9cf8c8208e82a13c8f5fb11f4d522533ec47c9c689081bc29b2803ba5891241469d64ee78f670ca05668f85ffcd0fa3d9e5810392286052f15630d361738253a9db5be0e348bf6a054d761194f21773ed51498fc5a5852f2bc404c2158e30039ff8ad367abb08188be89138447a004c3808132167d18443b49d69a4834575a2645bb082c825cae3f66aba06f42212bd1d06ddc3582b38cd4353376586464d9263f6465c052e6c7e80e19220e7e830b0438409ae0e598861a0d912505031798a0f9e3efceddc9685d161225a650a1a07dd3fd1952663be20741eb6fd94bfd3ce88e3836466ec06f9c184682260dbde36c09a2c51defe80e813b968dd1001909926e5aaa1520c0bf39d275dc2b38dcbbbb10210b8ad0cf83f370325d938a1720fde51a36a0d066785db23e2f29e30786293d74a0c47512d9fe43a8af8b660aecebb88f2bd7f638adacde6a7688c7efc62d8b443ff675fddd1c38a0b004d262de7bc889cd9f8313a4b2d685a2b88da67505fe1537a20c0cee885561e955fd605dc0f123786ea369f15f61bef243f2630bf8bd4d032ee2f9e7bd457c990d4a0e8104687496e61f4ca04396e23db1c37c5401bf55716dfd16fc79d4dbfda95c22c2d6f16906064fc7416219eff03fb7eee7cb59d490605b0174ec1515fc4ff63ffa6f26940421c021825f192cc9c4945e6031200c37a8796c3d86a91b98c824263289893ad427486e03fd678abccdee6e1d0de2bafb5372b60e91829265cbda6633e478e7dfbf6a0cc16efa084af850f66de3f97be7d3f7b1f94120384911ccd96de4a810199fb60a7480e7f923bcb96b68d5bd8d7347b065413ea7b815206253d67d7eaf6d4958a324510468037c446e8febfe2355eee704fd712985813447e11663e9b00df5b4c19efa56f3d3a747114ad908618bfaa3a20ff918deb52837524ea1af7764c67c40d3db3a55df7b83b397891dd213076fa882616cb976110ac6c753fbd08f1e8e1e2e3620ed0df9e725296748dec14315fd779129529cfc2ddab04ca99b027a548133a138dc709ec05e698be67d5efa12e3a1bee14c72fe7ee781764d55b0fcd94785439202311a146813a0a0ab144803a367d88ddd2a344dda4baf961ac91a7d16d1af7eb03138fa1dff93b3ab00a8633326ca7c88117700f3ec8ebeac72b21bbd0580d8afe8b70bcba105ee6940483a65f98620ab363fb6058058f1f8cd591e67c5af3fab97891a189aec885558c0a2906f0219a0446069134a327afc569efdc26103d089b12bb9884ab3580af8d3b70a0db32b948f27ac488b44f5a7ce174d9db0a53896c239353707faeddb9e5b9c26801a8050a0f32d403862467bff9e64904bf3991ba9e881bca051b17a156388d6b07689404fa3e6030de5f03758f108c3cb1b6c7ceddb5091572b78f4a301d9fecd3fb8fbd57ca66f79e67ba0bd03045570bc57f4252eb001f63cb21b82d0a3ad9304a0f85cf587cf1badf962f65d67b1317a68bcd140c3e6db35d4424efc1ffbb3fab6f909ba6798f5cddf71058f0536652c7aa9878f0eccd5caf664ddce63d5a661ebd2e85d61cdaf177103df1e6aa0a72d36f904219eec42485f6df3f5293ebd0ecbf20d3c61e3503de9b66b9ede89239712ca5c40691199c6250d53d9e6bf4c9d985f6e7eba7ee60223e0ec27e0cdef3922d60f0f81c0b0f8fcb7c59b8f030abb99ff9520d7a0979f4551b87425544107c1f9b94d823fe085fca55708dc6debeac48bfe619d3398dccbe5d8cb37e6fa99ccd5730c22fc757a233a739262aa9b47f6e6f98e381f8cebe82ff35c8b5bca0d7b84ef4fa0cf17a4a5ffb8cabc61e8490d2e18563c3ce805bd3f2a4e3a16a5056a413d9ff3511b8f8456abc6e4c69dd7f96000b009e968fcdd21871ff755e19febfcd787b852aea3cbef9341806d0684e2c56c36718b19c482e06cd63f5b71ff5dfa8202a54b89e3cad9c3c34f39ee7c7a9be3e789e3480a3e773ed074f06dd7a6cd77df9527dff6a10d5dbf086bd7b9e36e2e532dee7cc361e7835999b2342a8e8d2cab4903bd80240932a5940ea11e02773eaa29057cb97393dfe02c98b5b2dc22e9caecf9944d0049bf24cf6746149e8b77e19a36f4937c3b685e3af10a0a3c762029fbd596e1ab2d8597078e9e3a2a954755b1e7336ba13898364e5b8f2d51e60a1c7bdcf9785af27a963d5fae203251efe295a870ca1da6eff93aa866306301a83046d2d6e35786dd7733b638033e5ce0c20f1e0bdea4a3518c2fcde3a8d11d36f365a03e495299546ce884ec46a38bb83e61a70f6df7f43eecfdaf17d0ece7e7db6f4e31f2630f0fd1b9c9e820dde5502c79b844544d26eb5c6d2c331d24d18a5b423396c4ce210113888333f8f743153a11104c8053e36951703ef8209d38bf5a4ec9ad9d42277a98dbe9192874d0f0adcac36db619c0efa097db8467caa5d84705044a038a05afab5630929c7203fc7ffeb27c5775ee61a390676241b1479e454351ef60613aeea4d17bc7599af450fdc5771533c4cc3c3bf328228220a0aa0882a809fc10abf9c8525a909576688b6bb2b10d90d1355ad9a52d69a74c2903a10ab60a9a0a6bf183d80e91038b1e5a23e479b541616225997e746cc9f36a76028b06dc951c8d20795e91ffc5050789454a668923cf6b920c5013d4e65a79eebdf7df9f7b0d3ada9bc6634fce7df975b72a016a42d89c085955d354b7afd513a8cea651c69fd5a39a9c53adbeee1a226208ec25ac883cab36ffc6a885adc590da534e9ed51d0d7022ff6a0eac28cfdcc99fdced730e70265ffe9953fd994ffd9987f8335f7ecd39195b5432040b27b7241c146144b0627c35cde49917773be6aa521041ebc1437e4aea6084a34d6c4b76c2225a41e2456587ecf6e3b20434c43823cf3c09021b0273b03cefbd366fb93f81cdfc3ab9a5febc8dc79d9cf7f2ebbdcd8608e138dab841d44491d6c394c2a6a934429e370250131030d7a2679d26cfdaed6bb96153f9676d3ceaa4d669af89fb04cdd289596942e5f090266b25a1114f9fae16371f79d6c50790809a90fa3925f24998d372fa4453b9af7dda8cfa736a84fa4f7f4e933f2b7e6af535aa348e80229b11a3e8452682636482598afab192e7b4f8358b8b1b2c70a854e090e7d4e6ebb41d583f378018d3e439154323c2d5f2c4b1d294e714b980b93515376a7c4cd49081803e00464d48bd86e7be8e9b3fde179e24706aef8218e8932e6b8f037dc265ed7ff0fa586748935f3b65489bbef617e8ff02596a1fd266281935c904307ac5ac04bdd014e50d4d1ce6d48ca6709436b2f6d231e4a18b8d2b86479efd0f56f58c309a7a7bb991e52e99116ac69ba41df28cf2b557e1f6894eee0ba9778d7e9f77d2d2ef7d17c9fd3e6fe256f9ddefa2ce8042f120b141ec9d6ddc36bfebb4eff6b4ff7adabd66aed0359e4de7efccceecba77dd9f6fbfeb9ddeeccdde7b7ffefc0ef7b87bb4f7de937a52efbdc8e7f7ddfbb11f7bef10e83db3acdfd31ef7de61df3b99d4ef6eef36dd86ed77cf7befbd3f4bce9a3e0989d73b700ac993a4e449e2f5093885e449027526f32950f0da049c42e1498124b87e0a5eebc0291434d893c5fffdbcce81537e3f0abbc5f97f5e9780537ebf00fcf9ddc1e2bf9ebfcf95ff7a8df3fe7e37566a0d33e71f19f1da064e19817b7f7035fced72c9985d6543dff5b159071240f75dba311b516454e4c79ec75ed3c029718799c9517f7e0aa563e9c3b0d7225838f7753deb7508e34eea64f2d7982ae1d4355546c3acbb1d4e998c310d6610ad75098d90239365e0940e7b1d03a7c06037463029c1a9f43546e2bb636cdff5c01c32beebbd300719cc5075d5992b22b28767c50d933c03873f5e5aeae588227ac1f4f401849cdcbd104497978958892fb137281c59cea117b7073028d452bc9d6832be68ac04c2076347c6560f8a18210eaeebba2e6a4b98d87f5faf8bacfbc64723585e9c465541b8cb632c31d11b389040663dc092629aef1bc3fa8301d02ab09a2d301e6134dff59ae57d5557f5811071cdc995c38d298631a36f71f5a08263412c0287a4816cecf54aea5630f9eaf9ee17f3bb1ee8b58af0dde062338426485b4b9392d6689ce4639d81101b1e602bbc9c2fe4d7c3de7de177027a243877a2f6107bdd014e89bbdebeebb9eb592facef7acd211e894fa07161338b12eb01e32e475fa4192c2d077ede547238d190898dc4c1b9133571ce1d368dbeebb9ebd998ef764d15516d6c909cc39c73ce397f39e75edb9c7d1e82dee19cf311fef379c99f53b2cf39e74ccee44ddee49c73b7cf79cc39e79cf31adc7caef2ce55fe3dca8ccffd099f734ef4b9e79c73ce8f3f18aef0618f2a7dd8739d81011f863fac7db838f5619f12815360f8173c6e113c92320cfb540e4e818f30dcfbfb6f85ff16f9effbb254fdf7434e9c7fe1e0c9fbfa74089cf242adf8fc91119f0a815346e0e0947756c954c27e1cfb3408fbc2febf3e7d8353def7aad921c6ef501dcea03cbc8052890192ca38da718b55b837c9fd7db7c2777dd8773d773debfad81d6bf3af52550cb6f8079cc2adc278d68a73714452377d5fbcc1083072ead8b4200a5921c3ba86ceebd33528628befba3ef501a7b82f061ea41aa59e39ad15ad53f7a84ab96608824b337bb67825e9667027d963c9e778a8c53bfb445d2edbb675dbb66ddbb6ddb551c69fdfeeb66ddbb6f52860bf3de1b728b342ebe2b7ee6f5b8fb66ddb7c65cefe03beebd334f70dba3e458353dce6be90fa5f4cd3e79ef32899191e5c75a65147627ac6b4d02b98fc5e0208264cd0ef501c78a260a8a262669e2b938f17c41db1199cd2325d19d00cd9aa124b5282dac110a197a2d9124c0e791ea6696be4a24c37044445a4ecc6914b0916bcb134fd983982a9915fb78c4c834031001dda98fa12863e8fc1e7830232f17d3e9fcf07c77fdcd21c9ca33688c69c708a2f88c628c47da22625adeabaae7bf5abaf018bbfae28eb4a819b1f334b3c724530d6e6da5c5775b9aeebea51b8febaaeebeaa3b46cd875f53a0d4e840a06f8b38997988acf7dfcb5fc1cecc3e73ec521e48967cd6c1ab71e8037f13f10801f8049300869109b1051064210824401780104d9394ec5e00e68596b11f749daba110962b58dfb245ddbc89db44fd0e66e4aabca489453bf9f7b0d6e9f6c1a35b494c47d823289c4a2d1b94f1e70d522f9548dfb4413593212f9da3e1961d69011e5d473b89db4e1c8544efdded927a85c54894de632c993bcdbfe7eebd1b4df7ade467545fdd6ab260cc85df6739f82c129fc0657d1ef5c7151376844358f5f9d7322d1ab0b4e598fe8069b9c123c92385933ca3a104376e3d8220e058b3c0fbf77750b163d96d40dc512267c8c2961b4cee21b4c304249581fa2dab6d9de88e272097221938c38776dc029fdcb841a2e051a1fcd1c45d86274947849438bc2d11c02c1d3784d912b66e878d11e2d495e4288b4854db567673b30821cd570c8dd55dac5d5a75b69948de302b49cfb245d4b9969bbf443a1a5b1d603014cdf86152f327a88406e84ce5a15bfcfa8f17bf7b155990d18b3b61a546cbeac140b4e69d75ea05cf10c309d151567ec940da1b1c1d265a3e2cd8668d8ee1445c925850d215c6e56b860718bbb51430a32224488b6166e720d9f55eb35ea003d63fb18f2d7d5a75570caca612e1049415b622b29d23545c1e413a3ec14559262a8810171399701a7741f5b0558f2bd7d1cdc824a5cb9080dadc873fc8990d21e40d3e282ac89238608b9fb5c2ab09f5a5c578f1a9ffbd807720ab832e12c2d5df0b8acd8a1b91ea2f143ad6a64e0acc87c35d3e4759552a60d014baa7145ad229ea09e9269309e922b3013922a5a8528d239f6288a077004d543c3ccd96921772fe49cf315278d46e48426debaa87eee0b4c4e2f0fae66124d0553eb9654758885eddab6be25eefa54094e719b15744440fa3cc943e6739fc6687d1b40e8e0b04415abb0ca5ad44d4508558985c0c31267c2069259dcbafa827327c24893ce8abffdad4f9158eeb6491cdcb57dc1269f66c1a334d9ebf9127a1e83cea0fe9e47b57eeff77abd5ebfd133fcd9c4a547e9e2a67c99a1049163c457172de0949edb86a82aeab140b6fcf8eb0aced3358df1b5e39c7315704a57b6f03053709e4574d455e4c6099565baa6414b6915a856661873be9e72ef9c732ff6a71eecaf9eaf3e2d8253d6deea8ecc00daf57a8b822835faeb50ea03809b1b538f1e3f564cc3ef5d0dd4a3c7af6f9575295d119b309c73eeebbd239cd2d107b41dbeeb53216571c584a05e8737abb826900fe557ef3f4c574f2a3f728a183905b9402f9752e57843654eb9b2c532c432f721ea779ffe7079bd180143a3f583c9b23e9f73f89cc7786d2955d9c0f1c490390f7befbd99c1bdb7db0f06bd7eb225252525255eef80534a8268ecd98cbe050b5e9bb124245e97fdf8de7b4d06a7f8f77ddff77ddff7f55a079cf2fe307e20d0eb1c700a3088c6ac8eb3391d50387ac83ccd4072bde2802c16363b34336e82e49ed763704acf09a7ecb5185f5555beaa7a132ddc275a56fd709f7059f528ca9ef6f06794d944c1b43ca3ce1ad8f8aaaad2d8a4c7a74f4d5555a9460ee9c7ec47883cc71e307e5d95a8797a1b93b1d28a189956cd1638f28c2e2350447665e332838c489ed1a4aa929090789684c46b1cfe851272fbeffb8af57abd5eafd7ebf57a5e87c129bd1d6fe1df6b46fb6f0fdc6b487f7b16ec8bc50f4000bcf6825302a07cf1f32950a0408102050a14281cb90dbb62b9a8bf3d6fde407971f3010000afb9d82398cff39cc7eb79de1a6ffdbca7172c9fe7e3e90e3cdecbe3a93c1ecfff151627192b324d413c2b37a3534aa5c813cfff860890f555af6d00dfa7a39effbeaf675faf6b785e09280617357f6fcf82fded63137f7ba04ff1b7173e19756da13cb998f93dcf39fc9e67b568c029bcab4f02095e33e11412a49afeefe7813fef4d84bfdfcfb3bff8ff9ea4407c55015ff53a0b4e51fb1bd6154ad9afe07905afade0940a4134669934fec81f21fe913fe24d7406d58f78a1077964c463d019747f24ee03d1090f6f32465bf2888e1c4c43408a7a9ce439fe237e6f0580c685edaf78fede574a345865594959379833e094bd446794afaa6539b640c8c8d5d898855ff54394f955a8a7e257d5b9af5e9df8aa9f80cea02ebfdcb66c48c5412155a14e1928425b5f2fe194118268cc02c9f89cf77991cfbd3711ee1334a9b27dbee34438479f690d6e7ceee3a91ce73dce47789490f2731e8fe373cafcc5282204848819da0e539ec159150e2927a6115bf21c47090519c2b3a4e3c382d2c2a5d4614489289a1c3344b860fa703381e48288d70c29b1a43ca749413efeefe73515bb3d3aa3fced875430c6a6e0941d54fc23235e4bc1292324e67ebe5e9a371d8604117faf37e4f75854dc78e468bcae96e49ed74a0fd414214a55afd49fe757815e7cd56b283845c5729bb2da32bbf1842a3f4ff779423ecfb3409e2b7a94950dc93caf9f3c9cc28b94f83acf755e3bb159bff51ceeb76dcbf36d4bc4c46f7d6d1aa46ddb272fe2d2d3498dbf25b69b6d8a29268774818324b7453ed434dd4491b5c86c425618db705cfdc8999155b3438d68c481499ed1653b24c2e20211af26e053d88dbff79623fe2df7f4b7d74c70ca56550ff4aceaf59257c6157d1ecf6b2556c7707e76f959af61c0296cb248cd5fd7bf16ffba0e31a0dcfcb5f957140c75a6cc789d531bdeead9354ea2cba0cfe3799d04a7f084b008021343a5864a9ee3162d3ef7fc6d033c76d05eaa7e142165ee35927208f1b721fcd6eb17704afb021b5f45c68e8230a1e4390ee2f1b7df40fed6c9e192531a89c2e4edf5915208d85755af8db48bdd6ef7b58377bbdd8d1d6af5a6f2779eef3cfb46e3ef7c0cc4f9bb2041fe0e4eebef767038fe4e08d2df0d89f93baf5bc0293b206f3f8ee3d8c75eb83bc871ec31e80ced8fe338dedba4843fa34ad48acde5efed59b6e6df3e6e03fadb03db8efef6c296bffd10a5e6ef28371f7f4701a1fadb6b1670cae61f9d513e9f859fa33f847cee391bcbe79ee55e2357a074f82184e0b50a38250427aceff3b97d9ff7fb24250af7c9d0e7dbdfa784fb3e5f9bcfa33e9f4f07a535b5a20443051116f0f0392eb5a8d9609220080a2b4c050c1e3abe981e2e6262b0cc7a4ac833bafc3e8f7e7dcebd4eb1b747c7fefe7b3badfced751150a340d788765cd7c2f616e0764ebf05d8a7716f832258d04f118226c08153843291e34592bc063310638e2b4e07a9e9e8abc796fe304145f301aea905cb664371c70a29124e6e66c4210574390d2d39bc80c8d201ae8d78398b4244a59fe27143d15b1122b29a1b44ce44b83e487c9c39952b9060b009edc274c87c78190b83c1e2a8ed412642cd840b1be4170e97dcbd0faac018330b2785cacc9185d34e8d056e4076acbc91015101b2c1d38c661808aa1e16646fdaef7ef86b7989e3eaf086a2ec87cb87558ab92797b5212cae766843633baa388c00ea61e3b3bb3a0f2d70af9f62685f2cac7e8e96f21a9c63f509b9f6bb91cb438a2e17507028e4eebdee59f3a970efcd0beab5b498184dcffe2e380383f330c749648312d35125b741af76e62253f4911a93bbca9f58107fef5ef3a0ecd74c9f66fa7c3e9f1bdc9f7d4f5f8dd9f7fcb36fc79f7dbee4ec33cab3cfeaef3217a812351e5cd46419257e76c4602306b992675f871a275882e88851b121cf3e1bab194c217cc878f89167df4e7364640e6cc439f2fc7a6444017f1e9947985f8f98fd79a4eccf23647f1e49ce2323563208d165c4a2e3012d4bd6592f439c64bc015991e7111c349a58ccdc44cd29c9f388cddfaa81232acd427890e7919daf7d7484a078cb81cc92e71124aaa60cae184a4c48791e59f67a732bf2dc73f6ba3cf77a6e5ff7903d644fc79f7b39fedc1bfb732f39f7965ff7ac361cc170c2b0d96951c9218fa003870d49c552a54b9e7bc59d4e548c558ca6281979eed9f8a043f30492ccc96d459e7b3b236dce1ca5139c90a63cf7906a951b5053cbca1b943cf792e278ae28cfb1f3eb3876bbf0e758efc43b71d3f9e718c79f63b13fc7c9398e63a31b1a8f63d88f3299c3da538e4e90391835e4392e3e20886bad2988876309798ea1e44698a832ee8093e7782768080767cf8e1a943cc74f333029629819bbbae4393ef278735ff3c8be9e793c9ef0cf3c396de4d530f2c0c2fecc03fb33efebcf3c9e3ff33ec8338f27e2493c5a52799092ab5ac6e48040d55c0dc933aff835550e268811643e66c833cfc60232ae6a52e8f4281de599e732e4acc7d12c0c479e79af8b4f0d992cac271ef2ccb3d91199030321cf3be7d7bbe796e7ddce2df8e79ddcd7c41df36be2ceebcfbbae3fef9a7fde25e7ddf2eb7967f5b5df11f7c906262d66d2c69b914f5326612bc771eec3d5cd0779def9206fccda8a25a4c6e479a7b2e3e589ac0a88180e79deed28633ab4d00a4336e579870c809a1029a50f123c2ef2bc4b529fa809ea73ee6b8fce30190cbb7d0dcb39e11a4e18ecc69f61ae3fc3473839c3cb0d336cf5b58789fb648391061a8be2cc1a08a4fc811f623630668430c1c9335c346ead04bd10d125cfb0cdd7c525e40e8c0c97913cc33b3af9eaa42bcfeffbae7d0d17803fbfcc97f9daf8f35be3cfefd69fdfe4fc2ebf7eadbef62f719fa060706a644cc8a1a916b23e13b10269c5d3ec21cfafdcb2c74acc4cc5998e3cbf61c61a0f47684dc5a41c44fc20f3f5614c479e5fb526081e26a52653479e5f26d404a639d7f9b5ebba6e00f8b39b7493aed69f5d1a7f76997f7693b3eb12f7090ad8b84c38218b9c7064320f366e441031de58c9b3db231957a406c8cd8a489e5d9b2b15242124689a3562c8b3bbb3a247d9c1a9a825873cbb35d45c7a7046040d2992673729056a428ab9b66d5be09f5b643bb74de3b14dce6dab839aa033c7e559a7d3e94afeacdbd1cdbaa6f1a8ebfab36ef9b5ce2a85414d4861e656796659969d59236b64b3fecc62fd99bdfa339b9cd9e5d7acd506a52525af9f183e9262b2520c321c4570394bf2cc16bf5e7b51f34c86102322cfaccdd7372890962f268866f2ccee8c08daa9da21b3834d9e5994aac55b0e1413050d1ff2cc02013581c85c4f9ed7755d29fc7995fb29714d89abd59fd7197f5eabfebc26e775f9f56af5b55f89fb6404324643a88a44485872dcd24edc8aa38c2d10f21c3c2e409f93c89c9b905011234ee9cb8945e6127881ec92e1b35c43ca9cabdc044547e4dd7028d34f20c6dffe042d672931aac5ebb31f8d6ad15a83a0a967530f8cd23a5dd232e25a4905b810830ac8cd88a9275256b15894e48e462c5d3192f71545a1eeb81cc78e6ba9e9384bc3fdf62c37ceb1e8caa99eb8b88caf6eb5854d7cb460024b8fb2222296686a6475eda92903c4a28816c6c654492b54107b8b2b6a4b46a76acdfdbdf7efa35134e4beeea3515a6f662c8a26924270f829fa010345fb5afb80e3728206d4970e918e8e8d9b8a188ddcb082ac8aabc58fa31647182811bda24891958e371c2548c833cade1b90c69ac2e0961ec2dadab456a16bc3a0c674701b520e590be1c57634a1ac52fbb98a857a9b0bb5a7936d29b8da551ebf567fefedbdd8df227c34c9d682478aaee3c2b2ba69d94213f212e7849c29668d18015810ac9b0e42c598a210200d9de851c193e6f26201dfa3ec9da6a907a67e88c2299b3ea669ea816eca5bdd92aabb6f833f2d04c63150f74387d628d87c58aaa09bde08d9071e9b9c3918721750b99a1292d5c319a3a6e0a54ab487aaaa2a7feaaabea0fe08421d807e93a012c886e2abbe82cb064d849e88eafdb1153385846c09adc801e4a481c462465493272c060694e1d0efa1203e36971072c6902a58ca90733236bc386160cac68288409908855ebf4fdee0f0f8d5e48fb2af3a9de8c1ad20b50011c5e6b622ab4762ce1c2e3513264e60e82af727297188268718dc8f267f94f8f3f0ef587817a61205594d9a1017a19d192f238b5cd6940c8292dcab321b395a41313a326f1a730113d44c813642808f465989f8bc8f4659797811a7a967530f54aaaaaab25360263e511b9aff29ea390af42ba0648c0b73d3024bcaa9120f8f0f201b696572ea81a947e3611a15cf1928d1b5c245430604f4e316b6a2d9a69344844afb9040ddc4b5b52856f190b9102aaae60f10219233f04aa64843e10204d943620c016534220989719496e09e4db2f0430841d57dd5a728022c4cf1a04caf340f3a885c3046c04b5037349c681c5cd214362f3730216e14ed9ce0c2c789caa919377442e7072a4754079d241899b725a12d654cf9cc68810a975c8cd54d510913bf143c429c58e1c3ea89a4d375a066d66284960a1a8ecc9136a89a6f2d572b660a8041da3819bd3515c9b1410c35ad171a1d4658d1c8d0ac74bd720b6f89cf69907d838ccc8a9f24105c70271600a2c30f0d99159b32886a610514015967371cbe64104de1d0ac000089b018419aae72c68003f82815cd8b99b53ffffc7ed1d335d5373454aed6e9848e94d892a8c354c25c7558390b0b810ae9d038ad3b5908143dbfba4215556dcf0ee952ef0a4a81cdd53da77bf7de7b90558351351d382bc247a7bce2beeea3535f47b400313aa5c2e8a7147eeaa754fce89fa61e62edd3af72c2ef36bf0bfb01784c9568aa48b2b0923b05d456aa964bb19537b907813f2d04a632353f3f292de4c8061615479a184d17247c6cc06c79c372450299650304d0351b41ca0607571944774ca46ab494b8511023b11a89b5d496135cf251a92d991fc247a5b6825e2a12dcb333d0624b2bd2a3346293e738d524348eb5ae19645a0c081a2374684674395d7676e8e8117f9320c29868ea810a72937dff28d54c911e17c9d087aa0db77f15edddc2bc7defbdebadaaaa0ab36af0ef20db531d960ae9d49d822801742100d5b32a4d9244f2c79300c68e1373446d429c64b52b89840c5a5923fb91d5be769defba19b59dd2290e667a02dd68c5d934e59456bc35bdc47c9241a2acbc4a16f05165d3f3ef3eaa4c169f361c69dca076189f645922a2ba703c3d7589404353fb16cee0c035443df3c1a743c8f119e2aa22c8ca5a0e0f69345c647e952ce620f3a052b55c7b51b29773ae7675ebf3dee75424c63edf32e73c467795da5595f52acb39a712c1f4392c73ce3957f98ee39f08a2bffb2895889c3fc76d0abf763435558342ace79e0dfe521154333b3810747b7607e718a008d39f3e4989bfdf6a013883f5791fa59a6976bd6db02f8b014540df432d4cd5e0fc7235deec0eb26a4c15cf2ccf10bf9cdd257035c80ab590ab6c67bb57bb67fdacaa3d58410b592d9cdfaf0635cb598fb638e8081898f9a7f037fc3ee7265178c37d01f5420fdc17d098b9b702d003a6fa10829788e976acff07047ef4c96beacf3feeb2a1f843ce8517cccf8d16c612392c19221f282b2819f5680c501c636b384ecb0f6547f21c7f998f7a0ea004c93183c65433a8c88d8c7a54062e6af2faf90454dd280a5b20d619744c0bf700c323aa79c972aec1b4c92a0d0a0f6e621d503c0dc96a701ee1a3536551bf7f94ca03923b6baf7a566740b956833a38a36810d54234037f80be41fad1b9b99f6acf1e20d66b2b9ab27e4d8333ebd374035178a76e697aa5e372170085d3a9685452d5b35b3d7251bec65b87da83f3bcbdeafbde3c3877bf2fec59f55b5581bdf7b8efbdd97d81655936886e0be97fa155ad66e0aababdd67a07d1096812536333befb512a181ebe1e72d116c428d5b1e8f73e4a250483f7ea0cacb6fa288a069d41c7aa07aabe822babbe047dc26555f5acba7abe0ae96274c5ed5b874db2f1d07919d9272f1b5555633dd30524ee1af2f7f6e84f5f48bdfbd1a72eb13fc73f5d357bf3d4a509b5409f5c6bacf728acf7dec97a76e964bd13e859cf7a260acba26b3b2828282828282828282c6739cb630e8c597627d3619aa62cf7c2348d53ef631f7361ecd9348e87c754b34227101f4d2ec9393f9a6c2afa9a893aa0133d50784c359bb2e94e590e4c759c6a36e63e4d5956c8516296e5a966f9300572210be46ccaa6292b8cd398e56c0ce4409eb25cc8d9638a12b33ce64e9eb23c4dc66cccf2214aea591618c731cb0239907befd3742844e1299b0285c314c88742cdc62c67dfee996ccaa6719a3239cb5138cb599eb269fa7f4476e7a7fa99967d74073001cc31a5971f382d39f28cf2511e1a41c696a488a0e479f8511ebcc940e32a428485051d7b3edb725e706892677409f367b409e2cf68b2014734b81c0f67704932da25b3030a498e048f938ca23e75d319e0af5f3e8afa13a01b8ca8c23ecc08c2b1d4428f8c8a7cd100737b81c2d134f9c878eaccd8c8738a0cc25831baf0eaf28993e7f43802153d5547705e3945f29c2e534056f404f4e1a88751268301ec5d34059b01ca8f01ca17c1cf69d3e5cf29b305f5e89cee145121e847d33eead3b5eebb677b08be279171df11fe218621497f46b191e7137e67d6883bfe196d0efd8caefdee56e4ebcf281c2af7bb8a8a9c1a69a28e2bfe9cdaa43fc7df53646a4423e9cf691209794e9752e592043fa7cc1a52667f4e9b21e494ccbbbd70f1e714ee459e53add203d05fd0f8b3b69191679df3bbfe3922d7e2feac9346c85ac96c33fab36ece1a4c93e9e7ef7a4dbbc911fd59c37995de69cefebc6d76ceef5ec68b05fc9042fabd5ecffb9e1796f89ec78042f47b6fef432fed017b6bbdb7b7f67abea734164ff800622523f74038ad8a557333363db43fffce94ef8e3f63f82ff36b0ac57f3d90c47fa3a8e6fefb462da3d650805152561f080402bdf6e1d3fefc73feb9c22ff1e8f197949444a1fd12e58d5fe2750f38a5440d4ee9b97defbd4e83537c9cd82721f9249ae59390bc9e84a4e749487aa4c8c24eb0b1f9409349dc8e45546aac0dfde8fd7eafc2ef0d61fe5eaf3724c8efc519fd9ed768effbbe3cce5072fcbdf7f62642209b89bf49f6dea8d3fb20b037c9de16f60e6ae711026f2839b4ecb1ebbaae5acb70fd76283bf3fc336b6a3c4505d4a51ad921122d3a584d47581b684e40b9bdeda0e114adab8c53094ca249c2c95bd9dee3d0589d2a4344e145e154513c55146b3ba0d40bd781d167da72a4a50d09f3618032078b155c21a484dd44ebaaa92e95d1719bfb020a2b934448f420395e92872622166563e9d64f5c092ee71bd20ff993cb18e1f68b20aafd8dd7af13f2753a1d90e8475f408b58a37809a8f456fac24a546388d22df8b39845d91245258c4a2cb5514570bd229fb8452706d7170ee751a58d264d27ab4525abc8de3746d6180854043202d9c43aa0d2d78396fa021ac464d9d8a975f1aeabba75db2856798a3a1e238f4dbc0251c0f9867db853d8ac2bca4f9d5a17af4ed5a9ba2296c72ccadaec7c9ba3be80ea9cdaa117bad0ab677befac4eab3ae604bcd7b5c7465f407b76583586faab8e0d16044534c8ada122116722606a294a0b526e35ed0d33a2e323dc10f10f156313382c95899e1ed3c2d3187803b775b43a5dd775dd7e6a594b70fa48134a0b5245a502261d0f2c2fcab0102a958f8f6bf6d7755dd7de63883aff43245300ad4f298a7ec513352a265866903c1c0047530e1988b13615285e58839d388e47c0020281719c2402afc426041e0090fc0e3bc00f2250f8702c592bf9ad90a0a93e22051cefc8f247b573a3ed157d56be3806aa1847922fef7b48eabd6877bf488c7748e0aff2e4c9f4debfb24beee0b07389b0d99bdbf6de92d4927cd35a1b1c9f43520bfe44a372e774523f4b510808b31c3132813918f6834026cd3ab82e562e35ca82b82f4bea7f51c602083184dfb5d5b932314ad43766593636367babea8028f00aac07027d522d81d5b14a1918e0068630b2acce82490926a8909f361e81fbc444930153a1890c9c490926429397c6c863fe44f8eb5ba4b6ae9e7d52d9761aa69823d6105354126b68806936395d86dd5d59ae46999808bdd27799a7b9f9ca26b994da3648d43d32aafa03c6716ce2abbca7b8bede649d595fe87811d97d9c3e7051fe4922beb1ec738c81724f52728cc8ea58b775d5a44fa7d3b147a4db3e611df5763d7257601c038f4421b7c7d74d62a1f7c2a124bbbb2a42fd79601c03859a6b12cbcb4d62a1f7c2675f7f50f01b03ca708872747ab623e118d12642ef851a848e2a910fd7751924e9907113edec27a4a41e91cd2ed181fbfbb6aed6254450fd4f92869fa4dbaa6cacea7a5c7aec0fa8381caadbc4d5e9b4d876ef43e27547877656a79a75cea22c50936dee7ec038061ed7755d75baaeebba755dd775d5adebba8cb9492cf45ee853ec10485b8d7e7b5d570d3dceae1b7aad2b8f4f9bc442ef854bbeae28c65efaf31a82885b19c46cb54ec9438c510d40c828b5e3baaeebda5561936559df90385677e0466678c43c13cdde0cd76f67229e8a611d246f2645086f09e26e6607767376e0190f24b439cdf739826e67c7d522614f14db1c106b513c38a44fc30d33e78734be384ca508621c0335946886382b39918c95219a3d0d384755055af8e893931ab0281eaaac6eed2e90ea8b22bb06a3a48e426aeb567685fd0a07e3ad344ab66d3eefcf4808f67d9bf037f8d1a764cc4a64d9766e045def49579764aa4e491cbae4d367c3abf81667e4f5f222ab3a3a1829d91022f4a2478f5d639f88ac58dc933b25f6538caa66f1d4e4b2efa89737359f4ea86ad7217d5b559d8abadeb3e32cca36113befc91c31bf2624db948c53db9535b11b20614b4c553e8509ace4980aa7b3a29c0d0e13f30b005b1c77f805aeadab43a3f0d5de7b5f22dd1298dd6a95f51ff348d272d47d31b0aa49a1ab6123f1d5ef46ef55c1f9b6c7d2c526b1d07b21b338122f3befe781710c9491ecad3acfead64e9564772642ef855a4f55555575d525b1b05f3e792b74ef8ce56eab2ad5507765acc1543ebdc5b279b7aa52e5acbaaa24978a86bd6aa960d695c652d7e3467a0ccc2aca326299b4808c6c7de84140841d39e166944bb25ae4ecad69e962ae455ffbdabb8eafeb0fd5cab8f6ae3be3328d62df298e76cb56499c866debd29ede60750c642e3b0694e1701dfaadb5a687395cedaaaa6a9da56a2575b2d632ee6a0a35b58ce5ab2404b68c2f54d246abf6b5af5d55555555d5aeaaeaf00329d80e3b379d2be584c77cad12eedddae9a2902ed5cb2a91edd389b73e752a96dc1e039f982c50892a4b25ad36309fea235b8e52db7c3a063ec171310a325412540ae64e9e4a7ab0fff4a239c292aa495403e0a34f30a478ac6b58f75ddbd5029bc421b7dd204b811fe42f43d256d26de0d02247d7940e8b1bb10a15d8f8f75a00023f9a2463fe5ccda17a6fd92719c05dc250a8140ec790aeaee5ab8e653bab53f51bb36cace343a1508841b7aec0b402eb8140af61ecb9e57856658e15f8e9c984cf09a797feca95636b145474b87a8cdacc829cf2bae3044eb338f513a7029718aa2bdbb22e91df7b7f954d9dceff8869be479ecaa22babeac842e09cc78eda4b9058a75e8f8d765ef5bba08f327bba345f9ded3a6fd57b47dbd917d014d5f7def7aadb2c46d04a2f7c2679bcbbcee6775f41059e395b0b68ccdf7d05255ad9ef14e4debbd0c40b7bacdc41049a683823ee0ba817c2c07913cf7bc62cfbb49922330e91a02187134a46040d6548af936443ba8ea5be806ad0c164e31ef7d735e52cca6a3083db71aa7c7afa349039f705949d409165013efac4247bbb3adcb26d40b7820702fdda5aab63b77c5b027028140edb8a6e16544fb796d4b2e8ad6bba95edac4ecd0a72fbcbc63e9c6cdbcd2e6128140a31ecf4a08d9285f3aa15580f04fa1fc9d5c2505b8abfaeebead92c19970f85c2e10f1b0c4a6d476a5b8cbfae2b8925b9241f1f4c14c92bb3468d2e2a2eb625b8925d41e88140cfb6a3aeb125008742e170cdc84f00e6d8a515841e08f46ccbdd46f3575f615d7b0942a0d047d200925860bde6edafebba9e80927a0c2708871370236240e11fa55271fa33060020e9e057d75b571522a4bfc1a5bbaeebbaae6bab5b75ebbaea7efc755dd7756587ace9d69222b7bffa0aeb0ca2beead6752583f90f18c7c0213bddb36af76ab7492cf45e98b42fa02a91a87568dd27c39de56a0c3eaec9f749dc5521499fea74b12e088c33ee0be8577dbbe11455e7d9a089ce82d0ebfcec775eb70b0eb5d8d15f57aa0e6f7f5ddb95affe4d8520639315952bee0be8d7b13a869cf1afabf73a7f7de575f5e83e3969c11221c329175724af39e0d1b2d5c342eb2b87bc06513068a1170a390e313cc13029f860591618b72d9155c72ad9e0db9a2eadd7831859e7ab0a21ae714f69f054aeaa31102ed9e39e36fd75f51ec8715f40d93ddc603c24e89f162a91fa029ac4be2581601f44483defddad861b581cc7ebd317dc5fd75508a62fa03f0899be807e7df2db789bc451e3ab1fa5a219fb730cb3c403e8acf0484dfb9ac660ad59fbc63fbdb4c5d53bf72ce72ae75c66884a98cc0bb920505bcca520871e2770828aec0091b7626c0915c1a03a1e9568249d70b69039f339438e470e9c5109d67c565cd48e82a425892032c1c0e49868f194de40e02c0bc8d00a8b8c138f730a490365614c52606c37522f6c50c523c8071823d676dcc0e7891584e5d5239701216240d8b6641471883afaa98a9a124f8aae9e21391d52666475d4c1a58614048c72201362ec4584d88da50a88a0cad21241d4aa110165530f54a64495f795a7372d405a8a082005914ceb860ddc081239f8710b225ecd689658374a4449a763753aa81a2f3ee72bcbb9aaba70099f33a8344a9d2973522123150d0110001318002018080808456118c779562ae30114000f4dcc444c4e369486c4a128c85114843108c25010218410801021484987a30140c809b4e738470fbb661b80b1789d2db15f41fa0bf291ca3ccc835c55f2ccfe028f891bc19740cd4773cc6cd835e9d9f4929265c459170511476af9cb7d52f89cf74e0adc911d407afeab2aa1cc06d7197b10f0df5c921def7a9fff1747e685f9916941472f4342c17a1804da1cf2af2a39b4d490d1fb8c0d36db0cd89bcf8b657bd4650cd98b7fdea380594606daaa04427df4b6fec40aa2a1f43a176af1cec648a17674c2a42c43cc5dfd6dca9d4bdddc38bd5e40977a490654209acebfb354413fc03e67ef3f9e8b5490467dd977f877b229e079681fdf3f2c870b0f7645e72c125efb0c90770722b128cd6491fa1c93c899edc68cf0c2c16219223d9e284c1401ed0b18071a75e9077637151143c49dcf2fcd3d6a97fc2e9b8bdc02fff3c159aefc30fe2037e133f5a281a6c6062fb3b50fa66bd29b5066e732ceee52816a92c8a1cc0f541eb9a65e01b1fb84ccc9bfa65cfafc45ce07f4b6bec516690740d118ca83d5381471ee50abf06ac5ee1f0de2043b10b9fdf0975356b68416625ae915b00444e685b31fdcbf8f4e203f6c8b8e2e2f47cf7ca953b06308c80691c352aa88102c08ec934089b76ea06a0e7ae7df1ea38e257e049dac4219ebafb4f8049e131258358b4117061153d951c09e4b2d99969c0f51e65d2e7fe6d394b9c96acb0be14a26834b016065f7323ac7e7322141e4c1805513f436dafa4d576659e403fd67647f839a8a5790eda7124b87ba83dfe82a49170453afd70189d9fd4e58e0d5666a5180c5029f614ddaad00af38ebb66820985d4d14b9262d333b996f1ef175b85558e7df22d4088130227fc09340c411df7be384a67deb115137ed2e45c11f534b8e26a85a1fe958ab47f5e329290cdaf8ab5e7c05deb9962eac6b8214e0e4291fd3ecde3e7b5bde4bcff420e5ef805ede2b44485bfee92a04d673574433588bcb483ce4e6986264ccf34b2c909441e76c2e68c2041650a81a482215169ef4029ae2a29fdc6f75d644f31396e975692b57b695373ccc8e9d12f475dbeef512281527154db23acf4c8d788fbcd53c985145bb49b845c4114a452628593f62dab6973bc33e9723399b9f6893bf39ab14142615d9e605010f5dd0ad0c75a0ee1890bf5e06a5f019514e84186719b4790f02723100231acdb488121908e5de67002e4de54682e1815011eeced0822eb95be8c67296dceb8a6a8dec7221480a1477c560d77d7160ac825116b76a004416e1b8e2ec4fa31e2e18a027ae0477c9b9aea8d66036db07b0a070cf9f7c289afd6c704d94d4e1a68deed8f19aa25e23fb794161b9a2d8a15f469cec9aa2b256d6dcbc06061cd072979a5d66d479c810f54c6b07e23d76d86e61921cc105493d85247a9709cbd3cbcb4488a5e88aba7cbe1b8a761f3d2ccaeac55264445e3fe74d45b39f144541594d284557a4f215d1452f4d0b4b96bdcae21e352c13864fdcbc9e0ec3475717d4d81316b231879dbf0d52f6fd3e7bf024ca1ae8588607da2616171e317993e23326961ba1806021d1f39a4845deabf839fb1f5942675fcc36f1c4c52850f511033bc3318e9802089c7d2afeecd78838f1c2e0fc768a4f94c70aa5066d96e4e7ed8552a57141af2d75a4855eb43aa98c914a80e4e4a8187193af3cc979f45662dd75d40f5e95ca7dbbe55597a37bd9ba7f1b54a8fa20f83d7617fd64fb8fe3a0c976186aad921691cf488f8c381d9e23e47a0d8a67296da258d92efc827fee09f87308daa2bd48054212580090a8f3976a89bdf160e8bda02ac84c64dd0b1fad1fb66667eeea85bfee0fff33a8613dd05f2fe1b0a2974594363b20ea4b53acbaa59803565973d06a8eab80406d887ceb1a05d0a1106c601609e8c256ec9ca7dadaef5f437e140d4bf872ffb686e470a0109d4948ed21ac8596d22aaae877d12534debb7e9d9ae4f7cef6b6bbdacf157013939cee1259c315a07326738257994b1ccde5a73834366aad71b12894d40404d4915efc55ed77f297cc5799ab74c10ce7429d5898a011f1292ddefeb3e8157e9e4952b55f17f8ecbf355410186a926a982e148af90155a018fcc51e809e14519c7543d1ee238613f5166c2a123ddc902853cec11e45cb32479b39a3891e92e7e1e156662d727f79377365d0d282dc4a1e554ff3f2adce001df9501975ccde93036c26a2cd89281031272b1cc8b8f900f093c4d0f00d0482bb379dc47082a3372f97b271727dc68cfc0210e2324b9d0b05eced481cb11ac4d8f7dd1afe7544148040ecbb1f62bfb907d3ba73b8e0a0b39301528e8b96a0470e0c19530f49399114d9ebf34913c611cbbe9210c57ac9546005d73f03dffe8d307eb8eaa90ce69e7beb6d45ba550148859e55183256742a41767906913065ebbceca9a8f4595047e31b7d354b2cce81a84a5b12913d6eaedf597109ef6154ce11ffa249237b5eb9dbffb66f021fc2b3fb397e81c17dd70f78fc2101e587495d6977ce002eb92ebb15a40474f38f335850f95357938d2bf6e9ee3c3f7d263d4b812dfe22c1e06d83964db823c8010466541bb2da6feb808d99b12f227048562d03168564c8f0ef21569105a8016b666b3c447164b174cb6f0344e8ddb8ae5ff1dbc6747b595ef9392211e5c42372ff2ffde1a6d1184cd219a9ba41516f93152331d6dba9aeafd81b930789ef2ed470accfd83454919e67697766822abc9520d7ea4bd92b0066ba6a7e1e13bacf4c29b5ee7ef415b9958bbc9ff3341c83441b1c19da39efa40d775036e7fe85c1cc41a827322db1960c6344da48a19a962e6eb3659a611232e19ac65616fd70ffc90356153bb77265355efda7456e657e233686a82074d26f4e11831cab00550081b94f054fdc6c9d5da0ed12a90086b724e4904948e761bccb8eddec3456f2f091cabb550205172294df3889e1950189eded039a7ff4ec9e095af94196655959c1e8902f001270d2852748e39b6f499875fc55864d58251f397ddd9b7d9bc3ceb49275a439be301097704712ceb4417348b805c01dd9f8b215071c9076a209b72a2bdb3b27aa48f61bf4abc730602c15c455082dba59f51c0e8cd502b822b4e962d5170b8c8502b8a48f09e990189812d09b8c80adc889e26e4541d40d45b3f765f26229fa227d6941de702f45b113bd7ad187afd8bc0d83a652c0cdb78a08a8f98c08441b5b4253ff8656a0f71c7f8b5b7b3690fc282b7a6869ef550173c3987e4bdffba52da381843178293f7129928e1d2e31b265003f1dcacf85a82b49629b34b9fb40a72d94a4237fa8e8a2fee611b6062ebda93ac414dc6c4580d6c01a81969c1844a109093eecf837708ea3878dd5779ceefaa3ce8e280b6057dad264e85b38661f9ad0ce2c96e87882ea3f5823415f2b4f6845857808d174ae1cc74d1eb2c23c1d9c11547a639ac9d1d72ad0cb88fc6cee9f2538b153c2cdb19c9bcd71a464fdc0a679e74d001667decdb6852335af50b38406c8a6803377ae3e3c56f15e6361bda372e338255b2eebb6c430d1892fe06e5af21174fa02427b0f60c8494c00967215cc21f6ac136589daba698e97c868c71f5899099dda9ad9748c7afea13d267be49847a490767392fb0330c278b3ac4aa38b7ae594d03105be462047cbbe3c27c2f078bfddb5188b95f99ed68628dd582a036ab8de1045cc5968e3bc68079e3bfc6ef690bde7bc3ef32e6b2bc57be410cb8797cd904c77cff3541541e4dd0f542fadf07d082a7bf10466022e2db476e5f365b247e3a3ca1e8ac6421f3dd2916eaff0e07d0c4dde34c4b8d6c582c6596b4088b6cdd9a16499ae040ef53c5e4643d9c42a028316bb94f43a5b0738f93a5997582084c788db9918123a095255c675761fb2d01b08875d8a2a0882fe064b7e53116406be1ff61a0754cd6c0dff8462206eee110533b395f36985f78c7c22bea84f2268756a3029b4480858a6fea0cd317805ad0a7560bac68898ef0071a99d5f280f582cdd24629bc6d3ca6cc20040b7d4ac9f6c0de10ed6d4580a4d1b98b8a6af3f9f9f99784f50539250c8f17da46124d60849b228322b659365320ac71a1227d6491bc67cf09909df5ba92bcdf1c45fe32ae677adf8a9d047f127cedfa923eb0274538da9d8dc0171530df4ca3f615e4e1c3917a0eb6a3c43d7b2696a4cc5f42e71de79d37809d13f1376079c37e43c5ca543b169b5651e9028e07824763f797a47bb2da2a9f0c8ba449381941e20ab4c982a53aa9b036287dab8c1415648f18c301a8f770ac7163a5fe9c5fea53ee0fcd2ff824f5f2f591c8dd2d00b27bd031db44a641a34da5e85063414415ae4057d4103d03d6cc06a298bcb11759ebda6bf9530c247e9ae9311de9d778b61d3bf1e3d777f264cba7026617878f7f5ac5e1f3eeb4700ff6094357e007eac6aa0e7b0c3eecb334c25a961a2906a06fc1f45524d546d82d598dd91d7447163fc1a6cc4cf596dc7203261b267854713115d7c78897371c5a54983a7f2e4cc7aa8724ffec14089617835f3ab07219fb15781243e52448de6d09981a7875a55fc53785ef9ce76550d970495cf916946afabbe596de0ae1a9b45ac4e4aab886a54778958bbffbacf67c30d16a24dbd055d3d023972c0ba7529271d752b8411065ed6ad22488053ad3d4fa8d2da41b71b9c0c310aafb4d082092512710a12b28f05dc64a72b6da6e889d9a28c5c672fd65a43e021f08375023822b4e87ed11303860541b8b2baf276938748a486704c39f0076a68cdf1719f8a649f1d5cae127a50d05cae2876c291a845d119c54547339aefebf97a135524fb6db6436f1030a8ebc7f82a5a0f2c25b8f0d101776968201b99fc6f96e4e6aea807f96144654a583577e53b8497d7100960054218de7058aab65554e6e53fdd547aea8912e4fb47c84c4ea07211665984ea9f348b2dfc840041e7482f6730d4ff6864e291e46424acfb03fb62852d1d4dfbd83157abd4eeb41332e7bb42a763a7c1612add2c5da134fadc0570cd6e5609e99d9863e5a372343a32fd2b5ed5bdf1a975be9c4a0154ff7a6c19434c1d620f43fcc1d0d981cb431b9dce3a736a7801257a2fbd2942acb84165361911c14b12b0ae040d3a415618c189e8527c6211c3b944bfd0f9ed2139b5dba5f28cc31f5a53fca14b588e81e7890ab9d8a0bb318f0181f8a3053114a9d4eb9af45ea90bc8b8483702102078ccc571b175070cd7c3b9c6acaa0fb78bd97d5702db422887c804c9bdb8c3ee5fe8079d22764755a03a34038f618c9f60e4213876fcad6035bf682ad3da1dec09676eed73a6bd3772cb2264f2a3a13449a3617127ff45540b0f0decff5c6b39f315d1e7ed5855046945ba06e6faab3f7e5c02387fb86ec347bf5d814ef0768e95c943cdba439d88100ed8fd62797641e9d24dee478a57bf2dfcc5e08b9c6eeccf9cee917c5f2e54cde1ca6f2e2c87b3111752737adba138d516d0138d2e0045551f88a46188ba86e56b988026e41837673e0772ee3d4811006e46442c200e0592d241ac707ddd54274e0800fb09353d5328721f415971d46bf39d3ca1ebd5d64209551cbc6ca110ed77713ac3c3cce20fdcaf5db51b98a57df50516f2d828fe5af79144e5a1662ed0452c680d8512cb679ca800a93ca7a8e4c86fc3f2ed56366b9f606610dba3708aff4ebb04ed3aa55a321f37ee088d0550eaf4b069917e9b73b101802effa8a85e12c36944652c3ef043f016f2f2e9218886c2c3465f51afd5fef64f8e10ef5ac6096f28d21d5f27aab36229ba225ffe8b99a0865e55eb9a898b2d0c1178672fdc65be88b9d517cbeab15bc7af7909564dcc44445641533f3870c723cf74a1733605395dddfeede7348e3705d6dc6ce65d18fb5ae03d797e4e457a66c65e33431c718f69ba7a44f22cd0719c295e6783a53e491e5a56e76dbd476d0f05e958e7880288443ef93186afb182882af8c457fa06692e4c4363514d4c5dc187ff1c5c7ff6f063ffdd4bdd38a4447283bada0e763af7b77d833fac9b7dc29050c5bf0d13734008671924665b99defa52f10004b08aed00b925d8347b3a414ea4eddbb8409897a9f9ef393c9b71d7d279adde1a86273a2b211dc214412a353e2b1079367a00a3808bbec2fbba24c360a181a029f73587fd965cbde4159559eec13331e7088f4ca7badab877d27ab534d31322d3708e0816138300ba4dcdadcf46648347d0944cbb2277ac2acb82c0ca6ed74de76184c59a8dfac340bc5d423a068317a62852649b45c0678995dab18824697f101bf2f8cf89d1a2ed121dc992a832b6cd51498136f14caabec86fdab3237e41154f815d30c6341189710e54df9389ec1f67d6f5c62b338413f843975f91b05d2ea06da5a4579bf00742d0ba4071466c904cdee5eb927659ce1993e339ae38e659d32ad60a6b1e8d5caa1618afaca8a26e78e889978a2b5efa3de17c6a4210ae69e233ebd98e6538701d8aeeb1e1d9f85c135a9bd0b031a829df97137100d1605a33343822a7682cb6013ac388f39470655b711fc64dc4e58ff191a6b9b8a0e146d2d5b3551099e94abbd8be6344c2d49cb99f45c30ec64edc6312f2d382d3c708374cefc9a4787d4874c19198efb34ddd1d28ce27622d92998022922d2892719b2170d732bd0f8e0b6444e588932f3f8466ccc78c4ff4541a7a7c4775c0119417c56368923ba8bdd309b9716d7e04562d349777d88c2caccbcca095d56fdaa0972b8b4f6ef12c44f783031628c5a1b1125ce7697ec8fa2b317eac80edd2736c8cd3de837ccdf10b25f14a801abc3aeaf765a50bdcbc1bedd265fd0fb3c6560b3154854f24a9cb520602c0a69298053a76d665ee84884cc82b9e9bcf8b30647649df3127d174c8829930c9d1690df038a06021f36b6071f1975319f2eb355b34463c1cdce6a0014ec1a58df22bda71f7071ecadebd616c080093be5cf2ed6bb70005753c62545136d74fcba5bd86b56a6c04a3c0caffd454ef0674d7bf8a31793648c7f9b54634fe0d41c74a7740547f22f0cb846d6d83e58466ebbeccde960e223d393695e222a3340f475e51a738a16381714213ba14772294e2c0017f271ab1316462be6169d094e6d01f8fd08851bee84722ee8942b915597d4921114e1add1771eb11a6bd079f5684b15f329079530ca940e4b619de50de4b6df31daeecbf5d0842cc6e7cde591b29312f636624c7b68d9ebefa3fc3c5ae183e44213108332d80f366b4b3f33e297e26e52ca04f61ba096d59e7eecc0d89e46eb385f9098b4290a34275ead01f7cde540f48d8f19c1ec81f61098cf4cad670141d4a627a4b0369bc09936ef21a6558463cebc3bd96c80fa27b8616b7a52c8f59041c8a6234a4334d942da148b2d7489111638a82afdfede5b2fab83f3a1919a4bd316ec7827b6cbeb6f10a57a3a5eee5593994fa38d4ab34d645452eb0bed12f7e3436de71c25ce8e8fdf154144255387ecb4fbf8793a0075b9a06e246a642481c4c6c8bff9ca3bb84e4cf364baa064828154c4865e6683087a1093e2c66e850c604467b3b464dbb3cb13ed7b008aacd1e3fae317f2b4d1adb6ea30039f899403ef7862b10e28fd37425a844fae96514b9cb6e9e0e35e563896a98878278643fd1a06219c887c5e8ac96d07863b0672ea489b950732cdf448bf48292848067cfad5cb66dea9c307bdad307b9a4fa35b140fa2c28eb0828a35946723b0658b187b56f35e408d2d4321206975e58a66830a03d8efd0aa42f5767554cfba6e3422a98b95e32711c11ea6b8ef324674472b4ac95ca266c9a0c231e8ab21169158221900b79d15c45903c67073df1bc68ac585e09e93be7089b609678257cd91e575c924b466091390066fca22890b27e7493dc54c340155ba25e639f52e7fc349a0c09b7fcd86a97a9879bca4eec92b84a8b04754ea4c8f3a7e5b3472270f67bf42fcd130f7c489d9beec5b613b76386a7fc009e5a06fe152765e5ecea42455770edc9a2ca94cc700d488f13bc85c21c1242ad59e09cbba190fa83ccf0cc1566b52d68ef6ee6e60d062152478ddabe370778b5d6ca0ef454097e43145fc1536c2f2e35086a9f182a62cc63a6313ba1412fe428f68e883c12d5f5b84ca8029dd2319db1a9ee01701daaf78a1eea412f27720d8fc7f2cfcc5ad25dd1afb08848d0b1ef41474799ddce8035f8059098e8aa2022940c0279b040e694c796e46109406eb992b294fff9b95abdc3a3b6d69d9fb50c474111bfdb73e6026f7270bbdfc64fd06b609ffb672e18e4c7cbc06f4d51b9da383e23c0831c722cb8a6960b446dd1f4b1855bc8bedaf82cc202c4d25a1accf7ce561f8d40a94b7b1d397500ad811e2066e5867f359c8fc98d932c081bb898d4c470cbfb8d19bd387a11216c3604392f00dd5ecba0ce0107da0a7e669e20f8420e9459f01ce2004c2fd4b2b2da1c1e449af8cc451ffe811687ff02333680b776c35a01a16e5ae5ca897d2dbe02666dfc2f9272b2b3d557afcc971190a4e71a19ec15cf861e26f2852683bb5660a29dfd980b40e1e0a9668b6a108749fd79dd8e85b717e2ef24fa91f8b9ca66c3b7572bfc4a879750edb5807361f6a9773d567ee8968fbd5379a49887c1a87d7da2c4f15854bf7d4ae799514ed20b6dd2b64a3a63b6657b471a664f0537e52665f56a1d92bedcbe3ed7d913af05afa5abb2b327dd2abcb60e4a9da6f51409058d5d971511550be585887b0f3a25b5536612dcb863b9e6d87cf62f9722740c00b3548aca96c2a71e1d9ef215712ed4759d12826f190af909c526cc60dc629824ed2ec1545860cf8f4cdd60840daab881ef19758173a672c01d0a05370b5c4cd3872152669f7c4924d3031b765acea33b4aca0b79a6f1512edeedf28564e1f38424de4b6a1e975dc1c418c0422d324e91268291ad14800cabbf23bf92c101159210f7efc764398db7c036e5da3c9ac2ee26abbaac8cc6f2e4ee8425c8431692cb0c400f951b58dbc98c18161098d47bc9049f72d5c1bc6f22d02203bb54c0c6f5a30af28501563ac3e9cf0ffa88b6364a2c74d555883e8837e3c9eda0e613e4495668df97a7924fd8c07fbb5c0267b3ae03c05a118aeb4cd6f936a669fd0e30815d3e915efe3cfccf35011f8da5c9e36cab3c16f7f4279ae70572382a809a9a3db7657d014eb3e07f681a8805a6641ba6464a3435ae47dc69a54e2aada0fcd535555a4799ebd526687591d53d0e9cbe1afb09af09b968c42d8ebe68e8680ea68181e8ba67b7fcbd955f3702cb9c666ecaf6dd6c16de9ae148b2bd4bb63919d80945d792cbda969bc661ba5efcfa8ce3dc0685e43cf31e8bd68234ded8bf7c999b05b5aff00bafcc0dc0875b96758ce3204c7d85d871cc39cb32194dc3fc31793e50e7e4e6b031d8f9732ba681636a9bd25a18086004048ea9faf661e90fea0c1417583b1d4f02b7486e73d183e16fb3b9b025599ed29c989962505949fa94f2f22eacb7a02bb0428cd00ff224ac750144cfc5dd629f0964471b67223a29b5d6fd7ab67ad3585286d174c1401fa3fb10ccea6c9ca1b433eab9b788ac49bd971c98af89461da85e3bf11733660f8051ee029a543a6482b1959e41ba915b7cc8f3f3240c7711a2c3a8fb2e573593d1e115c8e0532a1572006cbb53f73b88c87185e465b775cccf03001275e54c5bf226affcfcc0ca2d3bd45b38d2d516da94d4ec9a7d6637d22ea7180d83051071178b96f1b191b15e0fd2982804d78fda225636a186f3126cf3b428cd23364bdd662e68cc29e66c25e8aa6bf35892d1d578e4802666a46a275d2e213eed0a061498c329ee5953b0c1c690ae812d6bfb66f8550829e4faa9e86c3bd64e5238ee14e1332b1d6777ef048298f0f4ae017fa9fbaae34223a520f862bf8aa7cb253b8ddfdc23fe3f48553fba8df1002cf43c2253d787598f87a7685dfa12a9979b484d1c44a0bced2c123e1c4fd669b3ac646747c84abf63cc386840920aab003478b80193c03ffb31f3b49a46b17264ab1d7522563102bd0a0388b55bfd4ba74f68d9c7f5e74ed702df459abb7f28155f3c2ecdc9662d0a06ac6510516429a0744c57eface8fba0b08fa18085ea81831877605d4620c680178aa5802d17f44baf29b64ce0cd2bb2fcbd59ae35db33c8728510883ec4ff063e364c681f719c9ae097afef4ad6bf92dd856a3091d37a21bc9f596cb1455cce0d24f0d69c033ccb00d2be49eb95868f496423837aa724f768ed479db1a917ad16b1c09c64550177be131858a7c70cc1d187fee56f0831fdaccd211414020a300e8093998452b1c6a5d11162091a22f03df6f6e0a8cd2a49c54e98132568b7f2274a3b08a1394bca8d046c8d7dbfda154ca0e9a0f9f683f099b75de6dbac4bbe55b31dca3cc37fd67481bdd70c1247890c1be512922ba4e4475cecb6a3ada4b74d2f05b501af8018e9077a8370e7e2da4cac1e59070f17a12785640a3fe0d4fa284551265ea68fa4f9a0cbd375a088b5dd05c1b40358bb38f1a2565041cee5e837391efd2e76a219b875e07ae0aab8ce94249d171b6fe18a4b64224be09104cd52c2174c06f8ffddbe73f4770a13a1141178565bdcfbdbe8c766ceb8e82a78e3c39a3894d8fa3cdd6fea9a7151f17e3a176fc03a478e4911f7d0a5a1090eb09d140c0bbecc8ea8e6c5f19c7eec4b1c29a5a8c0704516131706888c8245e704e6a5c1f312d0ac2f3132d50a04784a0027117e7f1c17fd8a3740560723d0e413976b1ebd12cc9f07e8dac5278ef752ff77c99e432af351a022965677bb9fd484fa0472ac19e2b636653071b6887744758c6ee55c8fed328178357d6e9e867f03c9262e2c037df20f0d302485bb612089f47382f4a897bfd6098d6904399952a71630ee68d7a729af62157e509fa7112eb76ae086494b3a3383b7627f624e1f2c6579d2248f0e56af2c660718b02b82903b910d897a26c87e5c4e5f8c440c2b6f668600358082c3101316dcced2fb6ae466e56f4dcc806b3791b68019ccbffe4299461e0aefd069e4c838d8cc4d34583474e09214236b85be4962f5279704e2323679669dd6c1f8e45df510a1438a50e40c57a4f8d6c9a17304c1bec996533a366c344f0dfc2efa61625f1869a595ed6f0d220156b5f68982abfdc9c61a97b143a4b6ecbdd33d2766d07d6d1186a63e33376602dda0139988c8368e27ec299143595e28d32b06de2f6ed15a8b6208b52b7c89207d0aabb55cfc459091c9a5cedfd2c4921f3d0da32a925c44b63602a93763ba1ea56316ad8c8dcf78aef532e43ba9163feaa8b156bc2b096fade5f9912c4c5a2c1e7acffe1eaf6fbb9655db0e4b1b144904b3842d7a925a014abe713773fca3f85486fc2e2bda52cba4934d58a1df80953fa543bee4812f2b027f3c169f27023ca0ff1fb8e954bebf9b3974d7b0206de4dc5e61dd1ce60af53ef1eebde200eb42cf3461c7c17fb2650035f9edbd4b638ec133718ce05d34944f45991e36b8af5bb5c48c3a2c1d73703928908554c96a6617155d48ec0a221839da6a40e1b6058b17dfd9df1f783f3dde7829a1777e208fc0d0e3c129aee46ffe6f741a1a9688ac01685f916baac36ddaeb719347c78474d8facbb5431d94e6653b50341227d6fbf26d64867f1a0377adc6e6b54581d5954fde6057b6ffa57f4ccf2dd84c7e7411befc083fec9684032823587ad1e48491ed22cd21b9acb8fb206508cdd001497d18ed1609d8b812e370b7bc96c51a3b71f3a4824e6de431b441922f563aa9dea4dfee6c69d21da5b75f3c681803e72e8166f2d1ca999336e24d64ab757260b5d851475a153ffb18031ac0507e3fb6a3d43f8d48c78dd424ca2589484747dbfa26a0402f85c0caf262d6f192fa4e882e48aae7c5d45a80d3efb37857af39126766aed02731743fd247048d0985f0d55cce87c8d5e3de657c47d689019dc0243c743c59e517f3e8d37db0319a7000ecd5d06e8a30091a671c6c083793317ffa1a85c2410df981001b92157475c9629d21e8f5e08fb2760e01005c7fea31135715caaa8c09d4d2ca79d890c7ad16b9edc25d96afde5b8614209ab54059641bae23f46758e067294d35ad81ad1f9dd1841c5fdf5adaeb6d5fcb4207ed6e3d80234122e6672e5bc91be0173766f573fe57e75e64a44b8f7a8a7d96fa803290af6b57808863c1c557e30a46f6dd9c4f7dfb0fa36db69460a7da5dae76e9ae8bd706f2c9d0903676569a845a21a5c335114b15d00a488b020c073ef8d5dd3902a612c0c4deab22057d5486851b264d08028069a95bf6fe65fff35a106c212e08b65fb0c33c6ec88d8ee69da0ced5b79e1faf5d0c65bb863a8da67ee56ca477e27de7c29c0cbb53c403432070bbebac8915cff424167227965fbf8bc26a59f11c34f663edf8914b91f30165a20053cb96e804aa5bf5d1bd0a81197ad073dc09ad929febfabc48e3981c3d8858a682773146d420e2f961d4616c95df2afe14f555093fb958fb8e45db2486893b3916e3e274c0d120e32f511d453cc0c5ae234f4e34d8d6eddfe92f544195c32a727085bf6f1bededd16eb0d2ad5be02387e19f8cb77415acd225478c163493db1d01d5e6228cd1b03b3d3adb4dae0704443a1033771129280863777a12855d517c631471106cfb8a77388d72dc98e4da9ec13a6897b076c756f37fb79f6727e82bd2009e0ef126a97794fbd43998f3320ee7de52875aac6cce7e92d89c6d80c5834f5a7a07d01e05acae3be692f8809c1cba9174b3b76392e413c6c48f4481658135a598020ac8c6465e5480c3565e0e1471ed4dca3968e0d302ad5e1ee7981e11746110673e107684b0f74069c18a4de738131fa4c00828e604020a522a5fb45bd1004fcd8a64879e7975c981ebbfcb1fef3a93f1453189a5599fb3b1d7b5e942978347e3eb3744465d5a74278d2b69088b02c850734700a6f7839ee6c701b1c247b33e8565d41084628665a4c05e0d20c96aa7953731b181afc43d190c3ef9be5052bef2e71d53649bae9643e5dfad55f7da8c9d5a200f5108818b40ac95a02781e325423c2107592f7e62a39d2c95a7bc42ae8e149fff6f5f5ac8bb6c10cce3cab8021f2f1d53c68927a509b0cc66092ebfcdedb9539f2b5fc576d78bb8344bc44aa21607a8384ad490aad9ff41b9b7b9daad71248342bf917eb16f919c1871ae5eab1c02d5ecf0ed0d779c27b1811e0469b76cad0db0afb665f2f283cf23badc78c73122a4619003713e01ecc5bfc83e04e49678d3aa6786faa4ebf07cf89ca844f1777f2389710761bcc64f90101a6c1f58dfd58573106c4e656cdfc430632e99ad7e6528cd2ffb794b3e320fe1d40b7593308081bcbcc3d260fb96576cfe08becde68e6cdefb40f196e42e179b5b74b9d0c0d522e9dd511ee94a9e940e86b8a08fd5b90400ac4f07fda9acbc288db5f5d2aca0d4cd4c4d73e3a221782585a65b36f184d1b322de65d1a79baecdd1667c587f7a2882acc5eedaeff53205799125cf7f379dd04384a417e92aaf1514566593dcf0c32d6becfc740dc486d1fea688e140e09881c66823e0b1d8b2d5110945c442a114aa797baa4a429e38d1dd7eedbaf10187da8fd284f7351b16902510c2eb725cb9fc651626764edd3ec381845b9abc9c588415e23d9ec37446539c804a48989a851174cf1dd24b0131d6a374e08c4626a024dca285322a86c41e026c3b75469382b40b4cfce0510d6e385d0cabbeea561c212af9910b538b0b6e71b532c3070186d5dc30293a131c28b01252f01b7043fb455bf9c656bbc58c72d1a7c9a68a19fc35bed006f36b012c84ec91f900cbec1ce809800df86bc090f3abed42f6cae2841b812a31bc8b5562a127e5659ab8bb946c99d5b8969d156fb9ce3cc3a86e00fc0d45284a84a4d67efd55a0548e8ec9447b460e8e1a444bdbd1e55ffab84b4924f3d05f41a73b3d8d7aa87f324ac1d441a2dc48639e20c3a71527a3ce6c4290b091d1ebdca66f7b9f9c7365fd7f33472144a5dd0ea5b312372bad0b52da50bbc12a0d9c0f9ccd61edf19e9bdb878214048eeb86d6dd421a8762613206b00c5eb1446b582313b9148ed04e6d9738609efd6d9c4bb80795aeb8b5be7fc78a9bf43d4f20eec78f07eae2a07be4ad15bb709599c56434048e1268301f557f8114df0767aebec0989e86a4c70161cc2b841763d799bfb6d1d855423314fb6502981e66e57d9b75f34520dd99cc4ef38fe674e03789dcb36d67f4c72b7f914732d2a095aaa714c94795a9c507b38a7b42f59c831e3371c59f33fec31c0d023921a69a225c0819501637d72d84d085de53ffa383e5b80d7f5ed1d80361ae8a37909cf0421f0dc256ed551f3ded807ecfe0b2603c2b800c777a1b7595ccf44327cd60fa85b360b4bf0888e6779900191c9b91acb0e6471a2f7c4c74636468fc2886da60d677cb01dddad218d996e64c3b96fbe544c0e7266f9f02a19cd4bd8d4adcd85a651927c556f3aa71ce869a8d7cc7c8e4d7e466afaf4d7489b8f938a1315608f4c926115968079c0c62b0355af39a84a2d7364f687768d7ae755ce39ae0e49533c488ce1ff096a214e7da7c86257fc7f9576226addf183dd4a826e10279a84e8b5d5c9e0b092de943644848f19ebbfc2c687a27158f5e1586685f5366836552b28f1ed127cc1c0f40b23204da9ac9408d0643a5360624e417f0e6d999e6ceaf591d705a1b93f3119d0e063f6765af16cfd4c2c6510cfd0fb2faf972a2837fe4070914da6e7b0daa2ba49f5dcebdaad8c8119fa47743f871ef8205dde8aab7c8596b717d0ea98b6e52fe18c37c7c3f6a7db2188cea6ebc3c00d9d224d609746398af04a045bae2a004c1916a566a055c6a7ada20f35b95dea6ae3e2b18a3057462f8cb76e000e344c129e687761b261e7e5228a1b3d10d1a0a463d378317a44bd15b7b0b500002a8a26184f84aed5796323dec35cf5c6ec50176be0852115a17bf8ba31725bb5bc32edc98722c87c7abd808af88b73306e6566c221e0a46c57bc1de89f41635e623f8513810deefac2a43c2182d9230c014e5fb0892a000335308acb63817dee5524b60ef0a77ae610343126b8392538d6320bb271638556bba9476a068a9c5ddae7ca2b6f6383e8d0e12929a2e446acaed5f944d08165a26cf9e0f331532da9720e56511033585c27eab771d49c4d534cb68720d9f6dfeb7f101fc32f08de7d4297f89f87b14b1c08baaabc648de7a6784a224280cb11165a1872fde86f6fd7f580a2643ebae60585b57bb3c290133dc978fee402a9b7921d20426baf207a6a154aa59046ea2b58fe4d908d1f99ff33f1d7676c2a63a2b7325d73192ce4b394b0a9c32d0bc57540d29a943781335f06b633238c666da0018abe30831c8c5acb46149b3dd3f6e348546433a157fab4f1df1afcafb9ead5159d6b8c6dcf03d0c36aaad2346eb1e764c8d6016735c3a692cb8c3fe2b8cf8414b95cff4b710d0b6be420c3f640ead1a8f567a482e86d4c059f7660a55494999db1bf9fe91d835698f90fce374b755db4ae6a26cefe81f1a62c38375e56e5224a815e468252a89b77683bcbf997e0216228d331f6157cf6e3ed651ebab79da0a5bdd59b2da031963fe47488b4c34865c62a4f0cb79e01504d38accc26621ecfe636a1b0760f39615cf2d0a8b4c4449ec3036ae8c29cecdfe191541e0312ce36e6601184e94cdc62792fad8d9390d4de53df47194e763a3ddec1d32b9cb1e578ef867c51c147d55e10c94ff218033e2e01793753dc00c4d644817642616033133d5cff1e0944579c02cd216e17855868311d85b8c10c113ae16432d660966e2b13acfb22cefad7a454788e763ab5e96b9cb5a7abcf8915f536cb6c56a22c2247485d2781aa31bad3168f38cf328fa5fb9ee2b21d10c8c194bc08b7383b2c7e852e9f361d629036c33389da2221a449974c0385db23cb249dbc8c16ba58d6b6fc59fc6df2dbb44335fe75c0d511aadca5f9ac425bc94669b35432ec74250c7002a172d2794fa9d9c5b4c663ce8a1ef209b7f5f3a1cd63ae345d580b8106732f9784ab84aea566cb9bb203b75f977811dd299db51e9999c8b7d9eafae1b5d9203ff52acc9de44f69d7ff034fee3601ce68f88983d1a53a92716195f9315f08f02c54cb9cfe211ca4006eb8949c85258d0c2ae54ba46cd8d448500914b220668a738bdd1f4e5e1bf35e0f7d4068d7345361a50c8a9ae992aca112da22a68c78307f32823ecbab55490633a394c04ce90b1c19c9cc114c7a272de2d56e057bb8d83992526b9e12394a6a6405259471f1ef51fa15065bae39d18c3685a2c49a544e1a443a31c0f8a647c8431e75f9bd86a09ce509e79358a254fd76c078ff8b1dbfb362a9e9eff8297e4436c816bae1aeacd09b47848d33fb291e8e1f3ca710e455c5b493df008a793fcad927de663b621f482e09d710caf50427a538bf4d500c2d8d60a1b3c5bbd36b49d1a02cbc716f2b20a5f6d15352104c505c3d12096608d45b89b5e2db7fd11ee3846f44a8ede1a95e5e4af232184e5cf4b45204f134c79b3794c71a08bb810a097d23c47222b8735a9f64e5085199cd7ba4a1285ee91d2e7efecfca4332eb034a5544543dcf4846a2a34e00bbce02a891a72fc1dcc22133adc02188f0b427ee3a019620aaa59b261d036aee9cd729db584a904ad7d51eb9fe270d07d781d905782df4bb65cf99088db17c68ebd46883f8a01e9a0388363240de83290993e0fd1d75f02a029eb5f2d3633de540c254dc401e46e38bad92bcee27720cf4931b8f080864898c71139852cc77a36c31413460eb8195659d0f229b7ca049d417c7a80b35ab87b8601a242a1c37fd2b4ce9e12db5b88d876bd0a8c9e56b50ae8de7a2d574d9ee3e6896cdb1709afa2204afde85e4fdd452fb07210cdff6f06ff8fa6a26e9dfce01d0a255db4dca10a7982c34edb468b38c39ee0cd6b7650f301bc4657fcb094d32ae7a0c9527c081722a35875bb2ed6bcd25bf504ead9f826e1920324fa742e3841947069f5501c84c9830e3da96597f4474fa7e76fc4452ba36a931f5c584677ed7cb5fed0886aaf8dd0132883de240ebd40592c53cf3de05396db3a637432ae5d175ff55fb2643783a273499818cac19774f97fb22de169e93c877a5ef54d3c209bdaffca5915ebcac68aefb8c544045f51fd3e6502d1003390b2d130b0d1e530fff2dfaa3e08cb1441131fa9f981e5cb1230df2138785395094563aec145e30acd2ade5749634fff8f1515811b879de98b9d6ed283e3579810606f33cad2e8a6be0290b971a4d75ed30cc72ddd2c92f43a5feee8efc82f49c810dde1e6188c0ab3b6e57fe5ba06d73e935b57666fc98b29f09445999835c3052abd3d38d930033fa7b017c0f80e5371f32a11876370c1e8c6653125eeab8ed96eeee94402d45810b74bf4b395e7b108b6bc454dc092a5e0b817e5209918ec9a26feeee3c833192866166f8506a560a407a55d4bb2443dc6626b40e6731b58aab7b443ddd1b715bce76b939ec788194bb2c3664212554401603e97c1a2859c2d03cc9c170092e0553d95ee331ef09e64c6922511bf402bf1e2b0036f95a665c58ab54fd560dca45b2d45a957df990f6d139e900af15b57669dd015b89a9126072733f525c6f934176aa305112c422950daa4200210897e91e27fc8adf59f2a25ffd86be6b6de436d1b0e7d2166a04a9423f20c46d343d24c13428305e502c2fe101ead0ebc386a1d94ff236f3dad173d881e43cc7face83567afa4491e2c53118042c3d1882c775736e6ef7896f39419b836efcc15032fdf280fcfc8998aebf5f2b23bb21f8a7446dfb6151a7d6d8148e7b1deed8bcf90543bf6934c5572ae1b6aec147775ecbbbc25e66c7970840ec7c8de512d8f254b681f7ae0d751aa5367c63ec2cfe7521974bca0e67025c9e31682f060bbba8870ecdafae989d5ad619464b228f166a36f8adaae21dc835eff2fbca69ce41c509a89818611d97ec977074b59e2a901ae6fc51e8f6c8848bf4061e1d937dd54f92d0bf00d095a9946000fa40c6ccb9e111302af981caa5489464b0437f2187c0757ce2138e1de0ed0325e7c7d16c187999a2d39089725e58037b696f036f41d8fee6772884867474d11e8632603269147580e38f0da7d714cf3030ff50dfd03fb3c027d5931d9d33ce3e5d6e5324af03c65b3aa285bb42ccfcc75501f110be2a14c23dc068e805877afe6833e21db6bd608253e6038dd335b152b0c70bd453ca5a22ca355faa5f325aa9b9ef68f0a62fe5fc24c77eb0fb8ea29bd2adf2de77c1b19317c8325ab72417aacb7dfa2ab064ef297d0035b02e6ce635cd11b08fa25d649c230cfbff1459641c997fda5e5da6750ae34c0dc4d5db9e538bd728f05e6560aab66953e96f07a332c306ee9109c5220edce03a22d6792ed9b0b288c263ca00c6a8d0be80f3682b75c109c708e2c6ac8839d5d3d958947e5f888ec1b8113b6470ccf3df07f15ed2f094fd8ebd379e856394da2fb1f50e0c303c544372401a88dd5d2301396e67e9f7e798cd47ea49135008505c5649846b8a9420dd394562a489b060809ea64d3704680107f88f1c92608e0a6390021c44b99efb2c8d606bae29599191d0d463c20f2d6e01b1b295d5a1c98b5a104478d92e50b0a5bb1b97b9c332751a3d37f0a19c6342a4cf915076a6503f7ac7737a8dd5423c4c77a10784ca3ef4b4d60176db485d2caaa848396a3fce5041d56b6da457f7af51f82d750a023ef293711abfb57da0f05fbcfcf240ddafb230f3456f2e8203f82e440a53816cfb92a2d93366876d3480b854ad221d3c8ff2861667fd4ec31897552573ea6d1672fb7051c4256e69974545084462c85506ff4b217c633234b94bac9be34f923241f78e36d1c1de348ee01920ba7fe1f40a0201c91bd4484a00ff070833a1668a10fbb0fca588773cd842471181c69d01ac2f0ddd181eec180673732074728f16e2e6a24112be0b7edabb07c2b5f74fc9f361a43c1f0802d68c6c80f369fb2b607edffda3433935ad2159818ae630238cb630c9d1ab111e4f38bd31cec4f4316c40dda9df80481cae19e610259986e9c582a43468f306e2cab755ba23dc1ef97ce09bf6afaf509c49f54cd7c68f7c6c57e0caedf66cef0f58f6bb709a15f62b89321448a78673d8f8b16f1c2ce51560c1d771d9fa65c1b3e1c8c748fbee98477fd9bef69caae4c6113d02c73f18fe539736f4576e67b0bd3f330af5395eea4f9ebb136e1cf369283b53e2cb428c0781bf14c6fa62a60e4feb2f19318b8f5d95c5f93e5972a9803f33b21a858f617a61d9f954d30aae1af233c32c5c10a23b41c7a92a45aafe96bf563c70a96afcedd56712c978761c237638eec24f1fdcefc05bd0b26ed45c112ed5ffd4e54801f90d535622237b7678ad3b6fc609f90343a2545549288ab2b90e94a12b9188d4b4af28afdf260b4e03d25c5102ba80db1cd6fdebe931bfbc7dfabd389edea067688cf99fcac7676af8ce5aa615b4292ef784d14f2c9ccff4d79ace22042b0675f136565dc0f9178164b78e9eb6066678080c32662ffc12678d1d63cd884887bc08ac6086b944e7bd9511c443e8d821d909933344462ad198a278952ceec08be29b24d282ccf5477d0b30cb086a8617f3ba928635734a321902d8e68715eb5d1fc57acc9fc12a028a51b62a9e672e4b384d15c68c8e157b749fea4796714e75f0491085f81569d7e3cd2eeb2748c4a4d8c96572b872bce08ca312f84b7ab6405cce0d79c380c084888ea10096f60ff88e7741ce8e4ebbf62fe0df55108c854f2d8ad5ac45dc0332a521491f7cf43a7d3fa260c188b31e73549865beb2c0eb03e79bfb5bac88f84f2b6a11ca91227470c630e0c6ce4f4aa27f65984443003c1c2d2b716235a906907e8dc1ff7d77f751f0637621d0b143b2e2ad36b8fa26914b3e14764141b13d36609f29eb184cb92248acba7028b025ad909c9720a6bce18b92486f3f495d4c2af7698227223bfed83e592a2852e14d24f1d3e8eba6ccfc6d00a288b7d0952050988f61b3f1e995f8f8a0f1bbf603bfd111d34973b610b0ed618e2314880ec1c5356b6cc71190704021706250b55cc1baf33ce9fbec0894db83ceb8855cf4cebf58c60cffb8c100c21e6b02633c192103cc86704f60fcb8e9b3b5ba95f9cb85287763170d081992a33853c6bac168144158e08587e46e2542aeb19f914327d020167a43742b0a004f7a316cc65b3e853c7b5855633acae6d85c95a0b30b209a37d9d8c888de63f41a07b7f5b2947947790110fb346643971c86a1ea7662e66288a7ed39c4c22257b772454e9390a94081595fcfc2f372d26a526ccacf667a6e3115d300ee50dc23cd915020a8a8f14173c29bc8a4ad2c9e20a2be2aef818d9806e8c86d9e8cb8ccd55d5581ec24ad6e05e8167353718949089208152cdc32b5e8deaf804245a7ce71c42861f6e580c15f3928b1761679f33ca259a83cb6065b5ec8cdfee5a985c974020517d4d83214a6038623dfff8148dca270f243ebf8f84fe34fe26fc2baddacda6083407882de737fc575cf8241322c1cf107e59040f1e7b1a38cf1b3cc99b15167930cd517fa85bbade84daeb3e9f5345a493181d09ce8c580cedc165c8a50059d0773ecff30642c6e69bd9b54d37cf13429d24ac24541682ce146c4d8d3114d604abfa88b547631f20a19a0efa2e31a80a5b63b16a518c3c459ed61ca802d195fb06e0acee2eb8b3cdd2701d5bea775c74741fe36480e3abcfe41cc236077c0e7545b7d24b37babb1e4927b4140e2783fcfc6b8632bef7a78e9f068c23a8651acf2d5836131d6914f2c32f846fdaab46c746401fa41a441b9d51a0998e6f9a46a36d7cc63430ebcdb0576c06c8cf6b35f56d60f40f1916e352ed5f578f434204a59f3d30aec651a5f0bb503fadc3296ec264e1a12c1978778e87b026dcfe5b4f6cf772dc737d69e88cacc3eb391f3e613a61616c2f2d4b2e09e3a743f8dfebeef34901029b3482c9c670e90c724f0e5ba685a2e4b41be76e31eb17e881498bddabf5f0d3babc0a9588d28281f02339ede2825c5af131446798350200b4757a0cadedc65b5b12782ac339de77e82ae67cb0660b640013f375ca5bcd9d9032ba5703883e1a1cd85b74bb6c2a7a72e5c308c70bb55ffda0268127be052b0f88744e658470035e1aecfb2294c631d1f940d4013a1590036685652b3d2715a1398f00b973160b0e402a61765e5998cfc314f201cc8e7c2dc8a05e5629dfc6ba40c30d22771f4933dd59d5e6ed413036837c4d4380d68ff813a32816936d8988c7c1861f06a40e12f5918a8d9f9984da9f10a31803145dab15810c34517b6877f2a95fb0de14c00275f217bd76abe5b41f37c5543cd45a3a960ec909d67b357c3a78c1c643b61be43b4866adc0e3e93cfebda8e2254955b3b462948146d232998d2f4f13c4a7a180e5a127a5a819df940b97cce016fa988d44a6a1fef072ac78ffbe865333f5a8d7732696e06c3b803fada70c41793b2bf1fa5a5afe516dd53d43786d2a63f714ef46b216be76da5a93e15064f91afc568273ca2c6d41bd9bd7d58b476364fa804b65469845d9ad7e380316ecd7f10cab7fb945054b337c6488024703f6a51dc4dfb0327b0906fc7ea11799b470d427e4c7dbcd3e7f615f42d012a92494af14c44a6723f44f99004053121a84a5b1407f37770b48fc293563ee4869881d0d3702a5afb7e83505c0f65ecebc537860ca08e0ff8d005c1ff61646cabda387e082270a6b48499f27d9b8323e9b837d9d48df6d178ac3b49bc90a991bc63707e10c6c67ebc77924972ea9320f960d899fbfc3da3d0acf9e5e94bb6a9d2523d11f097d5076805f9c8975564d581bd46e9ae89ac40aab1e634239269892e45c1fdd5faac9906e24e755a1d98219db92d003614223772dae5bb713a98da17e0f3dd7ecf8fb2ac2e65d2c25b020ebc7e7d51013a194d5c9db104754d2e5f256541ef16dad86738c4844aacade44b8348af5e1f7f1db0ec63030d4249d018ea91dedc32857fca80bffa71144cc7d8e53274e4b08e4912700424f2e5e158fe7fb3ceb9b589dee206b3a8a12a594057854084d3ebf9ebf9b3a41294f5478ab95c073e551e9feb41becf7a38cfd1a20b8a97dd4408f9514e55674e827a5012cc1d92802f331399696a6bba778be51d9e88a4d56b67b7ac4105fc4951ba297ba4ca957da342ad2bd89605b5be961b80971c047c62952203e1f33ddd99e44c5d96bf09aed2cc1733257976acdcb7d095430fa576c84d52ec78b4ced41af144a51dbe01cf0223c9027a0170cd5ada1c052991361aca7fe097d8ed76e0d3af59e6bdd4a0048de7481a0e14ab14c1c78fb10891ce8bcac052353d8a3418b216ad2665ee0ccfe74483aaca0e959c2bbd2d13bfff96d5975c0c845840d14f0019a664d4f58508e58cf0183437882049ce836db175f911bd4e84362ac5cd32b13fa16d02697b72bfa092513dcd5d853f8cc21579f5d8780e15fbb1b464e874faa12393e8b620f418fcf6faa66341585bd6257944eb69432a594529252cabe04be04d904734ba837269895af13522d6a2af0afd85bc73077bf200d71efbdf7de5b672006c65503bb61ac7a9d09ab97bcaccdc1179b0dd77151a7a9c44c960663be701046b8dc410d4aa614ef451c9cc72cfb2a02026689fbeebbefeda5c3d118e3da77df5da4450c1cc7ca0feba7a825b983c4640ae614732180ca9a3d31bdf7de7922315f39e7bcb9ee5ec39e1f89c939e79c338f999173ce1552b8def556afec9ec95a6b8df3c6e67565e59cf7dd8463e2bd9bc3d438e79c73ce9d73def79a3f79ce91de5aeb9c73ce324132466ff60573ce3fde39e77deba61b268ba354434ee49c30a79973de7be7bcf1ad75938e30e79c29d071ce3dcf6e9733872587cb0b476bc36b91634768d078cb30768443518b1391745efce64819a1d842f461f3d6d2c1a3c6a605a66346c852d751a36469726c587a94e5cbfb919b2fef1ec3847a451c8ccd4b966defbd572c168720ea14ac1a429959c0f5a2c9c70495133c46abab9f97a898a10c61303020bdf1ac7b534f7dfcbbee1feaac7937daa13ec6bec288b92eeccfb7abdd5ffadfad027f1f08659f1bf479b3b20a7175a1054520dc60a471686a0aeeaaba2825115a53382c3abbbf27e577e79a73cfbfcb3907698b46dc729eaa459c6b9cc5943cb4d67e648b55752ecabbf725ac513113dd4dc2e49eb96c3c72cfc7cee022fc73de23f04db4aa27175bb21e481ff2ca4aa6ec4845ceac3cefebeee0910e3747d9d18eeb4865f7cc33cf4d9ecbd5f4eaef5bd167c65d5b21a531d46c5f79f7236345beee3ce0179ac84eb45eff2f1ba621278c0db1acf8cb8c409114fd39e06084acc87ffefbe7af57adc586affe3ebdca18aa78752e7b7bf5ffcd603339ab1b362e2988c114ec2cd96230452db105f516e1c0eced4c78363c83c15feb262e1f19cd013222e3eb84d3abbf4fff9ffe0510d10a10e1818cc838727d696dea43723f676b2270ef8a095711f58a659fbc4bceebc4cba59f47ace66ab0651a727e31f3085833ff2f8f250c3de27594f2235f43641f092b26e911aee64f9b5c18d918286224bd2f8da7c27bdfb35ef3944f7bef9e999b184a276baf3c2379a0eea71961d249d32624d0ce66a489987afe00a0880238401a2929601de318bae7a85b4900766dd71db8edcfee95f339a387dc9a479592f7e2830aab87d2218131311610c08e2252e26c2c5f004535d9dadcda36eec813b269ce641cac0de5ae0dcbaf3f0ffc1f08576ce934ec7e9cd0f1e727bf61c3eeddd6e102efe91459ed4e1d4b2286d4c594a4a9d10a66139a1b6a6f24d68282b9f7dd775771d6b90dc3df3f0ffc1f6883d8c32ce8de77bd77df989cb34951c856661d721ebbb321fdbcfb66cc6b3af5661eb79673ce435b8563e604f088c83967a90ebb680097aa0d87aa2905f74126cbcb841148650531e79c0969cfbb713658c85ee1bdd95cde8c7670e36d8c1723e7a837ebf4320722421678641b62df019c52d961cf31bd39e7138cece70544d31cd48d60464be1b4818886968c0c0d25d7f2e69cb3ebc115e79c73e0bd775dd7bbdebbbac2ca61e6dc094925859d0779ed1ca629e19f9c838ddb33937f8428aa21e7041e75d430566eefe4325f5d8629c16b8da2204888e0dd0f4635e4fce02c8c4fcfe3c6ea66d9fb6ccf3036bc0eefd61c738d32d75845d879905f7a2d3c8cc987c7fce43c673c6c3c723d273d2e3d343d3a1e01384551595e553d9b3945e910ea64e929860da69ca457fd7ce881efc994e3f27abc27130edc0b0d72deeff90476f5f2def3090c0a7d535bb0ebd09fffdc9fa7a7de72382b081efe2eef375455a445fd3fe655856a089dd9688d669fe354aba9d6d1094e1e0d719486b012c7175441234a9f125c6b3929aa749a01e7e7db419a3dc621e8ef784fa490165a52017faea4b5d6c91fa7d7dd114386902524e3f7a9b1d6c82586576bad35c61c89b5851432f192e0140c45613cbd9550956c9446b0098d6053b9400a8c969f61cad34a887129651bc0cadbbe27d2284680f7442eb35ede7b2285a80a60f2faf7441a9b183d518c80f7446695783dde13292444c3302acc00c74c35252dda7acefb88dc17bb76deb6f30dff4ef119a7290f0f6d73ddb00e86557d1706fecfe33dd7fbafa6fe9ae660783d3f32c7fc2af0970281dedde03d996a34f4135cbb2baf713f7a67b26be75c187abd9f07fe0f6c5a49289b10a1f75defdd1ac20f2d0e8f34abde94efa8618c90a562e94b91697e198d35717316c482328c194de588a95b4314fccf03ff0712bb8e048ebeeeddb5dea2e1bc3318bff3a0b3acbbac76bd255cdb7f7218dede3736eb5d1acbdd0cbc3f57cf76411a475a1dfd9f31d938beb7c8b2445f3b9a10d481472704918c1359c17d81262014241a472c3bc19d7bce39ebaef58a95f7bcfba6869c2b57d11e4ea9dcb4313fb9951a727655f39e516c9dd6e42e4ed4bc37891c4413eeceeb79a7037b37d824aecdedbdd770debdf7de7deffdc253bd19b3f7a3960a0f9e1d61a975a9815138807069459986b0a40a0835b8a490a34b93eb9ae7b8160daa29fb8b21cc7682815ad9d2cac45391e626b899a8ccb25c92d6848e30d0f6de7b07cd6c3c587aee7984346d12b64cf0272e2734ac875feb6e7870a874a822641ebc12a2a7ca289ac5db79b7d89b3ab2ce3af75cc5b6fce426306ac8c9e32854f8da0bbb3fdf9b675da7c4badebb295f3b230fa5b8c6d673dad33a1e8f9e52ec232946d66b9d7b9d8b07e727c7a05c35cf72def5de2d61aa21a711b3f5688dc61b3939ea9df374f63df3724fb9358c1e3eb9ca52aba97bd3293d46846f451c4c6a567bd381c0c39e9f7cc8c46aeade7b67ba112b4535e4e46aeade7444760445a8a6e24420c8f7b352c8598e88c1eac2bd5558ceec26c831292c4f3824c0c1b8586b1d1f369a13b0c27c0f4e29010bab8d7003e603aba9e7a1ec6119ed3ae660226011257826139609008671bcd8a66dc878472f3a9651bb60db30843618a70cf2c11bcb1e5e7623c270ccbdbd48b141947b33aaad36846574363c287764ba5a7abc59a92127c7f90ddb2b8ededc2be69c3345e02cca959788b04fdea2ec3867bd43701d5c69ee9d73ce39e78e73e6c939e7cc832c360e70b9d1d5ef003938dd51414ea7e9ebea0559b25fec19167bb7a5a973ce396fbef9e622195d81c25315c0415284039bbef21bb9c586e39d077ced9d73deb755b3bb7ced9d73cef9e79c73ce79ae03cf4197a3cd37dfe955060f7ea817820d332f6e88d0500415cccda3adaa2b1fb59460d65b6b8d0f60c6f99e6971ef344756af3dafacaa77996ac89939d1bb995c987bcfe8caaef5de5b46d853bc379f5162618fdaeda39559eeb9bbedbdf7de7def9da6316decde7bbb4119b9e0ccc955af77dd75575dcc89584b5a0e35485d483917015d6f30a08a4c406a273690110279a496269695cac02005904c1c081715a5e0f94f11287753e6bd243df506cdf97b97c42fe9f19e4e2f746cbcfb4f1c61200a8272155f73f4dc28c618638c3700965ef096c4fa925ad40b2410542dd082f8481664a206dad50c37678c31c618639c317fcfa4d25712abe2b7d51a44ff9c5b8d39faf527c122d0adaab5c6ef792e0005e9ab82f46d2da0d6d5d5d5b5ec46d31755014641c8d0bff9a9f1d8516f806544475542ac4817cc20609866662b5eb4a52e4968913711ca46397feed109222e307ce6f26e3de75ce51b8b45a9e01c4369d6a54ca1a52461a10551974a969f127ba145b34254b76005c5b525f8f8775d2a1116f4e7621d1f5250c210be7ed7559f625cd09f238710a0f4b4c1a73f7f62a950a4f28dc9e432d09ff30d5ad7733ec675417f9e09e0e3df75c1903e1ed2ba9e732f0f173a6ca08f7fd7dd4a91e1a3d88264cdf815addfc7bfebbe8002d19f2bb1175ad773ee22a882fe3caa5bf0f1efba2ba64e42f4e75c5b42eb7aceabd23ef4e7621d1f3efe5d77ea29447ffea1ce836d5dcf7994940e01d6efba2ad4dc050ea62a04e8cf35bae41435e4d39fb7efe914e5f3b7d8f3a77e92079cea7e4f27aa1d11cb97e568d30594c07d45f0bb95f278642c12511874b8829fc10976183841d1491eb19e104c5c750533080a047e825ccc4484257f8218e4036a089a01c9f9752acfb783b4ec2501929c47927349723649d021094a6cbe24e8919a0a827ef493a0362ffad18f7e8fa29fa3df45bf08fa2980fe0fa07f05e84761d08f16d18f1e517499be404db75bde49beefbaeec662627e57d2e5c3c18d2bc688142ee4d5118e4f0a1f9c8b76188b57ff929c1a2b747a5ad85ed0c32cf9a932ea68ada9046db0571f5fadb50593359a9a1a489393a076b9527b5113c2a450f9a052b39122984dd1bca65d732d5f0a7471e7278bb75dd72c19e3f1612966cda2abadeb39afc0b751859afaf6de58e77d622ba37ba731daaf196e3d3288ae80c4508e84311dc64a9abc825b67272a9ffb9beb05705db13e676c7ad5cf7f40a4d1c386560eff0e72ae0f68d107fc88a82bee3c6f97b7aef28d994dcd36fd39ce7c03194d2634f4e73a9900614c3765faf315163cc4c7bfeb7e218168e8cf3b6c60eb7aceb98ec733fd79b10581b1a4a246d1fab194bed2f4e74aec85ab109acda86ea1753de72c422841e3da127cfcbbae0a141bcef4e71fc43a3e5ad7739e2289e816c357250844346e766aeb7ace9d90906a3e3df5f1efba6af2a8059afe5c67bcb1d6da6bfe6b3ae1c5a63fd7472723b6579b699df10fd8e3f234e225f98908778ad324d04ace3de79c73eec0d88fd3d1272946d75e27401589f09ec9116e7028aa629c7ee5ec8a00c8627119863520dc961b2c8d64c86cbac2b67abde40fdcbbbe67f2a719947aad64644a3442734e21522fa9a8222b1b534a5d4a1a68d0b53fb7d2da111a61f4c11956da75a62d7b8e645c0c3f4003426b5e8c7fc9149817e35f32f5290370102a65e5a7ee931e94b793942b3dfddebb45532e1d62d589b1a921123c61535b271a66925e4160affa79d0d68b7ebc8b1b9f755c26f9f33d04c741b4b23ae0c984986e91f350185a9b710b9f851c3a7af57b22875ad848a0339c947e022b6bf1e7585d628b2e2461dc7bcfa7b01098ebccead69bf1535889064c103294bccd00c13c3540890ac48e082faa1f15a4757bdb32238c35d0011d843c909f07feef896e6b06bdef7affdbfff3c0ff3d3146bfd0fbaef79f88b55af879e0ff9eb84203a0f75def3fb189e7fb79e0ff9e78c462d0fbaef79f08a257e1e781ff7b624c040abdef7aff8928adfbf3c0ffbd0dde84de77bdff3d645ec2cf03fff71be39cba8f1ec62afe1cab1ab8d6f6c6225c790f285e4752eb85568e9c62e7e5c848d8cd7db4661eec16c70af5d141d8719c111cbbeb1e161fb9a7c5375d146e9edcde6f9076bd43dd08f10e3d5f04e8a5aabcf943724d1ad60cd74adc8cce82b98d4b4be783965213ea03891d24a014fbbeebba1b8b78b5d63a05475f904251e5c6a4152227a86f54a590404ba2a144810ad1c2d14c7a39b2c230458461368249c7624d797cf2919371ca10c159efae5755d5cef789070fbcb3050d0e114a589207080239406c2848593340597b68c1e2d6c4c399002c589d502d9d09538c9d4c2f486ca891f2a1c250b5551fffaeeb6bbcaaaaaa4b1c69eb7aced5921dae5755550ff808ad8829bb3ed808aa6d6a68314e7e328c05559d3592467dafba9dd402fc764c6060f2c7d1b573f592fc44ba5054c5300526e17413110208471345165e1b38a2a1583114c349c3501f74bdea7b42edfc88ac274d8cbc55753357f46bfca4b5d65a6315ab2021d88f59901f0662f5a7f3a5af5eadb5d61aea03a577bf27944e168f6357a29fb5ba976476c93367af8b4b3d1d206ecfc92f093d404878926595d85a96553ae3504a456ffb9e504a5fe9cce618f776024ecd555f8fa5277b3db743d74e1d095625aac2ae08d8808011828834aa0537d2060e617365c393ba9e0050a48cf81122b51c0f202424e265cc84a689aec7f501035158d89a0e87e03e51ec09ba414199aa42d1943f75f5b24ed5d673dee7a426206227833127e7eb8393b956024cf8d6010525957b32ea81c87011b40244169d8de09e29129d29db5010d5e98c7c1ac13ef5ec37760d8280084670019ea13893b6ab9d15712b92bc5a14b5d0565a8ce02885730111042637a69cdc0cdcabba9195a42dc9f8c8208102c5d756b1fa36847dda7dc34508ab0ba808f85670e0e055a2aecd0b03328c922aa09a4d6bbbf6ed25399724a7d586808b1bf5f3aff63d995c64e0b16102a62590cbb1a8864e1063d0c909ab91d2d0869e522dca942f78466060727bc5b694741f8c4cb8b44db11875c57002724179010b0d1d9ae18cad213716d848daf0b695e5c4e6f22525f3f5352364a4b23863dc637b2e4bf267ed840b19365a6227789ed6e256bcb829e93028c519d5340844d0b98c206aa234d9c63c287d8cd052a0343d4930952aa7a41a1a402976816998014af29e62aef6ad365dd82156d2d28710aa4cd008eab1b2e41551d209ada49a53350d032b322323286b1954040b6aa2cdd50ca01a1918fe3da13ea80184a2e8779998b44633ba70cc619acdc035e9a8a5cdb04a52f1820523a5f1d3b2600d8d454f8922a7280e0461e114e1080d3df8dc2c9de1cf3d3c1d45a4b170419e0500c450dccb4f195ab145b1989662df775db7a935ce1fd0485533af179838156708bdc1a85afa5241828806550916c5144dcb7caa3a6896c08a8480ba5480c538aa0c79100e959820f2e87b426d306e202ef534a1e88c21081e923c54cd259d000b4aebd97a4b1301a5410d4a839aca7572f8da39060c94c7c3c6bdcfedde33e963838d788ab9f1a4cc34dd0ad330f654924562449a3245ba842e8c7caa901bf80d9b4e4e758a31c618e31e4e3bf0e7bd20a0575579cf0deaf092f4b01b0e8a92cded93cd810e2c5f5831196ef40473105c518b0f533e5efae9cd69500bafa5c5d41453ee052944f205272e965ca8746c9ef86806e834004319000000001807822809a3d4cadb14800922e24c74b86048209947a37140140a86621806e22806821006c13088c138a0b30cd700dbf204f6661d3eee7d57eea167f2a38973e0ae55d8db3aecfab72eb9c2f7a4899c5f122ee28cd3fba76d3e211ad2c79bc36b538541bfde4daed09d0499f34b42459c917a3e699fa54403f87cf3786febe1fbf72eb9c267b2444a6f195ed22d63e0d394ef34e6fabd7e8c36c5df0ecfec94adaa7cb7dd0647c3d80530d89f3a2a948bdb8a0e09c25b8410a1bc734d6083f84f891d63b485153c611de27e4deef36e40fcb575f8fe0694159197025e58906ecb57c0c9e24148c7429179543a2f25bcb060bf2ddf81261787265266053dc3f6400c97641e27e2f1dcb59b1777a7c16aa133702eb86fa495525b986d5d16e0886d4d0726fea947422584b64f5482f2e5e6407b5ed700155143e5bf64204cf3cb1fa4d95e49edf03dcafcc37a4d66937a8d3d6587d1ebe9379d65e78f3898d6b36879d951843682bce1e1da4a8d00c88e2820289535bbc6efd2797661f32b0b44befe3c1c93782fd837a8c7e0a0a52b1e5bd40a354a438b2fb60d33608c03272639b5586153e191f5393df8059fb7a141451817abfe02b94e0be7650079386415f11bcd89e35e92135c814b5fc1f39bbb33d848356bb2defbf6620f0ce2227b27a4e440403720bb15e4964d2fdedb108d97e6261614a61ce8160f48f3cea93ace4f92d1f26f86783d915cff330188550f6e687f42597aedc89f134948a9e85a4e5c1e64a6080114cf3229245483dad1dcc4b088e24b1e07178e56dd107daa70a579543b0c9cbec595291af0ad32b07c83779ee1f85a1ccddc501fc414e9447e80598c08cd3d3a90feb45c0cf3a86e543ee5e34bb91ba8ada4eb7ba47815ff1b149641d692138a5d0d3568e6077eef261157c78453ecb29d745bdbe5247a34aeec724811e1fe729d4d4217136a1f5920f9ef6bcfe6359ceb54a64d6732998b71a80e04cd412e5f6486d12da5e824159abd51970ed08a61082e6c518e7c65c141dc3dcc84ebe3c498bd065e581d11128d14b3274a089902a440893e6df2cb66a4e5d316dd208c7c61afddac9c876fbb4f625af9b5c927d1ac60c84ffbb1df789d9dc9baccc5dfbed87152a25aa69fb9d58aad21a04c430fafc76c0bd70596d7f4477ddde3dc6ba10635bbd04740d5f04ddf6d4c31d16231ff6fb032a10d0a7538308194e2a1499a2ec3934bb8a6b649a2fcbc3bddfdedf25e66924ca207649ce557b40fc7b456ac86148d89d2c362e2c653fb1978c8a54bf179bc8f58bf71a7585aeb962b00261d490596664e785e25abe14897d1f93138ed18ca49ff74a9c974189d3ecad36f2018ea4a5118c5721a3316dbbd9e52cf229eec4090ac4a00a42f8c20340cf9b044d10a05f4f452d6317e470fd9b90f9d3801010e126e57bd9d6965058cdd46cceb8ff5723e0247db44016526ad8563ecadccd2cee47480c9f72a672f7d5a7ee8f73b30bd5db7bce80a9564864e02be93521b47dbdc043aaba86e663cd364c58f5ee6113fe7804f233d1aa4c01bfa12ce307be96271ecba4e008f6c408d78725b9c7526c0768e521109ae498fd3f32b596d293c2408ab77f791449de3f42049376726dc38b0c8a67b8bc11b7800d7ad96cc405d3482f82ee0cca9c761a4a17d747158ad8d7735b1c3ddc2665c7e0f3607a59e6c63f5da94813ee02210e6dba0f0c545130aed6bf1588e43fcf0c512e60c6c210bea3218ad5c4ac1614eadd71eb21cf740632d76b946662bf7328784b70bf59f77aa6a601aefdb13437635a0c1c32170691db959962ae099f2881652ae1c574f1307be432ce05bbd83da715449c1df2ae9c62fdec98f85746591a9a7ad7db87bb2153c08d55021a72d808a3e92a610552e7cb59bf68c29e27bbb57f4ae097f9d35efec40b1335030b689ce2416bbfd982b05396f39f6036e29ff5a5c005cd9a1a1030bb6b3b07391223bb188b490058e491e79f9559789b6881fba932a64712b466b4d1fcca0acb4e02e17e17331c030fcdb035b62cda786f47ab59ece1b1509c29770fa1e5b5349a6479e1bdfe9e7af49f8089875bf48a9414e10b9bde6caf462cdb334c5e7525e8c9b3e0fc11fd48c18155c2b6791a594c6027280b41e3031be9938befabc645a6dbb6e48f2684a314afaa8d18886c43a0ac63960327402b06a57067550e20a5c3ca1c4172d33cf9e1f70bc2d365d5c851110ed737dece0ad03a8d0bb778a9d583af3f9f5709302d11f8c6c6119dbc705372a639b8aebbf7ab918d39c5c67e6b112741bef1eb1c59a7425819860251739c8ca0e7ab8c42716f9c79dc5ccd08ce68bcb6ea1024d3c2983b1ef15047f221778d587b1b7d74017613cad07b661ad3ee70bffde75f1fb10f6569cdac1ce441e3702d7cf5b13e1235870d9f8703b80c4bb141ca4d20e94e1b927fc1ac727f72ad4a43004744a97ff8d4d11f343f08b912c73035766486a19a5e9ccb83ae55d9571cb1ac27876529ccda699f4753f381dae5722d125e2ced56ba2ad633e823093bce4c1ac769ca1d0ad2378ef2f4662fbe3695b88960b68ecde0faa87af0357c4d3c458346dab869d3e90079512295658f5ef0a2bd3f0dca2382f43d0aeddede4b68a0a99afe27436841715b2c7fc9d5eb7d093d7890524586b43d888f91603985ad2b38dbee95fd0854edf33e274845bb3637ab9c025760cdd2237a67bd597b70ab6a05d2fabd484333e0e54d472e088b56282dd4d86215ac3b78c203926b6afb9e4281959dd85da92fdcbf3a6fb22230ded912e3254a9e0ee3d67c06c1893ecc647e8332378ce8afa9804731d863f5880526b4c1ed3c3f5f7c763b4aae0f472bef6dfd4155ce95aec11f37113d0efd0e51a203994aacc699aaf1a66aa3463a4d1152d3396d139b0804e9f815c32672f72e178b079b4b9b9864eb75139706bdc9b44ee9c350936c79be579b8bb5e46469ae0ca2eeda2e7f5dda0e135f29251d0af519db565b550a5ebf652766e02ad9e4f98a61505ac1e4d4fb17dae74e714cb042578e18aa11879b6983e77dde3a900b3d9b8d6534704f1f74c87b19f34777f10fa5ec24a9359d319e696b869ed27d5f7b99152c9d0baf0ae9a85b152228b0b9db25f95d5a19b56d138d469e2f9dcfa256aba0b83fb36d4ebe0c08547eff0816f764e160bb5102e0d3af69c4a04d45de3a5739c4bd3f01ca5029360c42225b9c2bfdcc2590939a6b6efc80d85754334111234adf894d27203b98ba51111b34a9943d7bf0c41bf4d610fe045aedb260ffea5b8a5e39ba98fc911da64d149a0b996e38701a5e9672811275282501b9b0e580ca628886bee926dbbebe7fd62d298a1c831066bed8204680f0f795250dad7d8f8a4f7ef4b666f3e36b9906baa48cc64c3ddf1249c514b433c9e1a0d95b44937176561ff80c8184f5056d8b970d2df05cfdba633f90234f255589c55fccb1c6e71b6596cec34bea76bb31092092d9710ed40fa270aaabb8c8a781688dc8c084671a89bd9d389ae961e502e28db4ce59379dbbc92100e1779fd08ae6c42824b6371bd92508f457dc3385fbf5daac98b32e085742ebe2f5a88c01db7a15b3d17e23e66a037a4a571b9f220b87cca1fc1e5d23661979eb504cffbc459441a9a9cf3e82c6c0c1bdfbf8ab3f01d5d9512a8bb5e90f031069b8bd163482e8c1e04d7ace63707df43cf1fd543707f438e214aef7f10c92eeac1657edb69012754e4053a717fa31e09ff4eb4902bf951c7485ff4247565fe16fa58ea49f7c522c25edb8265ae8d29563feb502978f2e264f421987fd94ab10b30f1336b9260c31fff8878e6a29a6f095fd2e14d360ed104d57a62e4d593b1a584877c81c7a0e5b1612eeab57670cbc23425d4b76196e8438177cd99a8634a4cac69afce86a657d90d92ba7296128404d61147090490b1ba5823d4e911ada7b2647af1e288d357d2f24d6c5e604938d878d06be81eb66493006d49e7cbee592192974ca107bd247179bd50e17430d9182461f238a1233f1fa00af5cbd10373ad2964b29e4a7a3032d9ec9c038bf3fe147e2753e0113c9978486e2559271ef093b2277bcb5fe5d89e0caae92f4b1a654ace764958f0405880be946805a6cc3d496e0589daca7e4d59396636e5c9425f00ec087ec7c364ae772c950ec201cf9521145db9103e30884fe112bc10645b7e1ab06dd95e5c5fc08107ff31479243d92d23d62054c2e0abb278c1d0305037c0d3e6afb68708bd192e060b71b104d3c561d0921749432eeebd77784e412cea1217376d71b1bce330ec352fe62801eeb577784f7b58647431465ba58b365e0d9e53bd80abcdd9112e890f5e088bbc8be87bf65d5ce43a5c537ffd3bdd27fb770b1f70457a516f18f562b3f30a449eff4fb0bec866b8f6c55d1987644ca000d177a26fb873d8bef22faed37fb114f7611100216a728e1b1c5e22167d038c9b52c0586cebb00890103519c70d57b98958cb73306eaa0763b16ec3220042d4e41c3738bc3c2cfa061a5751d0382d83588338ba365480289c7f527b70577234e2dda3f1735f37651191ada3062ef0fd3b8c2368f9b0f1cb90898d6545f3a11d1b02134d3ab1d75bd811c8b3b1f1cdc4c7c6b24213a4069ad3c046c73e7716ffa5635b331d8d6a599019a9a8c185ad279bd6adc0535a1d4f9109269915443ff4fe0c75ea0157f43bfce11f045f30520a4afc81e876a88dbbb907aa0c42f1b770a363ea5f4eaf4bf8f673c24c44bb39715bd0d10ba545774245bdf6f229812bbbb14b99c8b3f65d577b5f9c64db1d18ed499443f49a4e120c0922ee5312b0c2010bf72270399ea67f030651d7c70429b2eb84359a8385d4c61590b70a2e0fd7f548d9e92e6087dd610218008c44fe5529a7be1f910922f3c3b55df7359ce79bc730a00481cb829488b706584abd179994feaba0a458b79cbf0a49181f1dedf42b55f9277975037e1489d6475633d448e9cc47051a51a3e42690e206144896150a24de8f0129a62f80645e987f44fc803fda3a353f0a0dd17de42bc1e923eb930f7b2ade1a899f6b18be1c7d21619906e012794074b21fe9c517d7480e8a2808938b5799a71d2e945572ebaa017f7c6e641d869fedfc95c4d07bab2194c07e5d4408b8a8410ea4e9b148ec6d88469cd6c37649b4f4ba45f068abe9d96fa433eff9755112823033c174551d49679cb1094edb9820854da63976ef26d621ebce3c6461839228fa6f72310466857b3ec488115ad371bd4326524b3688d2bda31a54e16b798840ac56dfd1040532e00b8d7915f0057fae825fa5d683ff6798d9778b2601aa95ed2e13ec984e76fcb6502e36e3717d02dd1c4f04c560a4fdf3f4326cf8967e48220511dd6766873b270826408e2419e3c7bbbcd084eb594eb7a2e7f5244d1092d7e5d4f136a59377a5a494184d5f0120fa7483982c7967567d3b5860342ce30f4f2e19e90ca5596429e9676fd192a0a046fc0522650457da554d45297de756658796de6847e653b2542f05ee1843cd3185da59dac0d5b2d6dbb71e901c05b5d82396b182d1172110844b291d5b87924ddf80208e1343c4cf0789885ce2e5368cf740f3debee9a2e26df1b62cf46c32af65240b1687dad0c7261441bc0f4c629907c4ff693595b301308fbdabe6c5c8269a80ba281e301cc6c62d6c01883baf75e28e662dc62813fc7816792bfd791ae20e54907468aa51e4a0be3f6d45fecfbb3be4b782947c53545e32f4f66b59b64364670598f13e74571749ec8f2791aeedc4e8b57c3c4473acbbeb9e4c27d9c39e04bab15ba4973df109c8033d1f2dc9f02ebda24361517aa8d8d8afc09b1ef93934948abf00d36655e8f408b00fcf7010ac42da014396f81e5126c0b9510fe5d6c32a64af9fe876d2bf770a47985635ba3dcc0c84e9288fc7b9f6937d7b2718d1e0b161c63d10e71d581ed0fb6989840cf2ede642e462020589be13fd7f414dad5466f2f5910931f995f7b37612341dc855ccb086c04a519b34d6a7a0e56611f962ab86cc00c59a2e7d5fbc1ae2b3c617d47674a541fd2426922c03867fd2a64e2abd3584f50ec2565bc2dc67697fd4ea4e8029d7bb6d5e7d7c28012ff64fcfded64b3ecda84e71b51671831e4d6c78e22f340d6462b981a1e4fb5b6991eeb3a0082e78983337215d81bde4fa16d03c01a2f6e4a2b027651f85d2b7c304483081db2ca008285efd59941149ed7d219602f42466472027b3aa0c9f3ede251081934cf0c2ce1848116a5aea71afb2adf58f70b604d8add5fd8af2110fdf4d6944f560abec1b1f504574ba143b7707cb50f9e121b59d75f56ca87f299f3743dc599c92938fce4270b0fa29829583769acf8c594996d0cf2b4a43e24bb0810d0ed45983a364bcce51e75502a9474114a885dd7f9b766e2687cfcbccc1942613eb96b48ad1a1fad8d12badfbdc100a1661b6042c1638a765282e884c80841ec56d3e968c307eb1f75b90777c59dbc31d362a61b69ed348db3ba2d970620117d2e9cb5344f1a5791f4cbdc3ff74aae9828d66c1e3bd43791cd0a60af84c959f524b0d2436f4b61ff1dcadb0d3da788c9541ef1ecefc339bd74a8c71937ace5d0cadaa1c99c0b46621c0141371fe38386d27cf5bd47718551b452ac42aaeb66b08344dcebf9d09c5b26a332ae07b69f754d11b52c43b8808e8030fcb8c355144e540bc67f3b8dacca9e616dc211ebaa1d2159a82bbc71049a1ee25fe6d8f091d085545201e416d418584f292abadfac222de0b38c9b0829456a63f0adbe1e57cb600f3884877fe85508758a22ba77319d69c89ac82c448268a5a328aa16af48f6f4fd76513ada278dd7d1d5454a218f5ee808606435a04a64106ec5c07f18e3d598dfd5631d9a4829b90d0823990578f6c58d42e04d1608fd8ed5e4214634e9e2bc06bc00916ce56ef0e274277b44683c8ebbfc2b62444369d789aaa30880693995fd38c5d19658741f66e93044da063958358063dabfef42c42a322c1cc9bee1b39e4159759906b4507f31397898785e841288529d7cbfb2d61fe38281075f905bdf7a22cfee8b7c805cb7a67c3395c662506fad3138aae5e9e8b5149499b8242cd7d6170201ae4a629d56e4a1823b74b1af40763ca78775e2c34c6c0f0840390a81e20b598ad3c5c3edd1617b4cf7a8a6b137d178ab876b5705d2672697fb844997bf26884fa030559a008368156926d54480e2e312d7c3ab8700982962c11b1616f21b1d4b0ab270b4a968a7f562a3b2496f4722acb1574fe1b21ed66090a1eff636b96c835d4254009b428a34d021b0011b2f7183d5cdada0368f2a268df2696059b9d3bd473c5fc33760451ba46225ca17b3bccec9f5548d6ad16dc3b75e84f5e229aded0de5bd11607065da6c957f162454510af772004d3a4c2ce1a27558d0c51a194b8843a369f7af39542bb4634d0331dd712f45a7c3537bd8b4f0f152c12a92aea5cd733538f1225c3b554d1f91d255baea35098a7a930bcd4d53eb4aee63c46ca522a3a96ee12e4b2aa87583e32851e1ade0903ea71be35827cdcef12c812bbeef1c1062547fc45baf6fae952bd65b5e2895825afbd2a6101401b76da9b1b20e8cd02495539fc9c571744da8ed6409193164665cc0d37f5498956370b529ca2756379f0b8a5abec809a31c8325df707ec88e30dea6d44843b9458585f259632ed3c16a507530b4bdba2c47f9348dd18d872d14db1d83d11be34255944898540d34ee63f2c31bf89a62e3c6e66bbe1c2872a445c20004c3a692ace72033e344a246c0f09c2d892b0c3a48af0828d61e6e5e120705bf805ec3136c072ba3fbf91747eeee5c8c20acb112bf4b38c274425d669f65014d19a39effec20828296ba43a64190fc4f5418790f411380744387053ac50687a331f440e9a4c21e2cd143ac203b1bf35a6fa5025568d38750efdb518f3f7040ecd73b0c8712e77c08cf4256f2286e3d4d37b5199dcbeb95422799cc9723f336938107e88de2f06187990ab8330cbcf17179ce66bd407010dcc5ebc2f479946650b11c692245b2c2a8edc370a26d34e995eba5b99174fabd778791f3c3324a4afc2882ec3d4d29f4cd21d5e7e013644aadc34f57d864d9fe28c4e5926421fb5fb05fb1ededbe348dd9cb73f9249b72105b1b33bfff27f32fb5c6df9b93446611a053faf23c348100cf1aeaf439552cf7bc6be9f46d61ca232c653458159d1f94f7419eec0347f2bd488b0e976fa9aad1c7a9b00c9d28ae5d5594147cbbee80a3195dda2163cb69539a4f17710d2cd0c63229d2b7a92ed19c39e27ee9e11a5b93681ad53bc6c369f820c514e89abaa059559dca309aa08bfbdd0e50084d8ffc82919412370289723eea534c9049350de53f201c93a60028b66a6409bf2cc66906253f573a676338b4979abdcce7b560eccda21762cabbef5aa9c8f4e252e3fdf2dd431f81fc66c4ce8b0b17749f334652ff3eb3f389fcf2ce71d48afd07a8236d7c61bc8504e4e25e4aa345c44a21e986d3c69d384a405543d29e87aed5400c757f1049f389c41652d54bbe5b54d1a613826c443647f9c4d0c13cffee35a84a6879bc675e47d4c7813cd7c6ef06cdbbd77e6ccacd59698ea6ae2355be16a81b39f5450587a29eced5bb7f92e7193204161a54365c0a9849a5e11fcd81dbfd3ac0f1eb4a46f0642640b95a3ef9ac4f1c3b12871c18c10c7c3d66531f6891e01d1141a664f647a293b8c3fc75c5d83201a4bc92c4bedba327e2d4b208a4fc665a9ff719069d6a49382a7a556ef899b9e172f8ae6c3392d6c27111909c14545831c2e4b4592e5eaf94ea699a1ef5365584a9d541c9e2391f676841a22d4b200a5c6005166c40ff5559e908eee5d2ee03d691e75917203b6a7d598291aad99e73a5eb297ead447950ea91dcd4222edd6f68dafd115d05ee6f99ff4d03e9f77fdce239e62060bd46ce3ff6b622b13a56ea0785f0b8fdb6e41718bb4710aec592af9d7e44ce3d3e9ae0e0ea05bed1a102189f1cb4b32ab07741b1e376e9d432ba9ad3337daa608d42d676f4b189c75fe24a7ba33629732d06816dbc861a33200d21057baa846f83ac4f315645578d720c5b7f29ad5740d48d7c94f0cd4634b1bdb31ba999650e039f3cdda0e1ecf97469dd2ebbb59d842d2d51b50eab7def9181dcf540a2664596225e67ff10d493d39b056e76a699aa6ac3f580428ef534bf9256eae52926f37b2ecffc0b97ed9dcbcdb02620ffd453ac90847b2f4cfdd8c9b8b69468a95a86b5127c8aff88eb73919f7f7f2f1171398d302dc0e3120f4041ae5a8604e29a5146ce2e12f6f8c88f6743eafa90763372c59548c4ab26274742244ec51cafff9413650235dd61de88cc1891237ac6b13cb0392b8bbb71a876a13d420a04829bbf952dd0044576d0a1ae1d77adcedcbf89008722f6bc0af96e1b4fe6fa642d8656e36e5a73ba2894c3adb8c0bb48333544857eadca4f61b9a1be459598ea09d562a8a56c15d4e5fa2080301efced43f65b05a74a04c8bf9e56e949a6ef1030f06bd96377911b2afdfcbed16e652d83026124e8210a7a57e3199315b9663317b961df379dd315608eb936a6b16c1e004bd009c29d0cd63eb3fac5c496af43953f60104431cb2137d9857f8a1445326bcf2dbad491c38b0b952e1286f7f3ec00c66365eaaf186386ad69ecf402728533c46233e8306a4b31fe4ec7f26ac04ea1605591fb2e260dd9407af7f8dc68ad96256c050298a10b8fd645921c840f17c905eaa88bfeeb27ce1f32ed81c7b8d082fd57eb4f5851519f320e6d914d29002bc8f58881fddc16067632c7e757091893ac2aba2fb6650004c7d30b7650e896e65953f68d5ea802300f082ac0671336ffbe3eec0e3e44ff73a7327e05c86709e0249690ab35aa52043a8b7c4dfa3e615a7c88face40a8f7859a53bfe110f98eb171cf0b22a779c831e32f645447c51cd0ba7c08f8bf13e3749dea2b41c2862ccb1cf59e85474ee192e8f2ec4a8a2634c476986f55e28923192bc3f0ae052d11c61d43cd25c6a45e73eb5265e2a5ae3d4f718a9e863439f92a1b00405bc30087542f32f15d5ba0ebb0d0f9e223c90f622fea6ef5034b7999a4ba50a6c65d21acb86d511978ac4087b8bdb05b1bca3a692ebeda382f5b6ca207efc08b6ae8436c48c5a407dbc9f9c7d3b77d423477505d4ce6dc96bb88b0071ff619dc009f4c32e189742e8f05e4b529899339312c38a2ea518700e1e73162b7b7015c114f5187e44350c81cb164aa1d5899d5b150d69080089f22089fe47e20c05bd736340d6075386ee49581ce85991d87583929ebc40a949bb9faec2c5aa05581eef79d41ebb8f4db5a64687b2e06846aeda9d368b00be3158d93539f6126b22c0d7df2886f1502b9c584014e8bba6427ea436019710f9cde30ba60eea30a5d35ab378c155d2d8856a23bf9b7206c58e1299a61ac311bbceb2bb0ede12c681d935962cb865416d31ec9a743dbcc6fb3c6c9d23a5a16429027dd886070162af8ee0b17db80b4385d7b064458135cfe7c13e967b77c7285add211e8896b84c0e389b819229f87d9a3b233e9f1ed508090796479de8e0a748f8e8976d99ec444a08e5aa80e92e41defd88f4f78794ae939603e35b4cf78ba78ca38b2813eff783ade2f700287fb0cd28a9eb874d2cca1859dcb7712f2944854e3fda120b576caf8aad92a4b796a90de3112bb6dcf5c52b5c7b7699dd836886ee697a84ea750d51b385c24e416f64b13d6641543f3c7b3438965db26035a80875ee6f49fe24985b9209c1db8fa4b66d4f7050f6de70a7c6db96aa187c207814dc8c74329c19ab8286a6f57bfc7474f6c632145a8e5ce73cd9c31e4168f9d9917dbc4e663d64126b7accc1943ad2f2c8017a5013e75e822dce9178da2ce619b03de4676a58a610717a3391fc2f66f85cd14c6fbde564d19f6a20dd2c39bebff013d60a2c415938ae79414c13b237482b6336f98d26b79439c8730ff881b4008f8db76570ee79e3bd0c0136b0ff63e28acfba3f70ab0c258212bdd4921e98fee84a37ccde1d7c684152a6f979e01a68ac20c60b9c5f9fe9872bf38b3b2f93ffadcc42d61bcb47a324f42c56cc949422048602f8e18850461dd15ee68bf6129d8542514d80ff99b1667764f694c9755400ff9a2e79f9999e672effaba98338f9e9c745ee0e96fd2f26a62c60ecc7a659e40ad47f2871da10f329d95e0d93ca4a39752285873d00a8229745102832996f8a5e6865e0b664e6ca7f7763147d86934413fc6d6048144923df8d447c527a28e2cd9289d3cc1e68c95ac9c4b8dcff3e7b0241057ee33deb162ce38452810531fae0951f848332942f149bc053307833de07f2108318f6189456cc5197291e9e6cad5f36146f4f3039d872385d1372a10d4814c5fa06218a8512f2a6ce59de1b41ede61961754bc0fb181eb7530e4ea3848f87170c165fc21c4ac6636c72196bb0a1ee42cf633d4d2a74bd013affcb3502de76cc7b4015432cc0f8d156b894328c7d747416cb16111222e26ca43205fcab49a1cc37ca2955e9655f7c523c88c382ae4d3b3432639aa01381e721a42a00f5be042ba63f54d29a442c9304ea260dd4eba844979e225720f3f36926f5a68737daace604e6d5842e81b8b3944581dad333b602818312cff8b1c4c110a5042c9a7dcc13c28692d44d910595fd19f6d609b5d4c3f49c7362fde434b73c0d922cf9b17dd5941cd5a7250ad5b3c567ee3b8ef232f115fb41e4419ff6bddcff1f25b2da284075f91fe0386ea25752cc1a9b292aa4e58c838a70e6041244ffb9c08dbab85884c2af7cc09ce0704a1429056bff59df0a9c5da6c872b65be59984c0726ab75cfc7228635a0eb7c60cbec76da371f4bb8ae48fa5a6672a7a64e96e3a731529f9691a6412aac14d2fea6d165f24c66289ae29282aa448f701483f66394fd12d6c752e7af5da91e148a5a226fa7d79eb88b33d618d9242fa921d633a27c35b635c58275274da2633eb53fd1b1daf173e824a5c22852172ac41fe9570a0a9907a140b6ec188466edfeb72fe7a8b4a6960a6688c18742e68e2d48aee26a5b68f04852eb41417d83cb78f9a58d4338c2a7a06ba541133951b0a9533cf8283579e1d1727725b17dfee165c9cd2edb8de4f9bd07677f429eea02ffce091f44bc5059a61372495889adce949c75341cdcab1fe2309e2b1a01122d968232ce100ddb3fb38441fbca09874e9cc755f7e752264a50c0c4e80ff54c92536eb4f133c24a8244c3e1dc0400155f3d7727dd896234c52f7a77c5920b59c9568f15124dd847a4369e8826a0579b8c6d66a9973d105708f6d8bd351fc4912240ff15fbbadd0f743f7dbe1c192845436c19b72f825af5aca617942c102c6d232de238799342f73c455932e4810ed48fec85c3b839d258ae5a15761543ec49e4873ef49b9040af3a4dc09cb43ec235416756796536f0b1413193c71b8794efd6dac86d387f8843a65fae72200cbe1516965e4ac7e7c70ca8de6a42c8801e91349844756cad7e26629762eb57550c9a8076e59ea733087a1a57a207cf90c8bfa96f2621530071e47e9cde27c63fd045aa1da7e79d75ba16b3aaecb6c868375f62712c901dc134266c6c077cf8d0525eb686855c83211c6fe5231b667323ddcaa3de33214e8f71da2d479a6237eee8f14fe41b902d7bd95f59ccc920f90367bdce4de9e41f9fa1a55b1b0e8642ffd52f2787c6043a68fb464a42eb3cf45d4168cd5c24fb3ece6679a6e07b0d584b46a3cd6b4590ac6fb07e5f04881ad4ed9aff699def8e2e31ae4eb340f02594c627e1f0ac29a4ef9632f550da14ee7dd442068e3cb8dc325e0ecef61417cdaf9182473dffd43b8f1a68f9ba6bff601f55e8cb440652b3efea3526c5d40bf064aa5dec47068d6e2f4a5d3488ca44204370f9b2242624d4550c02a15944ddbe2a4109e790911e35963d30e8813a0cd3408ce306553d9cabbdbbed120329537a6c258d050966fb2bd973c7109573ca10925128f06aef632fb4afab5486333c417d6208fc67ce4a9ba0a26007c836bed907e12f5711b3f767b6d1b836324d064d67023808482888b6721e14add1f68334935f26d09066e4af019182ae9c860f7a4ae578690ddb74990754a2518230833b47dec94e5ad6b25fa0877ba9a9ae202dec3e17a3197e59ce89ab9acf2502c5ca81b90b9c4dd25b37b4a0fd7a50e585b0d3605f80ea789ad830e9c31b4752668eb7af11c5e58e8620a239c2e473ca5b168249f736a34b8b1abb7e831fa40daa7c5094cd39017a7f589494b17694e4087053ad90f37a16130e8f4d410970d066f5ab0a2fdd5405eb09325545a159bf5d42e7367a5bb4be328573a174e5834d72fde4e280feba533f5a13ba3b31c1852d61893e08bd8a53aec89d12b4ac5f625ff12441ed3cf175137cc96988acb3f0702ff10e5129c3308306019f857f653c97c0fc1e048445eadce5202290492b6016b31c21de215dbe981c2e060369029b4bf391128e1edb5f6e62d1bc6d756aaeb5aa9c6f7b174095fa56ad94479d119501e675cc8eedc2f12cede866f0a2919805e2b8308b6a7252501cd8c7c0226e610d88d10f8c2585113957a6618e89edc0ff2cee0b2dc135cab34178a1dac4b06f3d042e4b06f1eefcc13879ee7b9128221e481d13379efbe492e4c9f3c809cdd21b110b80ae684057231d9ca8ad0f36e21281cab5114f8095cc67356ff6449d076302870a9680d58dfc588a2c7849a863844179715b79bc51db4a667889df357ce07d1302367cc09e843b88eca0bce78edee4a97d6a776437764b538a37ebf8908c4da69b407a75b1ee50ab5d504c82a4ce0b9c163e84b60d14b0d2a6c3db87b3159eccb9d1d07a1209e934fd19eb420f02981984f63bbd82c6e074ff683e0e9c4c0b202e3a5a520a68b2a5665cbdeb37c07b9e046322d7805831a7ef9407ce96553fec7965de16388232445bd985be91b5ec782525a8baac42249ab8431749a317ecddd84465b485c89cfcd575bb8f266e7c5badaa0dec4ecb2608c88787fdc2f20667b48f214bb2545dd747ba2e2a8561e04fc25c6d0d92a75df3aeeb312afa46f4b27e9c5321df315551d321f4543ed1ef35a6827013e5adbed957d62687436b6d08e9161fad0e8c9a81fc47c65bfaf8dfafe7ed6c432526b1404763ffaa4d1b680cbe0bc851bbf43c23fa4470bfeade26f2eaffa3227703bff23c484c540a2f9af89ba46b28ab50489d0718562fc6f44c9958581caee1f98819830cb4cb6dec3709af6eaaa5220b2700531ca5ed0a9364006942fd940fd1d4ce79ef8b48aa2f2f1d71ab425aad1bdd20b591d4f37260622d297c2dde64305dc33066bd860f1aa77a4b0f0a7328c0a0e137af1f0461db9ce188f796cd2250339e4a5737206fda757daa96a0d7dd184050617c8849ad07e0d33d594d8f2e91ce166721ff81246e0f0829ec7b1ef45afb7f2c67a2c1bc698720867943b4469d455610211833ef0d22ebdc5307802af804c55165470fd2ed11883cd1b4d763afbe4328935bef35cd878023be14ee3810d0d812cb6ff9ba23b6643066b9e46d3228c5167ca3db78bba4ef272f8ba28fae9c02e33d45e1497b5f58c53117103e1c90bbad22766a37e4324e95861b94e533d12463919a649b677dccfe797fa921370752e4e24e89c7dd9fce35291f02a47c0e52c68cf95a7a5c7bd113ee5c368a614f1fc2bd1110a87c4e5297d78a0081887cd1aa4c646c9628d3376c0f9e9c03dc9eef1a3ce5f5975e0f09305f2642d0bc531b82243f60c848cd19270d5322dabe4b1eb73cba2656cd446e0b91a8c59ec27bd29c18c03c3aaac8007400818bc7fdf41f94e53b922d671d1fdf83b44ecc35996f3545a3c60db35fa636ca4d5be724253602f5800b224492cfa5717749c566a85e1e5b09b5159279ff502accf2e3ee581d09c2ad2337bd39d3733d0cbc14906391f80acade6cce6120f722e40341853161cc6d07b21851ce86298d7a3c9f330ae313ed14d7f1a23dd603b2c1663f2fd3930561443cb8045f9bcc310a969d7b4647f328ec058705fa84494612aa1df4b4695ec0e9d606ce6476a4fa173d78b7120313f6552218a307d3ebbe9209175a91eae000ea0bb640b1ac6008faa802f5ba584f832f4ca6fcbc84b55366214f7bb5f1a1c753b8910a814f134b994d37f7f38691034de008ab0a02852704c6d751584e469248f47497405e08340ae7993f1c10c4966a710a40494580b4e115807252096cc1d942c402dc11ad093bc50b23670d23ee0b0ec1f473ee12a27f0efedda12796505a33f3f9132c9acfd1d950276025b02249840287496624ebca598781351b24b72438251a20589aea3e908a751b3088948684884d04c907605484bf273e7f3d6a3c653b6f3b5bc1231a54ca1a3944384b3735363e3d652e30682066f264e061b6385017bc9728986706a39c162b4d2a37293e2926c3b4169fb3899336103f1a2448ca43a5225021582a20772d4fbf8c9cbc18389914dde6543b675766d75687463735c72567152704c6f25b4416eca36992c9b0a1bdbc8da16abbda6a991a579c1a0a23dcf9a5e24fd5c105979cc6eca5ec8d6922dd644c6b62cdec4ae6156b0b015d52fa9975457932b698ba8caa37593f582854d5e6145a8dbe99bd5556aad0aa3aa46a550a9a9e633c94924c5137503757d79ba2639b88a6cb0d5e0cdc335032b066117543ba4164855d0a420898368021e096e227839aa252150137960ebc05b035706ac0b842950354a139042a0d921a94874000f871b035ee2b464016922046c37bc69b80e6015202c4395280d400a431380a421d106cf851b0b2f308ca4060c910adb8c37e13568dd40b11fd7a66ae83f65a637403c1a8d48af869848f4407ccf44da77341ab3bbaf47f7843e1f476c7c7df1d1e7f3d0e181630a0d671b7d1c9e533d79e39d81bd9eeb5ed3eb8c04cc42eed915f17bb3bbfb2b03cc39fff4e662d1ee9fe1ad7f0813e17f2889dbf061e00fe9467195203fc0f14fca87e20ddaf26d25bdf116f35708efbddfe49309ebaa86aa444a0389e1f6e284273345baae9df00c8c61642f26125f1411020cb1acc5596dcf904e4cc8daa840b1cb7e688305bc27cfe7ca7f2017c2898235a35df2f8b3ac4f15ef844685d05329ee5d93a7d36d83538e2ccfcb3a2571f5782ab793902c23a71be78bdf34086c212121ef7f972b1612786318e7680381a1112748777071642e14dd7d5f771c918d038644188eddee57268fc66d5488a609335e18afa0c6dd8a5324460dc653ca91d11d8d362a8966fb47c78242220cbf2f3c2e1650b08bf3320be142f1e5a1ab2623cd0f359aeaf6cfca0816af7ab4c6d289c09e7826eb5cebe85410c8e11dcee3efac74e177ccbffd3ff41dc89e74058767edd1e5c636c6717ea8aa123fef883d6a9241bb5b2a7c72bd80b5f61cfdd8ef82d45057211b4b27384f3435234698d9044a4a4466c7021b4b6130bc21c882385a208b73c528d9050606e5fb3ab14d9a1a9993f9f78c1d66ad65885ecdd171543a72b9ffb770dfee0e6efdd43abf6b65bcd41aedeec2d8855a6bad5d28d45a178db10bb53761f0158d71ec4000f48644183e7e86da6414b7d65a77c4b14359901f8ebd942e6ccbd3cd078589bab7656746ce8d499b359b3213739f0ddcff13619b36e47f94cd091bb41ce7f3e980ecf57a3da2b08d2dcd96b310e93a89a22f8b58d1154a4d24aa65ee6571c9c08c769e2975673845a9d3db51591490cbbb62754a67b2cca612e2d76e0661f273ef50bafee086b07547b1dc3b948c905e6262a3a324e7f3744f85c408ae645a97a46cea6a12b2702d3187d69e94de4ca2a6dd14e8884ab4450d0908b427ba3b8d6849091508ab9c1b22d2859268fd7e067470bc263011e94ed121215fe4070ea4ceff9387f4ed57bf7ba6cbc18b6162d025efe842b675766d75687463735c72567152704c6f25b4416eca3699ec9c0adbdcc8da16abbda6a991a579c1a0a23dcf9a5e24b918b22ecd68cae458c8e44a5ac41883637115330b5b0186b502faa5c2cb44571117cf964d352e84569c49561e96dcd51ad5c534cc4a4b4a55f544b5141d01f599c279be38e150a4e040a2e8a0b24f674e2c546ca590364535994c01ffffff9f9dc8e395e2ddeceeafbbbbbbbbbbf3b81cf337b57c1bdeceed5b67a5cf0b8ba7164667abac2e2585a122b4961f27558aa3fc585ac707c48394b6aebcbca617880b9d3028cb57540945fd9ceceb5e939669742a30d9111e2fde5dcad0d94a0915abac61c744220e8b134ccc05ed1835313f4ac019b1cab2682ab1adf29b1ee985a1179e174e51785752554ba5dbca591e4af4d5b06322d186f958443f4f4a5572293c5e2d2e37bc9ab515d8bae694efd5ff353d4017d2f2504a4ca0dc254560d9b0f2b04a2894ce9a4e5fefd5ff343d311746d80a5d2159cbe6ac36a04ceb96c669694411ca03ad09da48f67affbda9116406d2857aceade5dee70cbd6fcef2e7fb9c10704ef271ee70b4711e7c60debf38edfefe2e15b5a76ac1077e4a0674009e7eed06864418f6f7e934c84031d62ac2ec70f6e953c602439808f4481514f0edee3c050a1a61a289f7a9ce2f01986ab7a9d4acf5344406021a6d66c5c5cf593d2a529e61bda8801b63ca3aa3930ba1e3ed3f0dd1e85034c6b1ccd3f62024c744c231739a1620f5e37357c56993b3ca6e14e35f7eabb0e101c5a33e7af67c25e4e09b43bcdd7d15a3f1eed46c307b1c1f9d417fcafff9dd193460f8392f9d5a6b2b12c358e7e3bfd65a6bed5380d6354202a4b6bfd54a7083b622f969a8525e1820ce552cb000556a1bda33e8d77f7b150990a8a3bffd9d6a0b0c00fefda66a0b62381261f8b7dd9faa4c0380a78efca8b632867947851b47776fadb58e597aca2129b43a3d2860da210f0d877435020b8cfa4592dfe9322ec0c4176a55eb22d882bb9d2a260098aaff5dff4c6592a1e1dbdd4dadb5fe2e14b409834f1be3d801e80d8930fcd334475a2fc58e4418fe6dff6d88ad646186e046e0517968301224505e313140ac80e954a4a549b3dc9c8c9e346f67cb15d8a3119f3249ed4aece32cfb167d40943c71c2fcb9c92b9209b159b19393d72402812a86d6a4eb069b34f41d5466a070263542351eefa563c246a264b774ab90474b524a11c8d89c91c7ff907831d3ba182a230bda5042326dad05a4d963e7f12c2798457059715a4065724adaea920ec4d502137121cc9471576fcb9f29ed06114a54c684d04058ecb4a21848424f46318253ee87d8e73bfaaff7669562d1183be36648f0679c0b6e78a36d3dfc3766ca6e37f6cafe5f0e61794b3b4c7d872ffc324d6d1f10f866cd34f4bdd8dd9aa909e8af3b9043ec632221fc2fc63ecdb4fcb9c3ec713183998c8bed839741e656e3e78c5dcffc7b66fb6d1fe69ccf1405a0560323ab14f212f1f8b699aee41bc95d33d8f3f329622651ad95673484115fd3acad33eb93c7bfffcb7cf17030c821eb9d05fce376f7769df3bfff7ff6f729cc4418f6ecef52052f1ae3581f8dbefff7cd1e247cdfffffff3fa682cfb7bb2b88fbff77a648f0dffdffff8bc6380ef220ff75ac2c0cb772d9963aac8d8bc7c330b296ccb8a148e14061f72bfe77c4f13103d285f2982137d285ca3c0d506207a6826ffbd6397fee69d83191b843e2800eeed486dab49652b9a555738665a6ad89b5a3a28b456305e487e2b1e9dd6153d6088d65b5525defce084a25212717b427886b37ff12f92e41912f8d4d508529941594f35162cdbd2bd16a5dd4dca63ef6bb54857cdff77d33f2c3f0f5aa2971113cd45f95656d0e88050c5bf57865514d0b1565550a0dde0e8a5da8a46938690000485100f31a080400846118c8910c896b0014000a1bce405ca848202468cc2810864281402008088481a1301888410088a30008e2310ec3d05700e3c2fbc384eb23dec96af8ee7030338a208c0e4be48917a8c4dce852c94123dca17545182b03895ba11d4b883b7b04debc61f16900eff76538a4810bb9bf3d34cda23f8601c1c62535c3fd159b9f15e016e477b73fc513864e22bda630d6bdd6d9fefa81909d5e1e2a2885fb1d392fdaa9c722ab9512e874b9db2f7bd784568c1546d41648a57a41ee62c054423f4038c67e928357887d62d6716f7b0492ddeb1986f84dfbef99b21135e9660556694bd1228fdeaccf2d01fa2aaf02da15f4dfabb3fd2326e35315c0d40ebc41928e72c474639d35af944c966be1eed7a144c668e8b0fc0bdca24b735441eb10c47c3826cf33ee81101cca993d54c2b2d8ec1882eeb0800fd362efa8e803b562ec5a7a7598af51e0dba280a2739c00bf77d49151b0273bea9f4351b98e7efa18569576bbb8a221d11caa783286299e11e6d0f91f667d8e4fe43fdce82905f7571efc08145df7dd452e074643851f797ee9b78ac99ce7c551f4c9de2bfea0be79379848518f15d58c5a7631ef866ddacacb9b249003e5e6bb0a7e33db8d456c523e14a7b335e5c2d6f4736e8e487568391dd9b0ca36dbf26b1af7ab6b6b493c9bd34ff1afd69ffb2ee173655281d282cd6a66920de46e93df443ad885c716a34aa881a37cc4717180c681627b6f0347043401afc59456cac1fae5127b035cb0d76ee4a63a9ae9dd7122b7fd5e12baa56452593e27c05e24235482c002ce9d0902a26e3c3c1b335ef4e2c60ba7b9fc99bfd7902164f3cae890c40429034a921c0984dccc136521fa977ef4b40144b5ccf25e43a2664aa0e3c964336de0ebca9d6279f9f5b8be47b4131730ef17b61cb5b3c1bed3fe9b3eab2ed08b182a666088126008dd4a6ce70a314e9f431632874c43f4a57c51e00f333c6b3d694787c7b21066fc74f2d439ef71c0eec874c726262c5e5817da36fba8d9c557e2a1912855be1637519d42eb6d4531c0f4bbc6bed95cf891d72124e94852ecf55825e0076d49bc526305586da7fefa94c6fee8ac5d6ec0d456e686678a7a938e9f8c217b60c8c51c393221af128622abbd2cbd2f1b39a191f7d403bdab0a5c1e0b2418465a5694e5768247c817a6a103222f047a90752a35b843c86574df554a8f28168ea002bac2f454e566a25c46e405cd534181ae20c4158494a3ae6aef1644eb84ed4c5a39d9c3a54f99fe22ca89e02b37c77fd8a0603b9dac84a68ee4864aa7576f187c690d0837c83628afcd043edc820ec82180803f09ea68366ba3d00e3507467ae6026854a8b520d7349bfd700cd3b7c0775cbd448bebba70472f7cb94f6c8084a6cf66cb548545ee7d1b23304d442743ec442c4e2ef489fe01bf23880ef7f957176e42d6c777e33ce59e667701a76fe24575706c20b28d80f403efcc16b6712e86a3078dc17e025661685ae20d4e6228e765900345633d177a378ed53361bb91d5d31fca91fb6ad336e72a1b2b795f4a64f86c55c8a20dbc7a3617b523f7aaefb23bc8eb6f46304e9349056cd75f469876e8a280c4f560537bdf1a9d6eb9b08d0db183c73c3a52dd58437d1886357d306c3bf9b22b504ef3849a36cb16910e33676e8e35e96e0b4e59b7deabc3264c8ae8eb259299c2031f88778e695524540c7465bde172608c00d69883be2784f501e6888275b04744f039f5475571e40f5f2b44cef120fe7858e2b06757283d09dd423961864ed69906283c27b70cd44bcff95212e25f0fc06a6e30bf8501ca4f9ad9da346db1e7ac2ef3cd9987fdef247847785c6ebe8f69642ef4cd392a915884a652a6360cd0d9390ceca3c5ace5a6f477731abc78400596b0ef97450034bf40fa42649445fdd113678558cc1d5b2de71f4067891884542512a894b60750245bf2fc080ae5e7372eaf36e3a828e930f75dd16b27b8d6791bbd0c3f468b8409e3cee21717ec259f648099752aeb703bf82ef924109ad5cc84d5024718451e1b4c1bf2c4bf02b3b101cd79d6b73d900c09f9358ff21238413bf540b9e2e9bb38cf17cdf81515f1f05ae7a74911824a5c000a855161f89c7b565cb3b4c8c0e49568c3c2e486a8bd58820b2408df2dc0b034220111350bd092b17c858da92c7ea0b1b189bef8674f5ee550732fd1b34426643b41680ac833d17a11a25856cde96c4cc337c88485d8d620248684c7b9e687c3da0f5d75eb5a29c1f4ac2ff27761d67f9809b4997b162c30f2038c87ad791b71f7c0def8238cfc9c96f5f515a4e43d5bd8dc2cd952d693e93d1325a9e5973ec3047cd1edc19e806cdca6e03c8f7b246539b570e1d23b07bcdcafbf67199120886fd1a814ae6e844a083ecf3df7edce5cd37d1ab8668938be4a55dbea0c48e9151656b01c93e506a950a477461f3884b367a83cfb39b6894a7e2703348377c785881a2f6c80a9a44f127f0209b3bb9017f80602cc8ec5194c73ec47cf050436990864056f986cb4de28552bacacfa94a3a93b0273099a0d0a9924e0187e9ec53e2667e48e52c705095bd84f20452fb39b71be550000f5480b14e2686620d4d45c8d11a5a93a3ca741004bc9c4c40764dd6a4ef88f7a3cbe1173bd28348daf03754f9caa8887292ee8dba9a1acbd5d49ea5402a90f4c9de20b1178065e7172cdfba73bae298ddf908b7aaec0a2e79d17bbb1101d7afbdd1f9463f3591536c558dcbf4c873829bb93d4e30299b510c510aee98f2565e9282394868bb8be3d22e28fc7720629d3cf59f420fd799162ff4e7ac2e6a735d52f6313c44a66ba0c575e6e72e6d9a67d452d6ec798eae2a7a2260705c0fa72e495c1b5ea3279cec65000cc793013a198410d1e081ee23beb2d17aea0e095e145f66acbd3feaaf0def3e21826580e8580af47344b7e0dcb7c5d1748e988304b88d5966df694eb0b348b556adf19b5549d2411a3f4487e96f7be761dafabaa570f94fef7cfbc81ae8a43f717b0849cee422b28811552672354d4107a350de6ac1a22249073fd654aa8af301472321e57a86d47d3694f65312588daa3dbe61422120126cd9714820700b6944bf06c7de12d5f2caaf461887b54f9c807da68fe5fb479dc0161a4fcb2d4da7677a07359bea49aa613e4a31013f9eb704b598fa61da89fdea71e1d930d3eb232b2457bfa2e0489a17a768cc9182260102fc42cc4dfd393018174ef41315c1e9112296bf153e61b6be2e1c117e9fb0b1d14445b39a39595d10a2c72eb950cb1fe3dff17508dc2ffe637a24d3ef51897af1fd374647974ab85cf7953a0c97f89519cca620d24820c4c9acc4faa1f04ce4de0038af96ec96b9a7dc6a8d7f984c28b8c6c47b75202a6f5131655714fced6d72a38a1879058d2a1163174a223b3d848fe35be21d2ff4235972d1a45ae514f2df37e4f43271f29e2bd475beb3f5052b18bc18eb6c520708b8024c9238ba8282dcc94c913ae1923014ec29097a293830ba58508a2cf0e08670b849652dcd8351c3dc0a534c6de6277312640f9130be28a8c27cc32e224b4216fc6a898906ca4aacca2801349222af53cff1aa4f99aa079a119542a0f856b5921a565288180caa262f741427ee3e5fc08a20da1cc8196fc0d81474661ed1cac90404bf870d0c96375928e9ac8a9a728c451914d5b3165d343738c6158035bc86b5b575504c66bff286a42d8de41ea0c900061de57e0969b9c6549c4ef276a496ac865c95afd25473535be28a842adc559854ea519093c15141b942c92b77821f62748945f40e53a589d8c56a58c266f0b895014292bf710efef5b7f884b6ff9948a294803c7153921bf8bddff1409e13444f02a89aad5bb18d2faa99725253b44210eb867ba22d4ea7a7dbe89b06005c21be654c30e49f10bdb183be10be206692cf1c05f02c651ccb8bec6928ec706163f58081d3b7d34c1aa2148ea085ad52fbe9acd0dcb5632e7188640c3d39505da278334ca4157a4ba41da23376914e23cb45d55edcf2d969756206da1147d7d1bb46cbb019a1434f97124f0aff0be6c4fd299a0a346b0daceaad06092ce1f1301e9d225399610d1a223984a7992aff848b15972106c41d25e4b5a6bf8081ac37689aa3312554f90b0b3091f3105f5a78d0cff810faa3e871068035ace21aa244daabb237f8eadb05e2d65cd808f3c98838d34a4825e2b3254e163acc49af3932f50a1bb294242b7b1f2802e98d95deee123316574b4027ddc37b71e6d9227a0628bed46fe0702879d9281ac63cc5382ee67670f8cc880eda521ebc61ec69f2d72e04a2042c690a363de3b3d7ece7ec3a32d043a7b4a5277fb680dc4a321d077d5517c2532392c87f41428308a79448f3c18c01b342b3c38124e8da16f71ec258dd68b1f3b7f3051689c412ada4489192683d2f7282dbfa7396682c149b834ccfbe31c78d608306780dbf0e9e5eccb174e542cf4ac2cce39052107e8254532e93d0b62246cadcb4d70b5e9ab4623d68b16eb5b0b9c78b761c6e1138b76061d3147263b54696f610309bb5c1ee63ed127d8e0900f28b5c00181c52a78e8c6ad8dfd4c507dbdba97a1a3c4f5521042516faaf8422b2a4037ff3c8c006f6461f9221082e39b50dc14216a0c15f88bfbf7236c7fc9cf9d4fc2779b6f2e5f993f1adf22ff657e763e0ffe55febadb77ee7e34ff06fe275f763e0afedbfc79f94dfcc8f813f897f9b3f939b27fea7b737c45fca1f933f02ff999f349f06ff3efe12ff347e75be43bea7e6ed9f3f0efe2afe317e687e6dfc0ffcc9fc647c177c53f0fbf991f1b7fc4ec8fbfcf9d9fc27f9a7f8faf992f38ff06fe257e363e0bfe69febcfc4dee07fffe46be235f367e1efed9fc79fc42fcc8f91bf98ff8d3f939f9aebf37c7fb95f8d1f933f21ff989f169f84ff1cff137f305e35be4ffc4cfee3dcded8fe2cfe577e60fe79fc07fe4cbc647e1bf8bbf8fdf991f387f22ffd3f693619fc97f9a6f97af883f347f47fe253f333e17e0ff4cfe81fcc5fce2dadbbcbd67fe78fcae7c58fc75f985fcd0f827f88ff993f938f86ef3eff1bef3f6b1f327f01ff3b3f173f29ff2cfe12b460a84dc5dbefb90bfcb778c8f82ffaff7a97d3f937f881f9c5f851f947f2f7f115f38df06fe677eee7c4efe51fc71fc4edb8fdefd0dfe27be6c3e4efeb3f87bf995f9c1f82bf09ff893f3b34b6488d73423f125321fc3c04dc23224d3570b7ba8dfe64915bdbd6fb3e71dbf29bf54fc9efc38f3ede7fbc2af37bf4f3e90fcedf13ff1d5c6df821fb0f7d7fbde573e6dfc7df241e2ef9fff88af347e1b7e80f9d7f37fe1d39daf831f48fcfdb27f757ba5f15bf2c1ccbf9fff09bf6abe1e7c00f9f7c7ffc5d73bbf493ec0fcfdf1bf665f37efb7e003ccb77fe49f937c3efcf932e6e3e3b70f9f3a7e6912f28320f4c417c9c057a944985e1d156c848819e100875e4f70142b728ba9861b0d977aa9d2f9f14d4658d45ee91122d0c48fc1350245932d579b08e413b4cca38d57759e11c94c199ebfad3764c067dd8710460b6339550494829e304d2e1b3fa05ba613385703b919335013e6e2b4a8bd5da64e6b841836b9c4091d800328774ebe68d0bc33c8c0b280fca2b78aaee9a0e40874e9487ad6d508d69abeb3e08c76446834b4430ca92800d1ef1d3c513f0900bbaf90aa31048810d225af42dce310ce46ee2bf75ce305a96d53c803778c89a218ac182b59a3a10118bb1c51535873d87329beab93227a1bba8f371ee2c4f8fdc2cb779de5e0a90ea1220f08754d2303bc71344e583278a0fd43d45aa6e266533dce5ee8f54ef2f82ae06481f4b4d2daba2dfdf8f2713b4d5c13fcf6dc2d45bc41061d7a9e4f78ca14dd4d27e116619bb060052cf9ca9924a147067708b92573343b0bcccaa657ebe5245b3f5e49a2bca04704960101941cfbdb87ca0ba0a0717111b0e35ed273d198cbf3f402cf3dd555a2139734aceeecc5a03c092577f168aba759f21b9b64210a6b720434bd752fd8279b3688648af598c7f02bfdd682bad81721c0c11286a302c2eae3c47320e2f6528ac02f653794fd4c3b3c65eca6017faac9db7cb5be002709eb19d22708b74f7bc934ab2b6329170803741fddb98385605f2beae7b4243e7b4c868624d226b6eebb48ca7a1da33703918bc006c7d740819073df1bad85d04e2be150a9c0e4f4ca7074c050690ff3d02e9d39129726c55a669e5cc3b4de9a801fa7b494a51d353e44786a4e6ea18f0b6a000025974e78e0f3cc5bce0ba6e88c2d4e5775a81bbe1d473531471ad25e4344110876274e2b1b5d77f7f8ea36371bbc08043cf7013a8319505a30cc69940e7d6ce6788ed4b56e964b4629558eb453a9a8dbda1865492a851ced78cf7733ccf101601a901e2873076038f84b15301c628bd87a475da1d8aff05a4d3a32b874a17772711095b4a6412209d95bee2df7965226290384058c04dd04321dd3a36c733a48775a4aee025c03d2e315a15f7acc2e5d5b7a393bf002fc0ede9774cefbb542b9c7b9029e4c3fe591d39916c8ed57bbaac9dbffbd6396d1ee7de6759935265945b09aaea68eaaaa2e5763b0b2a8666f2476998d46bbd65a69e84919743b920b810e50da550b6dbfd1d9def2cf39ce567c8c19c663ddbe22ac97060d271dac78224d83e857681a2b3c3d8e80a554e4ea910324ba2294340fe5260a258d0b65d0d8dbd770832a83eeedf1fc56849246b4695be7d7b0022e4adf324c9212ec99eb5724176300822505cc1421962420081b3576284162839ab9a712173c2c4049e9518369867c831b383c926cd933029c248fb3b6001e3e7692919a0fc99d6484c945b97f73e08914ab294462b871026d3a40063e66b27cec61c2429b3f6bf327d3cc743e95e5302348c3840d097a9c1086b68424cb3dce9a5ba5994f244db1584c85d79661a0ac448873f620e7dff9323bb939678d0eb556184ce66d0966cd0d7b84d5273d6377ed666beed8f869726de9c58f0961f8586bb1ed6aa87c6a8de13c65070e1729aa49c5b8a88342106ac200e9c14307505c083247881da9a70d8ee0f0410f131cd2e8a152434d7ce09869c25333a18a52bbf9e1a8b59bcddcdc41d7f801b7fcb206ab0f8909fcb1409e1c646c0801e5e948980a8abcb1c187d3096a74e066be51f7d60ae328a5144ad48f1b56532be0c832d2630d0b2510f14324072a2c0a4685104d920461925aa2e695660f5698217c4829f9d2826afad307851a7ce8f801032b2d576e040125080ddbb66ddbe6e52ab12ac306480f22341ba50472d6bcc0038f198c60a1f4c7091c7d99ac5eceba3cdfdb65530ad3226487198424f981c8d291940f31b8f9b1431b1c3728a5f486e1c28295235f6e706a53270a923244f2588571b2a185309edd4e1419cda266389330ba186f77c37826cbb9bbd51524fedb327e32c6740b2e62428f113c590364882e593edc108287162a585430d6e2691141096ca093c78e121c76a0dc11c2c20e2364c0d84a26cb27a256208a31879fdb6c055df5ca9b83e3385b815ab5e236b5eaf081356cc1168ee3389c25cb20a5c610247aac9094a17141ecec90a6899a1ed66c1bfe803006f1092c411c20616a690a1839556e0a3065821127364f589e30c618638c313603450263218ccda0e9c3595b6db56d2a58ed7018dfa8966619c7711cde81e33016ff2bc751a0d60571b29c3b8ee3388e33f226072960ece4189205c395297ed2a8b9ba3183911e509bdd362b2f1a94a8a0856987274be4d0361e4c48bef4c014058616864c81a18af46108384d54682861eaca9ea5252f80618a7286863c94362569332fa530ec6d6ba2dadbb669a7158a58d991e3a90e6d93e2c3150f41dc191265dbb66ddb644d3c60a9a011385bbdd63aa5979be28c66503334db194bbf4cadb322118a5aebd46836c327446aa9add65ab7d6d24a2bd5f2376bdd5a6b6de5386badb5d6729bb5d65afbb359d19037444daefcb83f9874f4ca0e4a29154384c906b714d39483cd1dbfd326df4b5fc043002432664848210a0f2938342ac7c891343de21cb9b14d13f765324a29a5d4e5864ad315d7d29415973929e06082109a6dc265cd9c2b35b8e9138766042566c80f4d509c7077ae050900050acd162b3e2c39bda1a2a44eb15a7283132a1f57a6dc2d7290f49133c3d40b475a98c1e3040818e02cc1e1e9c707801359fc7f92029e00f6b29c3b139e6cccb649a949bc157e44e0434e1c1de40039d3662a8810c03903850f280296654ff955afbc3596b9ad56a0d607d6308db235f19075449581e2c4e986a91672a010678b0d1b75b610797a01f1d011070d941786a043e3a230819ae302103f8078dba0946913c46708255957b49cc142e3d6c41963064d0d2a2a30eb876b53a1eee4e0b8cd5a12e8130e4d91a08d42095171daa871a10645a70855d60f1b4778b81cc7711c57afdd5804b299d8dd7b676d8c21abf6ebad962ed6a7143f6d03d5c66996a597366cb6f4d226aac5965ed864d9b3e6b171628364c408af081761bc62768b7011fe5b7f6e20f6f7a607f7bea7ab8bdcfb0cbb47d4115e7316237ebe7416976a10ea9e61f70825176af8b8820262670b0d37d3f9554d1e21e76caa29a8016c8fe8baeb973e89773dd2e7de1bf10e26719d37e2bb113f4117235e88da31358a6e770550aa8becebbbf7d1beebb1e8721ff3dedfe5aef78f85af2a99d3e3eb3d3dd6ddc1f0be6e4ec378690e48c77eb47a866ffb313d56bb290cfbdc771a86f776737ac554d1b9f40cdfa3d2ee3c4e8f45dbf17b585b5f2434b1dea0761df6af86412fc1d9b4e07ea52ba605f7e5aca80393aac57a9c41415f6b5050fda0b76052505058e97761b762aa78ee3db49edcee3d12f53c1cebb6d645eced8f95032f88bd7d7cbf097acf859e7b38b70d5bbe22568495e4b961df7a19f0c860551fc4dbf69d88a7428f3f07fdf72fa07ff9d3efbe861706d4a4e679df85238dddddaf19286d77ea01a5cde90f0460bbee46ee4bd4f0c6beea5146dd214cb0edd3775d82d319286d7bdf0b438ae41e761f0b47ee5b6f410704bdf7167c3177d0d370f4ef34e8a1d73dbef43dfdaa92a9ae1b047da76104bda76100fd0cdf545fa06f3d0535003100d2d5c5acffd3b53e4048e8f1e3c718dff7faf75d08bf0b3fad7f5d3f836e3c562a026b11ef12f13414e17ac4aeb0feccaeafaeaf3f419d002b710da3fbadfb4d97c000f6feb0773d7abb83d1fdb67d37769eff75ef71ddb6efe84b847d6396f33ee8855edee742ea21be25fe1514f45e28b750900e61ba85fdb6e9b19b60064a3ed67d5f5a4c481731ee1eb6d109c2bc4d84255a2f024c728118c0b64c16be7b38de87c1ba9785e3ddb2afe1e8b55d6bfdd1847f8bc4bb0c4aff6f2883dbae658049ad19be473c8950ba5847103d8c14d004f1014e1f375c2a90e70e933a499ce4c859118a74483ed18c4e6903962c1466504149d39392912f7aa8a07658d2430d1a893b7976d8b121840997bc54a50c1553143637d066a548eef7aafeb7700de9fd5cff866e3555d4af554e67aaa8217d6fc95dc3965fb9586570346cddb7e138db7656b9c8d59c69a9fbca25c77ef4daac425b480a7eba2cd31ff3a673d63c3dafacba39975c1c676db3e180287b44e1ecc2e975f5855ca9e42bd9be5d216e3bc73bce3131662eb607dff6a959548f63cd7d1dcfa6f76abf7291c6eefd31a66750af465fef7a0acb422fe57d0ac2d81051188b3df7b30613a133901eb390d0df7fcd9add34e8b9f70e4690a6e30cbbf1dbed310d033f7dee278801d630bab79b72425ce79a5eedfb4e67aab8dffa1bd63c6b2e562f536ca497a9337bfe9c38c0121c107d04248d484b3ae44423079b3e51f87408cb1ac6dec3fb7aaeb6fdc0a943a6988fc389c3c52517897e050514842b424987849e2894742848e2edf39cceacefc9a0db03933cda7d7de92c64965ea569e7ee56571b98543dac48eeb1f7c2961ee76ec562b18fbd8349b1a658589d8ee779a174ed74aabe9f2f2da483349e4bf8bff1725ccc037a3afebeb1f7b89f57d2bcef8b7839caf6fdfc48f4beec5d2fe9eb257da077f0a525ffe63e34b4b1e4f57a89a063a4e6ecd9301c06e3995b589e983c84cca61c79bc607650913a13678619a068ee030d0e2be449210f902c9aff07fe22f81bd116f366236924e54b4d43be2ed141a531bfea51c455721157e3c1e6eca43f5cb2fa3e1d7c31b502f0e77ddfa739ae82c9374b243a8b6a090ceceb10ecdef4cc45df7214d91645d5267e06be83da25953a37afbf616ba4c713a24c567fab7ff5bb38e9f628f67c147f62be38e51720aeb8a1e3034c90aaee480955ce0421e5861eb4f9f2de597f60f0b55a2d4d14d3f6a8da76fc24d7a760ce6ce9054c96ed9f802dbd80b1f1bfdd453b37d87218a1a0e8e205ef6293ec9ffd65fed2ffceea13ec24d320528146630458139a13fa2300d140733d0dc9a7461d2c1a8d112c88414a179aeb47d8a8a8c2d05cda49090d28f71f07db7377efb7f79fd43f0e36f85e1863d60a4fa4c9de7f499e7ff7ae5fb8f851e0d7faf9a2f43c7ff0bd56f87dfa858bf31b5065c878665bc564e95f1593679707d416d3065f2a4b103f92237defe117be178e1e60edb5740366d8fd624c1e6597121a6cfedbcb9d01ecb3e6e2df4f2ff9e08318354c1e917ebca3ecefc55acbcd4d1c729b88ca236cfe3b8b13cea284ddae3fcb8104905eb4dc3323ebd55f69f83ce32fedeff9ef305c8b40b2fcb1688b2866fe48ee943ed5dfdc99b6508a12439a3438c42cf901044d84167ecc01a242132b4574901406d331a54e1aaa34535eb2b8d927b6f492a5ca6e514d75587060593a2171cc9a1134524e099946ba309145a0e6d3960af472bd944704382ac0073d36c0c75ecaa303a078eea53c4af1de4b79848023157fdf672a109002c5010c3024168000033821001d6444fcfc19027904ab316dc8a3963c026fc82312e491ac047934421e99208fe4cf9f27c8a3097efe44411e91f8f913873c32f1f3670e7904809f3f53904701f8f9530579f4e1cf15f203e971ee0062614f9716d2e3ecb167901ea78fa0c77a9c2decf952001fd3e3fc117babc7096406e18478df69a9c739e4beeb7112d9f3761e676302c04142ae1750d6e19432c5bb36fd00b4367d0098203181a45f22bc3205fd113230acf43f5838a54c81a5a64b0d5262bd71d76135f7482f72e4cfacad30f543ea50e2151411fdcc94d289e57bee155f54c1575d4111915ef22f4056a020bc72a8d62a2ce5cb45d5d5fc8a9d2a7db0c9b746c9141e234b38e04c40420e3588c0ca4e9f1af331934cc526674c823ccedaf7b0ff1e08c9eb77d583591de8e70cbb5fafe75eaf0278f9e1029921425861a2505957f2d4b9c2c2036d92d1a18e53ed8a080a68948a50290194216eecb1fa439b424cb2bfd0d770568d48fbce6a25f5fc83684c8fdd0b3d160aa7950bf947a51984e76f0f7dc3fe86a3526db77ed6280c067b0e56c34cf27431f7f7f3aaee69e52c84be0a5121174a127a39047bd83bec69ade1edecf8a2389bed6a341a6979b1d7b2101217e707e95186f578bdf6ddbbbe9b582f21f22517bd46e76be9434f2ece77d2cec4c559bfe4f9b38aea2a0ff634ccefe18863cfa7ad19dbfe7e033570fdf9f3e77b9cbff0f5ee404ff5583f3fa6df17be44847323d11bbe9e767fefeb456461b2a5972c4df4556ce905cbd55ca23f3ad3a6f315ba5359b5efd79be4dfd19a53f9948ff12e73ce597b267106d4bd3c9441f7ebe58b8249aff7f212e8250b9e2d41177849d5b85ec9b33695a9d3af6cf228ab3ca03259ceb2ea678d4a56af510cf0e274678f122b3fb49170c49cf9c1cf9f1e5561640bfc336b2b4cfd903a9484253ac00f3ea869808f5f89f685253af8be57a2c91eeef8b0d227480b2560b5c016e860cb95b3ab05e249f11e2cef0b2d88414a97d1a966d302492b9804de9f99fb1b723f3a96d1accfe8588eb57d5f286998e3420fcc9df4d2925dfbbe0c4384cd96600426968d0f909c5b000f1fdce87db6f7d8af5c9c94521998f427fc4abb1ec733dfb1680ba7c29a2ae95f6499111d9aa28b5369cf9f6f445b7c2dc0d66c0d3d91f9617f98ca29214db2f8d888f20406a41733a32d4411c6d85b16c7e9b166b91e34d91fcbc51943a6b26e8f01db6eb7637996d39ae77b089b3353fb664f84ee310593a4ac52a6806dfa9e376b345c9ca3cc22411309743c7d9c976acdcb4bb3aacca67a9ccdf67879ec913a35c141ab3419b39b749167f248a3f67c1a65268330236f0ac5895431bf0c133c1b8a56f11692361f4b6cbfdd3ddeb68de3b87b2f7d17f4a54ce1ef3d4dbfd77b1ae5e29213aae91817e919af60feed93471a259d3e390b286741b78f42f9cc5f27ab5fdba28fe45ea621ddf6befde8a6be6bad2e7cbfb464fa1fd5528ae3143fd005e8537ab545df85a7c7eeb7773d768fff0b97bc8b5416d5ee3e1a60128d7216ae678d32711655674c268fc9de633119cf5c99b27431a903feb4618060cab5a993541e65d67c9fb76a8210a0b44f4f244aedd57e2f2cfac045f9c589077572c2b127757216f49364cc7dfd2904c10373771a04ef2f78ec851968fcad8dbb50ee0b01a7493a34ceaadde9711b371dc39faac661f228b394360a17655496740a36044b9aa43dcd6006ff9bd2244d7e9673cf2aab0661eeefe343b594834dcc995d9454c2f67c226bad638c6fd79f60d2e4acb68ddbac72a89a39cc705a2971b3fa4065ce399fe69c93560d64aa66cb283ef5a37352f953861ac8344d141f1d750796ee4f140a8f20fef4266b4ba93757d8651fab28da5e64fbf6a9edd7f7f861071da0c4655f8982be140e55f6dd72dbbfdbcadfbe257d6fe517ca2d938243b5a5149c31dbff005b8ae9a267576fb1e4c45fff2d793dc621f7dcbf4227f40299762f73d13faa8453c8f06d1fb71e8f1e1801fc5ecaa3fcae50ca14598f987238042f981486a74398dbbe6fdbc4641f6d7c01d5a35415d5c6fffd043548c0fe90689c315576f7785a6a2928650afa18947a3306cb0db2947a43b5bbcf8fbfa7181c6dfa16eb0e1cd90b5e60bf2bd1bdfd991febd1bf1f710e47fbdcdbc7388411e36853dd81a34d9f6a295370cf3d475f821a746fbfb642301cbdaf4ff1f778a48f9f32d5a3d2f78523d62f474f8730b76cfb5928864eff6a91339adb6a05f87199ec5eab671a858b3e370a3ab7cb3f288cb1e4f9f2a332d42b4f8cf3a966d98bb445f7f2e9d0cdb21fc52de56c7271fe4402262d917428bb98c5a7436f4487e6ecc5922e12a0432ece7132997216544f21d3c9594c26a6aa0fe68b30df030d3c6d4ad4e910b8566cc32b53f87b4062035902b1c76ffb0cbbe9879143d4e012f2bfcded12524b314c2e6c298689ca26ca32864d9f0952349bdbb24b1f231b0399c6b0c7bb65921a84485dc31cc8f2a7d36a99ea30b96152c344a6d65abd33e0966298b278dfb66d1b35e36d29c6869d7b6f193136e6501b6dc08fda28d37a590141d095c94c09612e0690eea8e4ad55743d0b99828830004011006315000020140a874402816030c95220d1fd14000a76ae3858522411c762811808210c05011003410c83300c82300c01064167112d0e0012f407ebfb9150aca236b1651dba42e5717ee56ac68ba54740f938c0947a85d8f8c5601232219fa86cf5ca8f26373c22e4281d8375fe6d4b30d08dfbeb0ec9368bb07b342983bc6624618a7e0ff37a74be2b25d399bd3fe5b10c472baa5a252aa29b6a840a2267530d1130e00e6870327ef086a67d67299180d7b26b9daa11e7b44119a23e984e69f26576909581b03de225a22c515dd1f0ccfbef6d3a06894dbd5df869d007a5f90b24f587b7e14a617f5289352d040aaada3ee00eb32ba491aeae6180c2eca410cbb145d02b3f54023048bd40286fc90d50713645f09842792029a2ccfdf39dc0f828243a75d565c4b7099dee30de7b9ba0c830299ac501b52c5ce91050fedc87b24759544d58f37ced11d61b3778357c33379102491cd5d9866c13334d72e4a3d19b6261ad34a654345804da26548bbad31705fa29ace902750dd28722993369bce40ba841d05dda08d403da463f6589c2325f021259390467d529637c0c476ec0ca3e988c3f32a5dd05e45cb60f4d9c7eb140d1c150670ef5b7de89bc7303fbc819156c43699a89924545733d906e14a30b05b4ee2981877b9f46349753239acf2ff3b389a751d03ed8fa358fb8d005f8adb16cb869d03f36f921f1f7893bac0175a3f0683ee63bb305b1b490cd2aa44c8d5fef71331e5445fdf4a2ce1cd4aa171a3bfb6b73ebb8db990d15969c7dab01d0cab8ba3998140d56575e842f1dccfbdd1b90982f0278335e8a3d87b5221b62fee253f29f84a193be475577eb844c1cb865ae95304189c9c43cff0fcfa6c240a659084d135f3332b85efce9433c0385d66ade8fd452ddef711623654d8591a00176afbdff452374c201501abb5d0e97ec32fc356b621adc47205e1b806f62d064b9a249c03e6cbbc98cf931c047e78c08c81bedf6d0c6e02e037ac9686449318932771560adbd5d978b9c0e97047974134b1b315f012837448249443a4ab224de9ca7f62be600fb18c552c9f2be4ac12704cb87580c915f124ae8244b9f7fd1fe3d4ce75a7a7e0091bf12b8f6f57bcf1835bfe5466fe6515a51117f89c4a0ffbef4065d4472134c141af679981a86b4a0046e7e304e284181eba6f725a10c0f63f6d9092d1c7c7f02c85116f45ed5f74d10f2423bf973c9351830e3322f5b340c2936ff692e48bc2e91051a360499f7ba6005c7fa32d20452c2759136ce8ed4b0a8fd13ff6214c37bfe5fe9cb18ac78b46d3c3d308bb1d5f09110197f88dc06d7e93b7e3c5e8b0d8cfa9bace780c5d0a216c08220fa232d8d3b775d199baa35c5f066c53ba3a9a8b4897b5c3e310ad56f168379c715e8c5127993496a622aa04a2bb7274ce41e501038878d0889151fd7d30029f215c9426fbc5172a8cef4c6865fc9583d50dd1ec2bccd733b6a2c59627ab95f9bc6f45ad6cfa3e5d5af22480819ff4a7b2057d1bda01b50f8ef7c6b898b6f3c97690686fc03b0df2667ca980503ea6c039e6d9277a80f25d764a6700a6ab71c5536b7366364f720b3be450c8a112965e46d2d93043d98c3f1234a374c0430612cfb34fad8d8e0628597f3ee09217bf3856f03b1980951f87ad174356808438542f8b200cc728769bc904449329ad3bd3b284538e5b4cb41255aa44c4d1096af2e5842c975d61b9b751126be72b96ed7136024c92849266b98d4e4aa9743f740dba3e8420b6fc20891d8e9fb31157ea09ab8f907c15f0cfe9aba5bdd09fb300cc074c511c9812630ea8b2685534dde5169926b3456e71d41217c68697ab76dff2672247977b6233c3f0a4f334729671ff9915f78913230d8d191e5b4ca56f9135fab8ab869f15723e202d0008102656118fe5847c4fbcd00582186d8f4c2ca51080bc7bc8f857314b22a33abbd919498316e3b0341bd2fb7a2cd6cd743b0334e6c7755e85a666dd812ebee0d63bc1fa3a0f68cb54a632e99bc44370445490e992ea7b32982da31473092838a709b8d717ba7f5b871d98a57b0879021ec111c93cdae3fb25dc3184060141759871215207ffa3877eb42a11b9cdace8e0d255a445a0f8d3cf72671005b9b87d3f89cf9ff6184cc7c7a6e17d35bbe8b723eed6cbe98b8a8210c4747c998465d66e2844020347f8878ea16422cda9a095f006018eb81542afa643f765e2aaf6f68419f9f375d20f8c2747888f37c6c6b19d0cc35c09aace1174124aa5f0e3daf964c4a79ab6cf466347325740ba96d42c039c6683335ef07a100587997a48457a8718c4640a2f72fd30372618a99ba00f95e066fb11e2ed2b9f333dc8ba2e9bee6698f58bc2368fe05ed1ef9ada973f379149171c521dcd5c9f9508c2c65e8ee26dff4589c7994681143179a2546e1aa976fa06f28297d1173485d7cf6efe944bf342999388303b7f7e23629c4c48c0a50157650fc09a8528ab5b3c5701c959d3a0dafcca4886bc6db507a9545077fccae9b0e06a584f3c8d4db50bdb96787c127dd60b656713d91a455e7a658317318e28721848f82784536f154dec2207350a83a5405eb1314a72c545fe31f7c0367d3af713ed6f7a75a2bb9dd268ab170d828aad89c257a94247b5b303650c685ab2e29ccc4db6eee992980d8924c4506019f9ba20eef3316ec10b0a9687175d3067e80e9314c9e69088589973fbf055e5696dc36aabeb8ab1d60f1ad47fcc880152a62a4626529ba95d9a9e482b2e4f98428eaa89310061139b60045ebaff8defb713f5f5831c0b4e4b79d05848cf6226be6d50883e3c730a722e4be108cbf1c3bcb11bd25c7710849151473adf70f332f89a711c1cbd4a093421335d5dc42b0c7681417dc16aaca7aab695f2c429c35982316d534f2eae3b0c1e843a85893bcb1983b9a46644bf8a893b36f54f04492c287712672ace6518833cacf7a12ac3698e979a12544c1dcf4ddb1d567e4501d708999cac508c76ae2f15d84229d84f5c83a2c36b81710e75358469ea9411584ab0c2e3a22201497ee9468885ad9af9683405d67f6c05e74aa1af9eb34bdf54f2fbc4f25fb32936d55ca876f71ce1f75bc13e34820408c579cd81cf9be05c18478f13c8859c0276775c3215c3f711d1491b62f1aadcce1c1137b360752838c56ef6afc93e21d43ce638081438481c7f0cea47763ff24eb298d2e0065f51694e2104e16ad5ebc52f5e575b154b156c8cb007a4a0d5a9b4ff1d2956c42181749e769b52c60ba44109b7e1cc1aa1bdec144726118ecac7d59163ddb28086421e92f0c827f38a184423d1992bf5d301e5957cb43e990cd52c120ca0b32cd5a45f0c01b02e8305138f76fedcbb423ce02c58542c9374fcbd20402c190951bea029834b610ee62806ef9f966a42faed223783980819eee6fdf75e05a644bc2c05105c54024254f955917d3d0e88a2e002a9f1007832061135ac2e49f706249d8f291349932482697060f68a4111c9020a4b104d786fe41360895e5cbb785185b1045df3288e978745304c70b1945347b9c1312355705caa8c3d21ae4abc835fb4e10491bc030898190176b99dc8502ea4e1561557955a8d412ee9f6c585791c88e17308f2909165b6e0c811fa3c5acbd2b10b76c9262822bf4d82c38aa0369a15d5ebd60c0923f39d254206a1bdaef9100336a3aa233156a646de6a0b974b6c5be85dc990bc4c1e02e9976e628a53fa885ec32b3e7f249d99e166274aa54a192ec13afb9d016be3cf1228433041e83bf94010c2a0c6448bcb18d3a07f58d50e94ddcae637543d4ab1510561e285269c839cda08e460a7465a58faa0eecdef10ebac9c89d11d14bb53e04afab3f4f88ea6a1e717f9948c1e64a4abb07135ab02f60c306108e3f0f1a7631a8878158ecdb9d85347ab0c011364123122828a4c5e4fb18f4755ad623c0c171c4e28edf6a4970def5ef92769511e5ff799dbca62e8726f1e1a28a9bff87af5d13bd3e06cc648630205ec0c5b26721d5e9390805afb44913101a6b10d0b4e89185ea34ae850c6ac7def0ef1a01af0cf7828e67bab2a084f07faf66e106beee1842fcce51a75f1356dd5667b940fed0085e516769a06b4a2748ab0106daa02b50f51845489470f2f0494c67ae75543272daaec319ba63ea7c9452aca70d870a7400210aa03e906309d62890289088658e57c349532adf60c09ba47f0b41a8ce7d97db54cc192a94d8bfda304900193c52cef0bdb834260ecde7c7e01b7512e05221173ec5fc835b00140e73086742b96bc58ec9e8c338fcd62ef868fa06234d902fcba42fed5dae6ab3082a5ea28f1b869d5e2a5298593022ed5f9bdea0fc0928d022961edb7a6aa3380e8e7904e10a8df98b59a517f9f87e5617e5d6a839fa713003723cf05b84a3cd7be86501be1b1862862f7775423f9648e957d944d6025718f08ca9b92a414b52c4208eec0bf1abe2d138157382a892815056de12a01808e857e99402f84f8c59384071b87a6ebb5a24f42379a9e17ced17ab16ea84fae3255f174d0258bb9506f28a889ee6a1966ecd92eff5bca0fba27545f9d9ba7b0982f96301dfe983d924a6c5c8b631956c42e5cea611873659636d5a0bcfdb2821380c56b7d51f42211c0984b7a5b7523f648827a615cc405180b3effbb2cd96d25120ec915666f315b11861b934eb5fc7376d181a880f0beec0f15b5d9886169a4ffb8b04a8db1666b068c85864cfdd8c2412b4d4f3ca0fcb76a926372492fdd058e92e9aa98a4bc5e82a57b4f423d6292b73ed23666ec138c56f8a0578079c3b37716ad1d2cb7906200debb293f9f569ef4300fdcc5f879becc4121e22d10a3a75f1d4d03c22d182026e14844696d9abe06d021a7258a4d80a4f33b34a37b4889de78b3c043c4789c178760b9bac2f8eaa512bf2c352198abcf352ba06350156781089cb9c1b4e8e70420d1775883ba4891c509e9f50e79c8bbdc30aeb785327aec390880b60a9e7ae5db5b86dc8c245c542d22a87f0aabf109d2478f727909fc704b4242614bcbd03d006da790190fcc47f0016b1e3fd19da88eaf55da127a88725d8bf86210a5fc47fa2b71d6c4e97026bf0d0390008063a41e29fd59b346a0190b4c6d1a9bc3a378290cb073155390110dbc73a21afd9cfa87c43ceaf759abc2c7014c331b1222b61261f7a813bf2a3699dd19bd580f98d1f610a9fd2454235dfe8b128d02e8f1d3f74202d5e408f6787250f74c0d22a9024f3fda9eb4e3f0db32c1334d6d1f7e9400065af58cf66a80974206fec5baf484f04c8818718ff4182c810df0236fca43883c3ca1e734e16e2dd05cd5b5f3502d83ec801e8f4087f90386e088299d6074694a12bf664e8ade42a34b3a5b48df3e176ca1112237d31a63c0a34b4501d0bd68d243b1f81f823278d464b10ee955e9709e0c1462d510f37c5f6b3c1a4f8c207d0012a619a2ab2aafd046410a7061a61e6633b505b97c90d36cbc46145499c2b9cab037587dbef0a88058664972b511559a88bfd48ed9b817135a339bafca06ded010a0724a522350ab5ffda7252f4861b352bf0e384b5465c804e0a45d98148b85739606b3cdc437113b41a07fd35bd2d543e50edc0d58874bbb83a82769777399e40ae0a7a79695a2389232493f2b6053edaaf68b4b83e7a7934e28ec7dab7522b11d701091559b8a24d37f8ff0100cb8d69143d0b1bdd34fde2deaddc21300e7ea4c0bbefc6859bd4290f2a1daec8a85c14d6dfe7586c6e3415e2a9636501294617edd45b4648dd1e90a4931186c365047f196786f7544317d8656fc11f6f38362d4878eae7e5d2b27b7e24c75fa28953ca8588700840e8aebe5932e6c468328c184dd4a0cde228e85d3fe9e39b92d3e4456a9653f03a4bb3b86b04c4a49ca51f92b394611d6a6e96868ffa5c25cb09015a591b9d707b622a94c868780c3dd5f9668dfabaa1687d35da4ae91517ebb7b1b97f087a35bff5d6bc035baa36e7ca46d205e02e0661f2d6a3a184175373e6526da059b7cb9179826ae09b5b5927dea2edbb1a45a2466992e08a981425a1e6ec63409af6b8b89797371bc467e2e8f3c5631a77dce864926963b33b08cb6e14cd560e6f8295fd3b537b7ce5ca0cb59bbab1dbea4603ed56c35f7a40b964c960fdb68bc69bcbd6ce930845d3f96e05a6f4a800e6bca122c768e6ab6b66224dc6c6243c04f3c3810c6161d3f77b002c51062a78e5b28243ccb5bfdd084cfc20c64f25660c2726e8da76ab812207f8034501c2fca7788a88833eadcb265740af662698adb91bbc6f128cf50092cd931d0bb0c73503c1532ddc2c31b62f16b5f3070ca723e551dcd3c2625d6bc06cfd3733eaa2f202e375001ce0d4bcdb01f42b4138a85e922ab0dbed863facc7130d0d6cc3a302aee6a8aef921d4e7bd3be7bfba7252c14492e27536eb77a2104884df105d465273b1bb8c12519fa0eb7ffcb5a5e65c6104e3ecd6367eafd066b3e6ec01e82cdb0f59864c8b46cd6aec6a78300b8cf20e0da2f17f6bcf07db8e483b6e74f7a87eec92a7b9d70149872412e8a6e614a4ee0f0ee06b03a24d81797ab420c55f2ef9203ba38cef08d6c5d55cbfb444ec0bc105781914de5f2ed030de2d1b4848198c66ed575b0482999423ebfc2f504c8b9249a0e9fd24a5a18a0ad33b95c01a805245894ca6a06510b0130fd764d569140dccd969ef753abc6b086b0d60f773f3fdf961c930ea5c836ce78062f0da778d01a62068d847ec589da616381ee22a50013834d01287e6ec1cb5fa4074901f6b7dfaa45b1cf212efcb9a731eca190f907bd0581066c348836b2cf75d84309b3344e5120b070bcc5d9101dfadf53d7e12853887c3d1d0411109d3f64520492b2822800a49530a7b0ebd3feb835e3cad41ad730cff89f79fc9fae55843fb75522ceb8f9a9e8716fcbf4ce6c05afc31e5ac96de5e61f77ce7bd4d3951958c211bf8d2a6941d4e0ea8a1561189547b48e903f1f582e23d1b313a956d8d7b2cb68af04ca48799181f3940c42adfb71a8629c82603ac86dcdbcbd56a1879f22b797b005079c61edd769d9c7aa74c52608147106b64b7b317424787baeea9e385a653e525d1de76f6c152cc7f60182a34c312b7ba469257a5940fa5efb2534d4e479952dbc916a5d63d2971580f76a72745834877419f22598ca764e74bb0780583cff5538888215d9ff692ea3608feaebca50bd9b393476b63ba64ae002dfe0577c365a047ea8a490917030389d4b0048f4e00c361ec8dcf4b193178d3cc570a67af8a0b762bead68b36b261a7a1433c7fd2a55d54d11884f973042b2a053c1a58c6f5d7ab6417609bfbe782c8893e4a1f085839b8052d27c53c0840ca573017ee941886ad282fb8bbd86b0b9f2b1c258d80bb8bc2f6210f8e2d937cb2999d5e47d67357a6d424d7675dbb1736a85ca2b802f8b5d96f377c6163e1090ab1ad15deb4a9d98b268dbf47e43359ad0ac6226029b35fa8da268d5316774671349e952478180eae04b0ae02667307b0a4ebeb8305cd06900b8be47958ea47f72ce4790f23bb9b283f2d0cecdecccadbc236e3964ca7f5b418a46a85a0625742dacfc30bb310925e07479d7d4a6ac7939238ac580364c465a66d43629a005a641c5b569198296e4b41037ba374d47b2a12a15720e5f33dde66498673e1706740933c75fdbf1b0da3530ff65203c2db78202641406d821d912aeb8a617060aad5287cd4e5ec9f575c815c3fcec66e135ef5aa376486626785356faa0b87f94f78618f232b80f96a5179705686e808f6fb36c19d16c0bc8894d5c9e98a02e033f9c086177953ddc32267d79eed527ac8ae5876aa6873107040a7b37203fe6320a885282785df1ba592cd8232553d34521904a7a1967d427f595d5fe0f064c9c59739d65840041a47ca872494cdb0fa9190fde9359fa0845a26e84be4f01152ebf67154125163042e98c5f369031d07ef0174ef4546082000f1f2b2d476ac4c3c0de0df71bcd4284a6240a9d474456107c38c1895c09ed9828b3dff2ffb464d2d9d1ba46f54a6dfe89ecdc39b7637024791c3591a7d7671f796cfd1d4f4d927fa2c032a8932e567d36074c81620cd87f09e7395f90c4af615c36688327f45bf8383768b79df8d4bf0be72a131d0adea02e6d11d9134dc061d48fd81980a8e781214cf8783e61204aac60b2585a582290fbb6c60f1a9a6fc856ce215968ab307ac0076dc94139b70ce4400c741075cb4c407b8992fc23f9ca3fe3a9d8ee5e4dbca48ec2d0d43362e35f277869cae67b4481de6ce41fb530d7a0525b16bf3220125d440245fb3ce05cdee8e1db006563abdd498f2be4b0bc26ff3e59018f8554a566f48e845fd85fb77c20d2cb94cd991f88aa1aa65db208ec4b4ebd0b754d9d1e11fb8b7deeeef15c1ea9586e1a077af08da372bb349714550e5a3941d10e2d627b32230e7d41ac8337ccbf293b223ef1248c9f9675246e84c226a1db09601d36385032dbe02f682122c02d130c778dacc826697075a62550911717c761ca3a54f6078ec7c588ee135fc9ff264114486b9bd17b2e3184c1c50c4ba5bd7aa51e96f94686548d433c8d3d04f5ff0c5db8d11355a4332b3e8bc837ac3d322fab1a0fdd057d8e9b0bf90e35b574df1ae42ce527a6333d2954845ff59658111ca53d3d5d0ec54a2058c74759fd3b81f9db740240331bf26d921c6b50417b7ceae2782020b1db5ab76c922e01dc82200dfb3976c68ef0e822c820bc1e9c011a83e57486c6a22c5227e5b04df7eb9075669d77304049cafa313941d9465921d9cd2cfbf78f5a3081a8cd38a1f9abf8e0fe06e0ef54274cdc6243b0296822d16cf51abeea58833078d7170908894e093ece80209b8462ebb10ba6a2248126482283411d00302bfcf8f7989403ad0ebda004c606747cb1b170394d2abb0d1f1ee49f3176a8b5422788ecbe0b03a498ca6261120eeeaa3644e834b2b44d2420176f609dfd093003f76f4e8d685088e954fd800ca53b28ea10cb0205115632a0db9fe311417aa9cfb1da6bd156819bb1d4fde0ba3a3da0c0e51de87603f27c8fbec21ec39f97bde45f0ed5ebdd9ef0636cfe36f4974b0f650f0ad6746b645c321a82f6280e34e0ef54cdedb7e002ae6e5cbf9d79b27b9a95abc0291faf6b00d380e038a820276f9b16412b8c9e93250e6c5893770d5079e863b7383779c7db4d8d677e90a31f1617c3220835162df386dee08281522c9a99bb1303c12b7637e6d1de50dbd6dfeb664b59089f12d9685fd0758d40a7527dedabf2f55c3f334b853207a7dd70b02b16a3055458905442b0ba224012cef0a40f3c1351f0490b975c7c9b9097bda4c845f2d0065811ec92a030cb0d0f4640bcbea81510ca04ca9e17a4403be6b46b52abefdf7efa92990c8c0ad198e407d46b557266e5dcbfe566ec2816bda82f60c8a6b1ba08a0efa90e142e3d75d4d6b02771da889cdd63ebf8ed21d3f136d77d6710954d55d517465967c204048fd69595b0354ef9f68753574cd0e6ce0dbb78c0d9a252bea6ff50f7e2e60fb7c82d59368f9013d2b4e9f671d7953d533b2b3154af2982b000ef87c546d5c58e8f4dfd02d03fa4a7127208efe8da8ddc8a602f0a37ef185a576f6ecc6e99c7fc6831e530590018a670053d9f63a1d9435fc7903a002ea9c06d650620b294b256110fd5fff0410fa9f2980773305f6f13576fa5c64816926ac82c6000017193b08413292ff194f5c5ab9d9397cfde36d0b2785e9b3833e5b216ffffffa04f8243785209993afff5fffd027bc5b1b60f2fe6f8e2836d74ebec236285901bd4a26961c714b96b41565dddce881d724bb3bf68c9794e9603a60b68c41a18ae4b1351d3a54c328c8c5a55396b0b908011ffa270807e698fc1fa024c9a30d6f83fcdaff9176b32f64f343c956b53570d71840d9ff0bd7efea9e20e91c6c66dbd96d50a379f79d29c2c18dfb8c03857c4da051dfd88a8879aa2c5c689a32d255207a28ab795f08111a89d9a656142e45230a8d3669865f8c22dbb40a635e5dfceb3a42bd363cdb61ca05c10e9e95b53531d1a8ff95e15712be4cd3ffcc686b429835658b8f879b623bb2a215eef338eb82c00201633c24c6b6c4881d23596937e14e415d87c3f48ec9a572446a50453f21b3db2f1ed0ed700331458781032527da8fdf1a229c452d22bce3b1f73a66042df4a564fbd98f69c0a9fa6d6cb31050ebf30921a99cd59e02b46b17171eec0f5a265a68f9bb02e4fce7d1b5965954e0e070c06b8fb717f5c28fc7b5852d3822683383a9b4812aa56b3af5752a67b533e2fc37272c2760add50b1a702a1e431a179fe756cf150a8873c0033d742860e81041d0cc58cc00d6e0fc43fcd33941914659110400320c970b6c3ad96d6de0d51be8fd29c0ed6703825403be1003e2e48311ebdd28800f6b2829dc807d08c22c1f879aa20d25507c751a140cfb334e83668a6e90000c61fdd92128d926c1677d5da1c99fd825dd1a0a7f23bd45d3bb33842f7d955b0f38cf590396a3d9dd00830f76bebe8f8a5e97336da8e0878432ff9a6b14dfe4042a10acaeda3bda38a3d95254cd06911ea42bc170698f959901b000dc8d51769811f125167c9f804591a0b433031b2a652f72f9d851cac2abc7aaa3fe1c8a511900e5f744eee504361d16fc65658072a3264f910476752f78ba3ed5491f4c1b23ab213dcd054895d79c2741a7e374b0767c2e57af978d3330e0e4851a11416f0d6317b7368e32ca2d078669d57a06b05edf70fdd3b5e9624df451b9c0bcbf02d8070e480d0b649b3f838585237ecfafa993618a0dd0da17f331cef3d951b269e1813504f59f31958ab6b849d5d8c61b0cf7f5f7081509b92985e81681a5332f9746f74801446c51b54dc040eb3a03de5f64b540c493857bb34ab72064a1117ef2d7abfc4a5e35504a0739df3e51598ba800a8caf9a61595d063e8b2d3a1ac82e264a299e068d5330f09775a404b128a7ebe8bf65534eb016afe3c045beebc6f6f1e211c93cdc5de91e32d42de04aa1b35d143aea00717c2894fde38b0119805e0632d293f59059490ce2db205839dd13663ef600128517effdbdcadcf3a38905505725839bc9020c4eb5ded8268bdab37ec4351bdab6ef55833a977d59dbe6c24d030bffdbe3655f2e011eead7863423b72cdd6e254b66d83a2058e1fb6973eccd34dba39cd7484018d033fe445ada0a4a03ac6f047d41118c54cd94980bc00d00f289a3b952e43b1417051c32fa6c0193105a00f7efca770d5094a20e9470c8e80b5d6c32993cc063c2d06b22d50a210cabe2ee429817ec3295183a707a12c4c6f76e64ea4784b2cc2f3c54a6579f181773291b2f29d6ea884de9780824398bb68308b2d15c8e56e03910075aef44bdfe2e0920bc1546dfa479f7a0abd547f9e7835b6a8e06dfe4984b2224ba1b782cf87a6917abd9cecfec3d55ff2eeef1240eaed8c2cc1244b906344cc9edf4630e248cc88235e7f4953b00fa79f6ce6af0ba7f9deb81ae0a1e5d2d07d9028908550818323edf4b2c5054c9d0bbe479bb42865ad5b45da8aaf300cac92642a582445837ef7f7e20a250e5c4b073b716e26e075f409cc2f471242bda767e3e6b65d9fbc3947940ba2ae645800adf46c48e3cacc87372fd55618ddcdb3a7fa2edbcdbcde80325573775b232fb97aa655659747d378176ae8a90292d0b4250d9581c5b076962068ebe0080361f61ccf8d09b89731fd24d9591663eaddc74c6e5a3e4a6c8575b2fc4fa854ad19b0e1a264999b0951d2f8594c457e5ddc980f338c8650147755555c4ccc4d69584193b2a41ba9f0d6181fea9672bc483701b78757246a3832b418c55b6c3106ec7316dc4e504c2664a4b0d798f5c83d22408c95024b12d4b2b63830726f65a4d1e0f31133e5159bb72827191fedb034c4f0022c30f8e0d1a9e13aa65183a9c188be4a2d0f7a3d6b16a0e0b3c0709f8db3e2c58aec97bee6f20d32a691a81f45b245c6769107d62ce13667585649ec48c34d133038074cf2b9b8158325739f1f116437633813ac11ecfe86da7052f9d440f8ee83d519e3c859834386505ffa0224b64220f11b38c43c6b08065e239e7cfd6bb593c2a8dc7b80b18db741bc60729030fa614976433d536eb1a5aba146b7c9f935dc5c60e316a3635565fd531e2d023a530681732ac247cecdc7f537ccc1e5661253fe062b1053f403c2dd25ab923d3f17c9a4d357aa65e64dd43c322932580a7f841347907fbad408744480d4528672adf2ecc309a439aaf492ba4afb54c07755021419a8a95874f4e6ad1bb191830f20551716fad97e50a08ab38c4c3e92d13c3c71618272bc985ed78f554611dee1e37505c1d5eb7a27b0c4cc8c3932671ec5c1fd3f61d7c5fa2c626c4a37d9381cc1bdd8c29e5cdaddbd98bbbbd8fbcf1773dc81eb1742ba513f38c04917270ef8416bd7dda8617f901d9fbc32c71d347e21a6b9f5c1118e1472e2a01f446b8b351a69b18e41e63802d72b8474467d7080972e6e1cf083b65dbb8f98031658a310a635e983234e8a72e3d08f46db16eb6d2285c876030747e35268c7419c106a219aedb483c35a6a5171785f750d8cf7a764dd88892d44b9350496df90180fa2cfcecf02a56ec408c4b9551d3288a367e5217623470cfdc17ca4cb785eff27bb0837f22bbf0b1b414ec9479190e55e46513eb8fa5933726e58c60db55e84a85ef6866698aedd4b104781a5100c36643336932c6667409b38eb8890bbbf352e156ccb8c9d845eb03c8e82ad416a61599bfde06be3f4bacc76386640c8a6e21264b2ecb2d0ccf375fac72391903a93014b102573fe18cace4f51b1af2e39e2d6488c842df2a410a3506d0bc685589d42a0c5be0efa7a116921ac7f44928703e24c8bc82e6bc0a8031f71a74bce3e8b904efd7d9b0c1f933ce3cbcb10acc72ee7fe6a49924916e90cb92b45b9f859e177743a63a03d83f190aabda2d406e2505dd30e363bd156055d83b3ed7087f49c4e84c3950d9bf4d7aa41c11b51f76ba169874b825b048169f677b676a5acaf7a4c8dc01d4fa0e2be147f13f85e5c9369ef448ca72836acda2e901cf91e399639c527f5791bb1231fb5bd289b42b8bcde0d5efe4dd26aa69a5bedefd07808e69bf12c945d5db78618d714d8e4742935413869ef110a03bc3c857b11c018cd22b91e92fb033eb458be906ea3b54527d725105a4fe9843bc8d4b44738e90058a441fe27b37c065410b57c10bfedbe102a9e86409f1ead6c2f7445e2d10d14013c1baee2e93806e5a2afb98a0c9c17afa4cb79642c65d95b7c0b80721716557a2ce45f738ffc4e06d39c01c2e2b26c9600d6b74d94c80bc09ca9813559b260a344725755b354d63ca958e163ff72062c7a8a41c578962bca0426026883b3b1b74120ece719b7c5030034ca6419b7eb428b883a56fe7620808c14f9c566f2bb664544ce404f334a8d99014c67817a5bf7bfa310a0e10c2452089b45fb10d4234c77f1f67590e46ceb2b8e00977527a34d0eb41529db3e52254328006077423bf2c669910412e8333340aee4792b44a525335a791fb1381c175c3d25efe74a2de714dfd538f57aca638a56ae8fce008808ac3733b2e354a107440f0f895365cb5175e73762193037197960886031fb64032e896d6a78d289f4cf984304eec3c46f48ab6fb8867b52ad2a9da227f6a56bf91c6219179e391974a34ca6546b36146ee9b4fbf777bfdde6774737c6d8fc73633c6b2fdfd5f719b538c9ea5d71f7a3a033570f9807e6e3c391bb8741cb8d8cd2c7bbf2f6c0c088a5773fc37565d1f15db9bfedae06f0d0483c2eb3ecba2776e571b4cdc0c50dc662d71f00961d079c42f8305aec2a5d9054816438090f9b53e2c96450b65e48a071da9b1bb9097631769b9aa5301872365ba6211abb11c379c314634a075677423cd18cd15371639762d6498e9be0ee39c9893cdb0df78a6f49c0d87d7b16da40230072893cd582a841fe2ac6435eec92e61b717f60ec8b0a9ec25a767dbefaf4074430ffd91f398916938179c417d38a4581ab85e12025396d67bf536e3931c02332df46b0ec5e09aa3de13e1b61357cb670e87dc9917d11fd28dc77bfb3523931d3f34479635c06f81ac97765cac062fdbe47c6d98a2fb4ba4605f48c28d02c941f0aeb77415aa95a4da15ddc928789d60ed413cdf1b729f31577c15a09434fc346c61001682234bb36abe755f40373c04afaa74083b2c3b0f087eb0159b4dba99849d8ada4a13190aaa298a27c2e8013d84e41036e3808fc178963994b46886515e529ed4eddb8a2df0e2b6da020bdeb7b5926f7e8901c903684ffb688c8cedfb5efbe6d07a34a125e056341e1c9c63bbd93eb5236bc0cc620af061bae099acd499a43aabffe3c820e3c70f05468f208f1a45f37dfcf4a67db40f5a4ac769b932ff29bb186d20baa24db0ec4f60f3c2c39b436a771b1fa56736ad69cd718dab6abf2b24870bd9914e7f9db725559498842e8568c8a8f81e520d063bdf78ee6b9f9f137f4e470d2cf410f6172839ddcf836cab25687b31cc7ab9cdd104d3766fcdb88ce133759de2bb32a1d35f39a02aa1b53ad450ab73b83e03840a8f13aa034f030931bf29e04111876631af481d213e218aa4ae6260af9fe0c45295d260f1b224b2666173a34c8c816623f55a1d0c70fe5af208631a4f7816ad943c3286d5bc26438a041ae2436ee0e1d46c44cd3b34cf050cb28f3b2c1432ca34cca3de8b076cb281397328c664f7b40ff53470c23d5a0ecc55000328ce27adc472c3799db7523d037e268599ab8a4ee53d8fa150ce3826e6d1c3a49a3d02b8127c7653e707dca11b47fd785b12e0a8ebad09ea36cb84fd88ce0e2657c78e7820c465ddc92a530eecd6d0c0aaf0f4884348c603eb5fe402c8fa20a70d2c46599378c1b7d82d0c0d0d8d60c977a43dba502d63002e39c0b777185bc4f763895e8f080c72b46c4fac533934f1b9b6bc398a1e72b331b7b31f801388c34713e09e92e4d7ea3adae40ccd34c112ce0b5ed0d32b0618ce9e784c867bd380188534519382e16990e00c338dc20f0981662a596bb309afb531ce1e3e674a36bb32aa4c316f42f54180b224f243849c916c608d8b58816800aa341547c4d521e376e8b4400092346e5a3929db400d5d0c8c3504f12d8e0c2fff76913a3f4174e361770ccbdda0d61043b7c4390de1765762f4118c98036cdd59ee3c9295b92498d9a776e223ba6ee3d45a5d9612e83f6e77c301e65d3febb4d4b0445c6b6f12775304205e44b6ba308454e29a0746c1061da0e4d58701098e760dc269f05d1804bdabf62f3167d5de7bb935b4218b9aea6cabefa5c59dfea609c76820aa657003a3efcc0ea14668230c2cb1c42857cf22452c040e562c213ea58fe9004b3ce9057cfedb1be5e2e98be3466db63101c2e050ea384970e59205c554d3ac9f092c71b5e24434315551cd24994391062601e7efc9a5893d8045f41296df8ab163a8b05031b044080c0427054074ccd7179e7943e1dbf756cbc79a7db60e9bf97dfb60c584c6ddaa41b21441a2164ef2df70e350fd40dad0e3888672963a6d01258640be6a85457664d259551442979e4885030910913d58f9c1826e9476aa61a465790804842fa5531117107f69104bb3cb0fbf080eb302cf6007b8bb7c03e5e876123f332f67a83375c39376c384e33210c2f2786cb7156e43e1774456e52088c40fa11621194fb9e11c490fbdb1aa68ccec17c31df076fb340760aa409e4ac4bd02490312390314064ccbcebbeaea4304e466dda05dc0fb56992e767c0b511596e9f9f96cd1f1236a78c0cc81737903a9035f426c84082903b0dd527943fb5a13159843c4e215a18e2f2d8802585754cbef44baf66b383320a55575d33aafa9563a27ad69e61d74cfcd128b430852924cf53298463fd4183680f643c7b7b4341fa96f2258f2fb95dd8ffe5e502a7a59cb4246d0efbaabee49a89af0bcadd7a0bf3bc1c7f85ff15e6a91e50e206b3180feb1c30b2bd27d67acf5dbec2e2ceea2d6fc13cf7ab9e987cabe21b39c828c828acb26b68ddc023486a1809dd1a46488aa88144d65a2993b0e5add7f36cc0095210c34fac75196bb962c541ecd80e10c55abe53714003122c89b5cea3813504c55a2e63d5e848bf64aeb5d62332d7304a22d73062a25f327b925ace28896914d42f997f9037b3d56ab5debaeb2d3077610e4c1a8c8148cb5b3e769396db15e97e9037dcaca568229b47b4080da23692a8c868c9519f3691f918599f7e5dd2af47f488a433fad34d7277d71af4725d6ee88570e4be5c650d7dad4730110855e104406a00c51a9450e2a701adb75c820a68bde506e74385560b0744c65ab06cd9e280e0be8724892b925092c7364a2249eeb79266a2a9e60854db87af3c821348c862d2e807a9a4f506b4ce5111de2b358fe3388ed35a13777f13ccd1966853f8ad4dc2133054b9576910ce6fca1aee95f4912e77d40cb973e186822714a103b9df4bda86f399c9b195e4fee9a4819656d1860fc2e694db3ce7d46eca4f3405f51972efc09cf074e7086070bada08807248b7f7223d3713731529e67c8064ef065e781ba848d78428ad87d4a0811a68a2f01886f7b98d6200754dadb9877491c9713f509bbfa4cc7386b5fb542e3dc91b535751f9e44e7e8350256f0830e50dca6d90325366ca95244d8b11434686ae5a2d3fc5a3f61943e6f5ffb6dcd65d5d1ada49a97337e596749cae35a5eb64d9935e7fd287ae4949b154a31c9df444438aa234054717c2948f728a9d14944f1bbd261ecf610ddf62f1a128de63f933cbbdfa355883f45b3a4a8dd2595078cc2c32ca5ba6e153ac21692015de9a70b757e1362cb626d4a689a0186a22a310873834e5ceac7247eec74883f45a73a7de33739c4cbd647eb86c994c2693593cbef2288d8c62a0dc1a1764b927f704880b43ec437b1addfed446d61a5923a38989aca611b5d99a7411877b8aad49eed396c94e779c4cb47735eeaddc36baada45fa87777871b28ac03917094435985c799bbf74322ab533087d2205f5ded5e03e57a2bc78136a60e877b74d6de436cd02cb08bfaaa0d6431076448d7502186000524dcc00a2992a0e23a38a2081c10f1e30111781ce7a369336b2d8739203784f76931f5b039e48070b30ec3f7391f205d43bb267c78e73d4fbbe955fb89a69d6b5911d190908f2c222a3a79bd266e9a2658ba630f2d4f4cc4e7b1d54f3091d5098872d3777209e6703b7c78ce25a47aaa95f3d1b2fd89bd73c99d5c08ed8d381f1a23864c0a1e5f283c5ed3b40d8bae21bdfe9984c71f9e9f57772a01e75432979c70a08d93135147082d7378c342666bb235e91a13ee21fdc2a26b503091d5e7cca53b337867fe76f487e8ff00847779d098b986cc44604045145a300335c420480458a0832b8cc2e0041320e1c957e582f880828a29823a60052663a0c00f56b00406414d9c018bbe0477947c7e65cc3312ca24119b4d92f082a09837c3dab24a6f1bc8f399b1d57f145180d8ea3e33d6f2b181244f4f8cc7c84eeb2d5f5de69d8eb5601e1e24823091c55a97a0786385c5fad5650b8b15df6879eb32d672dba8757b890fc2f6e91ffda244c236fa81da3410104966da44134ab200b26ca208b2aa554dabb58e5c03f900552026f043bffa8709ccac691a562140c3443c60a47ef556b224cca15fd2e887ae191ba88186acae94b0fa2a022474c10ab98254c6d473a777d49175a0b27dfbdcfe31851088dafc408d1aa881fe43f501e27c2825b2ea21fd6a5977733e5db36191de0a23627042d1d10a8eae1084144760218313dcc0052530ea17fd91fbda07c221489228d2041a3001095188b5112421307204238e86882085041120d4804914644c883516a6e003062998f84c810520a2300409214c4831640a05345952041467100390d9106af881d010aab0042e4021d60e50020d84d04408148cc2a0c5c8f59c152ca5f7f19ac4c08c29b91ea5431eedbd24a1bc1c10a370e47c721d9af908c57a7e60c41ad2b083231e00c18879e409a1980473389fd79859ca18fa15907efdb0c2b225e7238fba491bf57b49104b0321bb3ccaf5463d0e1cdbd65eedead0af3ac3ee9f342b98d337ea7154adb5ffbefa557564520028bd87abadaf7ed518587813984d3f202c265d1da84c5df4ab5269445f3d30c7c332b4f6463d8edfa8c7518f53af43fd3d8e524b7aee8e135acfc363877598d1afaae2343b43071184557c40662ad220a50ac79322acef7ce4a540b3a7f8dbe9bd8dd6db8fd6d6dbfa1c769ce3bc213cc7713de947a9a85333f7ce1c1eb72cb2e036aa632f6251eb9ceb1a74a0a69834578ef66c6a2bed496b6fd774a4355be989943772a4b6b76dca98dca34d3b3444253f8592e4f9fa7d9447a0c292dc4275621e33cf2047a80214f902aadce33d731ea00835283a3aaaa2284b212900c9e324429e7791651355dc204fa197be11639565bd415d7cd2a6de20ea41244d35ace09387c03d86842304b2c8f43af740eee6de97e4711cfe42997f18f176b41d82c5c33dfa7543d8af7847bfe6a67139dc49b390fb8e1e5db37d879eee382ddefb142dd666911d3d86a0423883260eb68fb3c8d6d18f24f32c3293c873d3f087837ed9cc9f22f3670aa197241c6b6542b842848a226cb08414545144860109122cf0011640ac48c1af4c4951e40422a2f8c20db260e9810f5a10042146040105b1f91d43cc29f4158144892379ec231d1494e73b896622cfcf7b38e8206a538d9a1a8d1d6474440a49810b40d2600522a8e00103aa9044094f70a20a3640e208c7cded3d8d77b4779847c5a3ea11bbcf03ee78dfa8ca626f576c2c2a603bf71eb477d84777ed1cf66164a7c3dc7d480ab35984dbb58b2d760fa473d80778d27bf0be7b6f40776efa482af610850e886052c466117e075f24c37e483f5e15a18c894655e0e08a3200c164cc5484922b80c148161be7913c74b308bdd9139b4656903e63a4fb30b2f3ddbb8cf9f8380f8b3d74e7b0a4b01eb4262af0820b5c302493c55e1436cfe3d331f01ce0b0d89f3e08652cc68b091128c104262891c9623206621f1ce8b08c84c5c63a433a50d8bc28dec83be133111206e2dcc718dc678cc331c4bd2ea1309312a18c893dcc58f719eb3e84ec41286334891782c86232e66171a73be9dd49b81a51d83c12761feb90d8b8872a117dcb2dccb4b723b97135aa4cb237896c5549bfeccc28cf59bfe63b4888da60800734d8811020249008426cbe87e63be80815a1e719f1bc9e473d31ee8a3b1ccf6cd21393a049a421911c2521f6d071ef2e63620f9a8f4dce1e60f7cd41b1a883cafd1c168b3a7d2c4423394a22f7eb45657a25923028d976a0c41eb46fdfb00fd2b5cb5877b96f973109e22822eef070b87d361c242071673b770ef3f48c6ab80e7514b36596ebb17d8a81275fa408e56796ffbcbc1640800522ccd00121c4508a641102a32f90806889987c28af925f49f96a9d9a694b7929a5fc8bc439643ea0dc53ca08651b0c726f3fb9b719ed211983842eda60d051fc94b22745382ff336eb9af9493191ef383d1b2680dcdf4c206dda48c2faf6140447be03550d72c72037b7b1604ce579145923a549de6c9f0fe50dfdbf4f3caa3416a48d176a8aacc86db7bcdd1a320721658ca8611ee01577c09ffc04f3e84061b17ac79641e68472df715bd2537614e1b8cdb81b1621ec1880343a5320effd0e9a32e6bbee81b4b15548585f46e6861b5c5c44f1944ff49b524610ef31411a1d9342487ff2a270d48a50aa15c1a2023ae6614b4461fd5a44386a45460b856683a9159137359037f6aa22844be4e641ee4dd3364dab35d48ea84d1de2344a647fac0fb501dfb740b6481662be5fbd206d341f0a1ba236da1185f53517e47e9886b15ad1e1910b55aaeff309c72fcf6a6f6d9d75d659abdde19f51120f906aa6adb6da6ab7d906e6540be6cc6da624f78d727bb468ca2ed59772ed982773289fd80290bc92e51359002a7d337cceaa5f9de5a794415f974c1914b751ed82bc99b8af70afd21082cb3cb62cd620cb41f40873fdb441b60712d6ef300c3a326195e60227723f084dc8584facbf016d5b10dd8ec89b6979706dd07cd1f74eee8cd51b84e336246f64e4fe5664fba136a5733379c3e5de84f0f6036e3311849d650e5ffa6883724b30e7c68f108bf33ca5df8479b6a1f7c4c25bba477a6242e20cbf537af8f930bc0917c9fd106f3f14d6e709cafd1206caed71dfbca28dedda3bd3ecd1af74652cbc32d660ce8d6d4661ed4521ecefe0fb67462bf6a010d222ab31d196542284e3369b574bd22fa37e1175cd38b729ba86db92748dbd566413a23627e7b83054a9665a1076664d4992bc19e54d49ee9f0c15a136dbcf360b5285576db30b694534ad08b591b1a0234243b935a2dcdbacfa20d498606d49bfba2a116a4a4005c858e912bce11da7592a13426f76b9d696166b25b2aca8545229a8138a293c29819fd791b84db395f69431f392c889ac3627f845615dbad487c2fa1b2d92fbe00f50eedb206af3c2417854d9a05e429de89e560de1f6f384b0ded3eecd6d1382d35a6b6dd4af1ebb2ea1b0bea77a09e5f135be725d426dba6d5d42dba82ea16d5497641af3309551587f8a70dc6641b3172784f3e36aeb21b50d3af0a84ac5c950aae4fbd5a30b1b2db962226df13744a657e0c99791caaca66d74db28a574d368952294d933124a0a1b5b48fcbaa32881378c2224fa3c6f062fa2500459ecc33db11c649a108e3279c27670c40838c082153a8062872c07369801121e506186d8bc4c0c19102018c902165644a103197c21072061904d51640d3e55c80090075600831050010d4444424a421032b4e405494ef0e3128517b6b0846c082c20c3945300c30c8050832b9860c9156a58c28527a220821019901850400542ae10862788c0091a4d78200a244266e0c44ca888044a8226090d661086342039438f08ca30a485226290841f3098150947520849414ea1674ac870030d7ec5aa61df38070a8b05629628b24cac87ac13265e6060aecc2fddbf0d439b67089b7feee7eaacb346d657f6e21c5d411e60f0d8f9befe1f5f6eedeaacc3dc56189ca37f6f3fbe60987b53e7be270bbfdceec3e0ba7a78ff7951ce5df1de5d390e25558ca35f3333331f67b01153c6caa3630f6a718ed4efa43652af3376068bacd7affa2b7a987fe58a28ab9f8035c659aa78b4404feeff07c19cdbcc626520a7eefbc2a44e411d9b53f738fdb1aecb751fbaa67497eb2957e669c49431b3eb2a39ae15eb8e3d99f5aea5dbd728ddbe27f3a460564fdd9edc771a315fac5c67b95ea22d2d2d2db6554032a5ad564b6b5555ab5438dd6a695dd52598d3727c63aeba2e4eef0d6f89b904736ef88b2bf3d205df420078192ceaf468c35be56b95fe028b3af404a73dd74d51b93ca1ec57bdebcaac2297481d00fc05dee91700aeb8f2b5aecda64b908651187377707175e897fc0d7786e9cece3a648cfc0d22a21b3ae44d671993f9766e71679ed13532cbee2e57e61657661211a174b9ca5d2eef6d20cc30320065972c915ce193abe785619843959354b06833ec38add34419768f53b9adef788419961a513a5ae595877459e54e6573f906dad0c0136cf004a00cbb0569746ff977471e3b32ecdd5dae1035c3708eee2d7f5d1e7275afe5d2778752889ac71d39c7a5318638dd4ad5d47168cb1d5bb847cdf45d27e9861ab75d43d844ac4f30c775cf73fdde111f5f0503d3b27a59617c5f2e33cc0beb2c9cc375d655bf776cf9bda5f87dc73bb62a477dc5ab2f7fdd6ad1965f181caaba630bd6d123bb72f0e0c93097195f1e34c360d1c6a45807b54bd0b3e02beae0f7f11b5f050303a37a7dcbb56f3d75b97e517a4b5fef3d0e5ddd965bfb05f3d6e5fa05a3fa9d19dfdf735d93fa65a55a5e6fea7d47d75978e4522995ebf8ba9ebab25ff75ed51d75f4c8acdfafae8e2fb3988e507a3fce19025c67e5605de6fb0679f0b248b18eebacbbaeca23ebaedfdb92838500fb3e0b8b36dae21cf4dd1b13b56e2fafa3476e697524e58a478eb6dcdece17a38f4c2fe78b710341481933f6643a92728bccd4e2268262234238b3cb555cc4cf10bb7ce52b5fd156ddf5ff3ee530302e2f3f7336834c213b76ecd8b183d4a3aadc2bde1e55bcf785defa721597f70b4e8181c12ed55d2a97cbe552b98e5dd8e582e2c228c728ef8be2618c5fff75edefbdb282451d97d3bbacb87cc5e52b2b2b2e5f59097770f4b547cd2b27b97c6525f4422f74e951f30aaf5ce538f4bba1ca492a5f8139587471394eab34921f5c91533fa901f3163c7eb9e59e9c3268a57606e1c162d64317eb147c69799d32546fb93665dcb7e0b7b4dc9b219dc18071b1874b1858d21cc6e5bdd4ed53eec1b83416064d2a48bf681aa8e2217a8c216c955b27b238ca1e0fabd465ce0947799487a46e732af5fa1d417e54b7e29cc964b22cc4c4aa9f21ec245de382c7995da8abba1ce59ecbed24fd9247b95dc444e8f2b1a7c8728a7ec9bbbc6004a4ee15edef655679376466fde019a45f600eabb65c77baee55daa361f2ac4bbca35f52fefd92fd9365ff08a19fabf6e76cf5947baceb3acdfd6184e5ba77a35fd2759959a7600e0bcbd0f51417cbe5da01735e2c49b4c20d440304e60cd1836342d8385ad86211d2f74104d0f3a0596491ef3d7cd5bdee73b9bfcb8bebf6ba5eafeb12b451fbe5fa38b3eb2c1bf5f6a99ba3b65e6fb168a3dfba7deaac3b73cb95c263bd1033a7be7aea9575677e59dd0994aaf87232a6e5aa4b92312da7b7ce172dbf579b2f5a8e435dc60fa67b0b6e28c09cee2897ef245d23b344e951f3cf81360a90451659649477a7a40e3751bf241aa46ca09696fed7f742f106cdc505c818cdc51e2e690ee3d25c09e334a7341706a58101e3ca18cdb5d17abdb5f5b2aee3cba9560a8f35a7de3abda34c1ec7b1fa0044a697b9f2e0719159f7e697ba3c9c3c751e9406eb7275a3d693d39c93d55b5a38ae6fcdf4eaf84e9eca71f2540315e92155084fbeb2e1a67ed2a39ede96a84347d9935b3e419d8a59c7a127638face3cba9950e5dbd8585459dee9dc2384eaecc36ecf4cbd66abb45e6da727770f44bde862bb3d4880867d86abcd32ff97b83eb42384a221c372e1b8b3add5f6edc937b72bdf367b66c2ae89503207ce088113831022d8035e6d01073e82887ecc2634f76516a69adb4765b6b1be3a8b55616bdbd2cd76bbf64bf542d3a148fb25faa533ca2728bb5917a9fd24861a923876cf148bf7abdf7f6deabaeeb8e3dd9751c9a6ab57ae440b632b72eeb945e8296d5d51b82f509a49bc562b56e2f7dcd69bd9573314eb3ae6b36677346251e5599c382a9bba711ed49b09ba6523ce8e9de4b30759cee3756bd529904571cb599187b68eab2e071defbd3e9ded3efbdf7944ae148d113a1b98ae65eebb25a2eccbbd65a2b9d3e7802e917758dbf7d7d79fde87ac5e30442c306c6c7d629cc59f530ae6c58ad2dc75f9da6e5f6aa95eaf5b4b582198f318bbee615ced1f255fffd827bf4e86a9dd52d3847eb2b9d16ce416ff3ca62dca3f36d513c8d982f1ab770eab278a48f8525e55e7b302e0ef756efdbc238dcdab07ecbc5e1d21cc6a579cb5db1682e0e389ce6c250e1b07ac9ad7bf4c3e1c2b80773576f5dd65beeea3417c6e76d39cd0dc00723ccaa00f45d77e6d66d1a2d78759c0e407bfdd15c186f1da75d2df75a77fc72eb306e6d58eb2d778234586fb94e77ddcead9b72962b336ad4f19d4e1b086746790acaa9ca67a88372f1e257f4effbd3cb5f5c773986394679f761ba887c0f918d832c5bb7efdb7aea8e3d722a85c5d52d1e451e5adef6b405cb7eb5a54f1d87a6ee98facaeab479683df56e115758a785659f75c7d4535c6fb9deb85ea5d52dd771ba854d47428b757c2a97200fae37cee17a0be780b90e578541d181c1b55f2ff8aa371e5db0ec177eed17c6630f7a7fba3fdd133d9dec6beaf4aef774d5e94d6f537854bd07cda74b9006cac7da3fe15ff5f73d1e67ad78f454aad7beeaf52c5d9be56d8f599f58d441393dca6a75d1a25c5c5d14efb87a0ae5a2f8552af5f5a079cb654beb345736acd5baac53f12b4f5d2174401b28172f411d7b118fab94b5789cf4b6bed6588f7a5bd659299c6375d60a8b4f91590c33ea8eaa9cf2953bf6c8292a950f05a5d61c3295366c0ed92f94f74d39bd293abe8c721005cf21a6f0e4ced29d43fd9207ef84a25f72ceb42242ef16c9f21de9ce99f681709cb35c1ba86bb84f217706e9973c921f0065299425121f18656fc79cb37ec96f69081bf77817d15c7e07b5b9d141f27d44be81ba083dcd54bee2e0da7bb3e9a579823466aef236119adc7207cd37caa31b7820443644892f98610c5de842132e4062054e04a96202c9cf22f273263f7fe4db88a6e70d88e005d1b26c0f542d10b5f15e6f8b501bd26b770b446d3edccd4449baa294f7308f118977bc773c9d05ead7478b835cef79574a49043c4e5f3b44c62c507d25d959bfaa0ff0a577d787911df0a5fbf86e7aad0f5592ab9739e4fa539b93d7cb509b8e0b434f732214e777ef3b1f16e749f7ee7d8774ef1c777df830e2c3f4ef0d8a0af86e7a03c09788f86e3a11e03dd3576f10d6aba84daeaf47e48d8c5c7a95529abc296716a738c1fb08ffbd07d0c7c9c1fa03e5dc7f9c6ef280244761f528d774b9922d82ed905725806e7027610c0aab2f79a5ebdd9fbc27c6e3792f7dc77be9f3a552097355c64a574a2f0a612863e66bc81c844ac64caf6e5ee9ca12e6aef8610e9fc2e449778c91e5b58b65284c5a6f0c5272f6f414fba0b798ebc187bd26632fd50caf0f1ff50aa8d76ec51d7b5cafb843af9d5ec316d74b31476112683635f2e4cb6883b2bdbc272faf7a9692ded2fba5be3a5098767ab52699e3282df19859e48d1bf2aea8bd27f61235fc7e71ef8971d35a11cad8bdf7391dae69b4499808e5ae03b5b1400de3cee10cd42fee313a5aa0cc9dcab8531fee7dc4bd9b70f76e0caa21211477f04cdce9deefb0f5a130eedc8f32c7e11cb6dbb2c00ba2c7cb586557cb9d73988171269134ca2107a3fe5cd29f44b3a88790c27ae028cc9e7479b53c6bd8b18b107d0debcb8f9cea0868c3a38b3c72b9b95b1c4e3caef088fa542bef2f39e4be278562c84c10477fe8482e22c11ea890b8f3cd209ceea107d0bb9cecbc7f3db1eef21e6e70c77b8779ba7b5852d81c6710784386c22688ef486574e82877ef9a8c9348dcc13c40b9bbe20ea949ef89d173136812cd29fa15c59462be98445b08e7290e658cfc3889aad69d12a2244431e594d1559f108bec490a8452880826a417c785ae4b216ad345266c9ee38a8454a8877a88c2aa6c561b849bccee20a46f59a678f3916d3faa14a6854210299cdf7cac6afad815aaaab37cb795bbc9369f297c7ef4cb076f3e32222d849b4cd6353f7cec2692322c8ff3237d8a0dae67c0869515d7a7b8826fd88065de914231176e230a4bd1b24db9f4e5384d2f250a2b9128b89642de10f10963aef7eb4cde84ef5713d413a8bc5f77206f52ef571ec81bd4fb9588da0c20880ae48deafd2a0579b3f27ea542de88efd72ae40dcbfb3d6465acda0369637f28ac51206dec91245d635495740d45e9eac4fd588320eb1148e45ac44281aa60cad098305f10216d34fc918e20bb7ca429c8fdbe42de90a1cb206fcc206f48ef771379730659a306493b206b406d0985f561f00b7e3161cad8d6305f10694ba80df793c3d851c8fd768224000cfba862aebbe031c4f8475b92fb9bcc428123e28228ec07058f292929610b1ec31666612bb3b299493fd4863b3a22fd70a49f0cdedeefb3bb78495fb9dcb9236ac31da9be72c53b658cea2cb7658ceaf352f952a94eaf275faa73472ad547924cf5916b92fb158fb36f82b057dda32b27ad503cdec82b3888cf3cc79e1a20609e21f7b0008f37320dd446c6ea71c01a35cfd98d1d865c7a70f99ce0cecb5d308f4c8214622f7396810c426836a982a82737889a47d518e671de515e51ed574e84db4907aa9f45e66cfed48f3e303723ddf923e44878bc9ab30ea38e2fc11a346b385c037ee941d2797c09eeb8fc05f3884288b9606ee71e631ea9842a8218c52e9614d693ad7d0da3235dc3dd0675cd36ad9db38655cd862492b6693d674649582156db50044fd6ccf2fc8ccb967b9e8882b07ea57be512d4915ac82af7bca65f8d2bcdd0822cc86206a8f1caa24c0ce108534424e73045b34ad146211ca510159231455d0393a46b4c5fbf262785382bd4b7b465bfaaa08c2bd7616759e59e2786159519822a17c59b5229dd552fa15e524189a2288aa2288a220dcd4d2d411b7d514ef128f230f3a62858a787d0c051ae371d879aee68facadeab333c984ef31667b08ea94f83eb51ee68fa4a779aee8ded59689aa6a3d161672c8d7374a7c13950efebb0b3dc9dc5a8af9c8236547450b8f62b051fc4b55f250cd6300c6908521a1a82a73a8227959a3ae1d441130876b71828ce61ba7814d3457a1593a9aaa8984c342aa69e4c436f514e452166aeafa28847d36978a0a139bd33b36c6770a6791dad4f4639ed7e320a0dce61bacaed2c9bb0f895d61d4f8ae495afeea881a3bc02b26019eab0b32cc4cc2a2ab84593dcc2e51a57c6127820d482675bad4d087bd3ea27ca5a8ec89b180f7ad04b036c0fa1a106415c80014a4a4ecf882c9f3292dac8cc286cdacccc286c1e758fe5aa2ede95a3dc17b9658c1a36cfcdcccc5c30b758b92daee89f646f7e3357c648bc324a64506e4cceb93506539452f9fccc8c5e6566e66706cf04295a426d7260608ebaa6e61b66fd6a71d442098c114c51d7a07c1e2649d774e92434813bf464964b16dc28584666898c51a2a4c592164c72de3a6f1befeeeed71a211c01b53882c2095a1c519b9c6f44401034c710b22036e33db1164d361684a38c1191035cc6484689cc9219782965c8cce68b79d053ad66503e23a2601aa4dc38b49ff90cdf35c64148c6cccfc014c1248191994d1952be307d9a3e768639426d74704e18dae0382c29cc911cae34e9d75cb9a2c638f3e92b4b56968842e4cdccf31e18c2d3e9ca3ce3e6bcded1fae451948d2a77ac790c5137ccf27c8ae98ea47066567740dabe1937e77d3526daabcc1537671e39a10b44f5062f5e00fe451179a302a4f41b7ca8cd0cfaf91b663704e99a94cfdff0d335a836d9b01051d8fc69e534577514cd53b75ee5bec87486eaa69c06f999716b4ce5c66498226a23cf4214b210e529f3a35f5306888ccf5138b63892f931d39f33b354ca95f9911162446d6c7c9e6509b539c0e7599ab01c519b199f97324132b33a86706441d2a289bc31bdd27cde034fe817d6cf643f14ed3b813ba028a5394d3d0b1296a1ae81a26b26cd74c6e901aa8b4c2f6582c8b4cc519ed7c01c1926a18c927e4d19a3da3d86709499e57b16ac41ca44742e33a3363a18a688c2a601aeb8630029c44085a39c2beee47cc667601e8945126239ef89c9ccba86945f5e3fffe248ded07ce64115bf18c9980953f42a923132334f2688cc4faeb6281c618a8a64cc6ce12363e6a70867dcdbb83fc0fd8cc280fa653fae2c6909923161084719231919a03c7fba630b2c5ce4b1c5d1f8a206791ee58e750776e68e75071e18c2da339cb13ad72152821f9deb9ce0444fa3f379941195405e19bba34a0f2a7da4f4d49de6a03f9d8efa4829a5a7013f595a8837ac5cb0625a39b40ce0044839dd0af05125532d539c8fa94c6dce1f53327d9537a95354a634c73e9e327dcb1b955353a628995eaa4e61a778041fde03c3100cbb0effc809cffca0ee4c90d27d120f928145108d659c0210e00e20070f2c9dc8970df42e7a18fae2822fa95b892c77ca985be9491177948fbca127451d8d94b0197634d724ca78e0f2e92d4197c99b007c9ee6e250f3964cde9c7c9e45d435305ebf6c234ec6c82604e50dcd337803d0af99432ce3837094f94133e717805b6a4216c075906f3ececc628e64cc3c8cfbfac390a3f8059012dd1f8c8bfac92d9dde569631face7161a852fddfc7d711728c87b7c511d844c6cc1464148e114a221c657e987ef884a709654c1d7b7248731a3ceec8f4a64c710e7b3abdccbb6b3a427392e1a93bd19c30111daa9373671c85d2cc58d38c3551fb996b3a125a1414bb596ba2a1a6920bea250526e552b141f55a81cdb4585a8837ac5c9c5a5831dd3d1862cb995e00200725c6c50d2d602f1b5c302f2ef8bea5d5046b25b2aca8545229a8121876a799cc9d14e5f99b3bd20e0820c61d49367724ddb1a7a8b923ed000e2f002023e38e1c29479be1766fd36497d430e3ca98473f19236a23ca1a36df1f4395ca2857318838cb53040286b0364823a7694ebe46f126b843e333de801a370016770c3067900223463103bc2786d333aeb833e339cfc13c920b2488cd784facc55147d4119d3ef3098f12c8273219334fb72b4b429599d369b0e9b6383a9d9ec3de844db79fa6ab3e5a6bbae5c1f41cf634c7e9164d523e5b00687971990b0307c00587979a15188c8d2b860d026069f1ba115ddcc05ac5dce294dba2c96d71458b231a1ad4dc68409a16472d9ad0e0f1793ce1991fbc72b4c2e4ce047942387633b33cdfe2a86bc699598b265d33cacc5a5cd135a4cfb7c06266a6c3e76566370288615383430060c8bc00408c8b1b5ac06cbc6c70c1bcb8e0fb96166b25b2ac1ce01d91f78570b4432727359137341fedd0c9d4e2e8d5608ebde9ce9ce6d67b7408618ba339330d1e2590695e00c91b9acf9baee94828a3904b0783320d6e0992312f0867665d23ea849986be7e2648d7883668c61d9906e7a0f3a28ce6dd4f97e626134824a7c5510e960daba7313558a3e6f0de0c6950664c4240692cfad4192cca6850685e1fde717663cf1c89b2998fb58a3e349f29978a0daad70a8ca58578c3ca85e9b246152dd73195abcdb5ca1b94e38f289aeb78caf52d6f4e37e53aa2e49a828279c523cded3d9a2bfa883fae28ebd794d49e4694c98c5b34e9d7cc6d710592509475cd0853e4d335f3e20f11084c91cee71fd435e1e7655e0020c6c50d2d602f1b5c302f2ef8dac03fda0930e020bfa5c55a892c2b2a95540aea84623a00c6a1f9c40e8d75073bc8638b2398077d993433cb5347872b33cbb36b5c591763d1b8b28e0594e73b8a70bb4472aee55c8234ea5b1cb5c0e24726227b14cce131937bd8cf4c411b36dbfa9cfb241a361f3414e680320a8a818a216b9726ca08a5845eafe994968801dee28a236a035364000cd3e228cfb832660098225196e74798a23c2fcec41f5126fad4cc621dc418342dac3f346c561fbeb904081d312c7e85aa232778f2a5de99a794f1c9b2ac5d536d50614856893d9eb51f73c874db6848afa2975cd04729a5bc742163e46915a17c4919f4dd41f4a899884cec61c6ea67ac629f0f262ff66716754e72ff2413d140c51c854999022f6c2a2b8a6a3d393ca23247d27aceb6f6fd9add3debc5e050d2d5b8d79cb6fbf63286fbabbeea474f6b6b5debbc6a5e722de34d2d0c315e5cc4a821fd28d341486cc003520e68edac33653299ac077d02372fbfd2b92c42f0a57bfd5dd312e1a8237fdf4bd7b39fa724ac07a24104d02cd290415cba4d8510887ed57a2c84a57ffdfa3e4aa32a63ec4bdff77144e8e57617fdaadb86351deaf7f194b79ba48c04cc17dbf650de94b8cfb83a3021e45e83e331b3f7044c190a902fea6b14b9fecbf55ee5386b371d66cc1047bfeac79d5c1c0dab9fa00fdbabbc01efd9eb43bfeac18be30aa1dd117568e64e6d74e6709531db4b35731cce01a773be1af0f53e80241268c35651e7bb10b4deab31b671031d8ed1f616cf6858cd76cb556e7bddec86451d54055039877ed5b05f3546dbb8107224d657829b114b52d0040910964822568f5085a20f2c41459124b11fa80d276176ce90b053851c89d17737a09990406849ac2f6332300df22a2cf4c8da67ef518d525a69b760a336dced35affee036d39170fbab5ff4a6a070bbcc759b31096e1baefda2971abd8a1ec1e6c40342c7157972d65acb598eb3d65a6ebbcfc99d3e3b349e3f80d48cd266026ddec79656ca9037dfedfc317f4ca039b35abf34f85b7003356dd35653a6526941dae687116dbe04963a7bee79d3b1209eb230943136a6a336dbea51d20f239667d336cc7312c7e970f8d3f0948155a33d354d93a4929431f63c5dc33365b4ce8a75a0726ba1361675b08b0aa0f294492c6c7400416d70e0c0d1412646109882ee6e8a89d4777d129e7c79a28a1ffb09249fa06228db4f2176088f911d52a954ba8677c0779887034ffae7bdd37e2afde482ef6b44c39eaab18ac2ecbf4b2a954e0eda9ffc741e233bfd13e631b2533a09f3bc28ccbe84cf6364e7f4c63ca77fe165ac6dcbd8e9cad8bc327672658cbbf62897c7c80d13e699b1920f1da8a90727b884715098b53729e183c7c802648cbe5ec626f6412f63a32ccaf69b6f22668c1ad999efbef79dbeb724dbb74fbfc33c40e0e94361f6133759d237f560fec5e21cb3b635ca12c90f946489e40753e02c91fc2028b700f00200b7f45a6b8acba6b8aeccae7b7682ae539cb6b6da9a927297cb75e93dd79da1ebd6e57255972bc5e5aa2929f4f5ba6e6f0a006ee912741da73dcf7e15d47e7afbe26079153202450e409642467e3213f540b22b3cddf352df3c8139a7d7da5d6bd7a6a79fce72bdd3e9f47a3a9d9ad29f4e2ca7130b0b7ddfd3eb65398139a8a7803927179750822d9e6a208fbe8b8cf5295cbb8b748dfcd82fd2dd2ed2af160db4a381867411d88194f44b0e519b9ea26192430335759e60cc7b724feea009d43531979f46984f4c19fd335fc8cbcf19489b1d12262f4f2e6db8bce1d2c5e5e7107923b31442a88491217adc1d5908477934c48e1e218dcecd848c91ef3c33c5a28e4804c667b6998e1f119a4f2018f80685c9cf0c80cb7b3ae48de91247d7bcb8bc0f5d237379204e392b84148f213ebd5fdffa1797be850098d7c3bc27bfb8f5adc6a2ce7df9358139a954eb8e3db9f5d3acb5be46e9f53d99d2d7b6b427539924a78e435b97e5a97bfabd2f2f143cd6ccfa2fbe634fc637a9dc5bdd997baebf45945ee9948bea9fc01aa4a7b85caef751c09c66c2b37d168b45f30baed9de8bc157d60b0f30ef7bf685c5c277ec412b2bc7cbed591faff7f2f25bb108e3798d471d56f7bd0174a3547e528edae91539ab554a2589923e12896e9b9494da96947e94aa72d36ddb2e5d10caab68109af2bca4dddef78fc4d9a6ddeb3bea69946a42fa354910cadbd758c1690ada58e9de1dd5355d4ea7e1b127d70f06a1bcbce172b49955f286c32a19232f679fdaa586da3629376be526515d63bb3f35787df9d2b56947e958b94dab9444ea48240df58d20ac79ca77379577247de43e6e1fb54b92c8899ba8b5ccb6d25a679eb4ca5aa5a42975a56d6920f31509c7f09591346122b7cc04a620ca27f2c5b39eb66d9dbdeeceec49798393f40bcad5cf761a48ca63f70ebbf7135108ca9ef7bdebba9a5129dbe955bc9951f2a69e6ef7baee7e29367a9828411679ec614226cb16a041b25c91c864b9e2b1ca6479c3410cc9b2f71e1d116d22cba31492650fa7e68bf9a20832e4adb79b226354fdea1004e17ceaeb6ee813aa644a730a2ae571a8141e4259d5e9616226cb16e8214290ccfbbc7b9ff76d624ef579af5ee76db9bbf875176d7791d45d9c9d27b3d75dafde4687caf4882c7b41b2ec611eb4892c57dccd17949b2fe88b08a751f65e2fb5088424ede4fba6380269052d08821ab88120c8811d4802bd9dd2f800ee892984b23de98927c832eaab5dd35fcd494e0446ae4956d3b47a8febd7e91b67f6480df260ef1d4541ae6b3a3c92c6ee1faefde272d47bcfd161ae5f5d6596ef3ea232edeeb8bd3bc76d9ce7d9ce721749e2e42e6a9cf7a1be24f9bb57bd2704e50f9f74ef8eddbbb156dcc28147513944d1f0eae58b57e54485e1cb6f67486ed4ce6d751bbb2992c4592f76e536cd6ada36334ed77499dec8dc8dd12f8ac48cb6f16e63348c3e00fd224128bf7d0c0037031a35e3f48bfe1b12ca2c49b29b325ae66d9f57ef0714ca7f4884fd89236fba4cef955cbc5e5920d98f64c5c7e4b38277b252a9b2502243690c60bddf08c2af5ff49f0c2c48431b2b932c650caa6b343cd210a4c1611219f24f401eb4734775b59b9decbaa3b734f6cc20739ffd95c60764ae4a8ba524f29090b7f3c8d6a35fbd0300e1388be650d7348d426e59841f24ad849e6adbb66994c7da6ddb364b5314281c2513af7e1494fd9af790084b9d8ae52762cd8ae9acb71efefd1dbaa6e5fd1b5d03bebf8383dae0f75fd4e6e51deed0f103b5993e541afd3072bf7be3a418c8db1094dacc9f1f9feeee228741a77ae9d2ed9b45286dc1f4a84a2b95542452a95422354855a592aa6a2f6da592aa542a757705fe944a5ba9d472bc021a8654a3210d29162f11dc4b88eccbfd318d1a87becbfde1f3d80b9e4a1a261b877132d1726a56d94fd5752acba2512bcda5db96eb3a0f052720d15973f0a027241278b0fb3cd249a20ee9da49a42964ef38fdbd20944e3421244b23f880499ef92bddce5dd55eb56dab75d32aa87d1e49b35d0776dd96fb75eb93cb83e64d9323c7793d39b4cf6c7534b07655ab57d4aaa6d52b769f47aa55d3aad56eafa6552aa5b59b3644873f1384a36422a790b58714941d88d32cfb1da13f2e18679e3f644cdfef1e8d54671e275b10e1eaf7b64b3f8348799eb76db57a1e49ab5eb5b5da59e47d42c22e4b23283145b63c54cc83a76cd66f5766cf9492bf0473c2ef08cf7e576bd93ed6a56fcd23d4660e35ac7f84867684a7359155b6236a0d94cf439921ebdee94b1d9143049bec7784046b70474830758404797cf73b4286df77bbd7e85cea5a60ca31792c50497d29efbbab6b45ab3b93fc9c6a964d2cb10410e50b6db882d317a65427a54fbc4460ceb20283e7d1d0513e72783299452a50a13eefe4c377c65eee34921476fa5290f2a56c263c8b82a43e930a97651184a0842f047366d18702f0f354282748f15652600ec59f0950df2c1c259313c86366d43d166f8804d2e85c7aca1bf2b2279a6aa062aa81297bab548d9989e0ab505680923d568d99535f01b33482124680d96bd994b380262184276938c95ecb5aab699ad5aadcb494dcf7569fa665698424c8a065efdf77e93dfc7df72b41a8f216d8c4964b5b96465062894cefb584f45c064105482b7850f4052d88600745b842ccbb1ce96a77bbddbdb2eb9d27a591275b3c8d6611fd48108e92c938a7acc7374db3b576ef3e8f546bb5b59af21bcbbac685746dbb266e2495b5da46b225cff57df71b41a87d7bcf58bf89b5c493eb58c5cf23558d27771acd9de5b2ea96368df49935d2b67dd3b6edda4f90c7cc1b0b48c3837df6da4aa9942fa521fa059a3aa78cf3cad84978eda76ce66ebbd56e458d07cd9a66edb76dbb325b1e3c59146d80af27da36f32c2addce9e7629d5c083e0a76c6699c53782d016e5ae38547a3cb9d6eee3f7d1fb48ba767bc50ed3e8b2f8891ea6d1659184697459ca187a9a330eb557668d074f773f20a134420b84f238b36022d39049a7200d5945267dca78a83c68ae1775b69a7b56990c05b9c7f6991bb4a1421a6593a9a37b0cd135b4eb7bae200cdeace017768d102dd9023d5c9ee77e04ef45382f9158412431773b0b652134f03322a497357f4799c7968540014fbe79690685d03ea32cc4579237414c59e651803cdf32599e3aa12ccfacd3459ecc9f4fe87932d34b4ae99c3950b0419640289764790f06241560d9af303c814ef10415849ea0420f1e76c143794f50c1678652da8072716ac37de6f053ade6eb9c73861ff785494897daa5446245933cbea8a4993b0ec919a0c8a36a6513be3fb3778984f748a48777b53dbc46b44b50a5615147fbf651c591483d24eddd1d3990bb694f482ffd3bb91dbb6fc7a1241e5be9dd1d7bb246ca51d27ea271d73a12d6ba531b02c81d267df328f7ee9ed7df24753434296348f55da9c45de37ee29d74bb7b57e7a6fba87dfb89764eb4c15d3b77edddd8bd1b35afbb208974120e8274371953a2a55bc1fb5d8fbbdebd91f4ee9bcc1ee91d0ef147bacc23370a31b3a51fb7064fbe8cd52853d29cdbac42735e829388da50230aa3a73164ea275187e9a911b5e919c5630c1999d7eb2a5518d2df843db1a645f246669a637eca3e6579b60d8f9189a58c69220aa3447348de8cdbb557d91da76cf24c590c87c268df1e5bb6627fcac61e5bb638474e631e42f480e0269443994e598c9ea109120db975e81a1a5638817cc91a1a5648817cc93c4a25643acea14c6708b2ccb20b3fce0045162930c3098662b4075e202aa2810d981084580e3f60020c3ab8c209473788f5cc80881a88cca0c9155f10434c460182204d4043185a4044143d4778800a1314410a672882418c5e86dab4345106258840451168f0428c5671d403244c704493229ca11a6d4ea0ef3c73cb2f0da1c421f5d6108e32f9892a14a9e42bfe4a5ed5af092260668a5da8217cc95fa956a71d6892bd6b4de8a0887eacb55efae4066b601264af67d9a327c85e0d92472dd70e34d1852499be5a79c39d622dd7cb4c12a266d2b99b24f338c9a47bda072437a183255bd3ae765d67bb4eebba6e722ca5b167486e22c888bc5dcfbb771e3c9c43bbf71c25ef13acd13a7dcf2b813ae078274780760f8ff45a0e879f2062924958ca18ee27dcb9aea93587942e460468d76868db25a7829034b525e6ff6aafdd1f9e768de0b056b3d6877e4daea8faa0758cf9d77ca85a92830faf19ceabe625678484473bda5f27e3280d390e088a754cfb8ff6c64448ed3d1fba66b4277dfe0712f681fb06e6701a37eb0f735ef3c1877e4d1efcc30480d0d1b50715a2e61f7afe5544d581caf3f44dfff5abe92a07c5f75e66bf5ee65b072adb715692c6699ba6e1b1ded068bb2161f3e748de0d21a7c5e084c24d866e5ee7791c8a237d12364717797eb9527a1da86c6bad987ba2bee46a63b74bd8cb4b9660c5327ce99e2ea09452fa2b64add65a4a29b5f5f338b472b95fbd03a16ce910c251265b99e9436db6f7ed8cda70d7deb74032f348bfecb91b5218134d84a330ee14666fed91235d33729689ae19873092377d7b996c47996c1b9396c8187b9c7e1dc9d6464b51a79b4d3be079edd33540ba66bbc55ca676823c8c764662e1f0a881a37c2d907e59d92fed02467994d761673db7d92bb0c1061b6c70b9603097ebf53aecde0b0683bd6c7085abd7241501bedeefdaf584728313a471733db299b61cdce947ee1f587abd067e822088899cd8a086f5bbc19cef5f88d23ceedf49ffb86e2563a815029b7ac10992ba8e92f33030302f2bd5572ad5bf52a956776119d256f5dfb385c0800457850ee8661b6b6ffd61e403338b98918f568a0a8b42199593d62019d301f9c0932f402a58923b6e3b89646b1821d9388e9b737292da7054debb577a13acf1739d516ad8a3dceb4ffb6fa7ba17d7a0f6dde58e7269e69808714ec7691d50a41d6ef44bbb0e37769043dd3f9c9e600deddbe746d2415a59a5b0a45440f0deeadaab2e77d255fddc2944359938c2121484047a2c5407156a437dfb01c40e1d279d0b4238673348d04c621e994c748d6aa8e4a5dcedab8b4add994410cd3a544f66169abdd50a2671b7ddb96bb7f565755027dd56d463740d09ff74459dd3b99fde934977e5de0c77e857c5a28d946fdf64ae5b9d4196f09a139ad9eb6f47e431b33df74a272d6d97783bcddb0f5d23ea6c67390b1e57df36dc937bb20fdb5b9c70945b2e56af7e3872acbe611ca28dede245bc936beb22ebdba5a08d4da7f5163c8a6fe1f9d3af39a508ebead5e6da7afdfc9936e7f068dd7e75a57cb16e410bd49879f516ce59e12a63587814bf43bf6a5edd823a35af700e118b3a3fdcd8ee6d7766191f4656bf5846ece11e1f639e9ed8c52f0aab97b17a6f037378ccccf238399b6339cd2c230732eb32a7eecd508cd1352ba8a7bc7e46d7b06c5785e1c965db004161f527f533682651cf722713fdaa0782e3429951df778927103c7dfa357f704308e9eaa8a3ee6833cb5757447d05cf2029df54297747bf96e854992caf362052663f7806f976ce08dbd571772ca18d1bc8db5758ca174b95312c7864b9887760c1a2ceb7b3e01bfd9a00fea15ff7f316ec4185393b6d2045153f99926eef9c792a39a48253785455d2e7ec627c5d8e314f3d6289980bfec53c05f8800766318cd3affa1309c7e8573deac40921ec74e8978ad6570ebc49a5ba2a57558caabca854ec94f5b19c658cd18c240100003314002030180c098562c1704026ea19a57e14800e9aae4c68569707421053c818630c0100000000000000401030000141d5d4626a0ee4a36204709c9c402a8a08ea684b10c8a6c11e38a6abc88894e66297c704226937847ad0e6cf22fa1182ae6d7ec85a4bccae04d6fa7a78108000f0afc9352a650ca33bc4370eb3f2e6225baeaaf2c85fa3a8de3e66ae170be7881e1d33ce036f5c637323bbf55f429666ce029908918c6c2cef55ac79702dac8ff91f97ead702d0d187a9a0ac54b00c84c22af07b53e13d48d670d45d5c0db329ea3f342eb4db1faf25e5462c9791a6b5b1537e55217b848f81246344405893bec69f3ca73ef47d405a554662c56456ca97e351e3f7a1496ddfe1fec1ab448bd0c8a0ab16bc63b80f08a4cb7aa9d377b1fb80828a026ba968b7d3fd18daaf08f742e76ae3fdf458ba8689c4d48d46107ab6a5b990810b316aacd57297531c7f13fb9941856831334072d03a9eee4f2924092105299b20eaf94bb99d0eabac6afb11ff3d2e1d9a9fa2eea7a56674fd7d4d983c7ac85acc01fb517be0e688605df1292149ff401262aa8cad1ad568fb7bcc18da1fd764e0b516da01bd75b51840ba4bd9577c20097da6117066ab3b58da6a0e6ffde0fa9f614be13f9e3be0aa4dc44adcb70487f3bd189ab9990ee02e019df4d6fd70cb6eeacd7688e835de740de1bd6de8189b9c9987bceb6dae902a176df2275959760b503903a42b5018862247aa057f2232dc0e623599687eb32551f1cd276a5e0d7e7f95163b737f6179b9908514ff4d5756d70df0671590913a42e7b6d89b0c40d4b8baecc734435b99365dce7b80af74c1d8607957bf9bc4b9f42b1cb6fb3087f9604c969f4e83322751b0c572f6f22762b8b9ee75be327c4dae3b03a2645aeec6f2841cee5f4af2efafd9d2de70efe18c82e847ea60fe150cfb18c6f308837d0fe33c0b8cee9c771510d463cdcffe4e3a0e87c79bfd76f7d091dc8eeeee8cd3c7c016d51a348dc0d2398bb4d92cae9cb068b86c0d0541a668e157631fefcebb1185b282f75e5e8cf6482dd7ba36a272502cd5d254e690d6099b89089250d9b18a96427d43ca18734a4713022dd97f7fda2dcc8915c301b926b1603e9cad4ba25ab4dba4150821a0cfb85bc298f2bc1f1abc719c94c7000fee99f671b195c2cd3826bc9d22bc72c698c230c8cbf70275797c596f7341c16202e6379cdce0171083b34cb7daa6f71d084b2490093bd08840dd44c3500827892b4d9b1476cf9a2c71caa023d08ae85f781e9c7b8141b648f1b193210606cba366cf56f0e4f00a377a87499df1e8d6cbe29af182280d032c9759f4393c896d0f75f5ee4d79477e2c77f5c14e24697e3a3a28c223d2d9151f9f5f3ff92d9da2742caa0c7568b033d76a66ef2ae570e94e4b1abb60dc87ac7e95557420ad49fde6ffa75988ae0b02682bd17633b23d6f2406079cf9cc04c8a0b81350fa744c9a3dd2f829be9089a50ddbf6fa37ecfad02315fbc142b1d6328995e0e693a8d504c07daa0c284433d571ea3c205115fbdb17a3e808a65f19d521eeabc036fa6f97df2516303b0beac446af5f74989cb9abaf1fde42c17c8c3a32a8c3a7c4152e29c1b78bc3fc4dcec2b7400af920b7624fa4081e667254ecef512afd965943b14356f1443bf5e8b6ebfda17b86121f9dcde721b8666493d93a7ef900e972a2af3cedbe9af2c1a3481a3d396fd62a2e30b1e48230d5056739649978cf72229cac610e16d669feda31fac942fb63c6a286cb79690ff3b6bbf410a8b61ec581c8cc61dbcc449aa5622defb25614ab0ff62487f983db91c88d6e1cfd415e6895079cd3fe2b5b8d818a3fa7f402d1adb406603c554cd927879905ca379d531d4eb93201a014822716d85fc7c327f750d99c4f30227dbc5e828a6009645e3551d76adb93a280865dd2a96c8f1b758c6bfd9f44aa30ca7c7dce76dd724c2b14217a3b09685967ac146fa159c8ad38e75243b6a44c8210eafb15b64665f4061a68a80cab5f2380135a181a3db3083600f3109a44751cc4c123a69abc824c1101036b5460c42e6a010a84fd57e53668a56a9f83f78499be77201fec5201aa7a05be05e6007d6dede3c310f8d0decf92484f74cc8bfc9846a5f3879a79971c2f673d45adf43e3416e38302125be73c042ea50f6b4c935a95634217b94ea6666cc9aa24e4dbcf439e7392bb512c48124feac7e9d28eb6ae7545422f172b5cc769834d4c4190506dc28fcfdddcab06db398d1393c0817cdf867fd9ff63a8118399c7a5238ac2692b47b55c3c20f12aabd2dbf929bb7e7a6aede669dbd2a89c7548bf1aa07d2d78e94bf472e9ed3f3ce12ebb4b9515d60f6a0cf2f363465bd97c613f80b1493bc1cdd86496d012031191f53ab1c8cf05a61fba2e5f1053608fda508067c28dfa2719c2c101748fc2efb006d02a839c5bd51b56ec2a0fb55d39e3fa5107b9902a5019398f07fd28e5783b690cdd79662610c57d87479b941cc62de9481d1eab52bc1eaa45459fe65be64f2710ec6c3e244903b0cf96089226409f32c0201715f2848df1c538b84574c7bbf1678091a9fc0d828e15ff583df7a7f113fe8fe42f37e2f1beea18fbdfd13fa5a03c1a6fc661cb87765ccfff01525306b7b11de947c29faef0dac5380ad52509d6731e4faa8729cdedb125c7ab1ef93f10abad15a50130b399a70d2e491d3e5704d27d540586fe8288f6e518524c84c85f5a14e3f2620bcb16ede676490b433f2b8dc0c4f2d45d3229803697744003f59a7b00caf07e6cd965946995b3829e1708a89b42aeed5287d92ad9603eb0f568877b9b6eeb8c7c217f8f4044e443a82eca62b46e237eef0032bfc9865481e98eb86af8166b9ca0ae5b3710f692bd317ca7088682043ca54b2cd3f5f3102626ce24964accf021687775aca6ca9e822d9a5998ec0d1c778449ffa212bb186c3ac1e60d84bde46fcc611d63176189c737e2adbe15bbfc9143b028bb90f4ee6e68648fab595f5db79b9e6579bb7039681bf0f1b1404e9a2f3e474761fde7bb0962afde1d663265ed29d21bc4f53b46ef24ef6e2dc45826edcb529abee9f716cd44c3d1b9664c1d8c42e15b90ff2658ff3600b999d58a952c972d3e600583f8ab340705abf607e8e834228ff5001a9dcc420c8dadcd00e155d4c33cc7f669d6637997d34bacf5347e07825484e3ee833d60391ac355a10685e0b22fa3f07a0ffec3f5308e316efcbff90186b12ba5a4b581cd2028ba2e1a68435cf218eb177fdbfb4f41c32d448c177316710cf22a1cc0451071d6ce1802aac98794c2cc729798f6e0b8b9616124b7c41083aa01fa44c2cc26022ee7f7eb44dcc1d9b0c037568089ef0196acb57595a5985320be6696455aee79bc22265449ac6609dea6eecf404ec02d862c135dc9b5165ab0b70d52a440869c24d1a12c43ad65def1e29c0c19ee44007fe4fb5102220b7365647a02c15009187b4a2e61b22a99d922b867b5e12508b74e71e28f80d3123ab2805a6769d2c0e88310901f87c000f680ce8f71b067848bed7925af9f5462e7a1895f06b56796821a89516d0a005e35762f731bf162a4269aac8b3d0bc5df10106f8e6b947d25cd4ea2391bc274940f98b441b6fd4feb4eb361c0ecf2e0e2d60fc9243e3a93a6b3a25c8e90d2dbf1b5adb1a962655bb492c48a9d8bc9069c5179d4f11148a28a393a3abedc86a2a8922a5db4ad069b0d4db3ccb4290355151f71fff4f3217ebd87acc7434702c12de57a4931386c00fd647875a93a60ed3bd2e9cd56a7f6af9050f2a303c1232be6664192ff3004e9c98b11b2c65a8b1df69ab81009eb947aaec7e0e9b0626163117c5e9ebe0478652b5f7e5fc1ea1a79f81e20bcf4a6b4357cb07076ac79f6f98571333c83cae38dcff0a6527c7c1970652874eb399c3b9c6476c440122e1d6c178eaa52ac34ff787700435dee30334afd2c8827a3dc2a16739bc9e7179b952d8be2108744a6ee623899905cdddfbb59478611c0df316a80d3d9ec2cc3da4d809ec08c14e683c5f866a826248fa20038b3198a5214a7154218b977cac3b91a694b197d7addad1515cb409d36995ab2921de4cdb1f05789d832d11aef1d6b064980e9115cf90c15aeabc2d24f05a1c08f23068970da06a8f8b556b9e260bd707413d56ebc2c0639d25519d9dccd739604a282bd86526e4f0c54dbfe3be195c4a8caf82f8a3ef98e3fa17ed98a6f08e6a6908cc95c3f66270ae0523d0ee45983bddcae8f8dff0a5e8d1e52bd50b30db9e9326c3e6106ffb045251da2d0ad0a97ef7e130cde166504485a5dc0a866f1af858e5b9e9fdac025ac91ca169dae995aae69869eb9e25a1071db1ebbed36e97ea96da66946c6285a1cce90ad851a25ef8afec83e11007278935764a51a93fd99c05dda6c93b4e83ce8cf42e2634aa7a2c70546d0b17ab2bcf6fd1efff4843f687bee494ad384cfbc16e1ae5b1deb9dcf2f2116ef9aba7bc4b5a8a128d236fca3a45e248b8bd637d6f00848198dd827ffdf2b7ef9b18ac28f2c7b4d9e919b4eb1f17c4628872e6e80572881d3de5afc6b15f03837fb979d222124207dc942a0a152f6d2d39044ffe42733d38725ea50db04489f1baa44204b90bcfd13725a20600fd522daafd16b1d3e9080015c3e41e34ef10d98521df35be98107b8292a9339b0bb9578086467199f55e9e4db7fc0837c9f7e32b7e814319b07044f7514dd170a31d7bca27a6b07b896ee64313460592e16f4e40fd1ecc3394a8ddc03f04d521e32af5c0e39f54e0a6c31ad22e0aa52b190546d9ce1055cbb6fd2c0758fabf07a513205a21401f0d80950ccb52dad80bed59469a1fc0e22096948246ca048c0cd53e2cf9a28b4c021eba74b243344898d0859d33832b0023138db3065c4f177bd7ebb2f34ff9324789dfee363df47c8ec0ff078783cd68d69f47b5025a075d6f91a3bcc4ba63f2d8f5a65cc05e91aa4e6a2bbf0b52c8322916ba25212c635967eb984246c45209ac2cba4cd487a56023813798dedb35fd1f34fcd24bc6c6e25a250d4b06aea5e1878e82c9b6f2c090dd73477d431f3e9f595426b44e2f14d9612a19f12638afde2130cdfb4da2a975ea25ca3b72b9accb16bc95d1770e3cf623f423e5b182c2c60a54bf5acf47890c867b19ae78aa66e65e514a429de19273e520a2eb8eb9b03e4b54df04a5a67cd8a42f287ebb9474bd69359ac381f04894069ba6b9dbff23ae4f45690cc01ee53e3c7c37c9b34cac88786907de68053f91f8dfc1fdcdf6576fcb11177d5c826624b183b4fe26ccb90368776e099a174cf005141f188d380ca7607aad618adb340c520ad82bc451f8231a575afc1576ac3aecb355a0d667efbc9bdeebddc26d1d20226f538af4e80cabdc8a5a6b61b5a684fff1c356ad0285d38be1eb47fbc36cc0e170418a8ec91ce70fcc34d2bb610ff8940797a49619c6db7d497ac342b452d8e964ad3a4720cdf59fa3e197bd7045c09b425fde1565af38f55cfa9474c5cd4b04e81b47ffd0a75a282a4d6902587ca7e2f8236ffad0b8818759cbca180f45028662bcefef73c493af70cc22e2605b8f629f4b4265e001ce907c0dbec65effeb8c603d4cece2f18854c40a296725d5bee24b15029b74f87444fc7172b927aff37b30658c9378694955bfec4b24c1a4c15a1a4639701825c607875d457ea1f153084ab9e22d803fa7ee28589b07786fefff48a7586b1b850bddcf86cf4b9ebf76baad719ed548be452b36526cece7e8568fdd75b09c805a86ef2a5c05b45f85d3a370fa3cddaaa91651bc9c92c70f63a74946ba23e4fb61ad44e0c66c4f9c204c336070051184e2aa572f8463bab5ab64b7cfe3d52827515275b40fcb7c782d76a47fe31f1002e85a86169725e399a1a341f53713d2ea96dd52deea0fa82617457017afe6aaea5fbe6ef1a59d9770d981fe389653d45efca23888d0d27a081378154eebbb2182a81c9be750691201034dd774596d8e3539f7c7cd77d910e013feae430fb15ae4f48f006c8b0c077f5a31bd546172bab2dc085d79cd6a48ec0abbf758d89139488c2b292b915c90b7cd76d804c5506762cb5ba5fdfdeeb0cae9ea212800fe2d4b1d1929733f9c05b6bf04eaff0fac7de7db69ee9e1a2b607eb8dc00d2f01164ac5c8e110806df767db610cdc19904708af750472db4f32587b4ed3cf4457397ed41cdce1175edd1fa89c722fb8a8bc4a3276602da25603c69c462b3ef245fd781c08afbeffab8892bf654a70e0ef6e6eeb0e5b4d4601ca623ea457c9b1d2edd4b3effc1f709172c0efdfb3611ca766c86f43907d83988309b103016ac1c190e08f0054054bec5b62363329cae35e9f23da1423e76ee4c70a9539818d4923a5af04eb01bb42c1794ab994f7839aaae6666a2a39c5950015f2e1fa4a2244106d67a8c3764d1318f07d050aa365e080b032d74452974babe4c4c75d0aca1c25fa7ef946ea11e211220806a90484b3c8f3a4474ed20fe35d502f274eb3e517b1ed27a3f3d83f1744a51362c16c51705549e476aabf19b61602107b3d7f3d00afeb15471373ef047f4821c2bf9a255e2d9d46569a52cf4ef72d1398c6a204896a866e1827ceddd4d94777f9c8d6a71c5b1e212c14558b0f0241a4a40038c0ce039e7a886d2dc3c8d1ef01341beea679f24e84dfc76022a22e76b1f11dc170e65947822ac7496afccb3f03854d80c7ed0516aab7ce919fd5648dfc5367ae3d333ab45b737f5039f8bad2d5f01f8e82cfe4bb43b97996f9f01779f36fd472ec23936fda94c8d86535d72434f0c769f352f03984744bef12e06a1378c2484583963640745b50497b254df410b218ef95b8b56a192754dda62c91a5c90a980e9640ed69065ed3b8bc2fd26a062060511955eb056e9d3366974be9dbc77fa1b5c18cef0e8237b0c7db224b98ff25c8c05e4a77dde5650d0d9facd4efd76c7d370e18f232a09695083a35145c4dfb1b21b19f788dca559640af369c76ffac09bf3572ea08a67e4724900612e607be1be4b3eaeca4122b7b415b78b77872fa053c1964b0da2b4aad4001386d00047d56d1da289cd22e5269e68881527bf8534631b07c22d39799e21128779706c811b8d0e22cb0dc37ab5a3549037dbd9480b83114c8192b9535ad3a08caef694a213c187d9f7178bda7e24317e28932eff1504b8c894a6dee1e553b8922e281be817f50e5f6c7131bbb1f78870f1ec3b28906ae3e35789241d2a90c0b0f13b7f3ea2f1b9a1a22032ca8fc9c749b812b4636567b8f6c2a1f6feb2f734c07d83e9e6ebc32b04e0d3926752313be54f22441b584d2529650d3668781145fd57f46935246283fe8a87a5549db3f485c5374ab23af6d4952ceddec6525cd099110f53267e127ed0bb4ca22d523fe8d3a967f43111adf208ad2ff0596e801d58875115413347a8bbff7ba7ddac408c207e020bbf19f8b2a9c1acc1dca308735d54f36aa2eec9f9798dc7b896f0d6da1ff800aa0eebacdd8d20a8d3ebc2dcdbe7f3686c51caa3aa900ab778d617cc68b283cde967c99b720cbaf04fdd519c5bf04c655f77bb81a51d30ed6afe9c5fc9a23bf24c28f1e9c3edc96521a9ff46b429c5bf3d7e206af5fbf83af342fb31bcb25afb929a2239236de120c20402bf383a3b1442d5145e22cc0e4df2fac2ff86f56f79c1e01df83589c79f230cdd48778535a82650ea740fa4c1151e82bf9824054a4efc9821cb6c6d4f9a451ec80c1f034035859ba24d96a46287df286efa1f1c78dd79df1ac91535c5551f8bc616574818cfaf17e7d60e1dfbf468ab3dc03a1640cdc6039063df28105965335d91a3ae274ed3f0832664cde2157549c1c89f3a3364294a6d6ff365a8861618e4ad5c480028590f42265af3e25bc07524b6fc673e4fc52a0bbd989681c028c5ac4e41e6fe9c0499adc2dba31e2bb71ceda3c2948f487610a2b247e450c961c47b00514eae52b74698df1d4de205ce23c901442df206c6cf6dfa023076bb431f4d04406f0136b5424dfce125c6f90e12bbeb57c0cae326569dc35e016870311f393023854cf690c28cf883610bba3bce845c524c4b0afeace44ef92365765011080c61882038d48c36ed03863fe7380017269f5609146ab58671fa0728825a0bd64663e08fa5cc45a827ee818666394aa4e84286f8209bb30bb576a8ba80995bedc9a2ea1fce18b7ea5a575c602710acd73603cf0e3cd7e936b02f09c82e04f017444e7a18c464a01f3118ae6941a2aca80edfbb090aba4ce757b1d4651e9aad50880f069ec0c2a8b0c433753f58b7e35e2caa00fab61e5ca248db8d4ce65ade70c1618fe697b304b62bac48ad8a90bf02141576fc58c3e335c7492ede71c2aef830dac92e2f07ee623b88cc5a73f0cdc9ecbad815d35f55dee926bdca2c73c32695cd1635daff5342c5acad01360e89e532b70d0b1529ce82138cc726b776a7c98a43697bdd32d5ee9293754462fb225fd54fa650ca7f2dc095338bf7031e2bf32de99d07b6dcbbc819e06b4a58348a48d4cef9104161124e66c98915111a1d461806ea1e73216ab2853fe43a731c0752926a6009482bd5eb3ef0f7c5ece57aba3e36e0417f0df1ee0af33905f37135c8e2ba27cb46e452d376404db39bcf4b17ba0a044df2eaad95462bd53a8a85f8d49dad68c827ead08473a2b2b0d071dce45e120d3c3aeccef888a4f79f1ce37de7394e0db5798c7b8a418dca3bd77b2d0c02aef27446ea0a9b616705b2b68d86d03967ca3f057c06d3cc1166637773cb8f52f77de8cbe0e16618570f0b84cb5ff8b53a69d315bec5494b076a3565599ec8ee654c9c127986ce41900d134cb4f6c98a2409d8e37f8d40c93d7073bf027fe7d1cb35946800050e64befe3bd69ebbb356294320035e61504d098eedb67e8059e910589a41facc640a47bf8b4af847794282bb50ad1b44593d2f2393e7c542d79566c63f6cdec91c48d0f358748c64f9229e492bad719b2d89262998f2611218c66eac6f07b6178d1e553d80fd83f54a5516bf4cc99e2f1df9a7c940506af1ca21f11239daabe07aa85d15f99243b6be9dd39a7e013a22e08355a740a80bf5eea94bac2811c5281f9aa1d352fd1911ef0a2ad4b88a81775c338cc466d49e3b4807536092f4bed3da15df571ef5199d5297eb29c920d3083d348f7a7a8f5d860a3ef65e3e0cb4d75f852652502db48002e7885d4f64258d1512d5b149c759624d270aa61a590ff489a25df62f8522dc2a66ace42a3dbbb2cbefc9571099e76268928ffe1372f7bd30d666fdde4184a0e705ba2abc37520c4f2dba9bf5425e8df76c9c934d24bbd2b88c09d6172b6ba8cfb3d1dce18d30a6bc80fbeba0313f9554d5f095699e05d6c51caf17498a0567d8be1a5e212e6527115bdd43ad35d14a0b95e2f3ae9c7827db2f67bd25b07d81db7fcb682b173ec7c2af80a1ef433bb6a62d28999df85cb78c888403b44cab1fbdcd86c302831e4b948aeec5cceb006176209a14061ca2a335ad9465f1f849aced52f9702dc102321fa12605736b71cf03ef8412476c5d9a1b0b392606502f90a90e6147520b2b6b62b64ca110a310443481a8e7b27498718c0af9a086021ae5c8911e60db36a167d889960d051332296b53da87a1b695cc0c8aa47244a69cba8196fe6261d4179a16ac7646736759c8dc74a9601c5dd561183a3f5623f03606a0aaadf77a9900eeb1065a262a636902fe7d8b2be6a6adf367e8f02a2f927927179f3ee7c4119d1e54c708f10adbd750f110203e82903bbbccb3664df44a07c10915bcf71212ed8298bc1aeb2ee73a07051caa08c93f3342371f28310b0e8d1e0e9033258b2d33d9e85998db0dc1e85d4d09043b1b74c01549f70aac88e4f362d386f62de6de372883e1220e9e68705ca7983582eccad9fe61efa273d3cb70318fd457f985eb3eba7fbb7855214b1217ac1a944306dc47c03c77e1587c79dc2f9bcb2b5da688b030f98171f9601b586466304c0c0713fd6321e2534cdc86f173455cbd7d833638beeae6b101263a8c70a9c58acbccb9e023b0b51a19db491b123da1d753af12a8241a49e41e2a370b12afc288c4a6c70d19ab666b77452fa794107a8019f28b4f027f2d2e3f4bcb427d95fc4624b56f1862920793495bd74e00f829f09cdc2fbb84166b0cd47d2fae5d6d1c7344975d3077a21b5d1a9986567d560666f1963b406190effff6fc1f60bec7dcc9abc7fc2341304e4a16cdd9bb31fb9abc32d0c4dd7cccb8b8525162adb3dc14472b85ba71ed42226e9b591f3215624bdab00b2909b6c2dde398f64ae44c124029f02a6cda73dfbb87e72be9719bf6fce597e59fa3817c16106a0edce6c4e35603b7d824a61ced593925bf76d84d8bd83d3e898ab04e50b49a9f0f4eeb607c0eda0974134606a7c41ee965681fe878d0c237ae2cbf67e9b3e9cfbb1754404d035ed7aa0eb978a74f0f5160bac517a910818e9573a89533aa76fdad11636440735f89b11487b6e3e52c526c8c262372500f0ea788e274de37f5522adda793e919365d23c30da96eb3fd4a34ee7c196926323cf66f760697a4764dfb93116acd9d512b7ab6855ec990fa1d0cddbc75437950387ea49da97bd0d92d4490291519b9f76b8adc3e8ab206e6bc4e88b1eda76224d4aa84ca511eedd92c7119517310743f3308f1b6d5c3aa408116ff9da796410bf67844dd460fa9db758dddf3c87ec001881268a76d42727a1559754417eeeb3b660dbfd093d91a7cd68b057c364b351539267674c9c0cfc999dedb0d30126871a9dbf884a929d446c44af56487a3a3a7e1191b5fb22dafa3c9490c18fb65ba604a038ab8f7a0854ed4889ccd7d9b21b7015ef4564167648dde4d4478469668ad3c0dd1ec2bcfcc9aed37be4d7ba133230c7a842fcbfacb779cd91333c2471150c55ca0c3a80f06b192b6741495ec6a197017c8b1157826af05ab567f137468975c7286d5c63414a37b6039bd2c879ea8cd9d6e4ae28c5740ba94e7d06589d80f332d1d7c6f6c34a8b397750e862cbffdc5fb0736f38596ea860d0c42fffd88a8021232282b9041968b93f7c00d7e991865d83d67572d0bb785f51eb56d915502442dfd1383339fa9cf7b47f4b83c69f122957e3cae75db232698ac3994e630ac07d63e3fb41a7ceb62291917f12f7e323ddc65a459a8b601823e46693b9663c750283fd88e0e1378b598b61b43f94a863e29d73e0f15c9b2d02cfe10d2d0bbc99690699d46f88b50d99a16e431e69c7003b0c3e759195de7d6b65981cce7e09cd34abb72aeea934f9dfeb1c52b519a899caf81d728a279f0c84bbd8133aff39da2c5d55673c554c3d7bdef3ebe4617a858c196265755bd99013ad9fea806816fbc3d1d12a2786e8c24d2e3fad7c1155ca1b69cd57a0f9c414391d3c388a6a93db7272da0400e328edf7ac3b7ccb487bd324f57f6e616bea50941a6bdb7290c048c711f7b6dcd89682b15691dd9ef86d25ad970282cf77732d245940b07b69580b0044e318d76df93bc9f6909366c619e2064dc501a4d49da6cad9b0f88dbdb4f2eb2faa214df3cdfed3e71d01b7bbc42887126afaa98aea38cbd0458124f5544715572b1205c2f3e559ed4ba57cf4636ec5ddcc0ff0187010bd68a1b62caaf6d64292a6504824d32d0048eadbfbc5c00f9004e7261129a7a12569b707c8bc063be958c8d882bec5aee1ef0e7768b12861c2d69a83ba5a09f683bd7cb9a46156c6b304be0640eb86039d717cb9c680f74b7324759685811b8d1189c041693a92864d28e61943520d7c206d7d42c70a49c848d09761b14ac041ec740e62100502211addf2f18310fb07d7a8892d8669ae6105c8b57fa0685de0a6333d52e99b8437886affd33834a1caa408a6f7f4b3936e6f92832c421a50f7a3d7b781919ebcc76532d5a39af4cb342572e0b9cf137660dbcd63933a1e32cd8e3335e4f9cf76b36d83f0d60d0e0262d8141d8e4b55c178a694ea408d77ffd73af1a04253416425d6b0d7ed3eb3c99dad6a03942b28461ec621d87eea5eaba0e309c71c3b9b070e7c8793790fab5d1804098ed5229d29cc3d7eff1ee0bc03ef08c1ea6b57546fc08e58c2913f5db3f1d2043449c816dae02061c05f9e8caabac56ede9e69aa5ce5b49511f512c49d1b5c261af822c7e38dc9e011522c4b80726ad96d27d68708af11d4c2d3209145385726bc65dcf5b8ae98ab2a58acf24f1ea1a41ea0f242c223218db0bc704fb01da5c7ccb85090c6457c959cecb3be0880d103f3d17ff52f0d16ca9bad4c459e47a90c96a144d9dc46941c04ad4129acea201d2925327e64bd36f882f3e81ea1ec3c4a6be124942853b23b3cd3d0588a6b3807fe1c8bca19dce86af420f8bf41d989f296b718617da5f7b4f083d223a7c0ec8bfcb4c148ddac23345030e4eb62c93a5cc6d96e8fb0718d9164afe3df9621b62e5927945a65a1ff2f058741a211f79d85b8a3146ac7646c7fc03a790babf7a151cf21368a78e51340f9ab3973118c154b71854f4a71838643055f85628f0cea9924cc88b39ae233c944f1b67732722ec2d3365d1e78a76e119e0b60dd70442c7290da1f3eee9b133cfa903540090448ef5d1d37ab4c3fce4502b7fe4a818ce8f16fa00e45a37c7c18a4fbdc7493395239fb1e6269320cfe24b3b8e51e1cc209f7be58d8a28628d85a8dd720aa019172079adf9f970bcb4c3d05a452d4e4f2d3345ba86ce021944b5d8f1d74bd89dc77175e41e549e7df05a2de149c9305c8f462c90ccf769070961e0edaf3e5d2715ba700a145e11b0d5dc4a1ca010a90a0c12fbe059c503759e873bf48ebd922ab3d948552397c43f96a035ab6ac0d74d6a0395b1c201dcfc9c0789d48d3e89a488d478dde8d4e1165e7b8a39548356f57df26b47496f4266cf287993016e0c873f0da6baeb9ec97f38d820b155a67d5377dea78a07e759a6463156f413d2eb8b891b85d7a5c20864ac1cdb6d9edd3bcf5676b4b0891a7c505bd37dc845be6062bb7d9ad4a23a61f5cb405fa0f81182f6e41784c0c1a863b96d43d3c57e870be19a0cc9505d5814613b2bce06c342ada0ddc5ea2bd1fc117ad16df202ea28842a650b5927d3453295b82e50795f49a8dd23445dbea5d41224c14d5515e5c65020e08c0d2045634895860824c900211de2db664b43beb465872cf5300be3618e130ef61407a21beda562a2e0d2132889e1ce9f2c53d8ba0cf66a26e283c44cfc17684fa98feff181a6cb3a10ecec416d5f76414e53a8f69a425b502eb9d053378572ec5a3c77684c7eb4b064865a80115cb3548ae8896da57178a2bc3a3e55317c7357f86c97c47b30fdbf023b8968899202da11282a7aa003f78f30e61b46b7ad712b19ce74723b4dec88b1c1018b27e824ef3b1260ad73b07950e58f9920e59352cb704d37fbe542b092a0d67c670f1f93defe2e68e469818cb81e4fbb3dc3fcadd9900d60fd0c62009de7f597fc310e8624b47b9012a7c4ed02f593f555e8e2623f3066bd9e289b82c97059c312d8ee3b0ac110f81a333b6db08859ed13890a262ec828493337e30be6ce68dbc7ad955c4c28985190ca334e75c9ea84081b39803a38118a8002ad9ab3d07ac8d1e597a1c804e32b08592518371650d92478130fd4835355434e6006e956a5cd8cb2ddc90a44395df6247329f38520e363204ce487bc4486acda50af44faa43492acc435f076a11899f7a470c22553fd7284463b7630ebc59006e2cc34c808f95e254c09652fe7a564596f3f58e37eee669cc281b8163e4f71e35c54ec17e3401e58bd18f85db0c8c8b0d41909bad3999093ea1dc69be8ef02663067493c6b54baaf5b7bde1c9d27dbe997d4b136522b939dea4e3e9600f748230f9b3919237f67f0c2731e6a218041dfa8bb346e264d6c8d3cf461b80b59ea8961eb3acc16a351359d467d9ca2f6b66b5a328d36043776dd7908e0e7f41e20dbd39983bb81f31f4036d611079194205c1089bc0d94ad45c06fdbaaefa24935d9024d07f16c82c8eae87831a5f15e28c662f8e71254d295ba4bb0250c473428e8913e75e344062aca90ddfd9ec8d323074d24e827da9796eeeab82ee3f5a29e50a3165d93f444168c29f33b29f8aadad02a508fe634f42a366b9365f7750f1fce629bed02b49790b7cb3e46379a575a2d21fd536bd31a9ae723cc57fcb81f7bdfbce8229add5bd5457b09478818b5a89612e33aae89ce8afb44a241d47e9c68395ee5b05fd2d14508695b53bde9c2c2ba05a15d497c9c77cf2658c977b134f14672254f3d1956046c7a33f6a065d637d31b872ae1a9e7b1b1250280af5a7e4bda5b46bbbae1985eaec6e0a708d0713ffa8e6986eec8d6119670a1a8f6e2c50f889edfa629df290f38833860fcc3c3a99730c55f4d29fcb1a65c53608e83a64f4e940d5606231c9125be576141ab8017e3b3c3fef3bf6d88ef6ab15b210a013912064c74811090e06b7026f6a79c262d1136b0efc6c7c396e5a535373a877b4594efbfc8f6ddd8e0336382209bcda93f7aff04363476d3320fa9b13209193da8a8b1cd5f2c084cb8a094f9c7af9ccd6a5eb804a8a21de70fa77b45613cb55832215aa8517251380b440564490b552d5c3e9f3b04690ffcbf686afd6f4ead325849e041fb1f8cc3794767e2ea15c978f4fa8c8ecf9b9b7022a9c3a21614c6a705a2d948ca0f4a2276f85bde738cb51b8e92d3431b9d790f8589d5d1282538b4299a947042f80de7ab462207aee58f2e20b78c402637c49b3a83b0ecdb2406fd0597549900faf1595caf2ec9028d5702e36419304ebc09bcbec1c8c0b9482c3a142bf92ff0cb09efd270f382673653ddaf4ce52af638c5c287eacb1d1be5e00b1e9dd54aa0f0119ebd9f77e60c888383912d38582ce12bd750da6fd34612a9bab731fdce9d2b55854ee736e39bfd0319e62f9950277ab548df58334faac984d085a90a2dfc44384478e524f9711e1922acbc885116b92c6c7d34c0adee2600ecba866ac1b15114323e4e0dbf4d594bd2a4444c3d696fd96ea9887b630d2f97ffc6de553ae3b02fce6cc0101c3d0d7bab0c2f780f6287ec96927f130c5145323ebf3ce9d3631d5003dcfc94b95526ce7f131af5ad6462413938fd29b87f320c574d9a3bc9494cd9c177ca939ab1f35dabbbc47ce833608c205ec54fe7ab315f662b1c619f5d879d8d2bac892b3660c4af1b4494363406040db4816ca2494b446e8c857943308fc8602d8febf2ca93b6b44d477013c7dcf4e458f93fa06c90fc967ecf0da62aacc0b92261e6214727e0b8ee8fc892c55ad19fedbf5e220bbf7c9f5716c6625dde2b10ede948030bc40a4a687610bea0366428815a37f104e898860572753652fa86afd979bdc9be18843a12e9ba3fdc93300548c41de2300f2b810346bc3fc615b06135d71204dfd1a48d5cf8adf8667fc71db6faa459e8f9398bc5bba5b1fb3f1435f289a89fc5a975f1774e213573f81956e324412b598390ebd9c3854090d9f352445fbab1d6adbdc8f6271c4eb1016a313f621e0db3f9f7c016874678d0183349f31c22d7033b705ad6bdb02c1d71604a6bf9486546be343adeb6db22f5fc3294394b84722dba65f4d9f3bc76a847317aa540a17db467a662816022d310e9b0020dbe61a3180600dbf73b6c14fd243fa76aa485f5e9d3be136098721ad13668d04abcea1696cbc3f5d1934a3ea4c079086b356d92239c478675202c4201a99a29242ee11ed67ae2b7adad830f512255b76f358dd3094f1f7b5f27aafa2589f14a500d7de1480628d6084c3d42de382e0c8f62f6bbdfb269ef9984336da14a16fd5ac79d30cf610b08445c00467b21c2c7fe9ab0f00523bb0f19f0b1a293dc589a00bc06874c7fee39144c476902044d2f578fa417a1c7661195677353ad773ac441c7e9fa3faa6a42fa6992423bbb4704ead67dadf9fa1b2d67cd5c0f668df3f677e46e9a36dec28ca7ee582640f401788c0802d1e5ce3c83eb04766a1f651df0f892c9902ff29831e85771148f3c86ce7bef1ea00cbe292b3156f324549df1fa9112437ca8d91959a8c5ce22ad6e16914cb2be056f86122a4cf235d20b966debbbc6108c03cd61c185448622ec9963d0822194936c0d628501621fe7e0f558d7d34492b5ed37c82d0649a787ab4f8a162419cd23249921b57171a11c06d13979cca4dd949dac5695345156af9e1b23d962759cc6ff8f81acae245410b784b19a7ca10242088d13d6c6902cf560ecb61588a63bf6d52d3b86b18bc5f985f5e4053b234173a184dbc0eac22946ebe85f2c04609a7a7e82d4c297ed7a8583ae2e5fe260762a2af4a1d9695bc1e9ff6394129e9629431691fce5ee634a28e307ac8983802050410698262a5ccbed3f163850567512bad4679193e4d211f06320f4c588ac1f99ac37c6c315404837c7c128ad00114bf50afaf1f8c3df9cdcb2eb977b71b8f644936a98881527a2e044d02cad5e8fed8c36fa11356e270783e02e194b8d0b82e1d7946c1957610050b85518492b6c68d2d5094064b8a6a454ae7cd8d8aae831cc3507cc66662379417901e1a32fe40879efc45e67bbc809029f3bd1a4fb4d254f0a8f1f6dbee554ae1e6d6c2cae382d2a52818e90c0d5c14570f92542faa1be659573f171854bcedfc8d933fd04654dbc2a84e49901cfa7c2d50c4f5c5b4b878e0894dd7d42d98857f6e9fa8d47c9e32d4b499de1b85939a7a0e3d74bda69b9c399909835a4800efa7c4db3101c1cb644016489be3bc39b493c0287e9dcd033ef1ad364a5f79ac3c6d185d14c7e31b00ca4852fb91847190c1400c590f182806d663bad2a191fa8e02f680275091d0922786f4bd93eb591b8b1797c22b3f732fb1694ed0b01b3bc3b45da1c179f690977ae53de775575f395f186dd4eee01df4b348c0694ebb7947e2840125cca14a61db4c0181457181404cea78f44150ee446a129267e160e9c9ad20df620b5544ad2714bfc4f63d59d093d137477910de9a33acabae093143e206c2fafe391c0e04a8cdc94ea3a0190c1d75a6699157fceb979dd7e674349e3e044728c81ede410ca3a30286a1b82ffb1a0b05a71b76f8917935c60c5047b08467945b92df335d2d717abac48d062abfc73d634a0af44f5a8195dd8960c7b09d7f2bb89a9c694da2e5c05d9ff8ea5a63a4179bb514b738b8d0c8e3c93c4db0e8fe9ae8b2cee3dc9d9c849d4b0bb67dc4675553296cffe92ced7e3b0e219a08745459b691180c4bddfe6ec3e10c206c43fd9b1cde96877309fa0f545214f8208789d42c50c2e68da8284750a2e32345c66215136f83c9ac70a0496a6ffa04451b9a1aef8b5e59169a66d01f93b4edf7a0c32320af20cdfc48cd299aa02b3ed15cfe0e78e1e9dcb5a8a67200d4803cd1d103433c1c8ef4f9e54712691d06a0439f08de1d9c1606718671c2d1d4b2bf68ff81ecc50cd884549a507236406c7b38fb9acc571fd8f5e4406312361254e9883e5a77ea4cfc632cf08c7138d035799685956cd5f5ff8bcf6b3a0847aca760c132bee4482142c010225f3c4833614bb48bb0dea86df8fd2c1bb5ce3c2d827be94e38220ba9dfc62450a49daeb106ba8c869dd163a7552d831c4a2f81e1acec896b533ed1ea252856a5420ea62af40a78484154a8c922564ac2bf35e5b2e555d05095ab8409a06cea4b035387e00dcfa3d8777920f55e1e32a31dea3a3a2a3acac489663fd5f1a8c98c9f529a58fe528c194e273382de06602854f7bec3ee9be03ae987293bb9041d301aab9420c817d2bbc6430ba00acd3aa33452202844389bfbe4018242d638554ef5cba416cc225a1bd441ccd0363a9f73d2ffc1d9a66b312a19b168c66dd23ef787d50b29f33d085903d7afd524e696fdc6bfd70297f8f8b35f6c6a1dd82785dc20816211387020f785a972a263f1257125463c00fd5fd529acb924cf9c894bb1ad30c39e2b22338f97dfe4fa23ef4e06c19266dffa7b006bd6afc1dfeef8803e7307fc73113935e626b9a8e57a5a2dc9ca70111c5e57ca3e20ba3c6fd37472d42f26d8d99f2924b8013d6af0eac5f5aec72f090fccd11c770100242db2293c209e27400325f67b0eb418c34f9ea6c46c244ce0c91cf0f878ef5ff7e06d2c6c748cf49644b0dbf5745b4010739fb0039b87eb976129311b2cb7caf9db5544deb48fbb00d9c2cb883917844502ac3839b413e13f8066aaa673a4df657f9056c37ce0a84173144ef1e26bd3c0fdf75a84200ce3471f49475be006d303c5445d7812f43c319d32faa12bc74e2afe351d95bb9f74849caec53d71e43a481452fd870e6380d1a9a5010bc30ad16d451798f2e29e7f5668f64d00632f393662c08b6ba1f8bfb90f2fbdb440603c10a26c2975f7bca3b967610ea39ab15f9ff3a240410ead9b75298ad1d50bcf743459510b52f0ef05284828d193ea58d4f2a12b4c379e5ab396eb15d55331d8c0fd081680d50c5587fa7c717b77f50781bd057df886e5e57b3d73ce1862f82a82cd9d70e5ac6d72011d7caadcf442770b20fd6333734bfa1c3d318bd8ec986ae39f07face04a3fe1fce9d8f23b7c71def1a03c231d030c9bbc8b15ca8702ca09ec91867e6f845af80a34ba353fbc930eefd6290d1719075807a2c94c673c1a5e57931e1046c1c29017d2c2481e100428461311ebac12e9541c7fa8468e98885bbb3f6307f87b4b35016070d776c6f58dd5f31fa6836036eae9eeba20320ac552ca3fdf02a593d0fedda9f9d2e1c081d5e281241dfc4a8393121634b13caa9fb247a61beb81d7e6ea6fb541077d1436ec726cd9011b281352cbbc83465f4d7f527b520015f3fad13d2972c32c810537ed3c052a65a5a091abbda3b62d48b8cbee14181ec69913993b70c393b50dfff9158c0184c266a5ab92fcead4531a515be3a3202f1361b8fca5ee11065ba07d84e86b708033a4cc546b3afb84228188a546583aed619dc6e55cd27ac9b2e0209ee0f609c39d08de1169e79e0f01d6329a15464d874339dc90627e85530065051517361551c0c067be4614a059c5227c78dd308d4c54b5ae8ad1702ad2fa649d4818ff1467f946d2c9ced5792f2c2bbfc515b86de16fed95cdfef724fdea6c2433b2076e91750373afe8c2dbaba90ae1cd9d268d39337fdc0fc7bf25bb54c6ceee999c96c710479539605f59423d8d8c9366349126bdf1fef7e9bdef8f4b250cf8644fd37f5639e495114cdf1a5326c5bca962dec9cccd2991718b94a2fdf3e696b17ab479a6b08ba28ec0b17c7e00e2ece265cb3e9316e130701a0494dc90b28118c8aec968165702170976845742c9e919c46216fa80ccc05029d9666742d2fd891a55db6cd4210719b1b8ab4a93d3e308c19d6410d0c46cb6c89ed0e699b35ceaeb65d2f887cf52bf6460628b2480d03b8b4b8a98dee19435ef0f0d24805691458791046c1637fa30612b7a0710d618a1c96382427f18a0568fbc26b9f20752090ae4d7934e64c3b7b71689fddd724bc909f66afac6ff148d9c867c482f9e8cb8513c3dc4935fc08aee34b10cc4b0fabb8af0d6e9bbdec334a8b6930f39e6faafe8e1ae7f12329a34abfda247976571cd337a338a593d6a2cce41f171637b62781e2c3cac783b3bf2b418ebe320856f36784311f1d4e2cca9e725f82d8fa604bc40761f5388cfaf4d03ce8635f2ddb1cfa09f59e0dfb677f442d63b77f4d2e24c8b922f4a8a17dd8d987ddf4819e2f529951706d532632ae91647f6b622e3e6596984d4ac9e1c5b289984377b099d6809e691f863c19e91c45c386c48d3420648b3fd4daf2f7970eb781dc07c53f294f75edd8b6583c69391c3f0e3dff5993ada3262bf8e00ab6f68b26bc13bd45a3692724890db55ef257b6f76a8e1e3d6a322a9392457566a70ff74e031d1551950fe6f168bc3e19423305bcb4776a12e453b9dbb20c112aa6f91ccb38613b685e8010968563e3542b881a867305fb6e914e69c56d554929576f5c040c47f35d7111cac0ae2aaa3a32caacd4115a04be806bfc795ad6f82c83df371c7385c306ac4d04042a0f4e339a7308a8774126f8adc13ef7b11bcfbff40042c2667e8e2bf0a972caed27e525b826efe0a2807c5ac636b2d770935be147e7abf3c52dbb988374ed3d8085e012ce1fb319899e5bdd5f84ac18f45817203c931a019645839932de76079c7847762deb723451a1ec5a82aca776a3c3a87aed622354293b69056364ecd857e3bb3951dac9ad88ad283711034d4ca99c2cf79e78b962409fae8b34999c932039709c7f1c95767c336f86e5d3262b8a57d800a40d5fc095de06998803278ad125880f32b9aa9e5619b1301437c37041f9a766ea70a9ea684fa5853aa9bc0d96d4c5d2498ef118eaaa55fb1ff0392982547b0f98832b327cd531c39e715bcfa10e9a2d748b596978098ebee8f883b66bb3173e2f13a39541ca23d81f1d2734adcd5efce1c40c4be03640ac4a535cc9f7418b8eeba02984433e3925828fcf5bce8ad0ac0a562a204f0f366b5f998cde6b3812663c48a45a696000ae8fbd87981e609a5ed3b1087e71b3d23c69b54f36e55686d9ee5f812186104755ac31b4162bb5e928285f8e1e57c05d30e6705c0e87018dcd610c66cc9a7aa114252599091182bdd37ca686e59761ec31a661a45d129e1b4c2dd887575f579cdd4716986503bfd195268e7d792153c07be6c4c384ec965add4ca2f260bf9d62e5b8c6a104798f47916f0285237bec41827ca1022647e601173c6b848c2efc5e5e6c72a0d2f3c9ee4694669573f6208eb75e140623e93dc89ef7d9ee19f78ed51a4265eb8e83d890fb8900ee795580e28be9aeacd6c16be07b301fea3608d8d612e1fb34261a073ea91a74424539a1b1329528a4e3822baf8aef28542941c80298a3c658312d17780f255d13e538a90d8869e6197e5d7322d586d6bd1bc3dd25b497ae198b92ad4fcd0e1286b0577cc35ffec9927e6b1cc5ee2ca4e5e42c6503f43e672b03013b4d09a01bee7b2209537836d16e15534b643681018f754a47d0561ad094d3979da23d3dcc1983ab27417766e31daf3c5a95534f368221a3802cadefe9650ea077969be6dda27e5e6f8baa1deab498e53522a13e350b2b22a159392a9b4cd3cc936fd16a50862b728eaa5b7f9f0f8a110a36bd8f6d25427ad7292f9a0ef56df16a104ae29536cb67d45951d38c65895a083fbde5543f9bd81b6f38be5953728626cc8605e7b245bb742ab0aafe0ed0a78171e2f5cbeb60bb9f9095397c2079f84aac101658674f7782670f47b1fedf0d9e05487dc7dfe695e1e055a797e267be8fba2c44ae63ea2a2fac54ef3ea2cf250cce77a6687fa41eed85476d4a3d64fda4e92278c000f2cc5a818d058c08ee9a494d64f2fa724ca045726273143835686151000f82affe595f295c6da214649d1030ab50bbc5971d67d69f429c415ef0fda887eea39db6a29a8f6f109624c5ea4bf147ff8195de69e13214783e3486d202e0df4417539e24d908151e2bccc51a425f45a7f86f85fb756a416383adfb139f3e5ae2d6cdbb559dc0229c942d387b403ac748144469259e13dee3d198c1d62cfa645c6fc6b027e2626e8f16f2cbd94566cb7e442a47ff642be3ba41e1b41d16bc7778259acd644a31446ed125c4e61a8deba2d1eb62db03cacdf73d0b566e4c9c0e208c28726e9dadec1d2d47c9365ecdc4867752481d9d9aefd9a51520e3e6f80cf86664d63d5e2aaed4dd9c4484d851f081f2e78804073408503c35e20820ec5a874aa9ef1d66bf2e010dc43bb8df3337f0a5e80ce62a1d80ebca16149dfa5de349409e0e2814060a71fce5561e7380664e25795066f9f6837a91da1087a5db520502f1026e6420b9e5d1a90db8914eb171e4af8cec6769746aa20598e776c3382341d78d5df002552adcd231cf17c488054c3d39c41197d19bd86eb1654d77251ffa9a8c024249f807f0af8a2a7b38cccb0bd07f5ebd6fd3c2ab36c4b9ba963f0be8bbffcdb7feae34b2ee7084f1a64e3d8bd600120d0d0a3301e7289cffd54b1f36e60117e959d30c080eecaecd94f3f9ed822ad4cb64bc2177cbff11e2ea9f4c6dfad55554c7fc3daa024cc64f79db0189a14f4e81a7751e4303f51dbb5454d8159d61928cf853a86a9d35a7b4479052739c751788cc92282e3ada7fbc7b6eaa9cfa4ada6d9bd16a6cca53222824ad0e8127cf34ff8bc373435b5677c23489e3931f291e0cb653d740109581670aa1d54b328d7e08004812cc0dc88b740b7e1984e380d4177a652e5db347e83edfa3cc692712cd6c51e08fd2969f11d76c87a19bcf0331e0035aa91e350cf046f309c6e9d993ecc18efd5b068ac6849bb3fab5a590e65b36f8ae5a96652e0d8f50d65cb41196517ec45a72e9ea9f0b593bc7f0ab1e0b53f363c918e8fec6959e54d0ad78e6df0c0c50fba08416f8cbb2fc5edd45430020bca0a8130b7ff33735c8b9473d5b7c7a41f94bee8942a1345e7761e1e228c2c096121b2e872078283396f38594988db7cf33a7a88b874aac4e41d58efbbad1586971c0b866df5d745e22fc20e2b11713361bfa01fc86b353f754796776088090b7990b60d2f3f6dfa45bc5751bfc29bfec3e49bbc250fa985675a40f2787fe5cabd5c8cce591d1c4dca421a1f0839f7292d4e4230bf9a4a14adc3e807c4e384d891e594678438944b2062fad80b9b98a6c4d5e4dfb6d865a0fd57cc3032d2719fcac1ef41dd2fe28b2d29d3ec052e2e6f80a3af6f941d1b523099c8707ee62989ae88b02c5bac9b5284b1ada62b6556d263eff83c3c82cf30c67dbf6036be1405ca21e559832078efbc32337b4fe0bcf2e080070ce8170bd2118233fd5ef2503a8b03580f6c45fd0d355d033be69aa51b166e6fd22cfb30dd86bf979484818d4e3a638131c4580926c96b3595034122bba238c4e19b64b90e13e46595244bcc323848bbe003e140b0abfc2c967cd0a0c3f31da021bd50222226f100f301856f98eacd997869837dcc21e5c51957f0c1555112d8a2d729a9b7784450507a96940a7dc911befd31be91858feca7ad582de3f0a9fcf08fa4549ffb07867f1620b5513a9511bf1d4534b1a7f8de25415094cf5038881109a9aac10fc29f3b071091f29a9a12a18be43358aed72de47f43b16bba5b095a43f04f8624dcd2d5782b19afdcef32679f7cd55bc486690353661f304b1dca0fc681ecc90ad284dd35eae1ba46e19e9a7ccb68ecb4e16dccdd04d7884a3f0aa2a8a736264e153efb44735db6d1bc05e8705e5f3c135485e838c58e37c568ad49970e0755bb1bf4108c4fcbb579f21e080d06c84ecc9f8f75833d2be6e8887cd4809bd9275b1d460623e0f9b51382c403bb671d98ff7cecd2d806ceb2c3aafd66c93a9a695b3afcc666a038603a3afa598e14be5c5308d9c70061f6a07d623e13918be78aa70448764fa02834ad7be133711e1c4e7b874f4be7cf359f82c342608da2e03bc4df0ece2433ed4fa597aa0ce9945c3e2074cc1981839ba87a158999a643c44c96a8032beaa9f8fd13356cac333f11b5fece20fa00e2b4400bdff95def38a895108fffb352175e062eceb2d43d75c49239a09288d9a57a89c927c496ad82ffdd4c26b77986c08001c1b70a67f885bf85948f95cb74165bab06c35b94f5cdf1740904e291ae123eb69f74a7dd437a9305ac7ba115978e295a0d21c3626f681206fd7a4093e46e4bcbe0b5cf74be9a8a5db35e79f9bff83e41a262df5086bb9c99ea4d2f4e4996ee9f55f124e61a4ded6381e0915bc94152e4840aef534f1ec86121b15c32f8aaf5c4826283408162f668ef28638b6ed5b06bfea638ca72f68f15f31ed3e22a87ceb1fc612937c0588805f575135147422feb71770bca9c10dcbdd399d75c6dcdec9bfb6755bceed29913ffd1bc44dce4ddfae88853350d125f78e2715eaeee9c215a5c9ff5f84b995237fd1e26a92d894cc10bebfd4800ffd646d42bb2772a4fd566a57d82ebc0da32fbf11183a0ff02f94df1b70926749b014cf65d49d5e687c30c9c130e88f1fd4d0277e9eafff9fedbad4b32f9b6eb5e39357b34ea106e3ee47da3c351b23930dc1e6ac237cfce28769866f52debff8ccc7a6d8418b8aff2c2acdcad0df8930a421d7b973b71d2a416f3bdcbd60c228bc0e4e0ddf8473e33f62720faedba5718497d35c680e36328587f70c7befc72742b2ef071f9b0088baf12e9f9a85607c13e4c80c3ecf8fe0f06bbb2bfadf89de3af4437887cf9d1232ff306aa612c8c42a153b275025a1f61e1cca25b80a4fe0e450bed0844ddb5bd7cc74b7a0dec337812acaedeaa6a79818c31de6d6d973f826b1c10bc2206f4a2311ac815e7f5291e5c3bd56334e262d3383f64d06821dbc863a51eece35197a0231a404bfe9b039e2e744e15d6d7408fa51995b281834adb602c2a56857fb26a6c15928555b0d3104c5727241998c9ab42a4909cc909656599fe5f75286460c95d453658a798ca77d134c999993af0b54b74110bb817cd048c7a69e92e750659149ed00164b6395735cfffcbbbce0c6e33bec01d45d9213a42679ec4cd1f39ed17173755a83a21bd7495871a4bd9603c84339ecf4a15889757513c5712b99b621bdaf49b08791f0ddf63269d221b560837587e94752ef70bdd84a9875f440f2f3e938502a2690838ec93177f595ade5bd27f5366175ce273321db4c7805b39c1d499237495535f3a86a8b30c218c668ad9afcf86246b3876a467641d00b3a022792abecbc6e930271b02674503cf36f1c938e86c089baf75f44b44db3479dea33b1bffa1f41181b3921d9f82998519382552393828fa4b4adabd2cdb7954125b5e53671cbcaa686429bd96881f2caa573e0a5fede44b4d94dbc1f698902d1538050ec263641cb940bb7c2cd5748772b6e19f49942f1090d6aa4142fe113b93e33466234c4571354bf9bb1cc811c7693682d144367346037b1b360c202ba1af1e60164de6e29b0395a3629e3a0c97a2b9a555e3629ec6e2e210e3978990594b407239c20ac66f688b76c52e4f3a0719a12b453c3bc1b2937bf93b9b86c522a1e0c01d7201e399170004c9c2827f6382a66841399dce3439db429a7fcb6ed5fc3f70b4cf49760723605eeda9b30d8867e1b5410fab85355f174db3f97983f194880cf8dbc8c172fde0d6a1d6593321a256fff012ddb865c532bbf7654ec9c0d1ac8f884a44c87ecc627c4afed4e6a4699ad6a38720047891b40546523ccefed294a325de5baa5c7a9401b031e201f1cad0fd0070b4b5b1b49db0cc27d7a16f4664ebc284ce053c83547b26971ee72ee5dcbfccb35a5a00b39606f9a1575c0088a176052740113bff25983b73f417f17c7d8adf8a1a121d2e2251b6b4a6ec7227312f47a06e5b9352e40af6b28a306050527be7ffb313768edc7ec4ddb422904d0a0b1132e499e6498b8ddd4931319fcdb27ed3d8663f6479e7144bbf130654b8cb7e777800b9f220204c499c124a525de064e780de04d70b10802731be4fe605297fa5e7470b7fe6edd1c25d3aa982488eae64d29f99bfd5d8880216c3565fa1502a3f8224e11a3c79c26d30b8a8ef0773163bbf640674eb9a09402eddbb99b6cf319ab63ddfeb7b5a5a627a3545b6b94daa3bf205b0ac3131d38a29a0d2d5f3356d7f50af7d11e508f85671923ca8444a3f276b077c2b487b1f709c7c9092b7a1f4ecfdd9c0c4de12b7505c8f6c9e16e39481ae3c7f7dfd015f49335f6f4107a2062d9df8581b8bfcdcfdba7c7138a9092426b2ec131823eb767c2ac63e316f027627a6153ad644e73df14de74d74a90f69bb1e7a69e895adde1651c0b5c44ab6ad29f16c706235fe1320d4b3e3d478c2cd87908afc91e9d68ee147927fff33fe960359505d00622874d31bed3df12a2e3c23cb2a8b828bad6714b28ad312a46948e5cbf30e5e270da1f0830c39b02b18b267c5c2e24ce84e00a0a5f777d1f2ac077f2570d2edd31920464c46b9ab09109cd034b400eaacde54e1ffeb9a6a5266abfe441f880ebee68d5421780a8b94150f5bf3258a015796cec7b88d4ee7b6d7440a185ea7d5ae02af08152cbfe0d69d8c9dd79db5b09cb14b3ff1fd25f7ace0c7be0dd39874efa250546fe25fee819b2f682da20f69838256b9b08d4b7ecf8aeae1ac05192ce9466a8e47e172010693e81eed36d63fab1ac58d943c3d7b69c7e4aac9a1e78e64487ec435ec19e9a3a277d313bd92b18681169ab2fb5dccf434ae89e12ec32423ad0925d529fd26b820b92bac4a50f94612cd372162aac294e1770fe855082b860567f3e33d081ef83e69371c9ba7ad0fb17f1c6e8bd05457f2d25ef622e322eccef9d02950840cda8b91f891218014d63bde8937e8e3899ff144bcbc7c49b813f520a382f931234409f457b2298b79f1de953489917092336d22c64e609a67a86915fe33a87a7033fe76105128dc4d17e6388cb88b4ecc70a144e9a01de03e4910473bd3f99f8ccbcd5c0711c4ecb2e84d45967506ed579c0f92b58a0cb7069233d8f0a1729d131644d1d9970da3dce410178cb16d2682915805f9ce1c71d35f736d3cb56628e74e78a8c1572524682ba839a5b2221334e081c9eae8430b8856b5df503724aa735a4eaeadb91ac91658491ddc764ac7bc233e4d48aa7f0b2ba85e9289d8be6fa48724360075de3885f315766b490b371feb36a1c39e7c8a6e70f8e2572815a7d9dc099914ef02b4a768da81b65960b67bf423676087805d502207a67d66c734d779744a5d96b46fd5b65e5fb9638905fc5ff98c3068eee85e8491403423e96200634a380d5bef04a241b452f702d6231cdf4dc6c45987bf2e1a63d0e940780e55451562d3f9cb311e70b69119d47981d98f53e3c1f0d0c089fe0b7cf78acca23f3b8bfc7f6774c24ed98513ed28c367ab193b3077a990ae1b7a0af8f52789dfa54847452c35d05e04514b284d8e6a51740eb1387c56cb0ccb5fbf18fabef4375168f70a4e0220ef7cff284a5898fec4e3ced0c4a2d5babf4339c5cf5a639023732e9d8684ecd60bea74456dbae67b9ad9d762b21e590cdfe44ed80770ce87d04141b2badac86c9ad98e838fb6eb852d94530b427024cbda8d5c5c7d878f42d25d3136a4ff5d6264938f7ce2fea195e3a0b4043a60ba64e26ab30ebb93a56adbb8bf7dcd0b413ba9ae77df2b901ef2769d86bec72da66d5fa2bd5d41bef3e24b61a9d1b5720f4d05c66eda0846b08b4a25b4dd1fdb3175ac9191a01b11a4e1e2a849a71aaa5407e1bc413ab22e2bf19243ae2d5a227f8cd69abae4bc23fe0f36577ba935f4f4a1d5cb9dd20ba0a62de9ec042558a6137274acbcc8332a6f18977b07937836a3d59041446aa243ca441b4836e59eed0322463c631fe84615df9dd9ab0bb9337c1af64c421978e3b3149bfe8d26af2169ce83df2b71514953548fcb03a277b8942ad99c989f720c3e39918e93f74d74526ba6859cf355a3db109929ae4666b396cded64f9133f339bbd83eab56587456195269de521ef75ac17142154c3a23f6dd2a00d35eef7b95db41e2c0d57f2997138bd4075dbb948e4ca8133fea02ae27038f5d3aa2b058591d12adfb5a1185f4a28d367be54e6993ac03408d8ea152ce51947354e064ef7d0ad780d161f12bd04bb3c5d5a322a599044e6fc6c3fc16929ff0500c2c4e2169b06c2787a9f3735cdd6ddde71aa28c0eeacf0fc84bc01fa67028e9438483a6dabf7997beb195edc4da781a4628b8dcc5590dc006a0b4305ebbe4129216c40e7328639bfab0943ce45d648682530b51339d484388f82b087ed5267e38eec0b98f1b64771139384498e3d4a548e3efb73527fea5a7e588075568b02e5536da870768b285e30e8e0c631a889ddfb252d79dd129795738e9f210e874747d6d2ad40cf82db13daadc0ae5fa3916577c0e7345f5abaafc82042cc186d7771e89183792f8517f148b19c7aa0aab56053326b46ba220a1b8af8082eef790c65f068fa51e386a5717dff8281d58eaa09d4800541b4d9ec3e491b84277f1cacdea781aaba0b0785067c410899009bb9ec03f3fe7b96ed935b55cd3c56e975463bfa4485dc3f82f3a7fa9bf3a32c0c22feaaf960740ae8850990b98047b4fca8bc58f7e45591184ecb61662e80e424cd4f3905e4052bd96c1d4f7e694187ae627787a44db80f459e6703a1f2fbe50c2bc01aa3f40dff054e87dbc1057b498446800a34404b1ad0950e79d2ac2dd7609174b917bb090a0025d93c51c67a74ebdbb407d8d477d12ade24332dcb29cb00e448f940442b43c036530519163774545a072f099a498dd421057f777d6e5b958dfefb02f969d8189cc88c8aa3884ab9436446af22b3cf8437e0d9ede5167b469db020c403b156e582554be8d8366982c1bc1d87d15ebeeae346da2f19bd9d048298c0fd38b25b2744d139341efce1ab083d5a5c4d6202d8502aadaf707215acf74973c5c1595d96dc98e0a1dc465216eb36f5bcae46e30f61f91afd5489c4b25540478ddeb58092b4918e3c1b282d8dbfb6f1088eccad3214961ec0b524289f3ddd2e16d48e0f818c46c79d58b13be2071284e26913e08956af3794f40b485ce47446a76b5e9738cf0170dd779b37d607ed7377f1ae45199165e804a018b42928b64110fb9b8792020b22c927a446fe5663198fed2b5dc3af69f4ec1d7491241775ccf2087d5b416fd1d14dc6d226f33a40f111a4a1233e0708620f2211fb11f9620cf9f00e34bd962eb011f240ca4b6137db92dae121ba0cdecd24fd17c01a35f95ce875ef0ef1430f8c06d470cb42d5e44e6c3fa79625410c643c5a0924c870a06cdc4dae29ab492ac70d5c664ee15c548a2a6bb5b03d7a01d760369f89f4843af98deb5a667e4d6f9c0032dbdbd86a943ce6ab9f6c37357bf7cd6a5b00388c283b410e78d748b41da634ad6c1c87106be8f3ef18181df3d878b7809209405885ddb19a1b770fe92f132015ef6cfd6d341d76d903842d6154b76fc633afc0fa7e3232bb14980c9c81b223bddc764caeb19a2d2d6661470d1460b5d83de57a2dffc35dae2d9c614118eb6a4ab9a8b6bc0770d56fd0f5c109f577b31ede0b06493445a10689c58f7a3e2095b97445a1a622f8cb22e6b49b4f7c07ea9a89e209933d1013426397072d345d27f8a4097a00eb75280e72898f6cf6f79bd01129aeab6673007eac420ede54dc3625262b3228fdd4b40e084a4cf12e25ae05428b7c512f65d7d9c1f7bed750af5d3877fa455d59b400dc1290cc0bba3d6149612b429e82dbc287b1bdf24fac3a51d25a3df4adcfbd79cb588d5bbea99f9d34d42756b833405ae73b232d5c7b7bae818e83f067a9963634515d21472476a29b2ab649c34dd8fe0ef204d618db7cec867816294c225534f3155d59e702eebc2043dbd8ba929b0458054a995e2c435687582e3be001431f68eaa099252400b2a70e84a942c265f1094d79ee90a83a632f95ed5420f1d407f0b3d1d99cc11a0f8c82a54eb006308057c2673af6726ee29f2485c5307ee46a3a237f9af3de0b7a29d738c63bbe918ff6a0dd2c3caade77cbba2abf2c8311708083f3fdc6895f88108e0e7e44374e601c1616d7ac4d3e7ef10c9cca8d9ce1e2940eab42a7c52fc980518ccb90372c041fb9b356093ab3e11b9c52f67f70908baea73cf0cbf73e34533d7d797d9d9c98933e10a473de3e215ae1bc1f5275c74bab381e47e5851aa1a927b9366372d2b90fb9b4341a75a1fa2f988e52fa491ab4e5f09789bbe22283d0959553096e98b8c70a255c6fd98faf452e87ab8d04775512d3a93397a3ed3227b46cad08a217db3e8f09098c11d8a0330ee66882798cf50b04ce46981d514f810b55e767cac25a43fb621823f1535e23b0185ef240ac077fe30b1c7c31cef0c37a7eef3e184285ce700e25c0479a739a08b595b44131fc528fb7c09f7761accffd55202b3b295c4c91190f3f12a585069a0331ca040d1f3fefdc4844822db17cc7dd1406dd88477c43c5d5f1e07c0dd9eef02caa2e4e23e17343a315fe26e02a6679afde788b7c48341687f47d448994ef70ed5e75676e22272664076811c426acfc01253c7f71da71343dcb7567a096ee49c574c2c86bb18ae40c2fcf0f4949262fd9d60235c9c66f102127b0b3a1f5505bc7f81c2e9bc0620456d4749b015fc3334c27b2e894381cb293d414f59999ad14b4b458d9308f4f006d07728b8310ec071018a181012a0bcb5c0133ab24a846356de644b8ff32b311913ed5f428ad5f7c9c0294fb29522c8ced5b830c230c6bfb8be30424338054b108473849641c4ad7b565f33caeaffc7294e7aab93883c63e35f45c18dcca5cb60bad37b5dbf197fcf8bf2ad901a55f08bd915e4a970a9ee4d16b4fdeb312b116a0a005ec0605f3755e9730824db7f15b253a4bf563fbc842e25b494c9cd2602c8458910579791670d04ffebe97ec8b0888ed5226490d31b6af297e70fda8dd36e0ef2a057c9e8b708dc09a5aecebb2f78f47fab690fbe8f8b51de112e1d50b78681f9b8fecbdb141ce6d95d9e03099d1d9f7d9865719b4e20efcf903d415083624b803fb0a6eb0401f8843c357114d8ab0fed8a8a001aec405b830bf7839ff5f55944b0a6fb03b270b62a06a6d079d098a4c37972ca5deaccee9d7110a5a5128b96b6f54aff13f238a998fefab6a5f412da22790d5d44aa785c5791a70948b573754c6e2a49ef168948b6192ba017fc186ea9f70694f3ef46ea175bf912d938da3b36320139c928faa318c5228addf21a259e41a8b822a76c7987e41acc27c29d8e4a30be969dbdf28629f66d91d1fa9dfc50cece52ec71732efe9c245109266e5da57c612826b3c472539f0397974e4f4f5c554973012de0f08ccaa605d0ba28912e2fe87f78f9529d88cc0083bd62377f7edf5a4c731146b6a2ee9db174e4c79e0250cd51071ed408d95e7166a941b420ba9a3d1f7500e076ac38c5c33283e542522de21f614aebe33caa91a1d689985406423204857087ddf26503f5e6bfe61e4f338ee2e2466adc3f5b5a724f8e1695c77e4a2472a9a6c21ef5b091338cca1ae87b6db8ba5bdb0862ab90f8e0f51d12e07872bbeb864060e05bee3c433c14b57b959b576472f75604632e110ce62a25ad387cbb038647b1886acd6794ce3433bd379ae49ea9f3ddd718b1b069714c10fd83f7bb5fd9750e622d112649a166cae1d7915ceba7210f9307dfbac1d851c2181f30549706a2084b566873fa8f9a056225ac1ed1ff280f08dfdb3690821b99a1dbc48c97aabac52bdf52dd11444a250069e9a457a5545e8950e3cd715b83a44258036f15ff305a4e02a49b8b0df1be18da9a9ebd33fb682c36df281a2e2fd71f03cab7969d985c85431f17ff7a9474a232a866fbfb43d2fd55b5fae5b84db7d0b8e94a335d4ed750f3134a0b1c3908c37244a7737a048067286cb301d1e5b80bdde60fdfc9aa751be09acd0f7fc202edb0039bb0b823ede0d8f947df2da9e5132f9e65a38203df8cfd3b486c541c2bf2a5f13f9f71e10314ec500236e360670242c7654eafd4b57a107eb1ef2b74b66aa7d08396e741b61a48fb38ea5e74f72acb0c7f56a246dd00bd3017bfdd2eaeffaad10f732363fd08760594150efdc8db1a9a151a4a4c9aca6818c0aa14314b0337bec10091ad2c3b651407e36ee464e58477b2b793894400500701474b525b4fcaa1bb38870db8f047a76c89bbd06c3c628a0c894642bd2ac490ec8bda076d1812be656ddde974c7c952ea230e9c196aff2e3f41b4385c7cb89735d6a4e903a96e174b7af1ec79403f14bd638a2c45801f214dc1c0ad5735f89572b7736d717dd620b913cc9e5f1709dd2381c191d34d5b56c6c74c77b1da2491d70f7bae7ef82437ec5663cf346ce2cc095fb4ac60df2d5f3583886c3ff5b1fe81f86f09d94656c918ead68177f120fb12d0b6c43e3fd3d373b7c31a27db82062080f149db0cb2dfef00485c9856bde8b7edba9fbff045a6c852c02a8fbe530d6677b6dc89cb53666b04d799f77b932e05f04eb8beda94d4cac4a43f4818eb72218d6981823aabe181d8289b7ce48f11543b9c2bb7987412f558f33f08c4d5cb259d9c8a7872f35211e41c213c450079c2b28cfccb5435d9c7f54549ca5fd83d1b3ce6105fdb0ad51c0e21eef7a726d95310fe54883d46c8271b7de0095ea139fb4fc5a836408eec6599d757d95a153d978e1f2fb5d8019fa4329b57e8d25d620c8dfba6f1fdf39f9012e828c00b27e9c5a0583da395d3869b04f99ed23b7ce5676ad657ad42bbeae71e1c0e36fd052313ad5e43a6c196daf7fd1c5c99a5b2692e57d444ac566cc1469792880f9710f5c9b8387588b7fc8dc6bcb31f6e58025f45d92bdf7f439cf033af073d4f451d4e856aad6ce6a1a39d79777b62e55589650e6136f1a8b6a8aa401f41a904284fc518c25b836dabd50b06063fea9f92a08f2307e42000bc2b89857c385607bd896664a2649f77fe79342cbd1fe79dce36e0c6eca9309d45b1e3368cdd93c562763a497b385bfd891bc210bd59c79c7dadf9e334dc8aee23d997cf41c102dcd2cfd7979301732af91a7e8b672c87a3b5bfd590ae89f37edba6b09e0dbc32086c0081c85b1c70ea15f48cb8807fb4dfed0cb12535ff6e2d1be5e745eee12000250b0edc155e3f310e02c1a0664a2620ba145386be44a23cf52dfa8ad13464ce395767db1c0aa49e5db7aad52d5bcbe6317d963141d0f600c6225091fc513c665df00bde82a68c8c384c6745dd9a91c3681228832fa799e8404e2c2ee64e2829dfc4b334d0074e3b79e5ab530b870f07c6466c2a50f69921644ab32fca530ce21d536a9ca1c97283eaf131e0436dc0b9a82cd770ba697a3f4bad3107db757a7eaedba86ab026d3bac207981e3cb1159695ad3a06961a773760cbc243778158359838592b7b36e954ac6006741bfcdf7456103a742c3976c29fad030b5583d6a12691728382fec03c6daa373d032f8dc71b3dab20ab070ef7e567f8eb7703573c65192297851af7b0a2a5657deb0e0fcadb4f7bbe6014a51f392092e97c57f2f1b32a0b0e2ef44fef326bb356678a1fb99e2c3941285fede75a768152297ac7f18ea6cbb1d3ac3bbd48c22a89d1b99a86b08ee4fa5c193450ef89373786c1791b830d828087fae85b21898f9e289d951c1a99c75dee20a4890206bde147d5336492aff0f8f9670a6cd86e821128c7284e94cf03fd911273d51850db42ee19e4580fb4960c4778864bc35adb5be91db909b2b4ab943ed07accbce6a9f2d1b843c54e115b3b49cecf4a6ee3fdb5417c49337fbf0bf336d93b9b9039e7aaca7dadfd19724432dea0a7f873cf623015373d4ea9b8557d6e2ccd2df50689abe132619a5139580019c166209eee066df7ea69a429c4f85b0c77c938641f4df6e6dc20e5ca50beeb7065750c32fcdbd00026e20a5c26dfa3f3cb5d0dc7f53317980e6fa378c6cd71a1aa2c10a300765aec2d8af65f5fe9df3e6f42e1669426c50b928a57c74302375416eff11702bd660def1e3d81159dc7071ed187f5f733024b77239655338c6c37848648a4eae15f81896df93004febd432eb534a71735f85944089653477f21feabd33758f4fc8628dc08023cbba1e1a1cc0498eb7d0b93635b49a5626f8a3c8ddc34ffcb368d26e186374bdf76862fb3ba6e5e047a353f743a74d0ec9acba0db82b2d8ece05738336c6e20d5209186ac9cb8bbaf0b5e8e4ade65adb9bb617897390916e88628ad88c8a586cbe30367957b60c152ca4643d4a8aabbcceb83127721fe976cce211e79c4a8d64926e1a42be7504f44e8f19a7021d4af0ab33d442adf309cbd83051c5637906ea8b132d34c6ca2b1c2a41cf545ad9e21f29747286fb368e2391306e8d27a21371f2a523e81660a88c97b6edec12eec7156e30491a95bf6329b7b43e850bfbf5c5b48ad8dd0081299394b32b9dae211ce3831a67f82065b2d4c952e1d9cbfca496b1590a70a74809a0cfb151c1c3d06cfee12a090f9f26c50d0a56a0e6de8ceb97a8480f54dc16d212d6498b4707a81a424753c693052861995f771e5d22c6ff019bf1e86cf03170759acfcad4d6703e7ba44c8bd9869716db2171159a0b009c153735e937dd180f94e35a1e567abd74e17c179628355f329d7622ede656bc22c156f1904b99f249571d8e8f60be6e5dc1cfff16628e0035c3e770071668c4811496ed02db2b38016c675230367ab33978963055c5ebed7032b5be2793029e04ee1319f87bb92efc896a1a6f6ca8c23c51d6ca5731b4e9c0cf90ebba94b970d278f58ec643b6cce03fd8292d7b96307cefef26d387a9ed836beafcb3c52b9a509b3462e6a320e4e5d3600eee1a528f40f055eae0fffce6d3c1dbf392659e6345b7e63e15e87b90440d64372e64213ba8e4623093e67d517a6fe711220631f7b3d54c9219c114ca1fd0857b1dec6f5d1aef8d921f919580e6f5b1bbaee1c1b86463b3f77b6450c1e9c6924ceb87555479e03747128cdd2350888beb94e6cf91317e36cb59e011923794a5f0ef35e6f78f25425d2637f9d5c46a1d29369283c9d48fd25ac619cffb71a5e9703448003db8d0d9d5714d267beb2150fdf72dc8d3c6e3e728042817c03ea93631a3648ce0d1d82d2e07d64bceb8edfea725bd089eadb571609e8a1e68112e0a9e88fa5291c46a12681f4121004e6c23a6f45692d46bc6f271527f017fdd5432718665c1a4f818d769254c4b9883c579368c2b9bb03b55b83cbc505716dae83c634d3393c3967ad46809380dc83b29f9b10d0c8b7c64b0d7cb2d79c0685047cc6791c04b7e0b4f39414f9ab4c74cee285a454e29bf2c18cac9a3c03cdc62ab45a679b8d9f3e7fb9e49336f9958a49926de0b444c85262c59ce6e52acd243072565a0ccf2a87d5276082e112fc3ef9c03b8bfb9be185727d29b746fca712dd131ab73146a1b0ccc23085db0f64cad4646b6eb136914a2b30c228f143f2d3dfd5db3d871b4a4cac456a3e38323756d089f2b1839187e38cbcec75fd7aedc05fa92f61dc0a919d965717d92a70d9eb563c9e054ca82083cc80440be05c5446060d7c8380fdc24689b862490a2c862c182f5a9cf70dbcc1430cee2f4c97a2bb695b6062fd51389539a937d582cacdd839d552a09b8842a00458bb9f9a6f96040dafa799ef5a839dc80d53ee24d2df4c2baef4a2842200502d2ea86c489d8bc14dbc061fd1bb0558fef980b621cd566e33fa82f66e8344c0f50052cad61df4cc17850c89028476a6a34d508e3e718d5e975b6ef5a19fc1c2028d9ff571f4cb57ead0d2f83433bf54507f5effefd9b37c87568b6fabd546127a424342f15ed3cb03c713c51484bf646a9440b25538eac912c60e4827fbc8dc380d7d6ef15314a6d3d7d9bd41707d4e32327afedbe5e1f88774b7c3400f160b2980f35f0334590469147cfb493c250627203f9857ddb34426b8de120317a1f6e773c24d4f02472d0d82683b66fdb2c78cddcc41175190c5a1764246cc2b861743bd09c9baf3005150e9b8829051aec306cda4ad613d121f9882d5f474767ad4a3f22908f0c265728a7060401985b71e55416df0a0555c595ad44e4d2c88fca039ad299fee0a13252e53affc295f7c3ec9371016c198beeb13204d4080236e8c1d29bddfe8bb66e605363a1aaea3ee275c5b5ff5bfae9700602b75bc5f7b911d108b823e611384aba533d535583817020298329cea6da27f088cb075a071171b86846895d199df550a3424f26d9ad27633e4720e249bfec827aa5ada04cb1e117d5141ff2e3e00e1bdf329d321722fb2dde6162fe62b8bcefe2dbeac4f458972b233c4eb4b1d312d886e1e109b505faa246c767b84348ab2640bb5456effe6627d4846628f71e786348c80e7bc12d280b9a9ca46a1a11f7103b92633d3d5aab2027264040660f44f4f63868444fd8127eb74fd525f7b76a176e0a9ec3964296205a0618cb76dbe0d9e6de407b3967e0d601615aa3ff978b1f7a0ceb6950b26c9ac73fa22311c4562e7112805b995a1b4250f5cd37b8d29d7e6dd9c402a5ff52fe410509003d06b3fe1b88eef5207d314a3b26692d0b5ac4d0c08d2101b1f8207dba088c1bc1471f7644be0adbbbb2aab2580322905b3749f595d0869beac588d462a51d8f90b0501da75d93f3106afc0bb0be06db24b122c22a6c3556504aad60df26c7cefa380e49be8d39207dc3a4004e9883146ce04c18e4bf1ffcb9c154093c875d00ab4c61b0f41140c380afa24aa2f3eb301a011b9e073b8d821d54c88648c4719addfbe9d797be14708d72388d0d81cf94c9981f4d47e0a5cc2eb5a42d2d33e851d5d401e3c1892b7a871d56c475134ced97c08b6f6fd8e02cf0e2fed0238729b92aa1be2436c4a18d234e7980e8701c199120cabe46c0c58e42563b63d58ce13409aa34382fced7ee33c7774f7e77d0a6f3c172ba238d7a9426bca83813f30b62e429133e46e9f09586f5bc117ca8df743c71ce8684eb01625c2f882999cfa82a4c7bd180ee501ae9525fcb0b4d640b0072bb4622154731342f940d07a9678a9696be31506656b62e82e594c2f11e122ee6d43ee58daa3dd4bed5286160d860fc3312d0332ca2930cd8990129556d152826400b92c44afb37a3a420fc271dfdcb7cd0b675be5f2a8c1343bcd67504b366dee7c8f2f65def59f1be30f324659ae0eb53490dbbb3152f8dbb230f993845b21dc19eb36aa7c146952b4629b444302658713b1efd8360f83a75ab4fca6ca0e8417b07e5ae2d2dcd586c4d8487a4d64343584fc5bc479b87bc314f30d71f4f53cf40a396b41c514e6bc193dc7b62f2925fca2dd0704e79dd39853d03f4b84c609ca372104a711bfa371aa58d7081342e8acb2b5260dae685d52e22e5c360bfc8f50a6668246cdbe502e9ca3945c24b7be720a01fa9377720f2a0b21c8ac6c2b1f586246dc9d98093114b817a531c60c3e8d46d49bcbc241f6ec23c182cee2944466732fe1ed11ab189a51c31a03d2e7f44312273617720cd31a020532d41e8f08c28925aa8456ce2471b5a8ae41561bb402f28b8c32fb14ec64893b11540b6e1fee0187f3a487685e4a0dcf7614cd46086ad74d74b66af23614e54d60576af9fb7c2148bd689e04ce0d4d8d289b7899afe1877bd2f5e4e8fa439854eb27bcb68d5e71281c1cbc2e05afc39866996f3d6aaf17a85094c812336955326eb5754e29e301df8a91b2cb03cd88f813ebacd31a51d3e3e032252db0521a2d807ee79fc97e811976b42f2aaf3d8e354012740dcce9edaef54cc744d405d4ce537224a6ee4d0a66f3959803ad08e35e87e482e1c5dce626dd82faf025ff6c51039ffc866d85e214ff34c0aa2c7186eca4ffadc7b90bae453d7273569d1cfd378030b5ea08e6922aff8356ac84ef7edcb66b5cf116f5ca6c7764c73d3fa3cadba1d1768e322782654e72bd2480f80276506d2fee197af5043fb3cfcd7411c53dac667783c3957bcf8d0bd08812fee8baa96aa26d3b5faf0b8953815484f5df5bb4fbb3b4a48277bb54370a310e981812f48783223c4778e54043be4d49daf299eb7e8ba116b4c20537d5bec0ecdafd37542f040832ed111352131164704cb6167d70c57e2b08d677c9675655c74a45b036b7a044b7a205ae792dccca94d1332e0107c3eec93a77985061c55b5994db45471c2a558cb67fae8a1170bbe3e3d65699102dbcc89b638d634e231e2822fa4eba17f4e6ed66764ca8f90a9bd3ec3b38af37a806531a7ac845ed65bd90e864dde971debed002402e24ea8af00c8bbecda5e1a39d13a28494283cb73438ff026d9bdc762c5b3649147ed9b0d53c8ca28ff48ca4a66181a5e6a27a24f04ce1658fc2fa74092edcfb205260d2cfb84df868e6b7e1d5d231f8e51b9924b4fb47899e3cc7dc5e011106abd8393600dd750eca8eac611b8399ee1d500f831ef72672c1b85421683f5a49ee6a103663b260e2857974ac636388ab27bc771979456a1fcf3052151c6b9286719c8c725408f4b29f970170d362c806fdb3c5a800e110d51759c4aa82468653b848fb17a8631fc563e51b79fffb74b72c8d2c2281c31b2adad3fbad0e134c183ac8ad5d61078bff204cf5b53817b0aaeb6ad84a10c80704e77cce68fdd20442baf998015c30f7d7d83195850f1a3d2d6c1590f0e9440914c92c6f7fccb1ba5b248e6a6f50081b4c076be2d536751aa3b619ead1a08bcd10ac2e036f384c7b052f992bb79762a4596603b333b4bd4f57bb7ad4ee2f3f1166a34ab41019a45474e002ff801c24f685cf47605fd1460909725e283350fa8050a3e3b1099eff1f64906acd3a18f4b54fac7bac8e21b82459302d7c1ef098b8b4f9aea23e31979d48eb5348fabdb4a0afda76d52ce92bcedbfbe6f510b37d6293cc5b96ab3819e7ac4f0aeb7e8590437095a1075733a83dcb40587a6a357ace4db0f38a0dee95ad1a211900a95c67994455925295fdac63b06ceb321ad603e3017dc5eae988e88ec72a534c5aadffcfdf2580dbba0c9f5e61fb1f208dfb4b2d51291456d7ffbc2eda4000937a823e9f57b2da137c22e9cabc814fc8e7a107dacf7feac22a3b102b94f9e825d16e7fb471851e2e27d2a2ab4b7a3380b5e67f25eb7d79a20c639db30294f94cea5942e52a3aa5ee00d3056a139c54fe5ca1be0e908ed5bcfe57978f1e8feb1ee9c2e12a59a0a7700e21147e4e971e68c3ff2aaeecadb52a0eee9ecfa4aee6a5af84237cfc04baf76fc254305e15251df95cdc504e8ac296c8de330aaf588c166486a90ea69c5b96581b6ba0e17d87706fbcff5ae3bdb7e67b55bf98c7a438e6e907c8cd5e8c69ae831d23bf19434419cbcffedf766b841042f6de7b6f2977cd0b2d0ce50b0de39b1b83ebc20a0f2744e9ef320e47cadf17e052735300cc7d3502705b5e4c07d342d4fbf0f7e752f1cf6e96871ac55a34a9b4a3b0168dea067a3730ec66aa2b37b456d38f426d362cbbc5dcad7528866118761f34fbaa696fa007f37ade4bff99eabb7937efe6e601dd6031081b36acf6e29a667a7c400f0600efbbf7a3503662b6981fbe5197c3ecced17a33005898e4fd6045d6c59fdd4cf7f53c9898e4bdf429adf1f558588c4987159d8e774be3e1ae90909010d40110f7f318e7260837dd841123cf892449a0e0f1014fc4fa5e1986bdc09ec6511a453197f9803234beb2c82b52c46abf8645a1025127139dda2494dbdb64e276a75e4e6b9182c229b806866a70d7201446f5e58fe8a65a458741584f9d3896955acc1bfa4d6a71fbd6851e8c2ce25efa424e16119245842ebc302c6be2e3738146f58b704ee8bd52688c08da40a3fa18088203220d41e2764da3fa44dcd08b9000a22d0417ba8c888c078f2270b6a38be0e3c2053939ef0e17422b84b7b8ac95b7d063998e9597f170602875eac51eb027331eed7abaccaf6890fab091998ea72347f7a0f1bd4819b458152afd55ea940a1396f50b964a8da254a33510c2770545312a5496973ab5c2a4a747f69005fc843253b21d910ca4174b767666b6c39da12487521c544c183cd2a83eebf8a0b23c3ef670f8d24ab663dad38ff9d8c3ecc16eed2223227ece179815654b964fc6f9cbd119274f9e93f9071146ff6ca951a20c5aac488d01cc7408611e5028889ee51b0ca2a3217af834bce2e7a73b0583ae67baab844d77651001ffac18312c5b79d478381dd1c7a231aac1a5e02194464535385450a752de8f3e0f46ee44280ec78cdf4cfd528a06a140214783073877e751ee1cca9d3fbb13e4683414ea267fe44fa7e8fbf28a1124619886e9547a1cdc50ab62e1c44977b42a86a1e21187c34109e2a0f78eccb8570a86b17c3b3c127f9530ec09d0c64090c639e95928a4d442e8333af589e103c3fab049836be01afd171a84e268b4c1a1fa30c98a756137930a4c926261928bed00aa0106411d7844c5c51378ee3679008330092b26eb1514038330083b5d3882415b753718b4c1b81b0ce228ac050cbab06f1293170c824152c2a008a70e1bd0fa5e9a1d0ef728d54e123e8cd218ffe07bf492978f6294ca1829b3dd4270fdbaae1917d2f9868e06957187ef3d4aadc9f0bd4bbe24df2b3d5b69713909f45c103e8e11c2c71c59941dcb2ca5d9b1d7d1b107113d1361b64689fcc8a21e6317d91a13462fed06a4b31c2fd39c0c66635ed766c3ef7a673a3404340acba9f35b4c8c10c678fd8887d584ce31e9fe83a9b9b1cd715904602ca8ee6e3136e06378cec7f082708b1595115ad66559a2db4ce66466c0833f582dfab9ea14ba0cdfd331617cbda9b36f543487c4fb1e5f4c53d4c78385c624fa56bed79c5845e58418842693c331df6361e9ab2b1a5cfc25b5bb5691849feb98641174fb30d755810423d7653a8254fe595c626620c0e178b79a8c501fc346f561430ae19c3152aba272cec850e7c26c078c3bcf99cb7ec08826b81ac277f6aaaa9a555535a5c208d08c4eb1dc575221bd96341befbdbc17686306aa0bf5fae6e202a4fbc7f4de7bcfd2f17e8d34d1813c184aeb4f6cee691449e31e0d0988a43e4757cb3c98119ac0a83e1b79d9a191ecd41a797607cc0447a399670a75e3225c840987836f7238de143bb8b94c698c3446795931461a23a5945208e955aab5aaaa8c52282f0b66188f6531cf145df466dac64fb87de8e2988752082926e56561ccd329139d150fc75859d58c31c6c8236a5314083108534f545642ddea6d78eb13d541298a1074b7ba83c6959f95e7c9aa689c53ca29a5ac9d8a704a0807770d5b523748b176efbfe780a8adb9dbb051575c4e92b04695aef7f83dca9d73f549f71dbeeea8bdd37700f8f706e0ce356cc38fb5e0ee3bbf26c123c10420ca06eca6d1024a9e7c97d7e9b31d7ca96419a5a35a8d12fe1296ccf5cb5d18e6321d1f90c075ec1270329755c2c7b208a84001329835bd97f7bf97772cfb515db61b10152840e6fa75eb653eea95e9a0d7fd62408e175f3fd1360151a6831e667da80da101e90c5a2c0b75733eee0c3789232006bed7ae3a904ebdbbc90f2135202ce0d1a351efd20269d47bc503082aaebc939619528692ca49b19c2aa57d9c11317f50226e05af98937972ac20b3e409adecc7bcc482108488c9c3c6ad8ee5d4cab204d229be3d8600e21cd008e7728eda787faf2e9d7a60b8af0a2b7eda86834d3c77c50763ec5345a7e4d7edfa75cbe072770ed5a9fec2eddf0a4033ea092ac642b818febda0c6c80c6bde63e69f2643f860e41ff075adb8bf20a59432d229257c1062cd9cfd7841a12c4919e99452cad2056549cae82e239d524ad9921ae1eab7e93eecbeadde64e4bee785fb4cb73ec7059d12beaab2aa6a0556744a08e183f03d197b0ae17aa731fd86b6fa9cdc0d8310422c2e8490623dcc0c063a1cb1a4457f3d8c07a846b1b41e842c3329218458cce229bdd381b32e7d3124d4d727eba24a9ce83a29945471e99f26baef31ca05cac6a4357f615735a9b460df4a7315b5a41575eee6222b59457e717383231c410a2a702efc73198feb4229980cdd77c8e3a2871448053b3b5908e148cfa57ff78ad90ec863e6e00c5460c3750e05851c10b5643529cd4ad583c151729df404a8d452cad5990e1e70bd489a93e19b957e75dfebf580b054abcb1fa5b412a393018e063d8b69c32eecf1688c169c10da1c8dea2321dd6514681992edf15eaa142d48bff4554a777346a8250d481ba07f71c680ca0d47aebbae34e7356756cd79f5e894e9561a7c5c61a603a6e0324a462edb715d3ce921a5743e4a23a574624dd477dd146db8e2be570d7380fd551a96838b62558ffaa761e71cb80c09c97acc74f418c222692c533524a4abd89ccb5445c82a8b15a923ed1ae229a9fc74542edb71659d5da42890342c0690f42bcba0a84522d125c2f8895bfd69d98d998e29da90e456bf4670341ab928da3e701f3c10abc710b4c79cbfa8366755d569495a55a3c78f1eab3a82550f0845583503e57c7ac01921a6a2391912164fab8aa43999a7399f1e3964f57337e7e34a3d467d345cce65e322912f6b525a91bed55b21153d7b96fd659abb22259094f2145c86f4e893b9584505493d49cbb90ce9291a4e0a2e437ace65ea2feb62bf297d29af0f42ba0ae9d40649a14fb1d738891a4d8faaf45389da86e2312fd890a31469eecec71866c2acecca84ccf3703789ecd873348c18fd9b1a9683206cd8a08c432702626298d2360c619735440f1f1717d5b018c41d940139188771228f29315771553153aac50b73a20ee0ba2abef0732749ab511284f44ab240de4bff915efbbc3927b7759c2ca0f2fa202927a53cda202aafb64649bc8a45e2bd644904a94fb13518782ffd6a23e0648cc87e5437da0d48bd25e36448cf20696ebd4d80b20b9a711ad518112ab558919a45ebba29da00c55dd78571b42cea02c61161d39a389442482f4b42181f1fe768ce49b1632f6558c5e2cfdd1887711847d42d3817678f5ab29a94623ab5e9d366a0a87581903932733cad667c10b205adccb2e07b94d2c81974b55ad48c21f4f5a7613180f049a85d5188e28a7baf9841805e9a458042eb828a1aa58fb4823056da29b324ad2a382ffafcac28bd88cecf1827fdec8e749e52aee22f8ac5793a238d6fd239e79c74be18a7ad25fa4e4d5a61d9334b56d7e32fecbaae97e275839eca92159b6270613a950fb18a9ec68ad2cb9a945658457f512132c618afbb6c5e6ad3d2e2bba53d781df050461e548e5348c1c47597e72f8b3fbfb96cf4f34499dfe33b196610baebd229d3cd9c9024b067cf4e35bef314ce3f9e1a9603e8483ce79c10d2caaa2e4b4e4a1f4fe9d3b0262a5f370516a2dc7728594c26170e0f77de5d54a3a686c5a0c26096c999edc8b052e501ab8c070c3a61841996697c67106a84bf5c3fe6f75c445b082e8cb6525bca5c5042a0d9b45891cacf744c818534b87b5d13e38c077d7c89fe653bae4bffb4eb72f60e35d40cebc297252be301039e6ff603c6858fbeb40585d80b2a85905251f5eab224a5f1d9e3239d2ec29eef65cfb2973a959d6f653ae8b426a0bbcdf94e612fa8f4fcf3293e0ab7eb9bf5edb2e4a4547397238df17663cad7a5d4f47c9b4e4844849cf18b2c76b43108b8d2f5c4f8f62b835c247d51bad26ea59f9ea23190a3d19dc34331ec46875e687c4d31bca3848abd7f651adfea9c63a49fa85b27e1e92448bc97be465a2769549f879a876ebf97d466c2622834e6b9a253d9e57db813da40a3e4a1e683ddd8c915b2984802331da7c7e4c7123150411486ae88e52478371a3774659ce543340c07c140c33899df1c3662dc7b3922e66a9626e69a66381c3dbcdb1e1173675a5ebfbde59bcbad5eb52de6d673a6a38526e6cab70055adc56271f93f681810e2f7a03947c34593a11de186aec8663a58acab0f098891a1cae778254d8979379b9b3b23fabc11d98d6faee8f359f618297cd3a9184fc1789b1c0ed2fbc53b55ff7297a31e0c001e002764868d26e6aabcf4d24b77f121925c5819ea469bdcd3fb8a2b8f6d0e8b8b9dec8be66068ae512fa48b9226af229f224fd29ca311004dfe0779178da5dd44cf0e451bbc96b6b92776c8bcf250e832642897ffb421f37250a35adad87ef17309f11f1b1e0922ed2e86c41096dcfe10f8980812442044624837a16e184da7640bb0408536f4b131d4cd0955397573422da403764e3a299d734e3af90d8398111b5ff1e40a7602b485289dda780b8e72874a3fb76ffa8d6366768fa537c6713861a858bd01ba9ccbf67a6ed729faaf07732a911a66d199743e0b3d98d1f99dd32e70385ec0430fa6be6f367629b8c37517811382714e3fe24c9224e0b393065f404581731ee3b0107c846bf4f98a0227792c44d724b75fbd26eec647ba331e6d4f3b2edfaccaaca3efa5b1ca99c0d2581a756516207d64973851806546679991cdc16448cf813238a3a780cad48b3496e12c089421d9149c6024337acbf4b604bb1b179091ad6e5c55ebb48ece3bd2a8bed0be26184886b32184b82d2efda4f3f6f5604ddff073535005724e9cf4388929c56c2e44de4bbf88f7d2312f45639d7e1042667e90073771a45334ab23d195914a17d4b1a2421e1ecdb5cbdffd584ca6c8499c6858825520d59188becb49441a337134fa194b810a264c6e3f36764c83971b65d1aa897924d2f9661c51baae5115916732d5fa72dcf8ea156132d53a836854ff3da621ffd416a50189210d733d3704d42fd5e599a79c534a49c358348a9999331e583ce9ea0cf460ae5716d2f4ce25357ec24017148c0563617d8346806e9f7dc0b071d0dd3888b1a016b5ae5695a5e99d1fcf084ce0e04a891dd13bd73db91b477143508438a8515fa8fc8d83648f8cc3c532ce65eb292ae7f486552a8460a499c8a2b2e39c0dbbcd399817ead6388c93d330879dc249f2e4bdf4e1e5e6004e75f7d1412604e6a93c2543e5e7784e8b1fb0b9ee0ab8fd3fa0db5424b9b9dd3d788bb9ccdf5c48cda15cfe3431d4ed97dfddcbaf1022fc9e2cea6d589134b9fd128b92091f066e8452f2b4a5860d1b0e89974b26ae3fc16bd49eb08b0875ab4755131b02501d1541c0e26ef06e2c8e8a205c718d7058093f0c4032ccd9084ed751a184237034ef5c668c11c21cdd1d2333337c101ece781f3c7574dd903b3a860d9f3c965323fc013f7f546ca3061bc51a651a3cd8d201dc12840ca78d12cba9fc864f3a295d37454f187400658a271ca162075818bd07637ca707e37b8e4ee95a83fd72bcce8880d90ff8f768b146b9eeb37b6100a27140d61686c0052d5c7366252b54175f8ab6bb790071fbaeefdabe927bdd158dd33939a1e398fda8601f663fdefbb2033af3313322de61dbcbf89aafb08522304629a394743e27234be960f7bb7d9952c835d87537ed78778ab06143086177940ddf523ae82484ef54d1f99c73b2eb0edba79d6adbd63674e14a0b52cf6f8ff99c454631c006931ea8208498ef478085a0ef6855118542a1e60e015ccaa4d220ef9db5e750d3bdbc9e37bacf6eefb19a8ff35cd90b34aaa74de29356b4b26f521ad90ed183018dea20455ca051335094524a29a540a3a06b8a1d14a9a2086d38d7e002f01b83bc4e8a2c74a82892040b1f6f8b3cd82081e2ba5f479401044a38a1bb9b99b99bbb9b00a2cd2649c564876b72851dae0aa1dbdfe1e2a086db6880e2f6c7c00331dc010d4e70583871db0bce0a2658e10ace0b6110831d9ccf4d09ee9057bacf6e364d10c301c6700016c438459b0f2a7ae0ac60450d2b5071e061cbd01204141c62a0c00a920d5a80e0a4b829c11dd2a5db76f3c015d0866843020aa41aa4c4709bc705e5522ebc7e966803c1cf3483a4c1ed8883db3c0d904cd02df07847207c1042f81e84ef3d08d90ad176df126e7fd4731bc76d2be46db1c5b5793c8110742dac532fbb9cc351dd867eb6ddfaf212978e9ef1e145770e47c61965219467a05582effbf63edfad271269271f56673cf8ced190a7dae987f5eb99ddf86622fa916362f5a460e85a7f237e4ad05bbdb2990f48ed464f83e3325756c8bb238db7601b99dc98e0baec016e467691fcbb71342cbb31c369e9061d26e2a984d1c3a0c6b451cc32b8f87550c24ceaa003267590019c420a2798d401051a93a1394829e51383e93a26436268ba0526434db886fb0c2ee7c242f41d15374c5c50360bd1570057be2b5beefb26e3ba1591bcee8e8598dffac2c69854c92e8d7a8e86abe16a3c9616172fbb6db779e86ad03b5763ebc3993e1e6adb247e27105788db220f57be796cf67a4908e12d6e124ac84b3f845e210ab8d4de0b62dd001b695fe6a3ef63eb824d51377a5f8d49b89ccbc6bf0d83749d8bb4baeece0981e21afdad6fa4ee8a3e11233ab5b9a11a0c6ca0530c84534030a3e836e336b93d6306ad71fb9b00ec0c2336b0cd782fc6f8e28c1933207d8ffe4d7eef518d676040f5a65fbf9a0baf9f2eaba2b025c3d7ef0fbec7840be361ca44c878939a0738f571903dbb839d6afad64e5432a5dd97554129a964287f402ad2808dd00d32eb03d1b3f8ade483ba61976fd47e207af606b0b92a9e10ea25bde40736646892050ad8e0a3c380ec9d3520038e01d91357da19f90f480b82960b9b50d336b46113ef3a29d4800cdddd2d74bb5b8a2204f1e0c29600c5f5d2e4a9f00c405c291f1d20a34d646e82559d3ea1ca0381a2ce1edb35a74531eb72ceebba3ee7b430e64bab7e415acd8b5ef3ca7e54a787a70ff4809f6f80bbd7e73f0082963bedcc25b1d358f7fa35b31ff3629f190f878624dca0c9100e0d49b84115ee6561d622c2ba979d16ad4edf29ba4d0023a2e2fa82cbb95c1964ec05f0c6ec98766269cd63b7b453cb9fae4afe34a5655919264f3eaccf5b360a0b8abac1d379f9a7d59c8097b0649e256567ef779715614486078a2affaee7c3ba99dd80dc0b9b99975cba51f2b84e41781f7727403eac09756b09522d7d2f9de21fb4d47780f83e8dcceff515d78569a6f742511045132e5a01278359125c773239fa8accd3d71b52b103880be77561ee00a63780579950af77b6635efed26aaad28f1801970581d1040d49b841133424e1061911d68dd66e402ec4e06b4684b60179554529e5f97ec8cfd74e653e2a11c63382a567998eba84eaae93e9f32ba51a95b4a2748b0d2395159df2f19776eadb3cfa47dfd90e202e7db474f2b0412d26e32d24a50bef5c307977aa3e1d8431483cf5d9ab89fb3efa7b437147bffede7c9b5ceca427985c1bd755f10413b72b28823a433af68df47ec7b21e394824d273348d75e567e7789288796a9194dc45927399925dc2925122ff80481fd5852e78d736c634a96d6c73e78f13f7bdfe1d624c75403b53653c2aeb97855dd7e5e3fae857e6e31dab7c589536830d610305b8cd67eff74876a3335b5fda8de4813b9345e04bc84111b8608628aad09171ee45745a69332351b663f4f74745dad61f59f056c35b5bf5f7976df098dde0af1c0fbe5f76ab2a6d263e04f7e24c878fead1ce9034f8e4563ffd80afe2ab2baee87549942bba7c02e75697990e95432de599369322ef1c0dcb923023e2f555b6031e7b8e074f3f46871f9d94cd4ce550137d66f4ec97ab2eed162fbab427959f7c903e3ae9a38f549e69f150131d498e73372e5bba8ab6c3e6d2f7c24fd150a71fa28f2efa282623a2b233226e800d149668808dcd8550c8783cde7878f2016b2e09aeab0eb525aeab6ceeb386c89b8410055cec43e41532af733446180984b4dceaee5ae252cb5696da2d7e663d725ce766ec983ee6cb58895a5d5785159adc67a94ad726f81ec1892bbaae8a1d28dcab350c5e71fb2c8e65ded75571842c6edc88dc218fd6a89b2996de61a8e20850343b489a166b94b4551c01ca8db6c4fd9e08de0176ea41d72f956289e52914f93adb01ede907859fa56e93a9512521d0e7863b9b257c0fc90d8a40c1b96cf382105a94524a29e5c1e3a128109310b2986ec05a74ca0a325e3ce530b4edc525a5a592dd5628adfe4af4c555ae337d2bcdac3cdb5e589ad25db1a563f5c6d24643aa99486299063fb5ccc686c446e4d21a4c9bc1869a8daa9175a7d665a6c36a2bf311e3b30f540e454f331ff0c74b2256ae06fd10d3a5d8909bf9682c6a4a643efae6c624e287d03bbaa544e5684825fac62a04d7a28e06fdcc7444fa57d199f9a0d7b297e6022fc25cc3c838768ac999f8eb56e623fe8294695559f983faa0e4093fd755719d144f50c1a5af643c868c5f2e8330c665684ae4abea1757da7c1a44a3626c388bc46dd068a156df5c50a5c5386b318dea9d4bd33b5706d12fd0861141c4b0dbb8a76eb487cb780fb6060821991e2ec388dd9ca5e99d4b6a2ca6d2c996f8c79dbf3116ce2269b9a2a75ffa3d9ca3878d18198dea021617755d4f174c707bba00e5ba9e2e4041e3ba1e2e6ce1dab8e1606cf01829821472f04416a2c8cc6bdf8b31f670c10af041cb65782c30671917e70701d2a917bf7060df4697375176390631372e3f0e62189bb55d0e47ca0463c4e343ea70a89c5f391c296d4d8d627101f86ba58e3577afd32fde86f0690e4f6e8cd31bb96c69a34e3b5c565595460fb519fa18f774ce7cd0c7f8453596fa58621c6a558c9893e5bb18cec5609e3959095c4373af345ec2355e9db29079e73cd5f89536ffe26ee53034177f30fcf38c7830361ea5b59a4c0f0a800b727158a23769eed66a56af66aa57879cfd90e797ae10474fb1a82fa03842a39fa275c0d16837dc7e7dc37570c8e2f62f8c93f44b83c0f1ce4f135da0c1cf0b7c1805b7eff070db0833d48d7b80ee46833594d579b85bdde6ba8d08298a2a45145bb0b3b9ac0d79775a2e03d78848643c47976458fe792fbdf18f929d9eba314dbf34ff18b186bad9e8f78370a786110517c589217ae7b23184314a39e79c13a31a11ada60dd0bfe4704da16eb0422bea2585ea323ecf459bb91db3d595d3a48c13d257b5c5adc17739abba44ec68b8cf375c8e063c937ee95f581a92e0ab05be3e7c7d3ac5aea7537c7722ed98f794e268f44e15f5c1c037d792a3c20917dc7e33e91437c9a95b6dce71349a1bb2ed9ead760fb450070c15468143f1068681084e367ad95a0c420c8685788b48a994f054c6c7bf911d62a623527a5d50caf88ecff1e2658c100a51f8f8985eeec8eb52a317fd85d14c072572adcb29e52dcbda96b85372d0352f29b9d25b1a03710d7a22418da297dabc7e4b9398c5dc3582593dd6a9d18a94524a6945bf441aad43fd68b4d9ec78f195d774ca7aa3ee8bbb28a9bc78ca8b93aeebb4b599eb16762a64deec1232af45e9d61793f496b499761dd3ac5b3eaa8f603d14bdaf8d205cd80d35e32e2ad68a44872d129d2dcbb61cc11e5162a0d87872b1b8c2c668a86e36ee4613c49d936297951dc3aebb2cbbaa53fa8a7e42285c43ded2a61bb88694f254cbf1a8062f969165855d38e172f0f1bdf7de7bef7d9a43af6dda2de64e98ecf1eec188228ca81b3f03d35e25d2766c33eeb3b12f2d6c54db5784cbd1b8a03b4fef98999999f908177467f8cf6e8f9e87bbbda36ff3a5d33a1a1774dbd2c9cd73b90d40082184fc5cb3932ba0f30102b9772e07803ac251c2bf71e7b2cd9fe8e3fe2e4fd328243ef32c124136feb4d4621387046b3446dcd02a1b4183c473cf86b0e12ddef8d34da85b43a10da5537c9f4ea9e0f2b7d884e50d8b0fa219efc72b3a0523c6a51db69043110fb7378943e39bccb9bd49267ef8268dc823dab76abf452c06f0007c8b5050dfa2d0cbb7184500dfe2b7a8c5ed634f8e743cd2f1c84e917b391ab57b32e79c7b0f06aec612016fe52ae4b9b8cb4677239802a4fcf192bbb2f29e6d183ced45e6e839ba731a0695d55cbc456f17c0a08b744a7417efee11558d73381e813aaf8936c2f731719db35da4516e1bd2eff5283ebbb9b82b3de5ae49d1c73dd290774757f9f56b1bf22ee9ef53e7b2db10b86237aa9178aa0b3b045e575334124f2dd94d653ee5f03a3b531dc773cab7218f77e2e591fb948f7792a46d18340cb8c67b9ae817fd7b26dea11d61ba33ee2a297f19298a0a8fe4060ff8eb61b14400adf68be94a87e4c6e10df9a9d146c9a76858a3e40ba0d57e31a95c12e0295ae9538b779a145d6ad8ab8dc6d4399d7257f486010be1aee85de432a166dfe615b6e8139b1801e5f669a20005c526b71fd7aae52d8fefba4b795df90ae9a2975cbce42eefcedacbeedc5dfcc4261d2fefb4c8cfd1d39e1a60739dfc80cd8516042dd7d9d3e833f0ee234b8aa2426bc4e51b71e5e5e7ad373a2bd172e3e59ddd68a63dc153fc0c9c1f69db3c463a24dd59124f8dce699144e2a9d2d2982a6767488776c6c5dd694cd79d4d77c5745d1ccbee5caca45ce5ce6ea25249a5a6bca6d4eab42aff66bd7b29f52af54eda6937950f79b77e7357b5d755ae3bcdbde7aef2e79e734c90b72b677bf2919d9f9ded66dd3813df22b3b7646f794b8bb6c58f5a5a1e4776b3b9a3436d331971672dddb8a1b976247b7dbefec6e6e2706a34a691a644e623fb91bda5c56ef12397a3a5845a3d6bf3c1cff0e7214feb5eedbb4fdb5cdc34ba949f79e73feb1ac576e5d08eec4c7ce6c2d2986eb42d32b47a9d49b3b4cd888bddca74a8d098ae12ecc3c5cd7e5d18961dd32416d249a39ca3b98cc4e521442ed75c9658f0d41e27f1490c824c1a25eb3cc36979ea6433ae9c3a94d63a75e490934e6121813ac5a4c34ecd936e9c74d2fbddd0e2937ee1ca7dad609c35c074f92bd90f016c61085bb0b96ca4514f1a86a55fb853ee9b8b932bbf0d71eed9e8b384da44a7b6786468ce9c3b6db898ae0fb0878666fdf0c369dc653b7e388de7681affe196f6838d5b2eb7546ebd76aac6ad973a05c4ad5b67f97374adb5d68af9701f5e3a6ba563dad6e362779da25835750ac98db79cffea5b3c42e372552ee32b736290ce232c979d26fa4cf9cc748868b04b1269f0cea04ead742a8514a5532ea2169dcaace3e813848d146d45fb8c2dc67415cd5dac9aee83cb4d8f2e5caecb5d643f5878e06086eb02af8a8ba58db26c6858a3acd7d06aa3ac03a1951a65fda4991a659d6a2c26fe41db7e7bf8d392a8682811ef4c0f6fd9d1c367c49c78c474620b006de30b803b6d3ae8e2917ea2562d36f1e994e4c74f853b854fba33dd6903b88a96a2915ef48931740cc0baca3106a0c1eb4200fce2505a3f515f00de8f90d1165b6c71a949fb713eccccccd0bd67b7b963febfa2a6c4bc33f327d9cde6e692cedabcd3d83509e24a21bcc5165b6cc187b25eb69bbbf61b224d32f17930124abfb47492599fcb9634be2b00182ab1953977042404a7ceedcf9da93393dcd0a21359b5a9239d589674128f4cf6e11bbd327cb80c69a4512d9990451ad592a7536f48bff07fb810128de24f0680b6c99b8d5e17bb492836d9c4edcb904353473a31645e4d73b7d2b89f0ba3ba85d7fab56dc88c47a213cd73e4763442801b9df2b9930723e4d3f360b807e504f604f5b8a0168d044b4ac43b537a4b4be9d91de974468574d2b1be52b427a594f288981b9ff21c9d128fea9412f1cecc774a8802b6d8628b5bffeed2a939ba0ba251ef9a8d46bd5f2e736e737648bceea846bd697946a362eeb3f02a8fdad6234507e9393a4553b1b051a4639aa951a48b34161fd2db6ea54bfacad935ea97644bcff1727449ebe12b5a0f2d5a0f568646a45158dcd0764e9626e6be0703f33e84c2e178111ff3fe0b7a30a907f13e34f2600810c37417df5c10fc714ee092dbdb0bf02de6de80a12931affbe5421b3de6ba38bb30599a98cb37f9b8d04c164e1e47234683491920880218b97d0268eebddcd07666aa5bbf2ccdbd5f77dabbf5e8139d74ca458989c3514432d12992e4e9143c0ccc8df7e3cf8349c5a107538039756610d18700d1c70cd81f16a3ffb8aac19ea9936553e7fdc09edb7f3f9d5a716d452b5a0945aa23d72ffc18845600cdbd17bbbd57f066b027fab82b86cccbafd8f6cfcc74b4948f9979b371e7b44f9ac9edeef9c1c850f9d9adaf48e206dd9e3f359a023e5236c72c83b451d933d16ba3e270fbdb008440c2d5e86f2fd71d732cbfcee53aec491da25ffa94d62a6db4dc653e6262aedcea2d9560aa9fa8a36fae49e951eb27aaca37d7c4c9d295fd42ceb8f22b2eee1a46d4f29266fa0b6d45db5037bb0b6db371337b9a98fbb71c663a4cd65569e2d1f20a83b288ec13aeee4a24ee933666ef2464567478fbab9a81b7395785a495b4cd31b9a5bbde50011c86db775990db2c51c3d75d66318b93021a32d8735464aeb78dbb95eec65894aeca058283fdc2b1d978dfe4fbdbd86e4bdccc01ce0cf75924d6dfb0b50b6eae112ec080d07b45811a5d90620b99eaac6d35976768dc932b0f5d1543d8b943f84a7b847b722d12122ce1ac282263d99b57bf17c42c0b382b8ac854b6c67a7d2f5ae9caa18925f060093b40d7b7ea642eed061201063f30810fa290c149010d99ea392a32d67152d032d7731220531dd372122073d500f9a9511224c77be920d72b5bf39eea9bfb717350c11490b4e10b432043166e43832651ec60075238414216324ec60af21c1d8dd0c280811918b843e2859716f58101876f1a451202b313269dd5a8fc83f3c8f0937239170f6c996cdb3bfb34aa998905031ede0d211cd0ce7df6cd8cee30030fcc04c7ddf8ecd384cf4d1ad56726f23a2a96c8e16ecce4dea1533eae878f3819f7e4ddb013bc64e80ae914992d334594be699c24dcd4bbc70c13896a565d17e65ead6bb63529e79493ce29e794cf70ca9bef6ccd8d1bbab921a2215121dd38e79c63be79cd8d1be21b8da40d8157242291f8a67ef4adbea66a7cb3b9a16af966740d11a9b939edb829e721f08a2ec9d260f7b2b97494a22129bd56128944228d46156b9410142d7888a3342aa7716eaebe7918113b5415ada60e757343d750bde850379e43257566c51563edee6e264f0a17c586ead6455e4ed545a6c3c13deedcab98937b751b991afaf82034c657b6c6442dad6c59877b302d4b2bf3a6a8dbcb792fe7e5147939cf0548c87151eec645b8081729d2a876d6e5d8c6c97193060f8337af639320b62062a8388ab293a2dfb0c52020c7119ab87d0634e99b167ae77adf0bfc2948fc7bb48d85201a55371b282467a01a84d07382c6dcb81acac6cb7d2739e75c75dfd9c1d0f7e29c0c9f80b01497f496e0662c40a14e6d310650e846e979c2a449113bd48dde9e1e2878ba50e34d09e090500e1f9d1e1edac341b0484f317289f0ce5e3d805a7f8cee4c1f56f75e30660cbba3e16e86bac167860af958db8d74bb29841036bf7e73a87edecdad69d423e268bcf91ccd73dfa5cf7b76368ffc792f50e8a6466ace3d28745b28428941cfc22753070a55374f9ec0201b044523429d82413b4e4089820dd53ecc79414f801c8dbe33426a4e4e40f2f04124fcb43531d286b3318910649c4cb451e7bd1c469df7e270c4248e06f4792ff14d51b70eb2d1415de4bdd0a16ea819dcb00b90b908bc16b7ef32c3f5b04eea0404007777170240fb7b6925fc7097e96077fee19d195a31ae13c692c910f5306aa98f2e485a8a55f141ae945ca6e94545619cedf6fee0512ef881090e3361a4894e6da7eec5595871203b171facf6961e64b09c62c030bd5871e184a810454925855447a20cbbac8a4e19dd755cdae25180c9083e7c69a57ee943ecd27094c45fb0ce5f1a1297c65fce7dabeed673b4a953ce562f69b59a9c1d022fb461c22e0da7d692a965e6ece9d92711ef10d86460820e9c28727373a323036d4ca3fa29a146f8a20d68628bc6193e69a7f2dd757f6c21e6261a1c6c1453e7185e265cce255629a59436ab384aa28bf63dc6208514ebbf2f6cd5082a8c50e4f637e0a0b8790dcba2fe30ca28232ce20210e24c479fa9c2392d06dc4bdf64aa0f088b0310d7f7abe23f0d899278f737e31edd4e7577f745379db310dbe875d65979053a145487b4a045b8e2f6b1529149df83104238676d5437ea39b741eedee284a7773e9a60580bf7f98d87e679a853d37626e35b8be8f630925159aecba7cbd6e5189755be5597615c7a9e975f5c963f7c5bb9f1b28bcb8730f805078099749dc371b19ced36df378dd262c8713ce421e72c0b35aa190a937ad3292d3ad539f6d5280100c00f2e3e58ed2d3dc86039c58061e217da0adf05bfc457e13aca46971d0dea68f0109fc8901bea8aa364f64d1ba0bf992e39fc5822ced9cd0a75e30ff1d4de638c0f563744a4517d074749b8aa9365a93bcae110d2e7e12ecad1e03b93ebeb3632ee2e2ed55d5c581ac567b90ca77c5d52e7e567a46d145b9a7b2f5d5f920b47c9730e73b209e61d47a39f75da48c7592643001a1d19254943e589dd8921a3242f7e7b1f1d1925192569543b9a910edb5192d19151928f741ad59cf35ef82fc9e8080ccbf421ff9d388757505db6271f7c77ab43835d9beb3268af4b8ada39272056bcc1d89ef8a8eb35d8b367b791794cf6fa0838996a6ba8ed1813e9e5dbc82411c4faf50838195bd38362b79c5c17fdb22720382abf7e0a82fd2c23b24a8e9039450b044774eb225ba304886523b3391fede67aca5d06e4ba5101a2624f41acab581b194c0b92f2eb2996d4430196c9ce32d961a6c3d9133c0bdddcdcee11f53c9893fb759f079372ec1450f9a5724ce524c09e726773130420a801094ba2a0422788881b22425571e270087125cf7b7138a88ffcf9b9efa56aa324ef85f48a43b227575f33d279b5352327efa5b54bf339b99fdb0ebb3b86bd5a9e5192d1ce6df84b088e467f64dd7b913c52e89ebf8d7464304ad74083b846ff92a28e7c30d2e11aade370f4c0e1606ca4f360ae5a4da6ffda19ead448e7bd68d130a325160d1ae9d0a0910e0d1ad120cb6ef45e3dda8942dda613239d07e39e2c69287a46ce391aa4c3d1a009c5edf3b87644d8150747a37f0961217a220212fd889c88aeb8fd4bc8e180831382cf12be16cd243d9dda793097d07b61d230184ed31942dbb523b45d3bb7dfd84da368d02574fb34880ad1a1eaa6caa98a40274e808284e0905011d1d0e86694332a3232b29373fb27f8d1cdedcb131c0d39914824ca6c746c6012b803791c0ec62e29ea26ea713856e08488ef8f7aa08d7cc0351a2ed9d169140693dc2343e8355244662f1d0ad0f7226f3d6a32c332edd2792f9da32ded32f25ebafedcfe361a821f8d7446571aea4847544454446444a4734494a453ce891dd112118fc3c151ea66737554f78a52e537794aedc9451d495077518f36128a026434d211f98898344ab4491ea0a00773a280f5cb3a90503624ba11e5585a0d761298c03a664f14200156631db33266402c2b8180684aa01535dbc976329eac27f3c97e3227d94d969315c98c643a59929f1f27185090d090c3f186ba613a18666936321886613eb574e370b8189d73ce39e79c73ce39e79c73ce39e79c73ce3967391e9365e5ef48679464b433e219f58c7ca493f7d29cc342a4dcdc3e1b71f64ae268f4b3dbbc8cdcbee47930d289e441d1a0f7d2a794064127b6ca19e9d0a0238d6a9d51928d7b7eaabbd08afa749e907b42ce6e242c08dd910e97a0304ad2a98d0651288e8a22e8dcfee8c868a453756a13d58875d2cd83b1de27fd90b0e0604442efa5efbe91bc709b4486db6a28327232d2e1a022d4c87b69c9e3e4f64542cf64aad58984184a9ec93397cc9dfe2f5b514fefdc8d06f1589ba8a7efb3efe9d4c63c2226ce3214960d6d1c311889be84efde773cce31f3302f69140f5be679442e85ff80cd75575ee734fe7387dae6b80c2f091dee1fe0fbce3b3c6e939706bb4f874586c3e1c4d35c935a499377cac042f075d7e16abff4cf934411a28fce77ae4706c24661670a88d80611bd7ea4d500212433face88b464b4f360de0ee9edec8cde8e56c36bd89119bd1e554d2307c04ba983bef71e842f938799b52eb578558e5bb4d95c79d1959ca327d3c3fb4e70b17767670448f07359a7512fc9755b2fd179309d24c64e2f8901bff592277c65c13877e39d7a61de12286e771675670d6fa797b0ce92db679d91936a529ad8168df5f196264b45945ac8c9b88cb7d95c3d75639977b9aa22e03c61e25e17bff7de7b97abb18f9e34d3f51729b55b8c17b4792f829e9fcc4cc77bd77b4f32bbb1e9a73390c9747ed2a9d34def66e29e8a68541cbd78245785b1fc45a0a11b2350941b23508c403102c508f4a451919fc0edb230a24697f1cdf4f8e2aedfeec91dd98d566781cfc1f266b1316c0f89a7c2b034d885b17296eaa447138c95579fa18717869d5989a4eba4f7bf731946f1157dbcb17a51517e72b343ed242ad5602b8fda11a53bf3bef2abe55c5fc8d05ade8386651190f1965f107b9856576eadbcd090b87e81af34aa61fd525a39fcc52db0070d47098ce778a75b9a86499a5211656021dc3dddf1130c4af683bb92b295188f2f3e5af9e9306044086fa287da0f58c10a42fa019bbbd1dcf78de6d2d394f79468b992087a681d56f664d906d85c69495154fa0e576ead9c5a124f8510aed05b96c45329112bb7ec8ce990a6b4514b53ba2c26686281763bc180417af1d18b8f5e8c46511bd1c36af4f86274d2e8f19d5676238de25f8c31b2314e8af1a8c538b41b57d221e9f02e228c2e3028f5f4e3d23f3bb3f2d24d2b2fbd672b2b34cb56560e4b2b55755df0eec980768311aca1a8848cb6b5450e3a4533000000143314000020140c074442b170442c14a58d7b14001096a850705099c7590e530819430c01001000100010080009000048e884e362954a0ed0f922675ce3fb3a0cd0f11c29df6149be3f9fcab46d24bcd50dd1ed7a417ad53dc76140bdf56a189106d8004bbda5ff2a3cf860bcc953ce40b52a09efe43548b332de1eaaced6c26883f69151f27b5eb21588d1486cf4446c56b815711f73257565619175d6d603edc6bce8559c07316ce028b1ac4c4756104659bcfb267b6fedb3beda2f807f2e3a95c6f128ae5a7dc9687ede84031e388fb4d35a869b0eb84042827c3ff5c0e3b527b36082ae550bf7ec85b0a2031a8e06d8e907efc61a7e504b48bb6c77519221bf05783e75c601ad62cd91f326e9ffab05e6fa2ecdaf36a78d57132c7ec1e032590bbcc96865e154a9729946d7633c4028e463299e7fe1cadfbacda33fd93db2f8638a4492c35150208bd06001c940c0fa622c26409d42bcce12de640e0da02b7e01439ec517523100caeded3f01eb0088ffc7afcbf2e163f59a18460eaa9c02a9da4168514542782a1c1fc69959573c2e6f913f02f5a18761fc230ca7d8722203666429ae2f40c25d81f97133ddaf4a655d2f557b2d010a60ee8582e9621ba91902b474c509c20f7a077a51cfce349db3dbaffeae27047a24e837c7ff53719ec685b4d877d39150077e53822c5c8ea25e8a827d754d7e30840a0da217e80deb35fc80047228f7817555ce6add72aab7d3c9a693bc28a2e680bb530aaa00d704229c3978d45cbd4320aedd6f041646401b04983c18ac2b8c0b83759e471a6af2e1752e3ef3bb12bb1f356be455115a62a5bd68200d0dcb49c09fcee891cfa5ed949d1cf2cf66f25d3f457448dfab872541dc20cdcbbf67809b09fc865abbb067be73bb56fd6f9eca7ec0dc98cc2ddb177b21547a8392a56b0391b0d586da8f2a19221ee63685db4724db674a0426ae8fa09118fb69b38e188973caf60a88acfef1d4e031573edaa101027babcde0d9533b1a5dd45841d075cd303f3142371568bfe962f76cccb09a969c36c997f02e94fab2628683efc54d4eaf00748082f23dcf0a6400d73143cfce3dbb2b7b9f47c9e9d4e1f38f60f559aae1ec85415744dc89d7ad77f0c55dba7adae1ac144da10288b98cac8084b69ac46642844545aa82f71ac94fc314e430a01b0cc298dc8e6fa67679e5a17ab802ed05b0f26a8ab7c6a91048bb054e32467a305d7bf740962e50820522c0c00c7c811e8d19322503f84a712ff5af515e5d9496fe4b45a24399a8f974f4787515a44799d80ce527697c9169345edd0bf457a50c546e7e4582437a1908ca0088bc3c4338268b0b2a018d063bc2929618b8005b341dd88ef5e0bbcaa3fe2fd7c66959dc6e6c2f8a6b14681abd58a62569382b51d32986b2422fd0bbfe53d8668ea00abd785a046a1a10cc7d96e6baef4b0f96b69a5ad7841075254ab313ab563ae93757edb1dd7c293c9a0994d46458cef2ddab8a499bc6b70d9f84f0b87c94a29423ebf5664f9af8e432247618958ebd53e1217bc36ce647ebb26f466afe7c9e6c60996635f37d4a6f7ad588368ecf05ed28a72283760ee2f19e5f9a8d57069367ddbb1880b38bacf88ef0b6ccfa8dfd9fa534cf4dbc9a04dbd0e359c8acf8dde0e94ec0253e0c6a16320743e8c8383aefadd5c16e268ac73752febd5bbefdfdeaf62c0011f5202f902c7baaec62037efc4de07bf6f1d3d963bc976f8342438f9acfa9a4971d2bceef03dc8eb4b7507e0951981cb55eabfe20aef5307cd48b272570540df9b910dcdd40e3700f4c167d3927e1c021cf3aff487f6e2489ee5130c355c904aff0ce231693c55a6797273ebe86dcd749db07da18fc14f6d5e262993ba1725a71b38800236dc9ae9a547dcd6321cf879e435e888cd08ba963a7c3ad266b0156b0d639766a765db842018e6cd2aea63644a6a6b8dd0fc75e05c207252827051fe3134e6edcc69588037fc6bbb4efeb9342a3a409e589a7a3bbe74355331a8be45075b2f816574ab0c8a6fb3612bf1d8a7a5f5ff2cb473e6864252b7af9de383ecced083ab79c128d176403a8528fc80767db007346cb6c0cc51ac0e979b782464529908d6ccbda4d57b3b0444761abcabe76b276edb3ffca2c9d9ef061c560b50e5160d6fbeac5b1aec2bdba1aa1a6b13fda2c8cfa34ea31d699842621624982bfdc0e3fb5638635e727e5e4793c36ca37f38c106f4fbd8aa849335ed9f4eaa55a64bd4fd75e4e10c8c59dcef63d3926fa1278bbddd5e34d59abce6292770f1122516110bc7a02053734893f9396d7f2b24c3bd387982a00ca72dbec6c8811b2e52ea73d4f0a2023be583354ffd80ed14f7a250f052b384d6f451a385b6ac93c530820afaa72ce14eaa049ad6204a455c0b12d7e9bd95e12b9c29a24d6e129ecf576689e694a9117cf8994ab26aa0d173b15153801fa295574a9ca309baa8d9b5ce1e632e31001f3fc6a180c3f394f516a524fa2bd703d3eb5eba5db089d4f3994834e583a06206bd71d4092d179e32bc49836dd84738cbc042389b1d5d992ff58f6e68323be8a9fa590337f92e5603ef5d317d4b84ff903866efcc2acb0bfbc5766f2d4c195dfb03f6b53e7c42130ba908fbe8afe916d1a0b1071798cce497ce7e8d29f3eeec2b0b77cb87614f823a17f777ee8f810f280a83cdb4fce5a7cac83d781b473041c39f9e09a4754517f2758ed62da35c6019a3306de3b747e6f85c1835efb64a0b9625a96361528e6fd9e0c422bca20722e6eb97da3a760595ea63f84850e8a82c1b96b66d287f0f94442e3f83005c0ac6e5eb56a849dc4c837806f48fed11a4486a6a9db87754d454a46c7e9ef73766f0defeaab5f6fb251a6304c4965c1a65307872b77c800b603899d143aa59cdb3b318c0e12c077be099f12a10a98687156c8edb4fc61e231fa2424ff421cacd499669d718ba5d822a1958bb5196e90f969d2c624ef766d91de33d37b5cd3355afe1129dd81d50ba42db1955a60baf27767c764afa37285c084abb10204f16d4327b909a6222e27e175b38e2d07f96fa0933c41d22780df372838ce64ff17872642dde9ad00cb145e20751aeb4b117d6d09023c1583c58e17bca31f45313c1d3e3714c710059929b73519e3f0fb8dae0b3f22c9854f6a9f6a8a339a9e127c0890a9af00b3aaaf90ec116e6fe24b5232d0692545887a14d4ca5e05211e3f1fe0e5e47979e729c64901dc57640a38abbfde44759f31e48b411539ea8eeda3a1e559d31ec1ed45aec4b39e6442a5037c3163a1e48432c69aae7058bac0b9a9483bc20602aaee41dfed562ff19fdf086f7238c49ba0ea4b37c9ec79c5d6bfa9a8e2b9702f97e3decf1f2823edff5e7be91d02841a48de18831697d8c2805fe9594d2435f835abf85f24487c7ae4aeab13a6aa7e6c0a8515e5b7d87bdb49ccfa842336b3aee35175903609b8d411d513b411fbfb98890be81f6dd8e856cfa78275308c56acc98a51b147988004aa0f15a62ca7849af462a5dc8165930f5993c6eb47f827cb124e852a1f72b364a1d6295b053f43d3cb0eaee085f22677e3d3335cfdc0edb4e8b5f6117a22b7be935fd57c90727facb95b32d62453adf09b1c08720d1550de71e2c32ad7640cab09e079cd67aea162cfb4bc21c69d41f395b34e008a091af4986a969357ca48410f13db9137c8be186596733dc39a12055690b078573bc63e1eb30641360b31cea43ce4693d7cfc6683c0813521d89434ec2ec38ab2c416351552be41e4c00d798d875a44369682eac7ec077462b737b8f45285f1bf1721dd9f4381872c1653539027773ff4205444089d913061c8179239f439311133b3d1a56d8c1e1ea6299863504e8cc1e6cc7ad776428c648bd1c0b6349fcd784cf69c720851bd1d51bea75671f6fa3bf3bb518945f2223357496e1f663eff6bff3780fc001e4708e3be67d6c9a2ead2e8180682b2521c34cb7a76a5659f83faec9b96f1fbb7cad1b0ddc9d0792c9bf75ff5049ab88de34042f502eb3d6df6e982d3ed23a81c8e9ff82c06e426dffb2715c38b419bedb72a1e284fffd879a7e9156e2e5f50ed1b6dd107e3be1e74a52dd86ab2d54a89ec825a0625fe2b646689caff403effb6afc3408bff0b418e1ff5b0bc9e68d77fcc732c9350d7a9d8ca6c22823b18e1514892b5003536c2bde4afabc79057b0ecb1d1ecf09683ffb239416d8d191023a4e8c98c81a44a870e5a447c86d187d5648da3f8d7f57417351ac869d6bec40e4bd7d5a592fb84ce65d09a19460a499f5593b468ddab5f7f826bcb350c17d04b5285860333007b2a3076165a8700d3531c103fc9bf2f48f4ad45f00f91addfa1af277b0db0d492958124098d83e2753daf1eb6cebb7752a07610b322919eae38b88d22d3c5ea00eb8bc84409621475681e27e5012987f316563e9a3fdcf361b569d103681d2a0944bc64b131cdb743a56cdd836fc29382ec2374da0ce776a2b61c65d5aaec829b922c135a8f66bbb8dfb0429eccc3c770a2f34e12fa34aae24dd404649b0c2df3420814c396d3b0fd01fe0fa1e42f48742f534caac58d9a02f83bfd1e056fa36e4bdf16c61b07c2914d8fab97807b08915253a6e52d92c6d54da1193dbdf518fa23dbd7ada6f40cef487535762859abdfaf38e50091c47fed780db90171ed4be4da851fc56c35b073003f4a9fca5559042af3eb820d251543489058721aa38dc0b86013a6176b4c71d2f047148dd7a4c642bef263d9d19dd951dc1333f92bdfe677fd43d4692628b2fadc19112a9dd4451dad1b08c291014444b28cc2a2258696b53505af33ecc736d9858f1ed39710161c26975fb09f6387f53b15fd6446e5c9b9e3ff242d5e448dfd6a401419eab303791fd3ab137882e9c4ae50579891e5578d77a834245d98d8f442d50c3fd6e9a6fa7f956056e892f47f3d27fe32d01d5e5d329f39842939bbffa6bd1dde3f981ff65a9d2b4e3ea6830d613b5688763ab08d38921111af2e935b3835e34ed8e41f146f8ac97c9bf9cd0a88295bbbc653373ba6b3192b6246cb72a4144b22bde67a2ee5481f1a6ab4095d1892e731379f117d0fe8b7483d4fbcc122358abb76c354ffb4b285a1bd94ba4a0db4ef2baaa584c38bde48469f6ef34476c0c1a280035a3b60d8af825aa647bc4b0a9b44a8a88ed32785534716462d91a8610c0e3cf6af931b20b8e1d0f1fdcabd24335ebdac383765b052fc798b3a0093dc9f233f37e624cb1b522f9b2884f29a054f10bd6ecf743f8441bac71968b0d414f192ad0048de370245549e2bfcb50a1bdde96ab8238e835ca20ff2043bba66fb5f8dbaecb392d1d4f8750a52ca31e15f613f653102047ac4154bdd46f713985df61d2bf94b5c77b9733e9597a23d099c9242c4143c7c27dde992aa8b672a42f7a6512af8eaf3e69b94a10203dfe96b4d7fb916fa29689255ff847813c30fbdfb5af1601334a381c316ca76e43005a4a0078f9e52013890e5099295670875fcf7e958e9d1749884c9481ff3874d8ed2c1d756af8bf4e5d0d43eea0795ad1f65897fcc78d45c353d1b64600b7c311116bdfb5507115e9e3fe665e93b41f1242584368b6e831219b82e5e50a2127bfb453083a8ad4a1e4284c43bdfc242d134d874b3ffc1b43233113fed6164a8237e769e5f0aacc5133e8ba4a3ad2433bcdecc474f1e25ab5f7e05b9168ba58613831956a1451768cc2876b1bcce89fdc53cdb646fccec3b454e8dc47cbf9dc198a81302885f9983ea6b416d09a066e6eec6bc6c4cc8a6a2f73e20ab4dda46fb602dcf8863d7fd976f4e95b0603c8e33a422826a37e3f6216ba7da904b1158da5c28e360d0b2cfe532acc35d51fe74ef411b089cc4f1a680fb30582338e9e3b5f10475e41c3f53f0fc1cfaff8ba5f6ffb211b336e5b996f14ee89d2e1569c02d081885685e10d3effd4b726a75912e6699bfb6489260ce3ba371e181fa52b6b9b160d054876cc3b6fc1bec606beb6d7220c5a406d3bfe6b48b4e719ee62a5942f4316515ca12d0d928586500bfdb8e393fcffeb919b3b206d0c77cc5617dc808c9431fb5a3d4ce4fe42c3ec5fb0d0cd8aa548e31cc559744025cce321632f75625033fd29589acf465867cba1decc819cd9555e2920467ea0fb7fd36c79b1b78cef808bab16748cd9b84284fc4c9a6c17cc1a31b5b596232f877e3d45eeaaff0e47bef3c9cb735855557c2b48a49925b54b6309764712b6c4a478a1a12050a941a78cad7bfc7f3430c14534545c9e2c091da7f05f85db133dda99aca14a594b9e1961a8a2b08d0b4afb628c9d65895818efce427334075fa3020f9f850f7d58f2f88ce45c12cbb3cafecae1c8fc35a41915c1cd02ee38608a31c2a1398904b36780386f0cd44e88166168f015fabd0e1146baa2028131d503a24d49051fcdbc22b243e07dc21f5afa9268bb04476e9512b17f6f9493f671befbe2971f97516639b14883b0b3e199ce10e611662d6a606dd3cca0b20122062e82c3f0e35ae194ef1a33272953b731e06996faa7f38e6220cce53901812551798ae73cdd9588ce0d215d70d4f6b423ccd9970861d5f96f6d25bc1a99b15bc4d33b044b27f9127cf16463625dd0004999218f736a566a6ca4b2b4fa360282957f65bf2f0cd95882b71a445cf928f5ed34ce5366217339370c3f0bf7d1e7144432455ae0526e324c320f25b75f2cad115ef2477bc17362740ae5182a62d088c46bd05c25679e116b4d93a91d7f1b1d86e4c89d70a0de268fe28eea92d89c90e440d63d5993c58f68bd707ccc3ae5dd31a811d86a6818bf5a420568af0318beb78edf089e7d238b39ea61131f68f4404b83130a9690142cecd858cc5fcff0c0944369f284357885bbadc11506d51c8d4029f503b0ad2bd80f9206e25d135e351dd2f13c5125d5d9ea837371811d60c7ffefa35a72813d389f9c2a102647de524c47d2ea0399f0e894565e8b05d5c4c22c758edc989fdc33dd4a65d9a980e1d3bfaa98507fdc159444937b7abb67110ae276a929c1eeb91ad401da27676ed20eae32cd40eda3f9dd7e0226329d24fecbac1b4640b4027af207120923f39c1b6a53cf7c62cffa375bdf3ec9df6ba1bdefbded2ee38cd92cd6f376fae9a18c04fdf7e0a5392c0828fccc7155c80090fa14ba8503d4ae08f3b47c6917c4345aad86fd17de10d02be1adf7218acdf18f34f24976659a6d5e678cd38f7882fab86ae031fde69df2f041ab612f4ccce812723684b7389c6ec2cb9704d33036a13aec32dc73fdaef2a318e0c8cab9a57091d3e9f14b4097d94186743a877729c9da890eb1c0a23ca73fb98b806d094f19dbbb13882928b142f47f0f588ec6964dd81167b9dd21694d90c5d6c19a3bcdfe6873b94908c8c8cc1d3f860d4c59ffb0125b663c41ee456a545a25486162a61fb83acceb0aaa428b212cb03db703355d5c8cd2d92c71d3b401824df6916bf52d1c205559cbefdaf488b834c4a589326472a77b6121c422d486ce1c0848eeee8c46680a9c75432c008650a971e9ec2bf0f3cdfdd189d0ebe88709afe2c93f49b281eee7b0706f22ca6d9909e627d0010b8e2be31996015263855490562e52a64304234f3e0ec92345e78ddfe947a03cb15b6b86d02a1119261599928244f3f05f045d7b07503675d0360bcf7f59b4dd984976cdb08739884bbe2fcb97d555db83befbe6840c9674f26cf57333ff76c16c04218947ca942e4429489c921a8cfd71a8c9e9c5997744c3f093071c4c2e04af32d7c553b244475054bd3460702f5194adb18adce61653370132d1313f4670e86235275e2ff71ddfd1beb74cc4177e476fa909e15895c28d38e4f721067ab9281a9d050d58b9edd855b41e365465eb6a50701da5cec11fd89cbe561d98d42dfe2b75ea78b151e2e81b860a61fdaa5f8fef29234b0d6ce5f508bfc54bc23a78f703d75f194892fc68ea5572c4c2d58887989b8648ddc1e71091d9cd04bb00e353d1b285821e6125bcc9f119e0b2c31c54ec044f9c3f51c11d31e122aeae8dab6bf1cbd136f7d15069051a658d4a1911322589a7c142430cbab857e0c2c3571041bd8f68a9e16bdfef7c9eabfb6175f910890c22aba62d80cfb66d4c0362daf11812e5ada4fafa55158a20209fda9ab2c32d5a944458fc435d55ea68143b771ae5d1f50748e7f8044c6375afd48c4776e7f99aecb1f4353a2ba266cfcbb46f16cf7fc4850eb4c536e933cd46c65031ec8a9585af35fe859e4b3ab5790a2fc20141ca467b237a12e5d4e3ebd7d06a6f3ab3faa843198546070ef18bcabc19ee9d21e8e166077ff673565d8c9e47b2315f09465f39668af1fdc171de1559043f216e2b0d1ca99b9b9a60e63bb9198d9e17debf76ec48c40340ac13dda456586697cf5b66314710991dbb8a8495f023571b6646aec526893b046a02da84c28c966f305bd09baa671b1100012cfe4d68624e457c6c69db522640bf6db57ff2afaa14e9df7121b41a6a0b56353214868d243dc7ddf4737d4ea0ac0691fe05ad615b09b4d8b05621d1f48641cd4ecc822700b5fa7bba09533116ee81c17ebcb75b8d468ba1da95c8781db4fd0ff1bc31594c630f71b611866de57b90b1cd34addd2a173478a037adb76a34258a605324f26d87b13867315a86ef859d1134afb594f194dbff622c7012ec2de71b1f8b703426bb4c079edef6da9db5067f739f5729e45ecc0f042037caf5778b54b2880ecb02667a53c73f83f9fd971220689155cef2d3dd0e5e3f5c92d56dd82e470a2800dea190cee28001b16abcf813dce437c8a10b7ca706abc38c8e07ab85e696b4a23c15e4be5728c12fce7edd83a11d6b38c3f0fcfa2efe374e46f732f9789a3235f274279c7d017817ef7de1e573033e465751b1c57590991ba07cda6a352f8da3f641a1c3b733c56831dd8f60a211b58edf0eec3e22e91916eecfcdbcba464ba2ce23d252e1409628fee0045628aa3990895e197c6cbae8898430079e03a24fc5749787bbf849b89f0e64da52c4391f1dee59c5ecd949206b3170245362726a2ccaa00a893c903c5f4d4cf192ddb52a334b7e8f86534bc9fbdb634e188ec5b55e722f384398d8587737107e1e86f992782622e3ec17d6db51fdb3ee6ad1dd090071e84c6e6068953f363c549ea39a45286a595aa914125d30bae99586fcb64f6f08b0e5f20a2e298da16f778433e1064d84d3ebdaad7d44876dc20da7bdb6b714166e6a3f734b0b3a5d9db17e94626000ba53dabfc490614fa98283e80c5ecafd3543b11f03e6ffb2ea6834eeaf2315ee52ee663ef21eb0c4e07cd0edf12fdf5b01c22251837f58a06df19a3818e8170db2bed2732aad512bc89c24af301fbd5484f89156a761c98a4788db72941b402353c2c28e782b6843874fb1d8052906ae0f5777becd3ee98f1885e491daaa517198d9966d498cc1b047c872196e9400963cf2359433fb00b61784a66c109459b9c403c38a8f8e231d67bb9295a2997eecade31df763791c68ae37ac9211a9680c92184fad1616eda0ef2d5b671ad2bebf3cac1211af65c2cd39a40d090c1e8227ab34e86cb312870080a2fba5de2a6e9bedce9196a429e65f51f076547baccd4566b09004bd965a36a0d4612f9ce8646ca73e99f22796b1a237b1ce077ef07d1acce56f5e0f9829da59f2b96e0edc1de15d8ebf9dccda143d2ba0668bcf09b78038ba01cdf7262bac76cb2e88488b879c71a6f342420e6e920e0746b7633530ddd786711b8b65b7e2d6152f2e58dd9218659b9b0ca9de1d1f50b8048cc85b0acc2fc60928a92bcbbd9718ebf82ae7387ebc16661dab3fc44ff262e37e29e7977736ba2b7a95184a1eac8bb99e669a7aeb64232b13929a1a1074d13c3df937911e0ed6678293b93c4d6a2dd967d25b93576cf89feadd12d62b96c697578ac86c4975b1ef020aa8137275448c2c3667cf486c6a0fd73feb0e0082e15e66042165ad7ce6a6a45f61c9073993e6313baf460c47dee301dc8537732743437dd9523aba07634547e2bb968726eb92174596a0df79583197cfa1341e3849b76c160ec7540e77cf38a8b640ed9ad2aee912678273bbad711a8d8c43b3abd364e310daaaaef12c97c4ad6776dd3383d8d0a66d665990b6fdf667e051914045c41327b5302695c67616a56160937c5ecb92ff73c2b96b126e34b5e0c80a87e619e6074f110125fb3a18d06ce832b603448a3b3e5544ee5c1e2120ed83063366c5268211cd08fad39581a624e29ad8934c3fd3a36726d2cc0ceb29f092939278130701df48d5c8f934f880bc6e1a9ad9cc2c5245ff9f3e25eecb3de8f296e23201c676590c4aa4246a83e841d7d6a65e82c5655631aa62d6757040aa1f986bfe38c63342caa82e83da0ca9559af1836b0a917cf6c5a8a20143aa25c87a326b882cd2508caae7f805246ffcc0ac6f7cd428b89a3df734c6431ac9d1024d53489790e4b3aee0b4e1626d6750835eb5f362ce4bce2ea17571fecd4fffb22a9bf7a7dae1257b2ae765c6e902464892987dbdc5dc71cedcc4a1fd7da65612d53e9caaf33919a813546267bacc3b12cc78f04af59d056bb21b6537e24e079edf2e337a8585438942dcfce90cebae8e2078b0795f3a4835f80f62c863935d90abdb60f1adff0dd03da33583fc7172af7cccddcd30f800b7c80a407680c94581d47bb069b84c555635c082c8337ce84065e283a58a71db433bc9a712facb6383358202ec176ef53de41c5f4cee08ef17807bf07151fd10547b411ada15a133803f11954d4efe9527a145cced215c0f4d4b03311cca6db35d25fbeaf4511505f500c50ae24d39fea87a5286729c315f62ab9b0d593b2f7b768fda703c0a9dc3113f184b29b7ffa8c699bd79c624704158d2fe0cb198313245f84cd82f2bf0ce0ac2349f9ea2fae751e07c671bce69dbc33cb01cc6520bca625a8fa4284419952b0eaf6bb9f8119cf03b63be47f7b417e0c09f74ef7acd00c7aada679bd795a43f94655e6d3886ffee8c50af40bbfa2dd222aa4cc81f53021ec73a8bfe688e2898897d68b6acfca202a67be7a8743a24e81fafd11ed4cb40bb8e54ce92d323f3b663279ebd97f995e43f92567048ae8ce6c7a21c99d271de3c4dc649e134565d8469c73959175d81d29678f1cee64388193b0df99946ba1fdcee6232b1a46fb602d0118559bec208d7e288bdc913abbfe5d5603f9887270fa74b9d4bab7a06f54db89e66218446d245433e515534f5b933fd6143e9d6272848463994a41bb3fb897733f6efffdcd4173ccab3ee8e6331442c40542a0c1f004c0b395eebe1a6570aa2c01b6acac28db385801d6c35c62720e4ca5d07b8c8fd8803aa9ab696dbff9bd562d6fd0186157d8057a30472135b421dbd1936a6d2d64bd0fcb7f872b853f2eb68189b8f755369b533dd157bb747b0e170d5982780c8e35b987031073c8421e52644445d534fba2b1b9679c4fdb4d24f53de4db638884e08e48d731e0f98f0bf18463d3eaa57c408052c19402c8370fa36e87b2d5e59251ba298857194db2f2871f03f8779ee8470c12fedd5f1806cd0af80155c172f72e97b96d8ce3bd8b3294e6b8f5d0fa11282365af7689a3e63efa097eb02770c4e15e44aec055e047be897be1b2a4bc2ba563e398a527780a83f19e2b0cd35c6eae0c5fba7a5eba3062e85ad7c2209472f2fdb9f2cfd1a100a93b6c11e80289b9fa171d19cf7549b21c96edc0630a46c986ccbc463676b6fce38e01b2e4d489610b88753103bfaf56c87845da78249b4bb76d06f448a8833ec9ca1214a3623352745407a9a383c9ef29d182aa695c90d229723fb224688d67e87fdaaa47600eac8a0b9f62f11a0e075250b32906a2fad50f181d4892e5d0148191c8965679c4511d194c12809bf593eac05f532f3ac6d4961848ab60d2f51656a51300b392f8d2917c3705d038a910b5322d7d4b81b3fa0c45603724752ae6d0f8ca4482cadb8242fe7c33470bdcd1f838d35dffb84b7e75c2273cf71c89dc22d16b247244625785c47cfe2f237ef9fe5fd8959ffe8d324040c392c015408c883ee492a10defc32b41c625de3aaa6141be3e15e20289401694160c074151c57514121cfd478eb777caff50bf4eb67062d78720cde003a9ca7bf97017aa0627045fb3da01397f6d08c9eba042f005ddfb46281a4fafe718d91308a7b24ae871e7c61dec09ccd70b0ae244d579ce2efb11ed07f0d1c468ec4b31c8e1e1f6394eba48d8a9381ed1ede0cabc2b0a017a44e930bb71cf7f7b31631a19498a95583c1322ca94c0ed2fb4898ed813a3ac5d701ebd30085226131328616ef118232b93b8e9b6bb0401af693574e6285b53d1cf78583d8c3e931123cdb094f07e0dacb4d9d75f0a934d3080af7c7edd04f143857d2afea379e99a7f10a0a24d6d0cbc4f8606d23bbb6f064784868c77078e4059e8f4dba32b03a25e45270b99039dd5ce401f3a0e8487a87dadad902ddf817eb8ab28636635da70d82c883442caa1a804b3407069ae490d7c8eabc0f288f8083bb3c9a3faed6b5e0f28d726d69d958ff2b964f78058a87d011683b23b0dfe4f2eba16ac3b84c579fecb33231f371fe850a9af2b69ae34d2620c19350602afa6394f5d05ad8bc9496c28c19d8c905321b4b71e61fc0d8eb7ca90088de9966468f90ac067495234f346355d1d42ce70d2924d36abecc22dd3daae464f0e6a7432d8af37854c092d9c100185bf17cd8f7336dcacd31362597f3b2083e1bfb65f653bcb07aef74b4b32df5510e3a35fa16f232f5a112af966827da8d4a2470ae79013da4fa7f29ff729965ff1482cbc41baa003ed7e78112e9a1936c332bbf639e49fb2a2cbd0cc686f55e875997cb0fc8e3fd8a1ad1d90ff561116777d10cf64f7f4017d6ceab0dbf8078b670102c7466184e95046bca9ff7ebbebec2ad14a717f217c983efd966d9fc7f7258eeae01015434168c09ee1d94d7e109cc2572762f234ceb5730c1446500efa941ec1244e66aec963d660cbe3151dee0c22f4a354a947a0e208897a0744ca1c96297a70a8c6a152b53baf4d0fd68810efa240417b361e3364645f33463e2553d0ba5d8ad1a5bc9cf005ff49418aa22f991b2d3560289eca5b963986c9291cf0bbf3053385654a77fb30aca326176f9d88c1371c4fcc3561a36c608955795ed892ce9d97023f6c98e800e2446786d96083e36f6ba45fce80e81b20beb563f99b59e7171a447e3610c8f94217391457bc3f404e7e2be4685336f4280c65f43de1483aea21939efc7ac356d76237db4d6b5ff04581d37f806d8c2c31fbd185415c7d8fa79e4ee176eb5052a1619bac3f7a3aac1db104a5ed97a79b2534c4411b4e281e1efd7a1a174608a8cd07324a7d93d3bce542c7cd5f866cce215e8b493a06d3a86e966f6bcd5e33c484ee3a2a1ec70e1302e59bae9837813a0db8ad493dd27638fe81e6146e6e84680bc759ff554e3ca3e36cbf8576a7592e784f7294b1c1ef4ec9c6708677d29e7cc6ad5bbbc7b60d6738ebdeeb64a27b2699bd535077697f0c84f73ae9cc517340c8320e3c4c6ef7ff60deb32e58bcd2d3d19c69a5474e224ece2e6ad81d41504c3910880e70dfe24531891e48b04a354d0ced2e5bd08e6569634efa39529936bd56a2e66f25200005562f675b0e8325699d19bd3fc5845433c6a5d39d7e11a3fcbc5ac3eafb33e2339dd0d3070d46fdc1e92a3d6bc7eb435c2fc090b489b9b2ab26d332684f56af025bb3e6c6431d320a55ccf72a81e1e4e433d48e5fff8a9b7b23987e2b44744e04240822268884de644c0eff29df7f7e8e9cce9211499ec9fbc8a57a446977cafcf42fac6575b2882f62c900a58b0222f772f09d18b6212525597d2aa121536e2ea61fb07794847de0405a3485c9a9782261c626e51fe19726cf10d9f19dfcd021b1da1fa2f034899b39dec05e862f271be5c33e809233e2e889899ab7fbba2f8e08ce5a5854a9ac0746e51c0c21cce066158f236cecd6cde7e111c7e04be2d061b394e2249865774718520a6a269cf8364f88b322d2010cd1de31027620a9878a6d1a28b14260b139f78943031f27bfc6cf7761b0b25b2fd73b25170127a399a61525089706b5304d733fdc97eb37b4600afbcf76722486d5f07e0a2171eb65f830bdf3e9bbba30fe960d7ea647226bbde7511f59c8d691925f388b4336dff9a757e59cceaaeb76a80ad2addf26529334cb118066fca8326ee864dcb65f00d915e09e5b513e3926062704a437959d3f164c0fda0ff4a9d6655fc924cd109341a5a8a03cc07fccd0421c2ac58410e9887b9eba579db890c3033a201a58ed524fe6f2c7c8951fc28558f7930043527b874d7c656f8310e11ad39d08ff350b1405f0ec83293f7a607dc5506cca4f928992fd53dca7a47419bdae2275c0308fd786d51e10940c38c561a02de4e1579853311ed96bcee331f4ecc0613bfa088b44427f3beadfbec72948047a9889e318a083f0619b0944b8e387a1a030f4f74913dee38d56c9eb39b1cb988f18495c72ebc3ee0742c5d0f800ecdc334758cd90e705882739bd8d042b41ee19c353143044072540a6d677db182bd75d3d1d31f9ec8d713942d5675cbf8ea2f7ab33437244d600964730f7556f35378ef5514647c6776839250d458595f8cdf469fa6c752d82142f72fe1a6f592725e67d84c22d32ce06f67273125cc0394940d57c4cfe7209c89c7f131508087775fef21527c298879fce03296fbf1b54f2f6dce2b17a817db8511066aeaf94ee6fda2f3b279f6b971981bda2cc6eccb56ed310653fd6f231a67bb6a5e9e54723d96a48affff9ceccdd0418a167329efcc87ae7784d3e9639ab4b05c07e757d07f791d52d65b7921911f6c58d35211fd8102f1b37e40cee686b7b4d96d639b83c0c161a67def7f1a00a56af934ebcd6d808027c06ade67d2e942c8d6791db5496c6c35e75c549118ec519d972590a31332abd179722afc5697007d4c2f052b529c2a5ca7c61b3056bd1d633e642b3b1869b76ad23130320c47552313f8dedb275c7482e2fbebeef6016aaaf4f884da14971c5931794f127bb1d380af1072affcd8bae44ca6fff407810d8b18e15e7d58b5e5eb9480d44c0049162d8faa324042b2a427202c07336f71062ce157a21edb7b428fa9eafd6e136955fc2dd634b1ac38b60c82e93951708676b22e095a3d8060d2a1726a2d8c603bfbcb0cfb089c2cc3462a518d62645e78e7ed8025f8d8d2202f260a9d14865f33db3f74dc5558bade12b989e40591d384a0947098565b4cd8e2c4eec087b30d306ee67e306a2673d6972124627e62079e7e6142fd87513d30815cfca2bc860cb5c6d34e603097062ae73486d9f70fd3dd0739a40690f8919a0b59e26b415bc22d878f293ef9d17795d941b37938eff3c0ca6011427cfa0e137d929d210db7c2b56cc9395c8716689cc55a71a312a682d3eafc6d970af39386030b3613a82b948e5b8110a5f17b15f52fd5508fd2098a8b0fe3292ebb21806d5f0bf99a2de79ee11f430a0deb1aad02c5c9035ae463d0c8cffc6d3df36221611e5d96906f60f7eb2be598602e5c763aad024d1f6db286d15ca5157b0fc90be7d3dd264928ce7c7c877fe61309166e7c67cbc0ca62ab9e9af995f5bdc9d7f95cb9170be881960fcc24a5adb0c590dc32494fca1418d6d7c966b70cc995e5c0b6290296ca67a5f58620df8cc94fa1a2ae47160ebf122897d6165517dac613edfee177f03de69fc6c100338d33ae2d376030e89929b56763275a991d9ebb20543615ce9abe7327d83b5fe21cdcaae26755b5a45cd70066618b6993763d15f25667b18d45c61dbe59e9c1ea923d135f649ec1ea4564d060d52268749dd6bdf5f314fa41e50052b4f26386408b84b2146f98835d92c9193168bfe392506a5475aefc46004fd7afcb3d89a0ee1ec872668b56caf264cd1862e300ccce62f457106941a30e015d2268b88db1b986d3f3cdfd11d1c2bbd6a4fc80733717cf5fc34bcd387b8c56027a667174a0d489f76fde9de0571cd77cd1cff7725ba0d3dd17ac6d1ceb2b404e6cd724fb524c22a03288a0645c82ab91e39c8bdc80190171031d13d71c4036a5c0331abfbd89ee988635cdd1e2e64cc0ddf7e49b17003dd4889112d8c823e713919d7037bce8a72940c8830e6f8b16fe23790d90e9e1d90b8aaf3273d2dc1dc9285057b34b8784df66b002e5b50d679f00d22aa2caf51e5ed33e13c84f72c7e802c18d1b72a0feaf92448325f2c5a8c0dcb0f79bb87f7027c3e96b3c0b73d1b6b32cfd2fa61840ff95ff69777ac574cb1f9c66fa990f2c2f1c934a43ff35ec3023cb72340c4a6a34bd5e34fa158006a82a0693011190b9e734a68184d80f53c82ae6b275facaa066dfab5b33192c3de965b1ee8b06a5c59a7380128c612e28c6df9fcb845678a6fc5c710913087c894e848872d22eb1db2394bfe968d7db50060c5a279665af2701f66901c7f0e81bb51603cd82d36641fae1c64bf4ba188576bb903c296d6064eaa1c38bf987a84f4dd6ee58e82e8efcec07345142ffc67c3f82916852e4e319d40f56e046924549cc0da8bc154efaa67019a7589a7653f5cfe461bb553c6836da4d45439b4f500e614f60340cd2dfd01db1e469fec14dd2e061a8c5825f06cb566bf8ae76d15d46fb76f3c4e9050ba0d727c123d7910028b17d8266442727344efa022587097eb1602419b52679140fa54d997cc2a7adb6dc5dbf2ebef77c5d857145b88fdfe58b294889c39c1ed02b3601697d6ea798606264cb3f44fdb8800fa593f198d9d3ffd46f47c82b04b5311c4204181482befb8fb745707bc48688cf1081231c8069ae3baa8837d845e87105f2ff66b9d36cd405a8f90634e6c3adca40682f8789c09dd4fca0c4460bf14e3ffead1641b88a62cc03ca6692094bf532731900bba157590a70c443a93e77bd200a54f5bb8076e174831815ca2172075086999c657b6a179516c27093e410c78cca7363bd40b4a4cc9202e708f1319a5a1e7cea06d1d719a624e0b11cfff873dc3ad954bc8847482bf12c6f37adcb04b78e9e5d31581c67598102c46ad058129078415ebe0370ff4a420772cc08d135d58e5701814cdeed13ee9a717ece02d40a7364bc162a7524d0dc0386a4b5a0e9a0df959b1a2d91b7bf76e34053fdac98c88a26d43a1d88b823c341915e3b663dd70bfa34b6f2e6218284ddbfac87d241851b3a7f9423944f5a41c02f3025d583014c1ee7939539ad6e2258e09d4b2c4e2c87b01f95285a9838259eac307469747245f1090e1be116efe2270dc1abcb05c9752987788f9b620301a16c9f08ffdfd91a714e9eb65398ec42cf1b1bd829b831fe2ccd69a9569f7408cfb539d6c4bb6b7e9c5f8b60215b6096ccb1bf4252131777f5d1178bc013bfc91bde8a45635299f56343e749ac3c87c9fdd7261ac89e7be9279978f19295e70e834b32fb82053ae5b607151e98231c3ec0e5ac0a50205216c424c8474521bc55d7f89ae2d0f20cd13d6db4ecb317026deb7b0830abd55b02ed3158fe33f350bc4c573380a1d5ed9a6cfab381a435259c2a1cf0e43a6751b844e7295c5472b1b2661481c7071e619b9a345eb3d4ee12b92363723781170591d0b476e36bdc1445ccd1cd82f47762e19ede548066490c572615890ea4cd7117e91e039fb1091881c25f93643db46ee1358ff5804911406541aab9fa9168fd7ca057be0b87adc5e21751cd7225c41eeea0996d2553ccc7820059c2e829eb71adcb68a88c785195838f5570a9746cb4dced53ae9eed09457b665c19cedb5fb6ca3978cf6f779ab650add7019e41ca30b4191b5047027b8c9cd1f77202f2d28f1320ed3b500eba4a7ccc15aa624ee1d0e10d5145c0fb4c189a50628b8024394fe04cb1980f04a2b824468529777d6daabbc62cb4ae7d85db55e11ec3e61ec9dc0be5e06d1647fbc2c88a7b221cc46a6e7cf8861325e7912a81aa91493117e91115e294442371c41764b49914b85ab042aa3cfb1ad1d59fc429bc395f84ec2cec301a60c9a91eb6e50a87f57cb3bef3c87e61169b0878f2cafe7802c7dc650b1e9cf08670ff6494f9f927fe261d22124070d17ed9c7ba89c515cced1a052b3f8ca12a57762eeaeba0b04c62ec01b26a9a767f0e29fe828b85fa281fd53f54b1778647b9da626031811afc3d2553b62edfb62807dbbfbf1a802e43651fb35668ef7ba4900fb5ed6a9e00a1f727aef5470ddcfd753c18eeae80edfb46aefd1009a547f23ac2a2f940814d145de0d714234b539c01458c5602322880a49ca506337fa1f1b5e3eae8e0762f3535c1b77d0bcdf2855aae5199207ee780e3839acc5a6a02108d60717d9586256d84c03055a09a4008f7c803f9697745513a816712ce9a9a1e9821a21a883c548cefdfd6af880e38eca3139f39167e276decc1eca5d07b4148da20135eed36dc00a4228864a857580c7bcfeb73fafc5f1effae3b6af2953429c3086aa3dc2d9ffed60862134a8d13a98ef8d20a5c47285dc0094be3dc6073a515021485a5f2fae450a20c7a08b6a5e3fb3688ff241e0d885028adae0b865cd07748f009410a27437349c9a6c053b04c82740584efa9ac45b1209f81d0a6d4c0085cd25cafe07555fb2eae07fa2eadd0a58b08cd4ad93e216fef518a502b3d66159efbde2c43e4d6c06204f34e01afc04ce4965c8fa490b99b8d65fb9399145df3f83bbfffbd9b3a261e9412eb0035920689af3d7105f1cb62e5f57419ae83e9edf5d9bfe85fb721938887496ebde388d8cd8abdc3d682cb921217d61a4259d93b1e7080d521e9562fc83c73c10f9a1ea994ca2293c085c6ffb4f89cf10e0432e4442b72df585d984cae1214e84a259d6edf8111a85657339b4e4575aafefe3a791696339d99b4f5e3888939ad8914ad35d901447f38aa343e7b7e04638886103d41c3e12e06350ff5ec8cb09fa1634e4d5544d1736556564594cea3aedfa3250196dfbea499254c15a9baa72f66a0f02896934152ce4a76a5b2c184fd73b2d7195882e1ac98f468b8b1e79dddcbbd949c77534007a83b3c6a4207b36ebbbe504f973af4f374551467cedce53287dfc91a009995468a3176a5d13dad7e7eefdd1785581bd3d1afae31ffe063b43291e55aa9c6f8d066da7d455576b2862acfc0c551465e547048a6a88abd3a3b5f138b07d0da7aa72e72cdc58016f184196f2a5a3737def33e9af1bbae4e449e906db438ad85a49aa39ff5f4458d2e483ccb9b08b55ff5ca2fb1b412e0e3029bc5c57337e8dc4a5d9ff7fc7833eda0722a5a0a2c5e9399419eed5098f60eb5e72d0b2881900ae1ed27ec90d68c445ba4f79d92b57d276d2959a1579b560e73a8a99eb9093c99b72bd6d99e251b0d4b7a0eda5c25443a992d9d2c2252f6c126bf773dcc87f1546a27171d2a03461a975e304a6c33c78ca2f14cec348233e1d08c257b58282ca48ee15367091d3eadb4257e8afc2dfe452d0d0906659ba72309e798323a2c02d5740959f5e9b800120a86b1fed0a5e005f504df5eca686082c27b29b7c673316d544226ac6f19ea0e86fa8ac88eecf60f41d8f6fbbd35669814e8f0470030a95279e05d59c68dbca5c8ef194e9b4bbaec3bb5367fbb8a874d813c05a746535416f8e470d7ad17b95a9adc1f6edb33a36759aedb7859951a0c8722333a0368e07339d4a924c54816d12068699cf653540668615cb65cbcbd4bf997a0c9536992e453472184c37719a63012040e4c7267c146586ae89d6c5b16b8c0d157c72589cf088806fdf68ddc5550d5735c2d099b862d6ea8196b99cc66d0f664d10bbb2f0e237489b21e4168a283a13ac1e90a00fabf27b39dc31aaf6d7f05a93625a8c458338fafac2b8eb267927fd33e633200549dca66ad2c9cfdf4d73180e55a14c3a1cda93d01307c445eb9f65231121d4514d50dd736ec24f6d46c8b2f0b0d073ba5fc8897ed8a718688885e8e25c58babae0fc70e430cf061bc49c3d16788ede58381a10be282676b5b7daed2fd5a85f0eedc15aebe8b8577a6ebc5c75904fa6a6a3e37469d1d14301aa58794901d557420953ad8e0eeebb963d81a3237db2ebdb7b4c2bfd75e78363b84ec9691f8cc26e320b40976489f5a7e32adef9b7dd497fbdddbd047fca092804de02cd7e9076425ecddc2ed56b6e78cdd28e3c86a5bc2c0dcab0e80d0009eb10683404b159393404a346f22c295e2618adbe00c8067c69436d19cbd168c8a401f666d684c6d588bccdf14312d38ca385f5e8aaad8e65596030fe1ebb27a265eba9e6c18a87d4b556c9fba9cf0fbb7b5b4c2af631420030fda3a0bb02ba61c0269d2b240cd4994cae002a5e28b12958dae21d271d1f72cbfe8aba05e062bc24fa63a86e54901954cbd7324858f6df0287655e7ee803d99601c778269fdac366bf8e865ba285d89f7a83f34274dd49cde424c8f2ed9aedcdd3d5e84167588bcf9b916e608106dd8f24e07176d8c9a5969d04baa04ae4cdd91fd7a19bdf39ef17b3409370288efbd8b2cea1b62f430ff5b4161d7d70a0b1f84be657cbbc879fd7ccfed528666234fc32cb61cb229f3cb54185e62ce52cc2b1d16c5562b0fbfcb668837c7bb1edb4c416a83069807a4f0c925b252a4cf77cf30154c527f4e02b0b9d046b102b842cd7a2e21e16a2dd5a611a700d818ce4e431bd1a7d28b4a51ab0a1d0afcabd5643a74a3049747ce7e216eb6a3dc306e4504f6f168d10c059b7b0b06297d87d52a25940a4b9057410ec375d2f49b3d088726a2f49349ced416fa5698ae9b648af3d451ce8d070b1d4d170d2da71d27e39c21c2dd10a55ac857d7021d4ad954605b254ef8e7f3368ea13c03b8e3f7cf0fcab6e6424e6614b5028c375d14485fa822b050f0bcd69ede7d7387a86b1b04afcba71f0d1db5121255536c47258285263f76a0ed77b027d054d927c4eebca4725efdcad23267b1d5cf075a54f6255c9721f97ff445a3f3590af12a6e399b541f84d2de4bf76c77683e92b8103ac0c57898158993ae058d98f026432f0950c2a672397dd8338953dde406a39247459255c3716af849261a740662c226568da946e4aca12379e9ab2a4051bc830b26f474028f0b0f58b619aa537e3ff2e9ba043d390107382cb33e2fd6f98a4fd99bed432a0376085a306b3c88a733a40cba822b0caf8e76e5b3590f128c302a29b818970c3446bb66c755fedb8b70783c0fd5c200c027cc588cf2da6113af36aa38eb31cd1fe8376c9847abbe68dc04903fee26777612838b529e632113ccfbd8089e14b9b263b112f04a5647d09d9460a21bb6704e0cc1e46c9c95c98b067afba0f38709cf52da6a50dd5221dd4c658dd83de1965dfc92923dbe8275e2e63e59659023fa8d85be2fb3f7b57c2c08dc93ca85dcca34976e9f60dbe4b59dd5e2644b8db9182f2255047e6005f90e91a540ad0a52959ea27035b7bec468ec6029270915bfff07c67372a0d487ba75ca9f3023c0f1a352a1a604783eaf406ce6f3087d79ff32433568ab72f406321de35206f76a929187981246bf64b125e4aaaa416efb871f6b12f614421ec8e90b7ce0ce5444cd3c2e5b8642de894206b5791fea2271e152d11e8e9b0527b230016b6d94d1b5349efe86c67a3bb6272496dd4b5ca0d79b92e07639b7c51e256891a78f2fdd498b7c7d4d1a7e14f46ff1a5afc6f33c3ba46e5a4a2407920be8e16ae7cbc899186fbccda2847961f1debe246c32f8caf07ee51838cb0c54b03a7818954b27141e14176d9e8164f0c4293ffb2114e62d105d071029ad16f2ea3bc58a05db42c68691886bec094263163ae675a1662ff8c17d740bbfb1a8698ea101aacdc6cba4c5874de83cbd43a4c397964f4ff0bb152148ebc46befdea35b36e7b4b0d710d88f7e839781b0dda5b5656c04e096e91cc9f5b627e935a47f0bd0d95a1d05b3adae1a8ea0ee8d0c380b28745c4f69b4fa77318199d21b92f795e3e049f2c97e4cb9e7118af74d6f3c8c580f4f8aba7a84b0a21b13002a38e54cfac90fd5d026da3589f88e518fcc4f9ad0315b186829ddd470a8cb748f9f2a73edfe116fc71f418759d4f9d53d423fa3a83c78eedbe0dd78e77bd16a48ddfa0815958e268191f1ab8ffa56efb990bcd6758c436cefd800f530912320aa9260340e8a13a4bf8fd03d7b6be18de54578312daae396641140be32426c8d866892528f771e254869a4e02684727d6261fb0d2b0c7baeed3dfa08dcf1773bcbf50eeab0de4a45d22036024f5ee2aec11c9025ebb87c9c4433e00bcaa34ef859ed7ec3618b1dd05f38f60c236c92fd6e984897e83159ac1f4c27b8a93a1943d8eb2033aaefbfe433f817d5f96f37662e46cd3ccad7c6f8492c409ce83d5a2e92b96c1920b9455cde630bd6117cf4f0bc923fa88b3577c0ba552c7036c8864f00d044bc16943c18f345325aa9ffbf3e23b34b923529eedd342516420b3d49ebe0b1fc4b5f53f8089451b292fdc0086023f7a56cdaaf209848dd41af71ca52b1264c066578a52aa422e476ad50757b178bb6fc8d96d5c2ff98097f517fabfef6230d95ab6d2fcad9874de1f4f75b66ac9f891fe20a053a836b8b8aae8310dc842b5a7977b4ddceb5569e5989bc677b96cfae13157b59f150e413802a49d3c665e29e861793a0f37cdbc732775e74ad774e7020a944fc0a4cd78668d20297f03b85b17f6f8f7b27b33cf027b3b56a0fca69cc9702a6254ec9f099e51bc0596ed8b8682e63bd6c707ca7134aaf88b8d7bf7182588430d6cc826c30c1c777a737a30df22958b7c6fe2f2545359342c625469c23b2367d56deddd6f52c3cb7c53aec80d8cb04c845837b0bed2635e35bc9581626d0c401d921f70791fcedfe468b3c0ca411c6aa7731ddc38289b504d5c7b04b56539aa32a8ba1dac2306ec569471cc99c62a6ac3bbe7c53072116833d27bb738bf241a57d324801974d9ced71de5bd6f86fe87d690c09d19375de49fffa506e0faa6a5d70db902dc8738ff9cec9cc8f98eaee2352a2fe31e96a41e0b8fbd3d9930bfd0991ba1bd063a916b9948dad3ebbe05ee3838c8181bb8b5913bd7cc87ed140377c0239df8cbe7a4e8c3fcfec0832691b8978ac509649e3a9c002492ece7f634bddcd5c666b3cabd09cab9542301805c4c44852ced8558479338d025f9a866fd13ab9860f21688349d423252e2b8ad396d694e675e66c71be464aa7937fdc28ce007d0d068a40c32922a4f1bf44e4e1ee151ff022fe1e98a2f27f7cbb8fdad0d4622034a068e5e2b0f35621e6f08decb325b2127b9c3a67b49b045eee91d63595a2414f301692613776589126ebdeb48ca3822c2e7c82ee4055a7e2a77a924d6c16016b3d3fd1a0943a05365a8b6a36746cb60b3c091486c509d438f0edc7ca21dc9b9ffb9dca55568ee1d904c164748d1c9135381179ba66970be8e66b52e159d136a58548e1b7906864ed1bcb36fa2133ec68e89384eea0614eeccaaf092ddaaf0ecd27207c12580e75613a99362b3c45a37955a2465b518aac14e84dbfbfffa0edf03d5792530a9f1301d782a18aee31badb1f73e55a75688a83fad529e3c170a10e68103d3350c10b751f92c6e966b51f67ab50a71b8f9ad7df0f9f6466cc4a7a136decabe35bb9da17ebb9fdc52afcf964ebd829f54b568a82226380524a6b7864d4bb8b49c14b914fa1c3988288c0952822cdd558b6f666f05ce665974f08ce12d7886540b984ab0d49b82bf97a78fe9ce67952b5ab69e445a3a11d014bfab9179e9185c8fa08e4a89aac5b352b90923c289856e402acade19cac9e873701178a238cfa6342fb9531e69c4d910e9a6028913e02b125cbe32b92bf75413a79b242969ccee669baaa750360e999b6b354a62c7c255545ba8f9364734525a51f01dc5ca217b2895a7245178c3d9a8ae423791c48cdf952e45afbc8e13f033da741f112b022bf11b83f09b5233e47bd08e26dca8fc799f4012360ffff40f39799f35d6cd58f3cb8e24f723733e98ba5a1cacc847eee42d66fae88611dcced38e2a4b9f3b90060ba16f7fdf47b059b4e9e9136f26ef83cb0e3d5a38c7c918e7b3eaff6591b2611c70f257a78afee3df0fe4a7d0bd139f1525f38f7dff42cff779fd80b56a866129dfde163d109a6ffabed98584e9c63b59fe5bd8627380488c7ccb7ee5fb4f689a2ce2ee2a60798652614739a03e55b14810515102bf482c4a874ad26dc12c6148547bc08e6a30b250a4922ab6f0e028edd561dd94154f653e5e5e6f7045ffa5707e8b6878a3ad80c4218eb30a81e59b88894b20156099b781a5f0cb0a68779848c29b5fe5c9ea21c7caa6806bc59062c553403bd0f95432b20448550224cebec7af7da562c18df9bde84a0083deea7f4d33df716b96321b6a85a49bb124b160e31ce9e66667b55cb5acbf6a328ed4227f67e0229e87bcf84bfb87fc51f9ced5c01f94bc8145dc00ca3bfd55a210f066911f141bf73535d25517940cf99a490decd780d90b056b40f0de065c81d5892bca9203c5a389c81055e074d721f9b5650a56f14c87da62192afa506929873c1b7400e474afb50c5aee331b99171bf34701ba3f2e7437882126bec4879a88d008a9e15a9d966a0ba99168ddacf1dc580071b342905a860211bbec7fc228f0fefec663c2a47833bedc681d431f2acc9a8d49dde5d3a80c7a121978878bac61d287e71fd1073ab2049f891c9284c64775686142943151e18a43e8478c79afb732e00dcc4723c39d7462c214d17b1c962e292c5bfb523b8fe2f69557b172b3d75ea7bc8c7ca6b39baa2b7df39c60b24f55489b717643a13c7a14d12ba7261d51a6eff2ec902218ba1f0b2f1cfb565321c2ac52bcfaa2e8a04a926a6bb68798933c341e27b849ada502c6f7ddf519d44a4048adf8cc33142fe0aa37ab1432ee0a8dd0d13f818fdcd43cf094b530e4c6b03ded5e7618ffa0077101cfa774e5792fc035935c5409b96c651a171bae7b6dde75e8f268dbf5ce9fd45a8df82cbbba09a1fde250c7cf0c38ffc772164763346eecc70561250ad11425ebcc18f242b60f4284233d4192de62b18bcfbc334108ad625244f59b85d6f832be877f6ee27ffb0aa193ecc9840fe9d31ba649ca37a628f4021bb54fb0d0d51e765e2b8ed0ebfe651584389e243c92d3925bea33a40440012bb4b3cc6a0cd04ad399191b3e604792c0bd8e852c47b0cc82fb4ed93987d2e690c783582768b4bae6dabf39ca6c52ab54d06cecab50e57363ce9a15d3daac7108f7d453339b506d4082ac3ffdc72efe31d2f09641c1f43fefb2352c459eff533bcaa8128d64ba92adf7f386bb66746d42bf86fc5a3dbb3594e0f1f70f1855a5eaf5278d89039ad6da673dfcd85e3bf0486941cfe804787b669a14b2953e51a2010b939c55c0cb88bc45c1797fdd98b183679c7827cde82330d8748e619843e27b39f409ac8d3d7f2ed4722d32a107860a7a8d65a3c2ea9c7d049151d67e7249361fe976704f5c608f182fee808fa2d13d45444b4c2637e232d1d345f6e81bf0a99de933c905eff11a0e814411c6fbefd1b90865441f35f0f22b3830e5ed82ccfe31250b58e141863c8f195c8b362b1f8fa6fa22969ae7d5791e7baaf6f76d91ca417fe6d09b677137a58fa3f915fedede635d9b00eccf2372f96e629cff38d37fcffc1e55b979fd25d7884227810aca21b81c1033868d6785498e8965b984316cf92461642657bc3eb022fb9d5816b87695b0ae9b588794e0d1c367ad1c13cbffe513d925b140efb9810c2b7aa43f8f6566e836b0e533bab39501e42833e3d45174de19762082c1d3f6ae67215c4ad82b89a52e9fb919fd39a8566c7215cba37a66b75eb77cd510f0b7195d03408eec61ca2dcfd58c0686b06f25ce47fe7434b7a0d83288ebea5835be03439948ed34667a0a669e69920a49c2528954ea900454c85e95480783e1e108c62d7a129cd64d47982cc231cfe5889ed0a5e3269954fc52a1fcb9d9f445e5dbcbcd1acd5f7c28fb3b1afc7ecab505621d065785e42a2f8840013a3981c59c5a69850b511f8ed1ec1fc5d278f62b8df52ecba2615f95cdd93363ee66b0353b203a62f078d53371f4c543e75afab5097a6784c09b821d707c724f72b9521cd002306c0e689190f73175c32f7e2a0f7765a0cd6cc0d792f99458500e77fcdc05603b4368ba6c475ea5f52bf5a15b5399ac5550c5d29022cc5e78a7199477c8aa187a73bc9b4e11279c07966d767e1222d577524212a2bb4af7ace66bbbbf66c208c93a6e7f273e643a5d1fed25aada76af16c8af328557a168746a21e96c8fa4104494b06fc424bac3c527cd34d6e05645a3bb64730209ee3f4e511a1e0d8b4ba8b611a6396e18d19831a37ce7eece038ad0b047af40167d1baa8fb1a714443049f6050cf4e5bbe66c702f6b9b1ea8fe315a770a61d6071070936b82a2ee3fcf122c3b99030844c03383486b2b4360ddb3bceef47f509262d6b893431b917fc6bba49e0d29cd9e7cca93f86ab901e036efcfb090257800fa8f75a9605358558b29d1e9dfe9599e81a9f1c0fbf18efe08e5ae2b30581d3b30a88d0fd0015bd2287524f22605a2349a0f0afb8d1ed51d4217b4af7a5b436d1a82208bbe876e827027d86f9efd2decce42431521bbc7116a1a96706690d5898ee4885f408d9d7e2c9d9e70c5f80e2ce86cd7cd5219ace07f3ab0d57440f8a9995238b8317dec0e70e2d5501e652b774f9e38ef2e85b14dbc2f5973572c2334fb5442e95c49df2c3eba0da97480d1be59edbef0c5fe7493ab493d2fb1577223a837baf115fea93ea46ec003055f441cd7a7802519e26117fe96e3cd94b89432aa569f01345275b999a82deaa782c82596bf64136997016042742b8470c7923e4e53b4cd6f67d65d3876c814ec323370717bd007704f4d31b7e4a2f30c779ca50182a76ea05976e80c9b8ad43a379874b9f232add1ae11425f9ab31c8a2e61c194d9652014f76bd45eef1d637a329861aa1a5d4d9d9a0a3a9c0bc9958a5de3bb8ad562551f060c19f53b7a9d5075827c96df545d54d072ea2102a09f9c35242faacac9b7ae6f9c3a18ac8766cc7e86058c21f506593b8d3951c5fd66d45d0d68feb294fa665aeb5729b2b91e69dbb996bdb135224b2ddc01f10784587fe159e9b94021c6ef12e992e287707abb57626070b3efa112e0931396a2d0638f9828bf97b35b916ce3579e75cc57bd32b71c67057427c1fea0d1c07af3f98e7ae167ba8ad2672dd8031fd4c68138bc1281279fad9f396489832e504fbfa7878ff3a3ba45548ef35f998f9c72fa7fa15a12a31b72413c4032ee23afe2c259440300ebbfad58b1ddf2f49f49e548d2b33f57b6e264ae4a436d6f45b164515e511909cd0be588aad1b6b0b12a3b39f8c5adcf4c3f97a5db00c9570984aa88c6541dfca9a59ffc47f349d0afda1212a5e5de9a8e3a2650c70d49ea0bea600c690f12fa7a7a374ce1efefab1700b18767dffdf7a18d745dfa503607b5d80db8c2b9979e0193e293fdc7e5f56ad7075a6b2a4fc9ba558daa82876803604528be9b680c536c299abb69e1ca0ffac0c368609fdd8eca873530ac1c0fcf8b7859064626e4738ba6bf5c0d975e1ad20e6d8470af45b5647cc482bd5d72c17bc2738ae2f546ba7b1955c4104abce588a188469b7b8d6d68213db506c9528a0e0097a41ad48884fb1c277542396ae4b1556bab97c8b43e7e151b3b934734af5a0641c50cfd5692eaf406a43303cd3332f5ed9bc7a86f211a9a3199ddeddec168a2543e65d62ceb0bf9adc8416fe55ac414bc45248ab18f108a2b8b91abd43bb9e51fecf59cda11da210c64f4b1ca5699d4c88001d36f6e454bc18e681fb74f25b11e0b78a1ec2871b295878504caa6a0a4c2f9f73372e6135e77a935a2aa02257b5bf97731fc810133f1b94d1361e0dd6ab4bfd192dc2ee19784d56d89aa88d8a4e3d1dee1ee8e9c46204a90efab2c487bd34ef123545c78dfe6b2c43644778e4623b2569c5d2fb15313c29ed4c67da4066f9d7a477579c51a1fc1a664cbcb70d756eefff1fa0caae113454f680ab1abc608d5bfac567eea515982f3d1c704dc0bc334186c31f7c3a15be805a102242f7b74d3cba5d44b2864d2cdaaa35aa9557031fe80a505dd6a1e38d07ce141cb3eaaae773572ad0ae0da150232b691ce5e1966ecfb8172dc8d4ebdd561903a89845d8f7d0ebf451f48b091843a25717e288ebc41d1d386c49a21ca52b08b2947ddf08c0e8dddb0b19e5a81c79feedb4a6d7a79789786643cc2b15c6197c8eeafeba37c8fb048aa59b5c1459f246c9dd2b060029af2f4bf2d9488f1b1e6066b10007efb8a1c881e282f1d94e40bd3678abf225452f0cfa14205b50c00b646da57f422a812f4a6d06f104bae096fb8b602b44e9edbb9364483e64160f0ac9d6372f5b9fde46ddd66720dafcb2c72bb20ae5bdf2e4b393fb766253a421cb626150b5ab29f82e5ecf6bccef0ac41ff29daf88c0e41f17470d07683caf2390a4faf343ee27f62ce47a2cc7516f67043401ad2b4e78e27eb45008968aef6b428694dc94e91c21d4134a92d8df7c58bff56c5ec09566f0ccc536af90f7443dfdbe46ac68d6af05adf6c5930898bd67fb59dbad6fc3848c2d9fa0ecb680953aa86622944bd444e1d37c3f2a9aa8e941e3d818795c289241f3daa9f10bb677f8f81f28dacb241903e50ba62087d490f5bcfa33e14e2da02005141938a9d21659d4efaa1111ca12f436d1af6951bd9206fd6fa3e6f081fabf2e761f773e3e06c286ae894fe384c2883a9a47ae029ed300c2d5c2b0fac36ae4dc627c21311bc8751497c16d80562d155fa24ebb632220e2a34eb00f4606b9d9ef9e9b36d10d620e8f86109936b15705b0bcf063dca51439eb924945517ab7c58d9a977fda244abdea86ec0f23813573928a61e023e405690172ac051f1edb7b24c5c6308ba9d1a11d27fae767e30397674fbbb62ce0512ad44a2854b0cb4e489cdcf4486c3f8a9e7d95beda4a7c72190ef54d4fd619af3947ecc448574183668b53a558f8fd06eeeaf4745414a438966053191bf9fc361c5179435d352e60543947915b005ca1580958c45e9ab6e214e6ae8d496a03ef756e0654e6cee3243584b44ecdb323883235e71c450748ec639bb855935022cf885d948ddfa36c217e0df07d6e396eed5df4cd1e558aa3586e7ccfe2113882919ab5c8a61c67a5213ca2d13ada10da23ae3351db006ddd2fa7ed1a099d40903caf0a6af099b09ec1c2278b8f249e1e4f2ed1b5684af4785fa479d6871e14b928367d72530e08efe01254323e4300851f16d49e499f488b770c29daddd2d03d11663bf45d9559c40b5650822192146ca388726c78abb37e31b030551704c449cd0b8b5e0de70e095b695026be5cfaf42e8f70ae107c27fbd1712de3651da635d705f6db16c5ca1df54dcc16fade1abc3dd780d95d7847e91f61f08e0be20d437869e747b3d08e9816d1b7283c4591d01d895934eb9532fc197b80f726fee4dcb6aeacb794d0141bca3f897a9677fc3a07dccb2b9b45b0b34f0954e293f33d551751f488040b1332a054f6180dec1a9bc00067d477496dbc51fb0dcafd3ed9e398f86dc2f8ca0da10ce315e9756a134225ee2de27ccaee666122bbf705979017e9ac7d0df6a8a71876ec183912b8dc85c938afa65075e812880e12dd8e9016dab64c6e1513951957c369385d31a37b447151845d80acd7ab713782005b50750cdd72561a1fb20c5c403c03d70994672734dee1ee7ad7ea37c40454a08e45b327f5abe0ce854ef6b7420c74548fe60810b5d77cfb3ae2929392a1283e1aad0e4932ba0bd643e445209c8592e92e108738601ab42c45d4b242764024c93d5aec86b5badb670d3298184df1af9b448eda102e69899c20462ffe6a77d41c0eb487f94429b01994431d62d82a233dce7570590141e5941210157f418f55590fcb91b67a8429d6c242bcaec5f1ef1a6322e558fef7a4d35a6313c3f1d3b0aed195f795b5214e3dd518d5f2eac58d62ca1ec03e986ee001459b39c59e852d09f4f0a8ae93b87dd7b4b2fd9f099e3cf76241427a8417639151cc9f059cced80689ae8c820ccbb43a78e897b4249fbbe68da16426ea8b80e55564158a0b3d4279f4b2c25dbed9bd8ac9ca404a9442b6c029162c9ed5cf92ad594b05f9359ec11c4e7f033b12a4b0c7e4611446b1cba90e9663209165ea4e08e438303e9c41756ce2088543809738cd47d69124becc2bf3543c73a0a20f34aa28c2092343b341dede07bb9be582e4eae67d6e3e28617ca1017c0ab709b1883150e00173d796b669344c99d4af6321db55c6d4e37573518ffa9130cc5059bfc00e26a992436dd472eb472c92c1aa135761037529379c70f6208b0d0cbe361d96f01438b7a470cdde62d57a21f68c2903b80659e3ecee18c6ea09a93212fd1022013820a848887e2c793ec6b08603822d240446209e0106208f8250d9359d38418bd9ef5127340f7b02d5dac2ec9de7ead21ac26778ea7851cdedcad5388c38b09cff59c5b20df53c9c3d5b722e1aa7f2a054b07230653f6257575d272d2866ad450df7ef308bcc90256644072f33f6fd4c45b0f43e113c6581c23323efb489636139c4bb6446855c32107c79cff206900a40ad869e5406ff76078a0584fd120e986e74f31f58248ec11957e12ecdbff31db9f0df83697907ceb658a103880bc10bd094c09a4fc8bb67a08d583e1b6030410de0879ad4e27d3b01d1ee7d9498467296db57649b1ba5715b8c5f02a377046ac2c145744c4f2c86460ee7cfc401eb70b7b8d5c6a89e46631673c9a92c72a6ad646de1357d1151f78959ea6663aaa4e3baa106945964c841da56769722235959aecd4f41f71d7b0a9e67e768e9076f5f6cff78636a56ef50461b206fcb51aac831a88b3d620e96ea97fafa84148c996e0cb438f92dcd7c73770403a700cd7d6265ae4bfa9146fb92a91920765c017fe32470629f9a0c8d270435e84ccc70fdcb5f9e60e08f67892510a73f0dad9ce881645a9289f6e825cab1bd9f17a6a50dfd34307494bd802f6c0d33a9223f6607fa105d2d266b0e8a000b4c19680c4e48197c9f946bdfe12ccb36cf1b1d872e39bf66e820cf87e5502c3cc619f498353d4f68b8f955437c862beb4536e05cd334f91276b538076416d7383377b9683949762bfc27b4527cc689c10eb0b4dbd2fc36d86eb8c66040159493af985fee6e453a19b231d9ef4bfa7255135eb69bebb3ab118622fa564b675877c228628f990dae594c0b0ce4450e2f1e8a79cf952006556a8fa595fdd69b27f138cb824225f7d051fe284871082015e02f88b7181d42da7273924833e83a7f25bd0e756e446660daa451315cc6d3873fccfb44c48995b2312f5cd1b7888c3e9ba4e994b4d0be0172e86255bad46b6a0882b72a058ecb33a98178e5dbf0574cb3e78051e33311ba8ace1aaf6749eb8d6f7ee6acabe78ce83787fac7ededb6e97cb27b3ebf079855d9d038e58a396d976c317fc12a22cf1f825482525700a9116a6608d34be072f1fff4b354a12a8011e118b7398f5b313f93cd890a8fa37ebbe0000d7c79b1c73494f3adb65710cf7c07530e6f84b50ccf78f07a892582c0038c9a4a5f54c378ab481df92bc52efb4c4622ae599e624eab23dfd01390e368016f51ef16565f8b705719bca931b903c2ed67a0b5499d2f0e80d70f1ea6ca8f0e4b00f3001abd3ab019dabdb0d27a5b8371645a2bc3af272956123954ef44fc4d374525b8870caaa406d6a1a02a036076b94951b47c7a85613c64566a7e062a281159c5eab1e1aa4f762d7d4b80741c4db5d2621b5cdace15766e3c7d3a45d622777d515438260d0dbfee7c20aeaff1e871cc49f14f34d9af756c770de3d97030bf404598cdad7ff769d2d988ccf32c4e2d1c05b692072b29a9a4bd7931a48e6920ccf8dc67b388b85707c42d0f97000b679003809dc1dffc801f78cf283d417810009adb263a7492038c96f56883040981399ce7071fafa18f824b282d78e181fa9d6fca04c0b490e20da53728f1fae0ded7aa0a70926901516ac21b6278d7789cb7d5f3de697dbccda521586c4784cd5d03232c81bfcc1435543f38051a967a268b7f5b0657216196905931d67e55d0f0fdc422b03ba133008cd80560806e4f10bda3045d05988836b26fbc63810c72ba8834222abe9e5de15d42c576aa49055cc9e6ae3f8f779ba3eebe1efe1f4c8128a379f45bc644b55a187d89398f36b0ce18a1bf4a792eebc56be9f0d4e78ca87b71050a7cf7854a46852369ff8c6200cc48077f718e0780f4844f4baf37b83d4ee842dc185ec7c9bac80b1d92ecdfec0e61d5d4ce7f993f4203924b0a3d189bcf2f0895e4546851825ced8f4cd27b17e395b5c99f55e9c6764bf75c0b859b6b3938fcb0cd874412041870d5caa627e01deb83473338aead441020352234099c2d0b02285b81552ffb7c97456e7cd95c0ed0f5629488739cba6b3df6a59ab56e762735408ae8644c9935476a936414395d32680c016a78c1cea7abfa592af008e5ca4998b1fbaa70855649bc600eb2db47fdefd6a9b9940709b6845d7445e63e4e876e419ceeeb75dcf867d10b7f84676346acf51bd95350e7cdd6db1d5412feff19478b42b397e215e97836212d4298952df4c07ea3cc10c98a1cbfae25df2c10c9bdccbaad690b95af5ddee84596cce91f43a6c0859ad5a6861fb5e3fe5ea2fa4b771089800300ac3481bd18025f2c50224cf976069686edad15ff15ffbee442aa2046dd612b16ff186703fb4d12c48d51c46d740855352ad68078c338ec3392a08fbec0d6a8ca57a9b5f1705eea98644d2123c2b75f08068775311560ffe8241719c111061ae510a8eb560ddf16235ced4fbd75dfe27737a1ab97508ae774da84e15c377c8803510053224aeb1a14947be7215b9528c8d8ea637b99ee9b643ba88cf40ffc29b0635f2c4ac02761a6836328a3134497737633a3897547669d69b060e8bf6916aeeaa162561e7ad6976526a27107e53c2e6db9f779d9e29fd2433940751cde87ff4b51a1e13c939a0b8954f3505c61a2af540f8fc855efb2140b6a48702e3a679d2a8e024698ae926cb102e19c3e4ee542ee275f23f5869245cd7469548ba9f27392497efa0ca77cef27609c1af71d8cf765d850331139cbcf21e1281e276be55caf1eb77d9dff6f2e60bcf387f8fd480e0bf5b672bda984846747fcb4b4e70059463388655d9307e025cd29965df2598fbe9492ce58cf0772778a2ae8208a23a0d127cfeb473fc45cbe9e9cbf09351db30e7604e23e80e363df5065e63448e0f557a62a9ca4e437e015a7ffbac6f325f9200e02bad7bc9474fd4ebec493ee445bd69cedd2462d0d3dc54801fb6513dee3c98590b18ec1db32871e9d0391d3b5ddcc08309e773b3d7e95d22d620013ad78956082966a3a96d42a9febd31644142b425717798a3805e29eb74ae72f96ff22dfc6125395d9c0dd48eaaadd57be16baff298698c5c1147b7bf2bdf68d68edbc0cebadab4af70bd28f3040fa95261ebebb034bdb4da1587c6bdbf5d55b5915d50392b82161793e046f641a9b1a3c5755cb40d0d63c8edba7aa85cf34c1a39455f6fab912341830b642a999b2e6f097b45bb1b8b58d2dbf64d23c075c6f4f861b1636b4119330d5216a16bdeb69b335f3b5c026b608961c7fcebdd552469bf6565f23b6f8fd2e37cb7f1c8690684872e4199541127d7451504fc16484d2d55ceb8c01b044cd5e59fd218578852a642def896ebe032e7f145efebc9acfa0a2718c9cf05c46e61ce72a14bfa95eb5938753f54d198398f482a5ac478a73e85547bf4c795e9dec49a9dee61112f0c56bda049916cf87a08a9725b4e36bea35dbcd7a04660b93293281443bd146223893d30c6001aa84d6fdfabde8e4e9e99f982eda84d6c415ca00f09abcf2dcbac570b8487fb3ef7c02b901257d7126800c774e2dbcebc86c194ffa51f3b5e535a99e9ec49f87f838f43fc08798f5cde58862d19b60a562c6481dd5d8327740780e66bfa9355f987cb4b3994e2ce95f69f07aedc85e6de06947844eacf6a6cea5a8a35e7984409ebf820a210e06c9c38e415f18003bb4f14ca5f5676812f7ecc7f80a0792b92b4b09defe4d55c3328bb56069166713a63b66e3732ec88fa552e82d1f194c3032e83044ad6cee730ce42868104a2bb56100283abe16fcdc1b39eba2a49e56505e2b41b184a924d6460f482ee832f87e7adb26101491d398752a51b0b47d35ea882ffc9b5d35c0353adab8b8e4e6e03fc0c7b5d24c3007b52914c81a0c0a5581815f4212d678ed378b8359f5995e1102e9437a1dd6f22e999a8a03e5c1eeeb91a11001890ea72207762f63ee1d5f9b97cbfc093f8b501d916ed015a5485f418009a4a6f0065740afd2355cfaf4ac877c5e366cea61587cf8ef0b3986fe7a550f5b2e9dbcb1de625da99923482828348cb31ea532b9a5d6f9da20f16368276a3727bd9383a5008b5c03fac55c4acf09fd243056004694b075f044049a82c82fb8bf1b4038582d8b70fe1ba995b08ae9853c19b2024fd204bfd9442d18592873986058d73e6274a709c300128fe18a6b64e92c57b3fb947005a450f34f0c2f67d13c41e0d0445ffc4728ffec155fa60fd1230394056e61ad1032650961e6b92b42922301a3223a02afbfa99177f3245a7ead074d4e1bb47a28fd4ccd104b0c6deea3547e73fe64385b2a4573a48c6798ab5a8ccdf1daf7a2009955fb645669fe5bac7eb699debeaa67062600e46e5535430303649d6e0dda4104ff28394e383fabd9de6625530aa49a9dc2c04cbfa2eb10e6d55c485bbd094746e07e9798fa5eb247c62f455164049cd7ee08f462d4e305dae8e7940cbe2612f75083855976b35b2d3aebccffa4143a0a3c4bd121cd2d96be91fe85cdabeead8548c3596a25ea49b0102a0b283b15edc4d87408c6b71f2444bdf3bc58e451e424a06c7eeadb58bfaca6068f35ee49208e9519dffbc0beadf6eee63aa35778d3f34fe158cbf0cf9996f41a0d8e1734ec344a8e194397093b9297cfb55670d1b75f576470d536af2536ab634e937044c50fc00a89b69994cc1c14f1429ed4288bbdc35c442d2f2074ebc352aa39db90bd322b9e30d1e0c3ed07d076d512616d11d98340ea5d3ff103c48cb48e1e0bb3eba1f22240c710ddfb2587193dc3a1ee2b30afa89b3b3b08812cca3bec66d42ed0514a2427a391ea0ca1cd83783eb0fcd80ea82dcd1bc048b24ea80ba677eeeca055c160796e3a796c627e75953b5f801a670bd5c271ffd43971bb2636d977338536d3c19ce356b31dcf1dc83ba8aeb7f575b9d57c39c60e9181c4420bc6c8c0c7c9cf19eae9f8b8f2894cf79f1e0a6065f7e0f240a78d887a86999045d185251b9d0ecd91656ea3879930ed919094da8f68191cde2ff2798393986e56342e641407916c8ae71e321305385051f0503e5dfc7d13c3ad4c32c3a6b0f48f5511d2b174be17f5b5dc7bde841f946ca2ae142d0a0714c94e532310708340c97551dba5e6daf652219e5c2106dcb6802d8a9a72dbf900935b10709ca25300c2745dd3f5c21d354c39d6b3e812a75f38a6c1d6007f8620a93c64e07e96b582e93a6f4199fda4d5d6207aa67bb31e524b18bbec64e09527ec206c0a1212b24063c536482d83e14407eb084763ff876870f45fd3780df76822419362a11e48cbc6edf6d54dc2715d1de9c2e5161c0128f76e88d90fad0dfad5c7f351f85f2299c1489f1a05da80cb08b19a0ea19a89c5a9144b1748e3b44b4dea6d7cdc7639fc27f63560eca7a9f4fda8e835c3a4e54fc7266f5537738fe463888345cf57af99c362afcff90b0b20eda6dbc1b61e5dd886db41c7dd7647f22157c74b6e4f0cfff0a5af6e9d4a7028757174e50003a27d81f6968e15e3cee55c6bde2e2e62f314e175409c00c57079a37fe0cc3c8d741e4b86e1d291114ecb2778966d877aac0dd8fdffdcabbcf8db8f925e9b9c8af12f86bf3da01002b7c70fdab9f42de9cfd530106f5c0ab70b6d55e0480c0bf104072e2be4c1ff3f66c6442a36f028416074847009752f1c77233fe97c4aaaa8441626ad6165525c0b840e5658f82656808e104ab1b079c22304fab905d3c1f0c188967ac3a21ac097bc7cd7b70515fae700c2f179740af76f31d35c7a0d20beba184016f6528682860ec6a6fc238c63fac0eb80435b83ad67a999b84264eb9220a7111dcbf49cffd446f4a0b81702936e5c174de6a3ee8f25505b4b7b0ededec2890188df26d6d61034d7187c1d0ac9110f47c5f83c749815ae0e359faba3ab22f0060131b8108040c679bae78428329bc383401de932a92392eb6a13e40f0e16af2c6e16feadac01b147aac951e982c006592a943c8712acb077978abd12b73939098c9ba46fdf9a06e020062a0df90b49029fdb060d3a3475172f6c8e6dc0140a216d4932c20822f4db1dccf49d9244a0054e40241f22745a9ad298e25071920352162a0b6ae13ffdf92e08fcbe811a3a23b6eefb25ceece001e21608b963e97fb25c4b54c680333e01a0cd38a35f822ad10382b640f7d4f7b0e5ffd45a6a5af97e33a7fda158f2908874ebdcadfe42d966deac94feff8cbf93526d4fb77d20857bc94d631a2ca1bb9533ae064b4d9b53d19055effb7bc9c53e5d2d56affe4dea5c587c373392a15e592bd4c931ec87dcc16b0d74e2e08de6439f738853fe9226f42bb214bedc6221cbcd5effef17c9551b43ce2019eb62a4a73e42f4597034ac915633d99f95e45299a8e8fe3dd2fa1e28b98ad71c16910e12fa0790c576810c1af21a3bf7c42720874ad8b4cbe5d6bc8ab1f2d291b7f3557566d2396fb080ffa47ac353e0eb278929a012c3766fa08b7a984e0438af5fe7076017850a6bcc0c080c30b406b9d15060ec146527c58ee47baeaf21f9ad709d5825e42d5bac6924d1f5da75ff8bb0cd1444b95782a0466141f41f98a76d5fc777dfa0289692788adf309acbb3e6191c8f1677427fb0b20dad3c4c0660267fc078f63f130eb45d8cc3c6c4791ee0dd38d06f1f8aadce7c6d621fb7d9f3c4425cf45b19ea7ecdf93389a96e766006c309ef7a5ced5700cf02690d55d31734b46d467b20624618c80b9dca3229cdf5ca4a7264043c235f1f878bddcb1c0f98d839a6415188d1bf4eabef6ff83dcaedd8d07281a7ebeae63bf56ef6569f08e3e75aef6614dfd947813b0f12bbc3d297cefe32064661888fb1236673f9e0a63188c20f50db6b62b79f1a681247bfb7aa32fae3c26ccb9ef331a52c751cf5d70ece7263606be260e34e07fccbab4efea766ccf753f02fa2170c2cd7e999ac13b3d92de2b0ce6f08fc6cda2cc2df3011ad575936f6e3c7f1b8d717118d9b6747378577b6b3711d759732c37e1ed27feb36c05431fd1d82b487bdf380f7070149ad587b100b85780f0a9ee20f5caa248ef7a728af3ffffb91816a5ada92798a7d24813c413c5909c3be6740c68f0eee94400214eea5174387fa2da33832e919551463831a5331e0132c0fcbd9ccb75adba555f23044cdb18ad4e65c79638a2a0443e4956154a8b8d4730ce683af93dfacfd36b5ff6b23ee7eac650f1565ae64e2b3b4ada84bf4fcdfaef406ff6acdb03372482519049a3aa510709768f3d8295c068f1565c2ca299d29bfb1f78b1fbb21f62540d6fb5b05426cb27d91c61eaaa6d424a379b1768f6d0439ae26793fe8489465dcb4a38ed7d3d1ac46300479f434952685289c5e956740f4bd34269da25aa71ca412f3010d12e6e89c672407e9579dedbe24b07fe3965343dfe8f9716c0d5aa1c8ed0a0a2a1f971e0234c29736f70fe7f685c59b48f052f171a12d5dc976a8d28ae11ee6297da967aea3cd5d940623cd2e3327bdb4413b638cfd386899db406bfcdd259f1142978e107698493779da879bc095c45bfdb230470ffca730ade87216dda25c7c1098e3241dca2a462f301af548251ba8f5d1df800287a844d9839f50e26a2c1273756155a4a11eb4decd1cf47e1cce338832769f291de856e42440a07be89ec09efb6407f3bdcc46b67dd188b0b28132811268ca0457623cd0045e39621244151a0fa98ba96a01d706e30dd80e83dbf60c6f96132f8fea1a4038e4b17c56b7c0a87f109a1071c51b526a8fbe891df1204fb5880f1bfbf373ad757538119126c8ddbd1401fef014209bf513830924ea97c64ed9289f02c22efc7e8a35d654126e0b6b763e419b6c010cfa66d096e18268cead3c2c8f57bb33ffa090f12f2357c47e5bcb770d825b9fbaaa67468f204d65ce0fe5b0a647c62c52f5dec6ddb0f90ce9ae1ed6216a7d6ed6113dbcaf1545632a897d123a57059fc147ae770bdae4f161f0bc6efc30437cce4ee83470f8784b22f36645be7a286233ea4caa6cdad244b8fe4937ad466156518b93528f124e72b13cdd617315ec2ab4ead89c1953df6758809beab4f4865098c56cbad6fcdea90886da8fde165709c7c794fbb7b06b8a01207eac0eb7ddbf90c6a8023bfec35d84fd49fde56978cbf0109636b4b20d082b202ce10a949159bc303af7bf185513c0337499f187f39d69075b901e830c63b6498b11c69a4fb61df97df9857a14035cbe62a443c6399460280e727c82328576a0803aa0b2f9b7fabcc699a078d56aeb72a5705483e5bfda9f47bfdddf371ac3f7fde06c3538422252c3ea6807993566017c628efaf68c27bec7c5488ee01b0105dfac2c826ff2cd54973fecb1567d148eb8565a295cfd21f3cf32526e50160d18e306c9ad713f4638971d5a80ffc798935dcbd688e2435346d39805ca6ba62acfae513e42a1e224e49fd53332294be983b547b1f11b766ea47e0ce0cf9333c53819d6ffe1e4050eb97444331cb6ffd7a5476181b71d8fddaff015eebfaa75b49f4e824a9c80fa01968f79bce74618a14f41b6a0114f87b583d48932508fdcb037906617ecd2918a84e3a854b60c3f63d340388932b162334c8d5fa21a9d05653ab6a2d716b86289598273642eb53b50a828f4d51378e0b15edcc83be1f08fca8627eed992aa4e7dfb75aabfd71af4385f4e1d627f47e18ebd3e971201f502c1781677eb35cae178bca39a3e7c859f872b24b588c5ac317199e55a094b3a01c3fede01a58e91e20c1e41f8e7ed7fdbff5d9a029f07ae66802f9bafeaa72ff1a80f4ce1c770c32201c88a62a04871ecde5582110ec460fd14a1c5d831a8ed48b2c128833e651bef3582645f4a2990a3763ad73f9682f016228578bda49b1ceba155de42730d3aac02f9893dc864b1168cb67923e48b822069b231fd59b5fc507ae0006774077662be61511ed4fc8d4778ac098210deb8262e372fb50bd8716ce33a4e019a75f0cb7e7026231545917abc2cddc9dde4f8654c4a14298f7027dedc9b39c0fe21fa2488f240d4a2d0cb788a90e92d8b46a868d509e1a4ff801e173aa84371ce08c935d6317980e05e969854d6ce240cf049d8300bd5653c3c2ecfdc8b2a615fb97cd57c66c0d3f636ceda9387379c998b0fd152e509ed88c6a650b80c3216acd4dde2b73026caab270804917cd7c80cff9b6bb6c8fa5cb69540c88545a869ab185c9df9d8c5c9e05cbd4812023053850bc2e1a26a4cc71e42781c33a19846e312188dd38336039b930343bbf57b0e3826140a4a62029626a6b31113ada9ccfd287b75d170eb5cf53011623528bd90502b33c58dc29f4579238bb4809e3895468c8be5c529b0132d6a6972be3780af7e53ee1d2bfd776385eaa5e810e207cec3f77bc3003cc38f8195b557c7eb116ca9209e3301683b56d1cc310d66c763513386193f829c8b1d2e8d75de0a68399467352ee8bb0c299236534d1344fa2355f35d05ea2d4e631b402caf5d5212dcdf41ba046baec354a8b7862b5a196eb2b0fcc3744e67787212475ae0b822637f2f80c989e7827b0c3a9f74759587e8a0e9890aaec1a379a929b607dd1c2debd9079d1e75b16309c2ade61b721d1897d06f733e3030cf504fe1204a10c5430e054690e31e5b827f058c78f6b834956bd5fb4c5c5986fcff5a1b82a8ed79077789eee98e81cf5312d9d9c927077ca45f4e9be3bb8b57e5a33dfbee591ee47239971a4958dd1b6ed16b2724b2f6d22a54c5206e50cef0cf90b8d7368c30615bc10f4a15d452a78c1883df26d59382c61ec210bcea148455de22134d8ab63af1ece543628524d16960f452a914aa4ea726c30362827c5ab06db67b674a8d62e9fd982a5edacb53653cd9690aaf1cf156457269f056af00aaa29dc438508f1b01fbb0c12f4d1892520f98f3c417cde48a7b43de2f97827de80e3c41b6e5a682d9ab801ea6dbc008e3c7c3032dfc58d59f9f47cb807fb602151dc1e3866d513b3eaa9b5e21cea9030f2d32104ab03b647e48bfc76d48776d56275021c663fd2ae268695019b38f61617069b0099cc1416b2ea53286356431a8c59adae0e30fec13966b5ba78a250f3d2575c1879d2b112a22266d5d327d933c40209e916bbf2b17e1a8cdfe5903ef6783b9fd138c7ac56437c7a52dc98558fcaae563e26d2afa03e8517e891f4299ca8ff62563d49e44b7c22e2c73ec5cdc76cc9e16ab815909de8122710fe8153380887e2783cf7137243be3d86884e9f66928fcff2c510d1012ab931458082f469dee1e3af7c3144821c21dd98224794e8d3b4c3c757f962882821c4bb314584fce8d3acc3c707bf18223f868c6e4c9121387d9a483efef7c510c1517537a688aa479f261d3e7efe6288f4e811dd98223d4480f469cee1e39f7c31448018c137a688111e7d9a72f8f82cbe18223c78b81b538427d5a719f4f1577c314452abedc6145911c9e9d38cc3c7f72f8648cecfbd31457e88f8e8d384c3c7dfbe18223e7cb41b53c427a84ff30d1f9ffb6256413ea28b2ce283c88e3ecd231fff7e3144760009dd98224088dcf469bae1e3db2f86c8cd4e76638aecaca2e8d36cc3c70f7d31ab287e6037a6c80f237d9a6cf8f8da17b332c2e3ba3145781ce9d304faf8a52f6675a447749131457a1041f569aee1e38fbe1822289d7a638ae800f569aae1e3675fcc0a0887de98223848fa34d3f0f14bbe98151225a28b2ca2c42a499fa6918fef7d31ab2439d14516c9b1e9d344c3c7277d31446c824417f945824495f831446afa348b7c7cd11743a426155de417494595f854899c6ed1b1c3486c69a090f6f876cae39bdaf48ce27b22f99e475e0c7f87d9d3a78ea2c19984f83277c81520536706993b7de2e9936ae6fc98a9e852fd5b22113553054ccc1e2b3c77e09b2fc92d5ab470520e71a7e2665903cd8e62ee902f19c779517ccf1dd8cb72dbea176a196e35527d1a1452756a90ba5379b21ff952971057da6b13bebdcb7e6aaa02d1437cc1de7ef7f0ed178e7cc1395f3f882aed389785c79cb8755df88c76b195dc762bfcba97bd3ad545f10ed5b1209eaa77098687f8dd7d887cf90891bf1f3c962cdc43a957ea75d33ef92c34ebc3a51216125fa4f2011df4b0047a8841cb2ac95422954825526d2aaec2e2e18aca07c48a4a100e848aafa8b0a8a8b0b8498585c557f0856159c9a149450588201c0815151515eec2a850cdf3a895f9643d22950d65aad06d4075ead995a1349b6628c5421e0bc13e02f010f708000b11c0877bac13ff546809b52ccb2a718b9694505a4255688ab77f3ffce03ffc6079cd3207c001e0566a29992a2553693253599946e4d247a30b836575cb7da51c6acf79e5e4a571e2dc0baf1f0b8f973eeec142f0c7c24b9ff502ebd277e2f162b73c76aad93284f7cd2adba966a712e28b3105c6376362170100404ed1be90eba141ace850f5c3ee028528dfc5838a2e51de2270d0ef9c528ad3b98e5aabeb78fc85fe587e21065e7afd30e6d4bb4fc76399da40aed0ae41587878f9b01707b79c936e2699fad8e7e328b28b4f7622efb0688489eb781b256052e23abee4253ee4e4238f4e119ee7093d5d1cbe7df49147070a9e27ecf8f002f1e804fd45f22d059f57f9c823051f6fa3e481c30b64e2e144fda841685748009236c0e1f59bcaf9f67be4065d24d32b1458f0f9fc110a2cfcf8274c60a3f6c40a76de4610e0f8046aa7e7e62b143d355f5d6a505821e72b786138006812775d97998036d8610d769ac4d55390e4c2482f7dfe56e2d1d5d3a7128c6374e1b6e4bb7abe4b55e2e1c573f1f88cbe4023ec1ab9c8e98d715114b0c957af57c6e4afdbd64a1f9513654f1e63ec1463ec768ab4063d0f2fd0051a5d247dd2bcfd26e953f6b36121fecde3e6de171b247d3a7e7a77bd06e7e8c3431a5c01cd96ec67a664c72e17e19f29a25a903798fde41c622b7288b39f187feadc47ddbb3023ec25153c768a49c7d8b70b83614256bb30d5b34c3fc9ed77c3039aadd9a499aa87137565a46bd954f34cd984f20492b954a778b4bb34fab193a8473dea5112a703e3e382740abd010eb39f6c487bb6ea130dc93331441779837bcd495fa886037084c20a385ffd499f24e1ef26b9516ca47c91781acedc0f524792a45ba8e351f80810f61740a0974a1866036ca27906947e4591af1517e60aaa019edec968b073179ffced5e201ed8e4231430e8f9f0027531583a77dc755de732eebce8bb471aecd972833aa5635c3964610141af198573386fbe3dc505a201aee9535853a83e85978f9505ea537ca246890fb51d2db8a74f511405dcc22f1f4a748b483553da7d7ebce807884815a4732bf1c8472291ab1f6191aac1b6f3e3781afce277a806bbeb9458f5f8f98e870d4b60f3d44fa51458c6962ede1a32733d9ccf9d01a6b9481a6cc721ffce00d348c721b5908bdc6a9fbb286412699f492472f0350f89b44df32812e550c78bbcdda4f929f4736136939667c0cfa21d37e82221b9742bfadce5877ff01019e010ff98a4e833495fe1eef1d23049075fe42493cc32e845ded2453bfae42237893cc43f91e4f5c33f0d9a4479067c51cdd3ef59b7eaa49f2fa9be9a297dfd7c58829b97abe9a28c792d81cd4b276dc0868f6280af9c7c29d16077a86f80f4eaf7ca5497d26bf59a437ecda21d3738bad4ce638b5dc594f6aeb3abceae3abf31c0dc4f835d53f8ca408185a09f5e6736cd80a29a210d760ef9338b7634d89213d2201097c6895b7efd48243624128bbfebe71202039c1dfb8cbe2fc021fef9c62c882a3d5136387f978f44f2b873f02bd07772e2695f53f09588ea7d613821dd12fb4473ce27bc822ed03dd2a710a7e27a6cc9710935519dd26e6975199ff60ee81393f850b5d3efc6750389979ed74f76cd36c09f8ebd8fbe8d52768c7523b9141264e5ad396296bf40348718d8c95c9f94ed0a852a79ec92eaaff67d1e6f4cfde9a3c49b5e17e09a69442e72e9e1157da218552c4b85e32ffee8a37fbfd0fbf00279f4b32bfb85dd44713d3f2c1fc62461093cf954b8fdb4d14745357df9f4f593ea16ec555577aac10f6baa8d10b2e0ec9a72e8bd8987f1c7ed1545019b38ced3a641135f0286db22268c1c678a8d403af524f08900bd79e9f7c260979f89cf98269de3ef5e5114f0059aa80b7481ac3c6de6cd058a497a481bf9f66aa5e491a03e59d583b60bd4e09c77070e276ae2f429be5dd9153645b14106441510d7a13a54ad18775dd775185b9d8a2cfbb94752e40b04c3310cbf2d80f1897a3a8506e63cec2394848079807f6cd0827f644a0b016308939201c89a92988722882f978f5c69979e449f4835484497ce2df6cc2dfe443ea21eeca1482552d9d515547de4cbe543ae74c9b11cf68b540db69452caaea7418f2484cbceedc84d33d269ba1b1c9ac7ac87b0cb820b34511768ca974e2557c20ba4ba7c20d1a936c7b8efe62a924f92d3ce6d97641386956003f808f09ddc999297f88a0b538261a5dcdd945038ec50261f0c9614b0c0f021867049c410308618800b0163086f223a9c01605ef2167e69e878cc4dbeb0dfc4e5a581b9104374387dc23c0a119a7829773677a6c431ff2e0c964b7277d360df150479f5bb2c8f4495f6ab022cc4d744743898f4ce46c69d1179e72c2e4c973b9cdcddc49831314e7284fc501e09659292bd402295a8a74f599f4e24959853ece3c5b24946015d7733e3a600871dea22c97eee917b77e0b0bb40dfdee15860b6a0c422a48c973f305ebee86487faf62e68a5e50f2048401a11bd568ffe0410211f77c46003c4c72780fc78146c6bc536c3a123c60b0bd2c39241a6d4c169b03df0584a29a3dc913a335a1f0eba7383ab875267c7b70c79387dce194ac2fa6c684f6916a30cb213e3943bd2da693048741983ece8c82c77a28752c746832dddda9198e556a5f1d9030dd27c5180430a76cb06664a4b1133a514d28f52099f53feaca656c4b44aa54ffe489e219dd213a8e78d7cbb65dd197901948f34d54fd5c3e833cb1c993a3382a71f696296407e00016d000838944a0051e247caf278fa1d21a58fb752ce2feeac0055230a820151a288131931e4d38ce2399081c1882143bee6021c9e9c38ca9d1edb2ba9f0fa324047c9a33c9ac841cdc72670a2f8958f4de0f4bc1cd2a799697400d23d1a8c7ec9184f161a92d00638fc5f1e4a9e6bce39e7134b50cd39bf0c34b8073d5c549873ce29e79c524a292510aa874986b8a26ec93ee02764617e360a1c4a1ed933cb30a5cc69d0af705e975f32d34c0f3dcd257548999074eae1cc61098650343c95332b61a0421f5e96e02dc76aa6b111b570f33473206a214ce2ad1cced7c2cd35e79c53d4c49c73ce7615b287467a104f5387449723587e89cbf2612e7c444dbe9556a8d85c7e1c0bdf363f49e94031042340827ccf748e7dfb3a177da1075ec4893cc723dfb09765461b46e1481ef6ad73916fa36cf2b24ce7a21c5d3ab739e90b45ee5dc9c679767b498b699b03ba2cd2c1387bde324d897799e6c4b78c83ae70eec49d856f272b4c3c856f396c91c2c4c4c42445093b2772ace41b76cea4e4291c2bf98645394c5162b1b9dc4ca56cf21426df3e13c76d9c4b9cc2b9cd5338e73f6cdcb6c94c72994d322c5c3a8bd1c85db0701771e42e7c46b370176ea31123f9851e78d97559e42f1f27397ff962a77024972e1c8585bbf078653c7791c3917be1c83db7de17f6bc35a66d2b728ee33807c2bd8f66e45fe79e8cccb84152d7659a91b3702ee3a03fca2edc7dc6fce1c3bfc507e20bfddd51bed00329320b19d2b370f7ebc204e12c7c4607f179370d7a9bbb5b970266c1c2f17f9f8ebf509e77e3f1905c6ef7be307ea1f09c41a32416881470903e85a3d4a73c20a35474891378c08b672f3e978dd5f2bd7eddb8e6b45b5e5c732d8738e867df7573d9648d8db0c0d6282ea3332699eb99df9c819c833e7dec6220d52090ebc65e289b4aedf8783a12889c3caa3e490fc8f452369502627582f4e9091873cd2da7e1ba43d6c81aacd5cf71607f040e9cd3f7ca6c92522a21aaa4e40a13b1095088297dd5e09d7055eda48d449552489c99725353482f55a70c03a0e670a12a2a4886cfee9b25ba6badd4ad2b2809109035e955a96335630cbbd4b33ab232eaa16ffeac7c7c42a14bdd560c5573bc1bb962793741323eb963001d1d1dcb4416c4fa60d54579bc1b6c06df6eb52ac343181156904cfd8c963e3e08e5a939da65dd6b3ac11e963e06ce5482cf2cdafa657fa15225ef97cfa6a84f7c51ebe96799884d88537828624a7b4a6e410915dba9b6bec8b8fae9675332be4844168550367d9eacd0629f7a7cd4f9b8f32d67f7c059c1a2364d514aeb7632e9a5494c439ac47462d4a730ad9853c018a5740eb8c587b22ccb7c46d31bacb93dc0eac747b5a3930ae5bc58f64ecc7e4b18c02d03e42564b87d993a4bcc544a3577765ebe48849c1726bb9cf649f3eb0af9e556ea6af1da37854c9f54c811b14e488582c8d85b488287b92e14b074ebc260d4b2dc6be656d372dbdacbb7552a2d1717a6e6cb042cdda20051efc49937f326c7870f162d56f4079bfa0108f0b2498282266ad6cc9a152c260c0d4293d892d87239076c4d7c854298635ae88bfff28588b09678f16b657cfdd33e2fbd6ab0669b611e0a5dd865592794d215006c0062d65b7df92e220010c2f4c5ebfcbaa7554fc0d2c3567d14a25d647a91b237c70a5d2698b052b4e5c5e7891356e8e0b0a29e456d026e16b7775a842578930a3c1a799bf6f251186b522bcb2e6b6dbe4cb83ccb564060ac4943df8d12d4fcbc4bc032155da84f9ba249f89953a4ccad8054d4b35ccd6e5bf516fe4d494bb3e5c5a33b8a0c9732fce59bab25e6cf4cf9994133058809d9945229e567699db57e5953d95403e996177fc956aa6d0ac6ba4ae8596b4c429db3bd544abe584a902d3547a6f48bd723542278a9aa042f7591e0a55a66173f1042ad9475e4089611ac1f45c061cda93947e856dd050a107cdea62e11ee1072ee125708370836155de8550208f70718955d58babdcc2bbb32ac9006049424c90d0f1c9c24373c70e485095916ce6c39801bc05b35797476a28a958a8e4dd5b709b00ed6c18d5558858bc495765c04a721e23460200c848150c0179452b7115d38a7ee011c7dda9c6251175d3c92fc892e299cba1c62e294523a722ac2a1945e284a29a5a214a554d443a90fa5f408a54194d2ce86d2ee8652dafda0b44b514abb1e4a7d28a54728a53488d2910da57474434744a0d44538b34554c3152087dc87229c6f17f1902f2323c49576237c7b28b2c1b78b52a21ef9e21d11f5f8cc969a23f2c9f139225f3c20a023df2e0a9a2d15350051d010a2201bf9e21911c2e6db4535b3c5f361c9a29a9a9bd9e2a5566e0470f343be783d3ddfaef2e3dbbbd48b5400523df2c5fb01801e9fd9320a4af101bb23f2c5b309221ff9f62e68b68c7c2610b90b1ae510ffc846be8c506cbe7d74335b46a94904f932ea912beda39bd1cd7f990898e710b32c7cc8ac0186d51db5a6d6603cb22c0a9a244946835008090da241a119bcb4402cad7e67fc6ba6409873edc26cae5d6dfb7260d6ad1edc66f520baec20be784ba09c08032c6100a02415256b8e5ce979cd0b7593c3c34804db02057dab224fdcd18940624fac28f962a910577a8810941315557368dc1560e992626b646580cf06e9149f1e6e53c2b76bdacdbd34ea6fdb85b17cbb31fdd5729abd6e3525fa6461564aaefcb07c105f2e94bc5040f8764ae910fa437fde27aaf4bc04b1e48be5425cb9505e48f556ade55e802f8dfa2291486423ea2e4cf5ae73c15b387daad6a7c19e06657c76a753daef67833408c4ea44950b35ad15ac13b0b0597e5926ea678134a8d3759a1d89ba91472ad10ef049220cf021e033c156c7e4da6c2aaa7427b5d085b252dea551dfca548877a98f8f877a0bc70709eb215daa22ada084f2d09d9d1215e4dc25a80f1f41a88e8e663fdaa7b8e32d1fb3e54586cbf8288a2e416b5035dfe3529c1a3427f87584a441fb79059a2dde0dd05754dfc897512aaeb47c19f9c4957e718c514952373ff2e181334272320a4ad2a7396fdd2a57ab7fb1e542bdc87003b81be093f1bd7cb13bb7f31b251921090a9a39a19cb94cfde6b085f55ac6dce6100be59a3b623e63d2ef8851d008c928c934b9309d4aa5ae7267b8153841a4cb338ac8a3e2ce243389c4f49a35b330cd86b6cb75225c2279262529fc4485b3b831d6af38b18ea46cca948fa83029c901ca710f28458954519e11938a2aa928cf88973d9fd962a53c1f9f14e6498fe48db24dc94e94ea9e9e9df7743c2de0ed7a373fbc9bebdd783f38cd0679365bd00df26c4299e573c4c7e70866751a04929a2d36488f7cb149c872687ba6e5f94e59267abebf5e1f902e0c3569d6f6e4c09ee2cc169e9cb74170befde4d2a86f53a915272d63c956fd933f0011849b4baab1e5a4b527ad12458b7d8a32c95f1298279ac49a9f5c98eb98dfef425d3616f3ad4f18664397cdb5038c7978a150f233bf5994c25a7cf9f2da1c7196c9644e83a54c4bf912bf6bd09a1aeb5af693391a9ccf4597cc3bcb56da5474891ffabce76c8a26e499db13cd7e31bb6cae1bec004efb002fae692f9f0582add0bc948eb5291b36b5011aa1d087e387eb81209b6ab034b5206efd01a617caa66c2ab3a9d4954a2df1e236f502009b4a02001789009452a88874ab1eef0c0d1de00b9baaf3b2762c9d3958a920150614a11240f6d777dd20d2205e31882e8860bbb5041dc451907cb950570b4673f8f615bf799c9aeb64a10a60b933ac10425c987a3dfd2e14ea12a2ca10e2c68831440b70fd9678f1f9e2566ab65c17ca4a793c6078371e4e9f6af55297553f0fc7e371f5f06ebc1b2f355b6a4e57efa449ecf168b0735072dcab4dbd41bda828f0a600bcf17878383554512a0a0c0e949e66009785e5d2e44761c090df2400011a65337f80b10f2fd427bf7e97cd75d372a15a6e8c5086c5f8eacc0cc0a5a1a26136d3ee9671191675d9c8cb48598949cb016c978a750581c18d207153028ca03efd221136c7981282eca9fc26206b6a6ab45c6307e8178af0d35409c4d7f1212dbb3026085cd79c023753208a944013815e07113a8890c97658d7be1d9a2701df88491ec7fc284458dda251fd0aefcc00fe726b2f4dab5775abb3ee5077dbbb613947ff55ef95997dd1edd2c046c8d17fe5cefa6a22867fdd9939a3430a4d3c758ca65a350b85051042567a67744c2152e1a987ae4cdcb1b6659c325239cc5aaf2b9b34a4a77686324d8bd1a5926229b660ded159660b965150b04d8bd1a5944214de99397381efe9ac6fb9e8b66ea11a64639f2e1d4fed152338d33eeb4fbfa8cbd09a232c3f624576fd64ba2647bfb41c0746bdda90d65786be3593c4d3d095e9db80a6a1e32f8d6b59b84f3466cf3070dc34623aa53e6708a3b4d65a2b267d605868ce6bdea94d3babcfcbe7e633cb4228de27a559a7f74454a942548162fe00539e6aafeb4376887ecdf8c2609e65b5d20c73ea180d6e503a124992cc24745e57c6df023f58adb3abc473665e20f4a734e38cdde69a10e40940b21a6cf32e3e52810b40df859dff3e52a10b3d1edb7c6857e1c5f3dda793ec4214fd3df1f0a1f63aa99d54163ef23ce1c8db958f8f3c416ebef091070a4e78bbe2220a12b226091ee090ea7ca43f7680638a001d113244c5e22baee2a07fde638467f5e3e30348fcec272bdc7d73ce6ffcf8f18bc48f1f3fe49a973c7e0c91cc4bdc73928b3c7efc683249a77e79cc6ee2d15960f4495ab876a889d22791aa41514fa744c79f5d4d2379b02b8c7f6a4cf01867bbb24970879a2dd9cf4fcdcb3b4827706857dd92a932ede7f10f0e71d4c72ef3b583d674aa0660bf7e1aac76d5a93a55a7aad91ab140f8e784f3122730827418ae859daa53753d7d32d597d9bb7c5c97b5d6c268893d5e1af3c2601b4f23abcfe80e35310ce352c91d043b548782c1ab3ed1585ebdb1530c8f591beab0daf5d54b394e24d242df8c60b411948ecd16ee44be748b9726d6552d5a1bb051132d46178bce9626406c57e636cf768ce068b7ecb8a2472ae9cc94694fe12642de9a236ea7ed3461b0d26546a3c480ac17f8f83c7c165d2215690d7a7cb0290f2376c79e221a8c32a6944e586be37589bb29cd68668139e79c28a17df044338acc8baf2e29cfa43c73d226e88e0568139467529e39e7c4a8cbdcd78591de97358f50daf348d6d96cc3049a6d902bd2abcf23d93c926559671dca4e9c7eb4564aa90f0edbc887366a8faf2e25a5339a52bfaecb6a193d2c5943460ee4ca473f19387225f74a460ee48a8c6f9168193d1a94d7b7f5c5ac06eb0849ce08f66a018733baa7c148a9b5ba36587dd21652dbe76601db3caac198055cbff38e8f7e7b70d8361fda983d2716ba268a2456c09d431b8d29f1a10ded5ec16dec3ca35f2b1061c8cf909f28cb6063dbd8d6461c1cdd76474adbe777cc9b49867e7b7fe70f04fdf4e936d658bde5d547f52c3e42e144ce370ef9d32d2b0b7976b97565ea311e7183fb1cf435c741bfccafcf6479c8b3ea570de55b167669489ff13b46972372d0bf0da86ec5eaa619f0e52934551a29dd54a9a97e178c65b5e531870674bc7429dd8439f896cc262ccf806fb995411afab217964b6992594619e068b23c7a683968e519f0b11c23f732aac8170d463aadc48060e3e36018c625efa7e7215b9d7e5e8366c0a1f7d3443d1375cc2b75f0ad5bd95e34a48732b7f4b33c4461accf98a14fbafddaed9c58ca5337814fb38c06e785096d65c0210fbd2b93f28de510fcd0f3c0af9f0cfaed40a17d7e52ac4fb7698326c0f4de4c5bf0e363163e3e81f2791b1ba4ce021f8f1ff3cdefe697f3bb39966d7e33c736c75468770638948f79b8d1edfae5dc75d074336c7393f48dfae55c68a20ee32fcc966383a60b73738c131cf269728b13930a151897326f10fbb06d8933e65eba30389bb2cc33ab62cfdc625ff50c9bb2ccc1ef1c9bb2ee86cc448edd665f752c3261bfbcc30ebee72213ce33e07b7914339177590b4d598a0b63caf20cf89657edef9de1de7a8ba2c52befd72f398edbb8bbddedc39876bf50fe8685421ea2dbb66df7ba77616ed83c3f3d6c0fb52c6c5b1edd065cdfb66ce29aa74fa64dd53d9d69cb33e06fbe6d5b8e11a44f93e6cec8cd31c7fc6618cea43e494f5d5bf1d47f78ead6ad0b0efb746ff3e9da9dd8b9edd6d8366ec3b8cb6d58b328daa57fbff0ce6c8f5d19ee31533fe7f3e5dbd932d2f9dc17a34fd2743dc686f975bb7dd5ef87d5eb7e26ceaf8b73f0af6326ee37180d4a9ca9592daa50bf37c01776914ff7fa4483b51b5d30bfc1bdc8b18667b20e7b0ef9385fcf3ed11766ce79e8ce6c8e797665b2eb587ea2053d3ebae1e3132c48bd058016fb64d2a28af4f8e1bd64e68725f8ec98cf07c286322080a89b6d2ceb0de790049f65eca3d3aa146bf072d7b79b31edc3f909f4a16683e53318b43b99cf60234a68adbebabdaed962edcc14cb2dacc32eb2f2e5d82d8d2e292ccb395bd2a0f8f1d44d4c3f2a2be83c750b736ec71bc1f97513bf26265ec25c3ec1e3a57b2eb8f9c8858f4fb420880bedfae45bd045cea10af7162d4e5052a43071d3853129b98949c96462e2e09f78c9e4c4f4e1a09f2286e9c474f2c957719222458a143edd9402c502a1c9abc2dc6bdea7ebd1a44285fc128e73ab7467a465995c19ce2dceadefcae85d1afd263996def218314caedfeb9a977c74614ad974f30cf837bb2abce4f67e99973e155f6c30f32b03acb9a9046a2507dfe42a726cf0665329cf806fca293e1cf44d3c46549126d974433ec973d037f11bdc9b78ff7513139f3eba35a89b64f0d220f9c82d00346ba754c278e7afedf2eebafcf2e0900af9ebf23208e9d314427ffa3424bacc50b7bca4248725aec2694f9fc2ebd62f9aeb9c5f4e557de2ee8ce441f29873ceb9f5c5dfaee55ccebc3c4ecba2c9e872a1c061dfe45c3937e4737e6f80356f1f299ca6e426d1c5e497f70eecbd9ec24ba64f3ebe354cfc9af8bd267e7d469b4a9e437e899443154ef24b0ec0c2d0a27cf9eb03b834486e5734195da263994984250be80d4dc971c837711559b2e0f2c6e95329df9478f4c924d394dcc42fc726ce5d9992498b26a30b0d1a92e3902c98b70ad7e5ad449fba479f42cfad5fde3efa44e3b9f4cbb9edca783936883b24e3ac1bd6a0e5378717eb93e598165db81fde5a11496ff98d2d7235536eb6c1f2d6e9873d81adc7440cc36030524853f017a57e4dbfbc6dfa14ffa229882997bfe02fef7288d5e02f17e58beee02fc779457744952b6fb9c7fdda4783d5b5dc3d1aac3ea3ab830d520cafbecacb439e5d7906fcc77f5d1786859855338d5592b909415f63f9e0a97a81f239d3b5d862e5601346b74422a2c74955da0c7a2b67b648a04e69b772420c77cdb7ca041f621fb6cd8dcc6dc383e313353a1fd2206d13a44f3b7da2ee1f84e2501cb0c15963f9dc90411fa30a75533b675ff42952f0291656df79067cea7e5d3497cb3eb54f9a30fc807479e5d0ca37328df49e3e6d6c7c1c277e9cd8f196935a142101b7476fcfa18150c7b7eb78d30cf81d9d4a1c1b8da0bee5bcbfe5968b28787a9c2f47e0c05ca301ce5f97d31912fce6f40bbbba058ef87048b06d785d965f34d77406d45be37b2b83180367a984310ae6e10936a37dcaaff77ae657e6a676ebede1753d71029d47f9f8c40978fc8e8f1f2975ab5e7ed2e0ac9139cd95251438043ff34903947569d40b739dc021bd4de01003bf65ceb9615e4ded21f7f78a32b5ec0da29c6cdb9651a8804d3468c8c7b2a91da32fdfba4630cdf2e9783a29ba504a29a5d4e793425e7a883e3103d5b34c9f4fcc60e7e79cb305778a749aea38e4d3cc2f9a8c054674c17c3a01a28b656135a85bd42d8b5a4c2d19eba64393da1c3cafaa0f39c5b11816b5cbb5abd6ee1c760e25776bd8afeddb8dc16eb5d7f8b52deba2aff3ebb33efa2e973522abfb01d7c76aeb5e8b2a416fe61d659ad93ea3a90de48b4733fd7a6891dc22658af3a26c67579ad90db899da209bb0963b5b16e2dcda1cca5cd6bd578ce7ad7925935c9249d9d62cd2c1d635efbe1b539dc6caa10c55ef9acba9553bd7706c99cba19cb39ca9263667cdb39340c2b2b2121f5ac7d193f2902fd52fdae3431cd6cd34f4d69839ecbf5eede536c4d139a4386fddb233d3b45fb7bca68d5839c48161315ade8ea35edfc4aecdd579c895abf3d13792370d5e3e5b646aa6500c94baaec1c06c913b34ae6a8eab9db80a8570871c679aea9cb7e75072a150366d3ef2cbbb66b6c89b9b52a9fd0a45a32cd2c1218eaab97563424ec3e550d65b43fb90cb9bd9423b85ebbed82097db45724543580b31d77e51cde985d1eab6d940be5c33c4115afde538ea7399a686970ac796193385c6184339ac5ffdaa7593b15dc22f31201c5ad940bedcf4295abf96778e98e2f8873253a8531097628af4886915939836d80b885febea6b0e7150abfae5f6bba665591e13bd7e5fe8f76a57d49c86fc69e9316c5e98da12574a8dd03eddf2183afb8624817882444271700317bc0443ac91d3e35d3e427185d55baad11a238db5d25ae9bd010ee987d46b749934d46f704fe7ad61f9b47cd26f5ed6375fbc38627a688a2e7dc63c037ef498416a5d1960d3f470fa049f3e8e1733f655370b0d9ceae347f9d240dd866f0fe7cb0c237766ef4820f922e38a049ab453da2b4b8e3b6d9d5456c65e0983da56b9aacdfbd23672657a284ff0f39753cae510f796c3d2f4fb491e9b906b39ece9f6d2349008dad371f769bac5e46cb91355a6df1d6cb99535f646b18f7b9ae5fc422ae39c5b58028c0c76064fcc00685edaf5189ee0972ffa64f9636083336b588e669151c404306003891d373d7280ecf4cffe761821f4c2ce3b6379e7303f754d7a21ed8b3f2fc6befebe30367b3b095ef429e4d33d94c106a7d39f975706ff0df9d6e5d5b199ab5af33600cc218d72053587fc503e318324df6ec5e0c8774d8d76cb6fdcd4d4d4a48088e836a4d52f267ebd9cdaeb9a2cbede98167fe51b2d9eba86bd6870fa498373fa9d020e51be1483ff860c7a2a579615695bdf352dcbf2b6a665c93ec4c83efc95695c2eff008fdd1804fc956f20e0a94fd974abf903fd392c1955e444b93613a5bdd4ded52fcdfb440f25ec03bb317ae2d39ad567b5aac7010db3cc28d888127a3d5128148a5ed3d230ebe3e3d1a86e47a512c6b44a8b594c6659d0c85e3b38086f7767c1c29d4566e12e02d4e3a43252c9d2207db19a3761e879ee2315c0b0054b637ed12028a341ea3162748cdb065cdd52409f62e24b06f4c9e40f583df50974066cf4298c43be9d0e89c28994ce7fa0ec11552e1b30d8a728678b8c29edd9b7875894821a11e591d029176c7ad84001831e0fc50b787c8ce223142ee8f1968ba74aad24348f19d38b1b4c4212814ded8b4d80a761616eb944bde5364a262ccfd4c71ccb965bb4da18f298f8a16cb24e93a7b7eb78eb0bb55086381e73fb85147beb9a3a1efb6c687f656b06b942ddfa664ccb49258080e3f3f1091ae83ccbc72768a07a4943238243194fe3169eca533b9df15bba0ad972ce7cf2adf0749f25587e43afcbb251ba2ec77268a364af2f7eb441cf7114b06722b9e7d5adcf44f2915b24af7f3926c5244fdf734bca262bcfd4bffccad44a9c21d1a0e7f51b7d5673cd6d73ce556b5e3994a35bc3bee5dd8dc944da7589fc72d185b93a57f149c7bece577c243ff1cd3b85e9cab393c018f7b8b0351a358f8a476e851a06f205f3aa2294c31cf68fc2bef98a31ce98e535e424effcca337aea945819cb2fbf4817f619135f1dc9b3afbb31d52f512579a9c4c2dee11b63390daea1bde553a7fab43553eb7252b75d18ae8eaeeb721b6dd5ae2fc43f3b09ab7e8f0f3ba756e724cb49cde3c3aee21cf6632b48def5cd778ea3ffaa13679acb6d94acd4eaac2592755d9787b02e5bde3653c5277dc5d779463f0b676653de72ec1cd2aca44aaad86c993a27b9734c39a7fb4c8e39e7f2b3a61cca0f4d9da9fa39bd61c0719ef54dc340be609666e4d22d6fc0485aba650d03f922376a31eebb309cdb2ea3728479f74589899cd33e661c1f9a2a48ca217ecbda3ecdfb3ae77cc5e5f19a9110c630ee2b71bb61dfb0e5592227652b87126bdc8db17e9d5aaeb9a659ae591247a75122d387bd495f883b89aeeb822c93f591aa7b5eae9de75d0d4e2b225f4e3cef9cb4a206b72287fd9e6b46be7af513cbb96755e7328d97358f64e21c3b163a7692d57516c931ecf6e36ecc0ab732cdb6029b50958a14d80a8cf9e617bbb602a32a8ca948612f0fcff22ccbfb2ccf2d1289e4da8a14f421d6916a6decda4abe540de8438cd479b97aa819c1b0639e87384839d48c90dc735248f2328de59d933c2c79d83658ce93484ebb45e274ca7412c9e395e9dc721b25dcd1f73ecba5731d96ab6b2bb9c289dcf4752abe10a7f8426c7ac94487eb1c5209a9d692926cc2de3977d3393d3f7deacc16893353a64f8c757e5aceb90a910ec93dce37bf483994d6ada17db5e1e5b06d9ef3b07370483e5d2b6279479aa41cdaa81766ab8fbff8d66311fcc8edd4b42222e7dcc628be5a1e4e5414342317b9e56169c61a3937a28f45ee7d61dbcc1d6fc5f896862dd78ac817a9191169dd1772eec35cde18db751726e45662cc5aa971db17eaf8cdede80b250cc93bfcd52fdcc0571f7dd667495f4c7c92f72d221472528e0d6212c963e293b2a9731a925fde91fc7252be1c731d3faa1de7231d5f3f1ba51765ad885ce11c7f33a66fdfb521cf42d827d2c1d725df244f6fb8de721105ac5794b2e5479878cd804314943e69d86baf4922189f7a8ca70414410f118c1f3e4a9d6290521463b6599020ad2353fd04990ad24122a5d246da48945ca1deb205d2a6067665cd2057be8a87583344bbb2ab21f2e6d8040e6ddad0340f603d503ca5045ac710f6720147ceca28658f2a47891d35ab21417470782009f2e9f99183da6164b513a4074e1224427c585e4495488f541e1f3d7ed325e6d3f32387a2e80e23ab9d20b3c7c4498244884fea47a3808cf0ecc81e5124893f423efae0ce7e7d70cc5105ac31288c065f7cf5c6c86fa71b4b54896ea515675f7533c958df4ebf735802ad897e4202118306078b9a73d6ea57ad94966634129ff99c219fd17d93612578eca662f5bafc6b1bda30902bd42f8c7e7556f77861a663d5aa3099ac43b05647e963c4305266241a8c2e4433a215d1568dd28a344a33a219c97e6444c872301f1911b08944f663663f1aec39b1ecd50c3fb833fec1ed21d61a94a80f6dc428681868832c7db02ffae47284f4eed859ebb05693f4a65e290e204ba39c528936611e73c5c46cca413ffa0dee63f690cb6cba217f7a0efad26f703a3ee61cf2db65ce217f86b07c651a0b87fc8a437ecb28584844f8421158e68d56654a78b2636a3730cb5b1fc5a20af5793b3509145bb49852bdc61a6b7cf1550e91ab4b0856d32d31cea06ed1513d7689de509cea584baf4118cc597eae42bae36bf56c26e994dab54fd1d25a6610ed96beb4d812a366cda0e9329b269206ab376a569b675083f7ab5f17e0cba7dfd83283664af5ea5a74a15e29eaab873fe490d67cf57045285bfa7941b3a55132a57aa9846bf54c9ba29005c552abcfcf1b255f62105b36afde2e88a7ccabe621677279d8e2c346cd78c594cbe777bfcbfb5efe967565166659d3bae6ac3e576b6ba0914eb52b2595dff4d8914ab9848d28b6c6c4ba3f8c520fb5d38cdf9e07aa3da5d3bb7a0dcbb18c6d80e577f61aa4edf3c3dab5be58835f9cdd269825f922e38043ad145dfaa9fc1cf2dba98f1866344c31e58c35ba44c732baf4a4e13f6711aacb39ed75c98cf98c6eaf9ee550be9c31b12f9a6aa6dcd37c837b39041b25605d16adb50f807222348f07d0f249a7d8984b0d8642945a9a5f97f7090551aacf6a3fa7f7ce8ce02fb7e69571c6421ebaaeecd1e0591dbb2c4a670d62a3043ccf3b89f1ca5a7ca6e0a827d657f23c8fd52fc72ec75cc69fe6f24a27b3b6e8431ffa2073548cded86a69251c2f7975566bb6906a715935569831fefc05f27d8ffb14bab164ff20a26a8d0e4d01ad70e68daa779204e5481f3fb4d3e697bd1d61b5667461284dc28a88a8d6785747755644e824592bd185a1375306949bab923a6f705321480edbbc31a1bdc3b52a48ca81de0b334b3368f3217da005a5b817869221d67c842c79aa429b9f89ce39db634a5ee6c89101fb98b26de68ffa8dc9de930137066e0c9c183831ccda848d40609c8784f24723cbe22669d2aeab358b1220914623d7f17613a5644aaa66ca74efca1d4cba4c88449e6844ea481de67016ba12931e2657e28c66a90958f268707a69de703f248d0b4389c68181fb42499358c433a58043d18e0a151746b4d3e0cc225583d3791a34a5e038ad6a5bf58460ce0b2a34ae0b261613f52137f990f0c074131f263e98c52c66318b596c94bd1bd14e57329d746746deb97761ba924ba38efcca9a152c542db2cc080bfc640003f96e80858bfb80af93407d1af9f4ee93311530036536509f8e748b27c47ff07cae0ffcc34dc10f17fc61f4c5a852ba3322af6e7269e8f891d7ef874be3d3382eacf285118d465dd775dde807d1a8ab3e5d36f1a19274a673929b5c185297b15149c465c18526b1c85d8c465dd7759d68e433da0510a29168c4f9f8fcf492af3453a68397891f80d0ead74004a1d54f06016af58b5c16b0f470db79916252424af146295dcac9567dd4b997453eca9746973126bbab559d09b9854fb616668bd73fb320670a28e57a288705ca5d21053852a7dfec46526f2430b3108d12c3ae904653d1e5ab947256b82cabb54f4d74a99c0a576db646c46613a004184196634c699ff30b33ac2d9061d9b7231322cbe8cce82db7214ae90c69d4a511ca40e79c2d8d544a8dd0b113b2e2b4bce5cb559a4194664a1741fb149a5186faaf56fbf328c6b408fa8422a28a8c2e326a7786d2681a2cb308b900e900190109b6631f05a24a3bcb6ca9405cc319be7dfe405544b4649473abd60ca5a1e369584e2badd572593386993b590ce87c2a5f269d73c092604da89ae658bd3cd35ea0684eafcc62167667349f5f08fed4bc6a3534af8e695f88819a7567464067a40d529a83f5ccae6661811143c60c051411dbb1b8e139a7470f799db9809c1373397b622fe6c415cc50507c2c9b8bce59ad1158b557469fb0d9c2f946afcc7a7414f0857cb13cba0ceec318e63385469df6937fad873c7467accf2fccac574dc67af5cb76752c94298b0c86852af5fa5a572bdc286059a534838d289735adc5421b8dd1050b794b8c6e01674a3bca47af51a8c5b00b93398651166c9be6d79db14edda2d5adf5d47af5398156807c91892bed7526f2d0a88fe52266508a882aed72c7029261d151a2cb8c71b1fc30e79cb9c05f8e7df1e47df8d46a85b08b466d25c43c23c16cecba2c95ef9456c0172f4c70356d8ec32d5f2c8f3324b87ed25cde94fa15ad8f7ad3395b8725db07b55a218ca7d66a85300cf3ccbd6e89a53a824a83b9e511b3602d4a27138aebb21cb3b4795dd78de9286f8c102e0bae98a486f5d6b1add765598f435f9631ef0b835d9775558065a64860f18d3b94c9f87282491cf2d085f94c0bc93b3367680e2fa75e69aa4fcc63aba0a8548c75b6518e4245331000006314400028100c87c462d1704022ab9ae91e14000e8aac50724e9ba75110c41442c820030821230020200020984d12007edbe83ef2ad79ea7765142410d3d519564fa420beb0d495b4b654b649ee800e8dc080d8128c2817148e2df79fda37b68f5ca5d3bf6a136c6d2163642a3d3d305d2b375c0df8089f25cec3d0c91754b87185d90ae7167e160414bf25c3dabc26b4f7b5c6213f268337ac2afc500e9bf000f6206415b8531a4e294d4f1faeec329d3f9890133ddb7a52e2081fc429a4330736dd755bc4da4d2f29bacfea90a36d9039519cf6be8a60bf02707527c2b52bcb9a34e5abadb7c92f680bdb193edb9f259c583c1090e506c26e37982542448e7045823fbc68a70619f70903729d546ec0a292fba8369f0e46dec20716b0751875f1494a05acae7a4c54f431b567469edd004f7b01b37a3ca08f399ae5831b98022a6f3c9b6d8460623cd3106e3b164d4eaf990f7af7cbb5f6dc910bf1dd9b137420a4fa68e6b57bb47700c5f139043bb97fec41ed05e1b17ab9db6064cb0eb69698f9e6d1170bf4755705f934dd0d2d091b2c7e2498305fd15d82b2e3b41cc3185f0855379657905cf335f6ae7d5f86a0988679aa836105408223e355dc01b3f3a09a48c8f2c908c9531afebcc98be1c09c918755089b8a504849a804bd65654978c63d8772a77a5437dff13d480b772cecac8a4c68accce6d7647dfb89802dc7f519a2c47118d1d60f2974020b15f6cf14fba5aa0d535bc6541557e808a6f938e1929d3d677f79e05224a504ca608619bbe9193cc8cc263289490c26c173a2f54b87d0e6bf27c0b804bc5d69f8fc5b12ef6b78aaa97d5faba49f589b36487cf79482c429d8f516bf3ab3dffc3e7b3063af6919b0d626fbc5eb25dcf690efc612231ed95aee9e49eb0a3de87179d187ef974506145dfe3c9b7f212eb5448a30d0d0e3755102bbf8ef6c881f2a39af708efecb0fbf3003a205141128ec298f98f4611f790e86a976261a5d841efd6dc9cef6724109fd411236f7114df5b647ce2f8c26b79e50add431d569d992435adb2c6a05d025c0ddafc31ef4d474e7c9eac2ad42f57c352f56f7117363628140c86c26ff85ef6e402b0eb0303dabc5dc90f08d2b545679cb3316485f0a21a82ea977aaa33ab0c42108c5edb9d41c00aef4e9ca4473479a805029477f5aa34fc25d52c1d830665bbde316e06370fa010e35430072d00c10c79594a81c8b99185c06edab4eb9451d836c212ea58ab1b7049989c44f2551213c3476f0944f96bce0572e64ad2a58984593b5f110719ced2c19217b25611291e76d07cbf6abedadaaeec697e4048381f7af0113d705ff623b84d437a28988d51002cf627109229577e0cd90834cc08bccea442a06eda867d21e40325401a0038b1e476efc6af61315e4121bdc7448c351e4d0c6c60d28305ccd4b28459ff8cc00d3a183e90bd4fd0cf91dc8c491a7263ca389987f25f77d45e40acab19134a9382964e8a85c133e2161276ad2f0d14d69939b4d5a850143fcf203d47924c4d701e9d0a39114542d298181aa99c10ffb748a45c498194596474371162baefd21e2ecec44c70c07948e1c1552d061bcae983a70a6d9ce5fe993829308c7c50ff133045dcb0cc99a33cb3273081f30412efce01a00cdc94bc4ea49ba1cfaf25385efe6c47fe4405abdd013b0b8240fb103b8f912fff4143d119922c353a046f78b8f945be77c1feadf1a1ba6b240aced2030e1c243a976ab50e613239ee30d5b80f58a573c48d4b9aeebcd7e98652f1659bb776881f2ea901cd97a4521d8b0ac03970aa98761599630201cf967a157f8f21b5b80e8e46e7fbf0849d26abce98ee4dbc12ea95b43671e403e18738bf53b181fa0f35c5d7b469efe8a234bfe9f2f438d625075e421af56b066a6cd087ad81dfc35321f11eea7168b1bbe908e69312ce7f0fd6a23315580fe06db43e4e187a4a747bcd47c2928ddd3d4e5910ad3607d2e1e9950a48a5ece16677820b7dea6b84933e4216b3536a17ba6bb1e42d0efad8cbeabed977585c8a08fe1c61eb1efe9ac6f4d927bb0c4cc68244a224a644117a20790f7c6c550f60ac5b495e9792476fe37bdc7b88808df9cafff0553c95af161d4a696cea3ac65a72b737266ef7e4771e0f101cc881499045262f80680fe141470c3e5e7151d4a81010b6b8588cdda5a647462a218638d91ee1c9887d1f01d9c713ec3128602e15fc0b0267e1c701c797b3da70b02ba59e886aa32fe5710d1a4ad1c8bce7f82da55733496fe8123168361db17eb097d1d6d7363c4a1f90ce990e3e4fb76bb84e1fd4174003c506358427ddcfd89a9554afbc27211af118804afe404a389daa695391de5ce399660f6a89c43c89bb86504fa8dc4279568c4f2d5d6c66ce518abc4b1310d18b48f14613a28960bfdbe57529763f7c974b4c26353152f32a52842a4c92b27fcdd4204417ecff4dac70b18d8b8eed13f50f53831a68702cd4c449183c5b66b23004b85e1f415084d2dfc19688334cef4a6532713dd6d447ed8c8a8e6e73e3ca99c7c716ec3e94c326a4330a7936c6b0d6322ca2c32964b38be6cbaa8dcd23ed9980baf2c5f3d9a2694e37490ee1b1848a0e27af54bc557656560c365479b788267e961ff1a67f406c4198f86e3f50ca09c333dfd3f0d79922ce89ce25f60c9e4347eaaafcf2b38986dea3d9dd94f87ccc65ccb22aa7ff8bcd121884007c26bbfa79c080f660b9ed40551a3fe80223c22e232ed00eda1f5a2a891535f835a3c013a490b96f3e7514379d82cab7fcd487d0468c1e1f60e922daa5140d5ed4f6faa117deb0603baa25ce9aefbafbd8fdf056a1ef74892015981d2c076b21db48c2519564516fd4f3d812d96469d8f9dd895f505c424189eff847b4af0cea716e5e565ef5c7862ab0a59fc5ea11ea69f5ee59916556668d5f018c08f1d2136f33d505beaba5364de6719ce613eea8c66fa7619ea9afce006b54b9502d84e4325dc1a05f05f518f08714d07ae2b2151f06b856878ed2fb7966814a477affe4cefe8be83ff29ffb67d9ce1308ca1b320ee3b2f3acb9046bcf6d3ac24d440744ed335bf53fe830956d0903dc0d1ca6473526806ec86bb2822afb7f4fed8c34465640f0f3ccbcdf2d832ac52adc9bce297bc11e59db738c9b2e075b20d40b04533ae8570bb6d97025f04b73d5f64488e24de212d7823258b38334a79688a21db409e350f3c3b73ea15c40f7a422ba261e9e93e57df5315cfdbd60f78ecffffc6ed2e60f990f974d91f2322d0fece60d91cd7680281ca132558fb5d9cac0bf644f3486a21f2157a6ef2217a1cfd4e67ecb0c7100e308a6af8a964fb765efd5c1d679e4c8c838d29d176423a545d9ebff0b49479aed76f7800a9a8aabe059bb2dd35e0b5486be04dbb480cbe6c5895071b4e827f3a549cd2fb217646a3e431b26350adb9de81dc5a3c351720b770cbb53d9694f12409db5f187e5dc01e0c345f055a4069890af2ff57f478e66335bb5d2e40c1bd052086f09928b8bb83caef2a7043db7e5f9a55f2f44729b1c8ee970c17480c2abd42b449ca0ed048e854d1577f9758f9494341232ffd04377637f50848fb33af6f64041ceb1d14eed3021be3f68c14be68288cb8bd97404863875e818052e9fa870945f4b37f2c695bbe59403a89ae8b5140af3d6bfaa369a4d3023d34fa7187edc0f729f437c5b0c78100e04ee3d035b77c93ddcb34d940340ae9a3f7c766b346f6c4a4c54f8c6f8460237ab6eba4661b30f1aeacc49f9291f165c52a772d0a7926f081d6e8210fd10519e3107ae0abfc1c7d40c57c5e135dd186a26a65255d7456871e70fdc87cae9f0b4d3edb453b2b1866a87bcf5a30fc9c915c6ec6f0463c1b53a3a5fd4d8a9d25f02dee95836ffcde95137ef8b09f03bef3b5470efce1bf478efbe3cb8e9cf0e5cbfe49be9e91fa8431b102ef313012c9feb563a8464cd623dadb533efba3d31958e22ee9ce10ffa9b5c4c7fe3914f72ad92fc7bef18dda6c20d056f6ce910ffca0e6bf95c6a20f3eefcac97b3501436c38d0a965ca630862d3517503e73e35c7fe7561d721f23ee03ee0034168dff6d3bae9b2e93d58b40c26eb9d13ae63052a8e616b9faf6f9157ed8167f3d9b4c0852e45c9dc3a29bb4b104432c2a3d0aa0c06dc72bdab44bf6e0104b67ce4468f80ef1d0666b59d4617c1cc602c305ec8a39da4bef51ad8072dda8467a965517fe82f49326d6e0f499b24f305ec7e8a34dcba8a0258d8d107750496228beabfccf2bf7d62489580807add801db7ba030879366fdf797425492f1f16d4d6fba6341dbaed4979e78481767bc92ef3ad1f4ed6c4fc04159acb02ce664e2ddb86fb78906c97f3d786f9b9ad000fcb168f5a9484dc5fde6a6608b51d77135123d212fd24b96db04854b41df733f59ea43873dca408fa2818ffee99a88512c13836e1572617d58412a1abac4e0bc8e7f1be20151dc71fed424d30887197ca05c569a61c963d0a9e8d7f3bad642a6485577e3debb06d2aaa0c52ae9251f1e235d5823af78bdc63fb023c3776c1f1d80b3ee780e37f4597b75c84bc6110af1d5dcadce81efa6640d75c31c440814607fd042f3637f7ec48f34f846fd418b71e817eb8853cf84a42d75a31c443a14677fd042fb16d442dcf95a59100347cecd0118ef467eeb7b6357da54b5e55004adeb64e596e58ce1b511f7638611ed68ae38e7d4b2cd70dcfe9343f5e5dea6925c389603e51fc59aec96006e007f369fac28cb3dd670213e87c9f83ce4cf496cccf5841f733ce3747d2fbd00a4e331de23c7ec9e798ab16be053ab0c13a3c5afe44ce1e31b71a369397e8cb9ba556d627fd68abc54083eb7d77c89b47c97ab48e2f749d6d3b876762b9b5cf2b3d687d4c098a0f7759bdc42d44903069cab82171ac96ada318773a743d0df11ae8395706feb417a745efada0127ce304ab2a0ceba59105c5cd1f772ddbca67e950122057df30a2f4a8098d771cf2b3b6e818dcd439562de8bdc43507bcbb545a628b077aeb07f60a37aac89c3bdc19289c37cbf770de1f8b6fd23bbab5ac1cf49204eb3e2052e9bcd0e3d0178f96c9f768c23630e294e73292ee7e361089810a799c426ab9d9610d377ebb5e380ef780c7c4f1b40f8502fdf915b657505a9593c7db43fa550342dd2adf319c171e02b7837fd2e12134949641f508c56cfb1044b12132806608b3d7b6737f237c38090ac7aede2e54ffc9c2e8faa69646ffa6bb2170a31e28e58d55a58d6071b1a6df59f14b04c955289d47b11cec75c5b554b2cd324f9ca5677d4986ca8584d12982cc1ed1bd60268337cebca9489eddb47b17eda870c231fbcb755e48e8d78c2e38be10bcb2e55660c08c81f631fb1a68ca4f7074465b144b82f231ca65b1ac2c67d4ff4c8faa4c43f1fef318c6c19845e2b7228659b1e32a83fbbf5122dcc81cbbd09402a14632372dbbd350f43dcfd5de5790bd2b9292583bd58c8e035db6531f393952939efc015733509483a91f288ee5134ef68d352747b19a59f511417d1b0da8256aa769e58a2bb4ae99e4e846a5e4738a343c282f626fc7e53b09b1979bdd2d32aa27e55c626251107cc20a696f20478b9f5e8ca0831bfca6231b82fdeb342de5f589c02b145012192f5b70f1ac78b12fc16febd3ca3c79f4b4e5516d32eddd17f828200472fdab07d672de4e676d3423ec315c3f45b193a3abac2c4e2e1060e2a5c0641cee1b9494d3d5583b434171e8befdb90f5d96bb44f5ef741347a70149fe938c1ee1a530c2166c24d9d8f01b9b32519b1aa0b11617b11449019739abbb01319c21041d7ee88e302e8bdcec5b19f6f101875935878b56a21e290a2c0f22c1c2ef5999e4fca472e608f0de4da35262876c079ff5008426f23da132c499611a19d5dfd5ad39b830363a8c761d19df76ee9e6c48b3def265b3d0223f0145f26c90d83202fedceef703516a18d6629d1fc051b792815b1aa1e59d6e4406b507b51ed2121bff6c239acf14507023f5d2e41f4b43d0080fdc3d798662b786d4bbc88872aa89d4eae03b290d9ea5adeb3245a079994a02550a5653c5ead62c006314bd06adb456fa5d23d1eb7387b52c972ca9c85559f44c7a190663287337872df96405746ffddc56e3c9d56acee0de8dc4e07095cb251e6c748187517821ec16485af717254031b584479038f8ef70a6220e4e7720382ca8331924a1f15b7895db4c32968f2dc7c9fdd2533cf0c2d1b8c532d4e502f92cc614196752464d31531f5c491413201a4e9a4ec8e626979d99443f01ea5415cc001cfbc61b578b02f2c1a522e24fe2fbb43a81a0bba6a76d289668ed8116c1388db1e3ec7d835d690f9fc25bbe828ccdc479ec3f906fff01343ab8ba2a48994afd048610dfc81ab2f930cac26e0c8596652153ddf959ba887b4ebe4ae7e9b18aa44abb885cf3d49baa955da474930a60f72a9a85f0628c9fec2c18ff5f104d3c7f0e291279ae763cf89c1eef98f7783980805da02de7757902b54f06db0fc0b6654bd0ddd16e1a96498c91added0dcb1168077da98ab452f5673afccb95f9bf458a3d8d34ad651a61454b3bb0af3957ad78eec87541053eb794f09ce154dd911dcdd8230a1972378e7f456d0aca63f72676ff78767914288f9f304d90e1f9378f84247dccdf19ac2fb5ac26c02455823bee8cf0e194acb5a0ec23df4893a7d1119a7ee44e7cd60524434119bdb1cd348b6546e5c8fda5917ce658ed951efbff0c326461810238d3c71d66ed8f3f1b4c3134f693cbb3f5e5455721894299a289fb7bad00b7d8276bf3cf3f47258e40ce12ed55d0b774882ac4c81b0a8b6ef84934f94af90760839d94839b44d2e9f07c631389dfb3ab344d0d29743d057f559f7eee832aef899729cc89d1e628aae941b9e4a2543386937487c97815dc56d94b589990f94a8529ec81a6cb596977809cc8c6d5db29d1224efc5b8f2409f5f476a6ec08a3a9525754a9a2d9b1ab6f1f42f68218e912f178e56acf71257be6c70c045506a1f52c162dcd7e0797e4087539d5ba639180ad7b91a96b55b26da7d1660549210d2822c4c2802925d4679abcac2ccc70e51333448ac9e36c8edde17f48fd9ee2728dd7343fcb2635603b75cebb0d237a4fb0eee272118b782123aec2a7992268131400bbcdaf652e759cc89145caa7284d2bc0d71ef1c8b63ae4138544007f3540f8031e82b93d095db9b18696b42fa2949b4048bac3f3bb1f6dc011333c51e83b08c8473377fae1f7ef16680557228a1ae9b37824623c0cf1c1a8ec992cb561eb4d795d50bd766d8a5ed14467449c5be958adcd0ddbb22571cde820467c43f844290841a3be5181e1fc6b3386369c12af27dcf99b9a7103b0002ca4ef0e748784e2d10f27c8f74154ee693f42df8aa917d213f04d3d841eeb7460820361ea3544991bda54de6e4ae2d7e896b5816258a650da91aacd9381373a141d48936137aa52b29671bc6c68fadadde7ae27a9bf676177a9c7a517545c0040f29ebc1f6e7a6371bea7ae9d03c47b05c5710993261a1ff46a69cb2b728ca98527c7eed6b011876d5782154a9aeb470b4b247779ab1f69b5c114dfe05775cd704c2f5b3e189a76a79b22c5a26fb661117979087f88e6e86652f458e6e4434a55736f6fa07ebf3a67b69c99b04edbfa48f19ac0c8b0467a81d2cb19e37099dfa2fa9380989df86d3a1a2879fb219a7d9439f74e3005ed2a7fa12405313237d71c764f82d4868d2214ac13e82fa187b85cf2e558d235da922665a6cfbb54830093758ded0b7e90d5323cc35e8c0810379a40d0514a08b05e097ecb031c124e45629758a4f5d1d51e979b0dbbb85bc1337de739d1c43527976be78b10974341a1cc110efc8f7374f7eaf0ea0b9b56600b2a334a939937443242d76594b5eb2960e8590b436a0e89d4d2168c8c0fc457f435502f6ec4b9b55569a574cd947f9b2e053792da5a699c55f519c18b2959663126e93aab52fda80ac75006915308f6728155a45c16561acbf1924a1a01c134ea152be746d0c93983da4c58ef97641733b9741d40362b4f91607d933c424607a8dc96f830e54a132d6e0955a0631def15c18c27b50ab4e4c884d6032638849b87c93ba645a19163980b5d2938d788722531093405589e873302f609bf7bd93d2b2d801adb76157111fbec537eba6b7d1df4ac019bbc238e9281d6b12d6d8f9266248248eeb4c42b96095d00e2a254a2edd232e9374434be8a87e083f8a22b8e4c8465e4d820e5a9b14ed5e3d41e35d1af22203ce89f0b5a5c402c5dcb625e0cca3c89dec65c509f4772e16486e7b4b69a8c225f90a7278b4546e5866711c037c69128cd9dea75a4504b285eca02178564765920a6a3b04cdee499604f507067eb106abbe641bb26fe973935a90898a814b5278918b3c97d8ff6e0bc77d9132980a710f51bc4c82a07d9c9c58beb49c063cf3257650a053748dffe916760337e12800d6cc9c5514a694bc0b2ce1b9fe96572640d9c84c587065d24edfec01747f2116fe33ec1c7a9cc29cd620ac3b8a08613526bb46cf8f2e70a3728b1ac58d6b0fb905ba475b9a7ccb0b098105f8601490bdfedd66db8c66bae8ab9224465f8fb8f90905edb78e0e86df3642d52373c53378be557726d80ec467d5144b1dac43cbdfafa006d75531f4700bcf5b84d52a9b0e4445f36248bd08c404da7c7e2ea40f738baa48a5839bdeec3674087a9c07ea97bce99a85f40a9d2b4b7e5de22a352a3e2729c5ef7d6930bd5d0c808f83d0b401117792e4398019e665e20717bdbfe495c07e8580c1933d0751e40bb524a9a5bf726f537dee814d779f1c29471c881a5e3f35df6507f87820ed4ff7e8f9e489b30791a7fb47f8dccd8d95f0189c0aff015b1fc1379b233b56655eea9918eed4886bd26256d9765922b249889e7e3d670f8b590430dd10bd3c85b4d0bee9dc032f46e6e2a2a04f6b9ca8f7fa5aaed5ae8cf74cba3bf05368e9e5c9c59f21dd81e76c2ebefe84316b28623f710752e2220d03759397387a996e072c3db9a040c4987a993381f3756563970e5f4afe8e026ffb04f1fd0b4569bb758f255111d1ef617239852e2b10282ef0ae5044fe4fdb00fcb1cfa403fb6e627a46011937f8478fc6786ebe9eaca5120abd2fd8ed43bb030219940694ffcdb88108d47198f1ef6509e46bbdf717affde55bb91daf412162e0f68974a500d1cd9f53b59f6a4732b8ff1a5721be9e31b1ad6579e50075b4d44fbcde8ca1665d92b4b6ad24ed22f41ab559a6fac703f37a19b81c89291ab554b3a0e2a15bf734507c09c0d6e6f3fd35a947a617aca189c238d00a51b6889ed52f0390dc86a7c05d739cd5add1efdc337ed28a3cdfb325887f07f8f27aafe42c24cd7763f74c4d1b52a32fddb5381c4aaf2f3864b974fd2061d56c45ef43a9b671e59296b1548649172be859b48a4f84797bf5b63478f707d5ac6cb2390e9b10a2ec9dba282c9a4bbce290961d55ce8ffc8d9cba5978ca96b089d49459ce26c00acab6586626a1e63e80e2c83d6f761c6c6add543c5225876cddb69f1f8dac0c2b0a959857d8f093c7b2b315bf32d256290e57b7fea8e480c61b78f2ea4f5976a9118d6235baa488dfefcba7fa3207616e8a428f5d486139b5003114f6c0400aed6127531e7e2918bf688a11a0409893a8b99bfac55db98249fa00ce2f12efca6997444477d421e4fab7e92c6b1c4315a5487810457407bde2224aa0504efe096a47cdcedfeb87722c8b3c61831a7e681740d9f69675857972826ab3baa05c8f8f9df0ac7e643276659342ac57e9276ac90c879cc43aacde20c7d8f1ce62db8db6025545401a3cc557062e8cab3b1f5ea8d0fd455fcd85c71e8735d5af9d07f8cc5f46133b7d1d037b577c044cce37092b3b84250e70e08c58b14b2335a74e88e9386e4540802ec9ef08f49a34c3d34e1561a1ad2139963497a8cb4b25ecce7544bc065428ea092e7c0106850cf6fe254db598d7aa7e292a09b0ff92e963880d3e012ca2ce13db4d7eee98383c14e33e871fd2139d5a83255056ee78b78014fea1911e9a84e3b946d0d9df05f6ce3aec49f80a9bd6041f85d1e41c62e99101d27f1ba2ffd3848bc8346fb37c452668d95f35d291f38630d8a1043613a0385f9eff748e5beb21e08c137daf27d418167602ba278626a11c7f3087e919c53a79a77f746f1bc22c267107cede511e6501f166f06b887f72bf54d57921d27c4996397dcdd7080a516f4137c8064ecbef26f15dc46c42d3c157795c38f671e93b060be5c490e39174a097588976838a0c22b2cb26d8c42421699e4b6f0784805c5ba008fd0c82bc84e15b2a09b73b6afdcad8d9db01cc745c34de2b9e1af0fd83c7e49b98127d871dd9a03e43ff8b76a092b7b5a6d1df6693e6facdd639967be78a349fc725f3ea562508fe521005f0f5655dc5a8f76755a20f6af08bfa19e56055f2ba8856cd54a203e49cb281e54b7ec2324431a6ff00bac872f1a005ff31255f0b55bee780c1a307498ecc980ace302215d5be193fc9d2b03f5fd45465d649b94e82ddd4c20a6471eebbba48e712ad0a36e4e5d970c99fdd8088ee14a142bee39e63ef0c3fff13374e9d16beed8d404a47aba2a8b13229e9a6c3c7ae782311d7d153f644d00d877621984e33e76301c2f4f334f6c32b7536527d4fcda09d4a1677acb8d9929d105d8059e894e8ae5fd24fb53bebaa71a8c2905602533a39bcf0a70d7fb44c4c5ae70d48a4a7f575e5f4b7a1a9d1afef5d2621c9356cc22942ecf7b741c9f4b6fa5b0308012607923f198e19a4246403421c7ac651dba9caa70fdf44c433f843ab1671dbbe8730276f988fd2dc289420b78c19e7aa7a686a044e55c8760047e7a90c15551d182217c2ee79a41c658ce306ab13b49a647f170422dfd88c1a89ea90ebb6f1583c0a2cb754173adf7b372fe831ea2c711c88be8260d29b3f04017434feb9f83c5196613963b57c6ee776f467d632c018c386299fce1a58a3c6d94301f9b6fca6dd2c1983e381bdccf55ddc83eb260333ac6b30ffb19ba6a38f84b91dc4e9c0339188934e7c317b4009078ceb288d012975cfcb68c839f49284b9e1778092613e2831155105dbb65131d070a6a7d12ad0cae1081163aa24029437d2a931fe520a7a5e645538f49a360d7b401ddbb266fbbc958933ea10c9cf6ad3ca511857d93d37d4fd76b254f199994f10be014135874f9ebf0fadea6d4a7a666c20186a52240912bf2ad1bd111329e86876f9f49e67080b9cc91dd3f05148328430f5206767810b551f73a33843e038938bfa57e9312f29527496bd323aae1eec5b60faded115548e14a3e7d35d90a9f5be3b1b3ac8e159d420bbca7e7cb4a47df2e93cb901e519e31ab04680ae83428fa1155cfe6889cfa4c13e4f313dab4aabb62b61de5fc0639aa2dc8e83f618593bf27166197ed84ab01de10109c809d3b4262748cebbb6ae73671281d318b17e5c1c7a821806244c6dd89d9b73a1b940ae1f74d4cb77149f46f16d672a2c178ec3cfcf06b2907ad728c02a1fb1afc1eadaba0d290191dec82ea518a15c0c76d75257a6c9dc941fe62b48f38679cfd09b590f1ceb819df8f358b78892ad6e716fb6dbdeadbcfb0d26dbe02f622b1783c67640a18d5a35aae7cfe21d2388c41902ee90e09a0863ca5352918ea0dcb1faad7b7a01178a6f15ca9c1d91e9fecf431dd7b25b0a092ecda044c443111f17fb1fada02d87a32792625ce2d61dc51c11feb8009d45385c15da4dd22e7a3a15d5485ea495cc06dd05f7dbc68f50436300d9dfe0095c60dfd01d3df76e8f1b8591daf1c4f829180a4146f774decf2ea020cd6bec817229681ca10be889408a85e0a42524d1428892c0c92fb419049e37894cc15041964f6820dcbc2944e784617733ca617235bcc37b2a9e5e30798168d9d6de199ec5c503bc70312de262caf0e2d413a1235d275c9e4545354a1abd2bfce02ce0083f874015f33d582e244803fe9b7a7be4bc6dc8c0198f14008e86cdaa8a509e837af6a98e77edb939f47ba6629c5a377b63b6da00713052fcaf6c2a0b07115a659821443b09a75ce3b142712419e9fa2ce89d61cecf3bace02dd341daadcb93bcd1601bf909827086b061b7fb725226e641540ab3465dbf3091c024d8443ba9569d671e834d08c9a9b5c09c7bf2f0cbdd6c1e123c803cbe1efbb4181c2479940b87f491b74c1969873ebfbc7558e83979ef957aa5004b8cc66ec45b1486da24df498e0594ee7126142ba023510e7aeeff35b48a546adf898c7846a58910e9e6fb157a3bce28de59a9b480a914a3de79910eb23927f1a952b079fa015dc13e353f18b9d2f1211194dc5cb9ee98154d7a3148ef3be7e19babeba470f03b2db7d4600936db0c1b9f7699bd5bda72f3cae1bd8df9f5e7d0ce65a7950fdccecde2dc427037506ca4144174734adb2541c5befd80aa87869a39c5a70aa9bd1cc90464bcb68fb85922eaaa5f59df622c8bfde6499aeaa09f333cc09fce234a0939735873d810a855e5d815c4d987077eec3351ce8693bc1b4c7ff3bf6e4ab72ab45deaee97c9a4da96affebf3cfb29ac91781c0e5bf9ce05d9921ed7ee8690566eabfb690d27a07861af6d8b4f06f4a0bc99bf4a2f24a4c51a565b1557ac7b8cfaa1b6ab86cec8539b662b86b048274c94c82bf2e25c71b38c5de0fae562dd96af48b8ed553078a6a4ad59ccca78605e20ddf5ffcf2216c27a34b04ec2c37bccc3133659342b0c64b6f88f08a2ef6299b92e9a7e5713452791e0ddba3302a252029e4c9f66b1b0588ae6f053910f45d4d203c11acce0c5967c365fdb032f893e8b4074ad71d51bcdebe70b01a115121600cc81c0fdec9aac198478284735aad9d5ef982112001d967c8ae7c228cc032d5555cf853151d1f5f121040030d05a6b3e8fcffe9940439e2c1daf3bcd3108e18e8aff65f2ea1acc89381a4f40446b5f06999bd8281fc1d0da2deac1a117dab5a21b9ad69b733b36174761dfab890e5248a4a7a10dd9506a9d45c13402833af9902b2d15fd4a31ca8256454c069de5f78eaa9ca55c8c6eb182151386e8dc63c7f739b8f20ca2db890aa7bf01c1f8bebea8e2a427f72af8c27bcfb3c71371b4082dde982d28db5fb76b34897884a8ed500ce4ebadb16fff2893471a014a0fcb06289ab6c94eb43fe0509a184350a70f1c6a82f73d04b34ea6db6324ee0c0564b4df78e126ce21969cce770f16d2c33e4d12669f4866ed1fe3f3b4854cc7b705e328902ee16cb4d24341dabc3b39e110bd90e0cc51a4022f3aa52afbdcbead4c970c73d00ed77da881bc12df08a3c11bbbe2b03b06eb832175b25fba6f90ce51309898b34fdb42ce3975e8690a9334cff880ac34c081b301e9e06ce3df6b682a669c62e560469671a9c002dbdae4268272bcb073fdfdf5359d998f08602c969e4ff78ba20444e08432b1fd543f861fa2ca62f4913a2dd09fb07850905324cb9be0f778410c390fcb6a826274bd009707627f95d13bacb1c3ad6a1fc959d16c357d7014ff5369081f4f8e15f8141b3517cd8a4916f6ace321c4eb612163a407413ef525df459dadda6fd634dd95c1ba856b48f47ca91297c8c520abc2c41978736026bb5592afbd6f3e60946eaabf719139c6ff189965cd0f7913380af9ae278678ab060c2a0bae3da875e00306a8fbd911f94861f1c0f05f7b630110da7120d2c08bb0cc19b670ed783624138b295bb4c5fee6175d7557ba24376e3508e4cc374836d343d2a15c65771cbba5ba8d19830d3c23f264041b545c02636286d9210eda511e3932f0fd0183769067eece98544eace805e95e2f72e6da8ddcfda83052708c491268cf82690b297a4f807adfc6daedb64adeed6b1c25ce86c9864e80d09ec95dd7d6882ab2f0ccf95a6e2882ab0580b16de57dbc3208a2613a8fd45b5401928cdbcd9cce9b7c8743e8c1e94137fc1acdf454d322e3accb38d4cc3c3d9deb2790434d335813d624e1277509af57d8862f62b5432f7866aae0119c64e452e5a60a6154034d729a8c5a4721d15093d24112fee6351191bacce273608eec735d0b46b9b0676517542d489469b0ba3d394494813a0b0e7449643cd684ecf0302219fa2d972314b8e75dbc317f62c89436c906eb868258c660ecda321de417f8501177e3e58ea5880020b3d68e1544813b4d2fc6b6d7045c04ffc562281daba36854db99b2ff420d9e5e6059a689452d8f2a6d07d3c8cad01a94a3c0de92901501c65195c2b72f3857b05973fe097b1b04a2ca93af664d9a7b656eb9b540cbc4ec0677ca09313730744371272b2f88412d498e08d367612eac8bc60bb09fb54dafd42918821acc82302d7aa8f1a14c0aa819af26ab5c2aaad02c89f4b298c73e09a6ef9dd07d77d9ec43d8184ed7ec37496ce3fac717179523021a7224ec1cd383820088ff85ad9d669493d934ed15847afc1089b778ed35e6c50029ed836c3e033e6e703fe840871cbf53c2c0bcba6e515136a8d97702e4a277e37ad0a5c59e27c5b54aa268d0aa7bb946f4d8a066d19c03d049ad943475e6d37706d52e4754d26cdccd0195dd2307162fe9df72e392f7e04a5848ba4ba94a25c204d0e8544745a6e0181c30a9399598887d3d14fe1196294405f61d7f7f709a2e93b4e061070fa35037facf6f8926df2990197e5b76e78f18e2e35fc0b8475c49c3171646ad71c2a4957b2b457d21ff2482c85b106c419aaf3a6e55db591e8136495dbc862077a14cd308deb51b56c1aeb1574164ce6ab027dce259b473a19755e3101659167069b44b5a3951188d3abdaa435c440caa73df03850b0e6696d19590b7edd77e13cf8610428e01dab086724165819f113195aec0bb76cd1c2184ab3909818372544563d7bd4d08f91e00b11a8f6de1fd9a5e89203315d6502bc1a7a7688d1139018cc0d5a90e2dad4b4be772c038326047452f732fef890ae5a0313ef5d3d3c78c03b60274d8f45879cb278dd45514f48ef3663b081c6e5c7ee8c3297cffa6e8d6a882cbe1635c2f8ff551040bfccd195473e32095f80fdc82db350de9f21f463af9fd08d1b2cb848f32c5d95645ab718dc0003c0c3910014dbced2d2df8d977203afc0a21cc9f6e4d6e2cdc6abd467e100200041c91c2440c42fee4a9cc70afd159807dffae0351f123b2128a4887494d99cb027e44f37e3ed7e547fa5d531f89431dfe262613ad2e6fd3350ef5795a0bd9e3af31bd8e7e10b90b0b3d4e93a863fbebc43ac8c093dc6c13a3109fbb0aa1cda2f7d7dc40819cd093d9e1be8be12b1e22a1ec3666a2831d689ce7dcacf426a3634c5d5c6ea07a32cd46ce8a3037e5449d53a30bcf88286f075725465fc8ec47267415d8b28c944bfc5a384dedadec4d00fe42f140cb36010c501015fc39e370359855d0924df5cdb8b724fcbf19efbced4c91ac7ea3e8b8dc72a9e73d1b2524b90188c26cd6dfbbfd70d2a2800381c713b1b5ff33eea4918c838c6a31347bb1b5fc0a099407b482c230eafc19a84fbb0bc2a57b18254b78c52faf05dcaf63b47dba9beeeb170229f10517172ee7453b9f5ba2fa656ed4f0c7fffb3fef03cfe69dcfbb57381ebe91b7b6ea43ed2079ffc0d3384a58bcc14fdd32dc622dc85e4b3334c125fa492d71968d054cddb938dab140314d7029eabc0c8f62b72a13cc0f0679a5e151d2c593a8170a383ca6c3fcb60614e8ffadf55db1711209ec2ed72c7e4ccbef6c36faea53599e77bb660d330750ca5f5a712299d9a82f9a2567dce3f5429e406f1a5570c674bd450595b88e72df49d7af11aef1bd632c1147c07bf76f327ac2f2b4354b08da7f9c1677e8a814ed6aa145eae501db135aa9cd64483f855387009a76a5e4efc00a1c415ae61223c960c4e9f7a1a92a94d6da5a765f411cb294cec72dd733a98a32d21fd48d37c6fc10111c76a90907306899560541d7c2b5ca4a03fd398843cedce8b9e910e53c6a05a91c7113c4d174a69401b9332d795f4cff0b59a0a28396501f4792e9c9ddd8455fcd74dec4b7c825a6beb9a20098e764fa26e5d248911c44007a31ccaa3cc98e6c3ed66b172a0ac82bc2de74ea1e17c3e9294d818a6f376323a1c669be3925c0a32d8ccc61b45253202ea455d0e8f75db576b92c071128741fa2d09d8fa89afa20129ca438ae4072cd0a89ec089b1c82854d55888accf850102f7ca145bed2c5c7b7e1c820d989621174229ebe84a0bf9834fe111d6d4bfd399bd54ef0207ca61627b66160b61cbe5008e13786afa4406ca5c0ea27bf5a89864b43e1c15ce8b9458a35434a00244ab0344466caf3da023f86dc324d525d5f1063944db82dec8060b72b85d38596c60ea6f98fcf57115f87b253d558640701577c916b7b867872193728a516301b53c9171b6975025fd09a54d2224f347abbb2691cac0d42fac5166b0a50515d45127400cee3b2759629f42c97ebed172a076f8dd0fcdcff7b8b9c9c60c38304bd42327da653108783e679e5de4ff2858be654d71ed93604610d95e8a9ca1ce050892b8e1fd802c3be1b67bab9c7f2040635aab083782c9492a15c290d4a3abb21cb52e562a331921d5b3fc409d0f195abc74c92d7e56142664535b5e6048b1c376587185f574e4d02847263eb820de1b54767a64732f927e2c066fcce5f6906eb46694fa29a0e8bd692273fcd94476d277c9e71e43405fd63c2522a88aa9ae4a8564bdb20ef729cedcc72e52643b3519a16be10c7c28b466d7ecfcf4dea296e9deda68d7e0f32f59b4203c5e30cea22a023f6b9c2f448ce12c40178f0137333f32ca47ffdf11ae73fe7982148c8881a09e9eee0a6e4815f629c165a8b9009c9d3ff7ec8be63489cca5a91e5161ac7ffa1f92f23202e0a323d50124d39046ebd68e344335e019228f321f77f12ba156693c845447c8875200772ba3458493d417fa5c0f0f823b6c6fd853d5a6c501b011b097ea19e9c8a4ce968d76878a43bb11a6804ccb59769f980068ce397f2c1e6bdb8adf21e3d23934652a77d3b6e71183d7ac8a1171e2314ff6f5e2f06e6ffd63b6756c6182781753b61cbbbbf547b1953f2baab7fc8bbd425b78e472bc0712df7d560ce365109c72f599ea6e49ea07a439c42b8284a676e166c3f0aae1c943e162e3504ee5231b8c908bdcf68e4021c75639fe59b242576c0ac5806702011ae825a96822f5d558bb47a7055c23d0649d1fad2e5ccec20a8f1cb2429e9482751264503e9fa625b9a0e3d8ef5781485a6b0706a542733381d90d2236cc5193ec4db5d475024fd196ae1a81d3d9b8a32e7604c5f5cfdf6e5c36f515d650d90b406f062fd264b814a2f22910a55a1c02a4c7e50f7ea78ed380f9f31daf76dfe5a1cdae913a38de7a104483f8028121f130d5eaa814e78861de5217a5fc79d8c04b811d0e555ed61160a316065c8f0535f73f03d4a15c09cd892617a9b331269218234f1e64f06d144c23149cf7fa185ab6e61153c66081682d5de5f27d4316ce77070a0b48f8750602b156e972abfe0d89d5d7c9c19be9ddb8cf19da8257556a65f1a3546d6819c6dc34a8de9ce156b5045beb41186daa369a617dff9a00159693670723e564edb7c63cc790776062582c939565b3353ba23228c7b6b88028b90de31b7ade25b7b9e18e957ad2158d0ec962f9a70488398014ed71267663f717b455d48366b08ac3981baf2980abb8e999eba27abbb28813452e63b0fda40b82080f2a6b47b8a73dfe814dbce4a10f54930563907ab522636a7d091d85250d4623b62e0124ef86a7f22e0f28c9ed25642b3658e95441034644b322fd842586bb276e933c2d208a46cca2d9b54b8cc5a6fc2b380f15c0e10ea15e3f824fc6f1a583734a16093fa923823e3fa343dda56c08e942b57c7a33427471ad0d297f37962ee7fb9249d8a5fb14a4ec8ab3c33155b4d8c7026d9cc44ea066189eb4c51d05cf012668ac2dc336c5faa60ca0b6465b404d465e92958cb8910854b68a0c6721f3deb4b848e3ba6536aa43f79108ac22ac58d10f75c2ca15634c67720b1864db8d32cbcc9867554e968135fc0404e652761d759028a8498fa56466276ae90f3b74ecc9fdca846e5bd170e5442b0e58544f21a930c3716580a531b2c0d61c56330cd9126ac0aab3725d5f3e63ab44561e7079f54ea57577587ab1b9ccee63fde3dee693fa47287a3eaad693107961939e0bb26e904bc4f20fa3e855ddd1069500bf5e4fe36388091300a0a8575f3710ddd55743bef66b38d9f3031b029815d5e57bf7063cad5beab3722769dfe6d87f5031cd0e20b7f31c6e5f02b5b95dcf62434ae6dfcc3cb79148f58f50a5fb77786ef8d926e9ddec41a0689f789b3abb09722d477f11db37af0ed905929be6b10a34a15bce9d9fe8effd63c928171ed1313b8d04815041b8362a5ff8c97dec6bd3b865b09e8ab2aec6fb1bc9bd079f74d7f3b73b1edc14c952de227246f0f78596c5494ea02cc258da6bca8baff0d48ff70e198963fba962d3b0a1536e0b81217f68abde398706a7d458e14876211537699464bd0eeffbd81419bad1143c7928ac2219ba69ea1b6d21c1176dbf6cd016e43acfc328fec2daa04023eee97e398a4ef854edfa3a27bc977a8820cc13b30f4de54af5a0a5b9ce0447de576de2cc71676542e035f1a71f6e7b25fd115338f6b2b5b3bbef53c35a18473a75785071e2c19ba1defff552e29dd16ac917f427aaf5e96796ccc23897a3a25352afbfdc661d342273fa30a84b92f9b7771f0e343c422a74a19d2314497bf3c12da36b822e8dfc2fbffb190ff44ee6042755d157bd3d075df54294b9264d59f33454cc8574f626d194e48d0f72db43c1e998758c2bf048059d742a9647b5dc496494517f221d85e7f68d06f92e77ef39b5bf5188516c1971540f03d6fe40b71cc9041e08c82aea44d8941810c7ebfe358f4cb0ee745a4b8430dbe68f14d195b88c03335f3621d48590d2aecf1904548068bb295a1f17422e601bdfedfbcc0b374eed15f4ce120436c5787ffc38934a32cf04e927b3551fa409039cbc67f5477e6264266026a18d9844db1f68109c999b81c92c9ff4787c6a0aebbad9d1f0dfc973286b320e590660a8c7fa689d64e0b8fdd8027209833159006ffbf63b7d681c2bc014d9c3733f410ea49c5212b73a7bb67bba55abfaf11f68b35cc02bdda03acf2f2aa13c6bb6f439d7a0b7997cfb4be902117e811604707e306f9cfa3ce78075b3de2aa0446162f306bfa1c7dc116222a964ef56907b20f830bd1f8ab6ea9a9567ad834f455167e21d0c5f8da1236db886dc3622036027d853a253142e092e1e0bf62de33230bdc9a5f616b9cbaf64a93c24f4aa41f41906157f47290431b079c126058fa9b7e9bc021222fc727f6a6e54d212518380ddc9b6385c11ff52de0b3b9ea4453c519e344336c063a366d81575e7308ee087a27d7d63db9fe4b70879ed8f8873979df5de173485c545a5ecbeb6b61c112ee0dcbf98e38fdba15a9ed96a5eed82a0d2e26e7426b1ca300a28da899baf37f6658ea2281c53984f83f910648a10fcea22b50596b4bec8ccbd73d1564b71c2f5fbfee610ee6108b60c4a3da521d681668d4020b425cdf653af6215bc00de22c254d38c994c7fd1ec9bde3ad3c9e776e0779613d43b3cf15be5aa62c156293103320b7c4caf79b3762d8c37bf85965c0ac8ce7625d6cdb6a35504560cb7ca5209b2657af5973ec64e003458b200276b4eaed2f06a95869248d0f9c850d62095b77f24645b6c37fc67cb91065fee3de90610837f7f11410200280361164db6da78f80192a77f08a04a0b2bb1727c381f5f23394399e5d1a7f9b2d8850b3fca6bfbf07c2fa7263e6f948ff990b46d5018daea238f22216fdacfa8eee99580ea0e895a5c76a3d9d823f17d7a8a55a838bb61665a4265f1711d86f183977bc377c3032880c973d03be776894ddcbb2131efb772524f96a2fab7910cb487f4c1faee47a91e4cf1f0b5e2759849ce89c13b9184d777c1907eb4045ce8fdb482fcc73401873a410f57c161d212efe896e217f0a5ec27a4d280fe54ecc5078ec7e6a879b25f7998109a392c8cc6baaee754209b1cb613e766076e01392b673d4118d09f4efb534453c94f9f9931475ccdde89bb9a9fb54b559b07748598cdf23f76932c23f80a217612af91386b23d8d57103c7e9a7baa7db45b88f22fff52adda0040df8419d63b99d915680af107bd2864e822e05d4d4b84baad8d4aae411608c11b7dce75fa44e94405822d318716f2021c168d3c42fbc05d700e100205a64073dfa7c01b411c3b3548c18a2716244d69541d0acdab0026a1264bee7f5b3e2e647893498d0354b7c32fbed1daad299368cd181b4fcb790d89a83f51f1818ac0c575a2187288dd9e8769e4012654da1a00b7e7a3e474dbac795b9c9a00d609461d0c45bb8c6eb1576e9faecf2ae99bc0c989b541c577ac9ee88a77f142af4487490bcfa2728c925846949755c5b722539c210e42d77c0a5cb06780758921da98cabfb921e72c44d90d03e6622a91c0a97fd7a20d01f762829fbda8e3f626694c53d327636b26a21e0427f6fb83719624928dcb2c23ddd437fe2ecdc0e9afd2348f0db4061a3cca4b4e13cc21e73b1eaeb2b7b427b6c3b12cd062f556c03b383e14ceda4462f2325dd93f4980e9d7e52c47565b63ccfd98df00772ccf874bae7c104b9902b2948190b9c9f51605f48c19c233a768913646e147df82bcea785e06bccd808ef1873ed733f8d053daba84cc6a6e36ac5e67302e5baec2e4a541d2190d5de758ed45d2a49e428eab9fa2366047db16911324a70a650f074f3c13cf7d34676a906f463e195ed786985d6b47145d5838c3299674dd0b00be0e080f76d51023e0436bc89415264719c000af24ed7586e16533f33d20b6c574d261f83da9848f919749bf1570d73f6c23fe6baa0bcd8a0d3a4ae02439f66ea25d8cbf64a3f3293b82c0a84c603f798216745d4e1f105ba8b90808aa5f59c085bc1348e87b137a776e6234fadb76e3e9a35f77f00617fd7b42236410459980ff8c4ef098e1e6897e8746df54c4b1fe3d41e864c6e3594f2065a13db6c7d0d0b3aafca78facc0325cd1230e3da6521724679e4e11c10dbfc126c76d2d9f4cabb7a8ab928a9308bb78c14c70ba47b1f90cca52c7a6fb1a7a1a6425fbcf0002c78375374b40a3b5e7dc3f4549cfae1fad9fd09b63d719b9954ed7bccbfd2caecb14faf7c4852822b50430368e5e5b3686d0f39e5cc2a0e6ed67a51bad34fd6d3f50befb594365cf3a1a88cc2d27fcd300091dc2162b14d4c3b13cde3335f824b7e1ad254805343b79bf852f1591825c6068acb53a255e8dc36169f3a971fa3aa66c397a12f12aeb6a040591fe3d29c212180fc6899a9d4c5f80819cdf0ad19ce59a6974bdcc37b001837e108e7ef60ea51b914d3e5f25c034999ac3b29fa04c80dcf8053480f45b5d4fdd0062ff9e14230a5a9816fda9c94cf9d48ecc89ac4615b0961350345b53f8ea6609f8612109d28c936e02d10a8e5ed1e727ea59e610bf4bd06bddc51f7b9a52a97fef9f8dd98b17e0cc1c36b869a44170fab49f24e2e93c64d3877a050390abf3372854f67eaeda116e8264d9faf6e4c9dd08cd04d9786c2ce0df66092b3d2d53d9b815dca6254e62804db325d1fca41de0085ff3b95d192362d045fba085d91fe9903ecc04e6f10d302230bf26edc6a5830675a24a0140ba7559ec95a205b934f72d14990060046f51c25c3271b3cf8da43ac518588c8d28a728e333b7027bfddd51f0099d99817e1dfb500c91774ed64e6c3cf8e48ec31e37e9d96e9d374e82c2288746704b401134a8bc6205724c10c903ccf0826f5c17dd72a72c6d0900cc40a17829112b9784ebc8ce201647aafb57f9238bd79998a3fa47fd3d29f37045272a2e2adb153fdeae93a99979a1c4e2fff0dc5bbb3ffe70cbe61fd139e30213e8db3aec8e9358bbdf06266cb3c2573f472f389e6c54a63ec23acf25a5ad16d3cc1f9fac1a319ae2e720fb763ce195a4259f7f12f68d9d6a9840b7e8d28543fc5c8a0365688dde459e40fe73abab74f459baec67ea6067cb8f3484d040bd00280938b10c982b86f56ecfb0a359a863f9194f1948d93aa024a0470bcf4f047ffefa328d613303cd41ffe7ef533ac0831d5f9d81c06abdbf374289ad46de7ac6bcbcb8c6f0ec87b5f14ceb11bb39fcd642e30876203ad893a5063f80e2062fa1f7a85056f007994fc528b54f444b94e3d95f48b7941f8e0010134025bb32b46694ef70178f24bbc9911f1bddfe0eda0acf760169608003f21a20051f9bab001e1d3bc62a20a7c01b1ccd05ec668623e3731138028db7bdd192edb1c72ebb32fa5ac3c4b4bc060d03e30e79d88a947b377f495ca6c1295fc729fd3bdbb1215f035df3b2d245406aefe0c5f54d6c40aea666936f3dedda625d0a5207f5c4ad3bbe0df00252f9b15c5ec884afc18980bf637384b8a0bc5bcfa9317c4a9fdc5910371e8dc4c6fa9bb246c4a48d0da1033eb379f8c2693189356fae2bacfbd842333776e19a1d6dfe8305dfdebbdce2ff051773bc292d51304a9bb13c8789f5be68509ff594eef65e5031a1c6d2efbe068e7b9117ca4d9019af222bec592b1bcb0d12e0aa28ea9358d8fe4796a52cb6096dfb7b4414509e08007fa8530c7f82e865a847cbc47d361021b2c4e2725f038f23084b4463a97eb140d0dda49ce1038730f8690feba47fcdf1130dd12ba150cb2a6b58d6acd45d295a4ec3723110b940b9adfaea7bf2f1c36708b8b6ee4756d89a955fd0eea18433a0580073c06520381833addbcff38f3504ee0176845218e9df2beeec03b0fa829f833c59f8fc9167d3deaa78421e196221c2ba2ab250a80ce31647e634c783a8f26fee9da1530ae727757226dbcfeb5911c6c0bb23f0919a3b879a60bd8caa6caa12688430bc9d66ca1d74daacf37ea434d79a01d06a9778ea19e8732876248215387f905af2a673b827ff59e977e3b76106ced2af270a09dc871df1fbff655e8751a27ea6083cac8e099ab411f85ac91aee4c416f7766b7950d8da2a33eaa7f0c31f79e073aa8998ea179e6f6c9aac3f981bdf2e56d8213c88b5f94d9a202bdf9747f8e8d723a15a7a0fe7ec9602e68fab323368cdd302679b8de0fbce7cc80eca87741891b62816814010b5bf76e9fc8930cc5673f94c98e94e464f82990f7aa977e15932d87c75b6b8d5304d4491fb40de2ef2b5cc125ec0840325d97cbf228620029a3e4b300085f9dba5a46d9ca64ce8c6e027038f57fed226a478a2eaf8480a1eda66dc16c056a1189df248b80ab4e7be73a3ef333fd0cc3f7d5f5b1104e4480a05ba60ea2022d6799166bbf1bcfb894420703f1f6e983311bee00ba02acea0f01d9f2d28626a69c128a534e310a817fa13789df47293658bbd04454b90cd2f2c8c412bb59d7c9166368b6613227fad9d998406e208f292690512f2af740aa19bde8b1e398900a387c4585025a5c4dcc55599a0f4a7bdbf088823b5fbd04358077f0cbfca244f88efa3742c8bd28dfc1c1023f9c4045bc3f3cf4807ce54f83d363c40f01322822c73764d7f354ae171144af575d9d62413aca69078b418411c2fc45c4147b948b7f69ac290a77eff8794802dc781ddce8f60dbd97df88e01f60ae69eeb3cabf79aa2760f31b6f538f1eb36b4235daea5d001616ec607668ef85d0dd766465dc1c4804220a52c01ddf346fd824c5f0047c5a2ea58b12a5d6960e2f8de90c42ee9cde1bdfd7c919b2547f9ca1936515bc0ab6441c83dd59d2e001c4aa325fc8bbc6d113986e8ee21df865c589bb976f24fe528ee2255f5202047fee39da7d29ee0e77cd3f3911e7ae51bed7145886e5dcac07938d6bd967d8eb493b139e375422f81df052256b621aaed2ea91897cb047aafea11241e76b7a913adbab7b90ddd2270d8ee4bd201a9508a2baf03cddb81665484a0e1d4806de53e086c680282c11200cacdde579400323d43ba54875944a12c9be7f206511a0324eba51a865e3dbdbc5fa6417d3c0fd3a53c84460d48670412040b5c00583a3c3d8a13230e81daab76a7f0d0607671441014609ec2558d48146d41bdf7988709a3d054400d0f885a9b0842a03a84d1c4e18dca0e73c0ec21f2f051b5aa031a0ae26095375956bea6972143e78833b45fa62316eac1db4b29bd0307f511dc89e94a71970010344200c8832e7800c50ea2acc0c6cf5e0a261a294d5eb0321efcac26c04a00a83d8d4c3f493d3bf896dbb208840d1e015df96ff6b328580b14acfe6bdfd95e3962a60ba709b0c404b24a601ced4ee47a3ecdd0a84e12f9d8aedbfb7ef9517fa2bac27a30a43733e770e306e002833033e1d1a18508a707adb21e014db702b38fde0b638b0ba564307ecdde58488a53d48e38b6af001d509ea41eeb47b2270d2fdde21f599818020543279dbfb87766796580ed5a42942dce83e34b3436eb68ff0af90a1866ca8c98e2112f1589299256c7bea941b3a330002d87f251a0a60b53812b7b39375f61dd26a3dadfd8078830105860f2494fdb80921ffd5c3baa9fdf061f5e9c5153abefba40dfa38d199716256204c45869df6d494855d975fbb7f75c29a67503449f82bf7977ed37a0d8a092dc2b4df44a14e0696ae2c213d32f840980658dc74c98afbce82d30f40945c486fc7fb04266fe179bf9873cc0a88ca384b770955767f22cb242793c1c3055d1c18a8b27be2260cae678c09421e4097dce39d671b506c388d404ebbce157c81245953bc099026ff572f66b3f1e998cbad4cc8578bddede0a93462cd023c1d81cab1486177a1ad0b50e560a7a0661402a09404f0bb669f21e06b2d73a8edef0eec484b01cf92b4fe0793d760d452d2003a7c90dd8517ebb54b13bc5229098806ee75f517b2349b0ffe6805dd3f1105042a198e96190bdec382341b4413596e861247d0c05eb53191b771a2c275e531876c179448aa95baf04de0961c492df810cf21760531d78f81a53e21aa008e769a983c90e23ecdbd30a7f44d7473c0a04a308c6db442e21514aaf92dd7e999985ffc9affdd5d693ec964b164b30ca228be646e6b516885fe327d8fb4914366a30ec4e92871411c84394fc78d03bbb9b2205bd83f890d33d816eaf51d17b6fa33c59c22e5b9ffdd78c035c5b18862a06a529f137261354f55cc887c3a6d9c53ba7ace860765fca1607c479e68802412663bbf1bc613c0b99add0fe711067609336a012021f4008957c53c03261d82ee07f008c02e003c213983005b22729e433087f8bc81e2f8dcff56bbb0e39b0d22a613fd2d12c6ff9c3e992c6d10d3b60fe8e7089f763f191f180e324c9fe899eafffed46fcb90dd73fff1c87f11f402bd7200bb126dd60726d97a12ae60703a2c0be0256c7ec372131e44e87fd497a06362e6d01470d278419eecc7d223a821b616c7488543b3f620b905e3fdd69c50301b8b8f34ddc4dc9436f96c31af080361035c6c38cb43ecfe035b98f305fd9e529340336cdfb6dd54436ee8a0b996100cb4c49d5da46f383f14f7066cab51084e22b0bf1b06ade7826f03c77ea5a0b8a54bf12667d8170020c10fb5d22eb216c84c2e740d813a6d269f95eaf7a1111d7590e93d49b6980afb80c9df8bb595f2689bb6e883557a476f0d6f7d9b224024ab6c18198f44c4fc94faa88d288d86fe84361486cf97b52b9739927eef032175ceecb47a153bf11174cca63e3b042cea5eb933682587685034609713604d9face52a5f97faa70164341a14a440b37aa11f9b943b4ca6ae864e439c489aa0665fd05272eacd2581404bc9b525b8bbb030341d766e24c3ed0b5ce12f56e5c213fcb8ec7fc07da3290477973da0a5c455f23707002f81cf634d60605702734cdc48d7b5deb2157384883020c173a4790fda6daaae17fe90de3bf6be90d07e79ecc01f823126e1d8218bb0e2230521161cfcba186eff78c05a4c0c41caaa40ba4b0f76da563462fcaf46e131c71bb06d33b72e0304371c4e2322d0305907dce9a32b84a19f7403a8bbe58c7d9c6dd629b70fce58b30bb20cfcbbe1f86910f39a579e7bf8f5848572aba262937528b19713a278d348c581086b40b50e0d21b039cc14420fe98d4b497251ed935263096ffb6ef7c270cbd2997e0cb0fcfd42fb9b8996018c63cf2d012a9593ab2c3acb7a801a82682002843997da22d0912058437ed029b39712e714a2506b20c07da870caf815b3928bb9450205dbb4739b5b9514cbd6f2f4339297dd4bc62bf53d5b9b8d1c430d6c9b533fbba00f52073acfc9044047121c0b62a90d433cb4e9681911d58a625b5702a09006fd59d8348ccfe404c3c337bc21405430cb7acdd247e14def8d3158cd3102abdee328160e45b8ca9f2c0e0cb63aa3f7f06a31d3be0033747f491a1c29b562520843ff57e697251505ddd5bc64f7469c1b7f61476c9a9e56d8a0432e585fabc1f81ac5e16f012872538caefe9072f69c666601806ec7e909374c582ef13ac2c663fc0cc6813f58d0537a4c7a123edbd52c0054f39a9a42bb091e100b7a2387c2b3436196c4b46ed0382b5feb71e75f35138efd2ebf5aa9430aed0d28bcb1ed2fda4d9dd7d18111d3315c131abbb6232e5603dac56a07242f1d40360c8fb19c19753c780f1d19b0cd02e0e6ada6329ed65b63724aa9676fd22e9f7f28619645301b70bea5416f1c6ede447ab10b2bf9e99a5900c8865e714084b3604b722cdd23e940b62bf196680ba1fd580e92578a31c9a56ad1f864c1bd88aac3d9d9469284be61d73ee57466ff0610764455cea8ead03910768fef52d6e73c36f80f93cd942e438e3827c5ec941d6f53c52ac47de6a53c500747d7f15d1df2580bbce169b01c3fd29519356f670ed52eeffbc95cfb4e0901b8ac12a13c0b1569cb39c96abc6453aa70690ad53d27aaa40b9c215c6a383222477ee29048b812354f42619006818a3cee5a59dd5b07f99ba89fd16122f75258ee90594001403f5eb4029012ffc385397f9ac90be8fdf04e1f407d40978c4d0a3325e4e05680b6661ac186259ab5b7bc68948d8661b2773659a116c7286dd8dce631c7548652a3da7ca6141b02ba884a7bbb8313e377e39a36080fc41f47088cb3e3c3cb0034f12031fdc89286d9600e7f807556d67dcd26831fbc2e431b8a1a79f8bace2801f0ec9bd15873d03f046508e47595ffb417b9930ac5011a582606775ffd7be0920504000238423c0aace9e5ff7cff6fdfc6aadc438423ff97c6042700dc006e22cb333caa39acd560d1bd549fd29788cac5bf5a512516039c53e2d265bf784dd71872e2e7dc74c48032dd9cedb5045ed7745f2a80eb0dbbe9d5c6abfe38e7a1ebd28d1b206b34d0e2475fd2708151147f68b43466b3a21502912088d1206b7ef912b286be35735342150d20ba1a5ff464a5b4d0ca4a5e86a43183ff08e0bea10ca76edc0318ff9ced859121387843800b456263dab5657002e70c30579bdcf31ee230fd24eab90258ec5d1d40642260fa89563804bf30650645ca6802361f219536217bb95660ca60c1cb51e914ba6a15c0b92672d9dc513554c8e62d33f22487e919aafea478f6af1edcb91c726e53b06d837561b2d9f301776096c2d95225fe18a97c5a4014428afa96190964471fa1c563cf6e4e1c9c31a2629239393dcb57470552cbccb6ebf1ea59c5981aa1414a95e90f50d205fb095ab3d36d7dd8d3b8db3ffb3196a58f4083c74d0719f57664edf0af9fb4afc6dafb810381d32cc829b841d995d702e360137c03911c7399929e6ac931cf4d69b8a1ed4df1880f5f8bff89551a6f782843a7744e95643073ccd86a5dbcae84635270994b50170c12c3099601f9eed78cf46b6f55cd1dd07876f8b0b5543ad5a19247f6d897fc4f42b2aac96b2d85568ef8e18c8dcd8328b1fab7e2ac006896509b37abe35d102a79c9220910d98aec93ca651927aee34b40f91d38cd7bb03f736ed637be043405981b7996a223099f4ed316f3689eac6cb996356a5e7df5a9e98662d336b6f0845fc33fe177dc7128a31593f56d09089120169c0ba3ab851a609bb80e771affcbf0915a67aa0d30dc58bf8fb6a314784dcfd5b342a682d21a2e819f02cd96a1ab17e33eb7864be0222022d301af7b983b25285c835b888eb5328274bde518f1612e9a484e874b403804aed2ddfe5d09f4b219f40d84eac023c7662c6a7161d5ec631c5bbd93bbd1cb3b5d39b417664c1c3853b29e69977d2f5e28cc192aa6ed58f16bb0561f73644b6ba1ae067236903e3b5574e90d13b3ccbace076176ec352147331f34d9b82a0e9700dd9d2773bbe9495cbdcadeb5eb906124577ec275e43acc71bb6101e9d90bd764e8f5e3c2884963009118f83a6868a9ee8ecee93c9b10edb062289b9ea7d2ffc70583c69b1c7d4ed92e1755844b00fdeb5e1de24bb3cd2d475ec92555853cb16f7d84e60fb5d5c51eae1bf13a2ef1e410c5b975394715064804b97784a30e5ffd2d815636fd12027a60abfba00426d042b4e4cb0a798b07a455f6d323b28d25e823a29ea8d006092ab4f08c006fda663e084dbcaee434b0ccd4183dde7edae714baf1921d042c930ccd975c2ac0ac40128c79625a0177130680123514be3f063d13da90982b0b27e35217f6dfb4d5ba0802330635d33884fe1614280e7277ebb1f0e2693c2a97a50a0471ee6f5382a8da171f6611606b7a9546fe28a327c5b5c71266b770510fa5022fef235abb95326c4f08833c6b20714cfc5c5fdd01b375791c3226f55efb37938ac04c276b1e3ba45c1856e066ccfe85cad2292602b19e1d02557de5caaea49efe3aa6a7f4dd702b744ff99854c3ee25bad1a04b9db8ed2870bab9f230169373d8efb1e0283125bc85015548e7caaa328f39f191101c00e0887649af36dbbd18b0911ad7b120d743ea6a5c34b5ea34227a2c44d971184b31ba4e73dd5e9da24268ac5ec7eddc9d1b82d6e8196af69955344caf665eebf390c795a321fb1683a9f76ea4fc94c4ad7dca24a92466ca4bf6d337378bce6c2cd5e8ce9e9f508707414e88558545ae0bbf4f33926b1da4cd7236c8b46080284d0231c3dcdee3e16f8b1f50fc6cfd230d0d52360b66e9b5dcc31a9ae542ac0197147f68e2434805b5682d4f38e2c741b102634c99a355440cee4924982ec04a036c96110078bc692b4d6e8b6b50e20eeb24c110587532cc524190812f1a473f6ebd128d164a4514ef008269b66385c2aa28459b00a67f3346a401719d7f5c608c8b53f4496b7f943c06444714032497a9cd668c07bdb9618f3dc5e954bd23752f86b61348fc0a379c3069deec1d6766602b579cd210bfaae7c546f3cbb74713eeb8e6e02e6a3310530f31b4598ee0ff9a8972ed976a14ef3da27fde0195cd7c754603e9274c1562819d713caf9be33d2314063aeaa1abf602c2b1ba55df525562126c4a813fd0f64a9ecd59d9fa7c8a0baa5ccf72215ccb6c99d79a89563f6ddfa71aa17615ec2adf2c0a12517cea47a12614feff28b1fbf457b11f5a3e55c56db8b03959a075e13b0f8b08903674be2768f3c006553bf31f412f4d018927832ac97ff113d67628bc8ba5439a44953b5a623e1cac2b43ed5195ff9004cd20e35185f7223e2e7dba2a820de3a80548d02265bdc3573e5290d80847e31470f49a4a5552c0aa9441dddee512337251e5823a7ebbc8daf8b51515bf4008e8b841892d9da85d92a26b066d853213511585aa603bae879d5f1d916acd73db2188e33dc2ca0356c41c5d53956cef084555f62b6a65115a8b5682b52a989ee49020cc9b7545dec3a96d1ef5be82afb34cb07000016a3a168482962a2ee489d4dfc5dd80664a4c4cd1d60d6f7bb4d23f429c52750b3384e17444247a597b856196ed133fdc5c9383aba967f62c599dddba53f94ed25ce59c9897ae78f9eaed6c0eb1943dd186e39ddc991a656af5af98d6baa9ac2fd0fd677c52e198f095cf8b3af5f3f0b14dda01f4ff831f2d57b3409741df6d4ca6049ca99590ecc9149474039d3e5cb192c2bb138b1e53772aac27a685836058233019fc734dd3137f6252da0b6db058e2e1d460b1bb2c89da4c59f519a9471d863c836c026010880c67ed013b93dd1101224416d0c13122356d239eecc47353d9fd07653ed9f8801d770d274db9ec1955d79cf0db166e9d9303fcd079e5af1b62effa023b765d157030cfcf04a12853cca6e71e9a758c336df2c451222f1cade783926f56e5973400dfbdcd92c176ab71284c23a23f156b508c7408497ccd27f423fb67e4ca6a1298f8f3dd0d38195330dd0126fd304ceb3e7ca94c64412d6e693472d6192968b7735460f0115f2a0c5489513d7914884860b543104f9d5a2b30f0e186e6db49db6f57bd079a232b10a585896ded0e6b3d374c3ca39f68a3429d3410ef09c9b1a7bed01a84fa7ba3b0002c615e99953029d720cf29ac9ab1f35dddfda872d2b50ee83368801d2770f35403cbe88e26624bf52097baf6a8e686bf66301352c0d5d34839314b302e951400158b3d305ddb0130021e3a5f6f5f88bf584c817403ce92abf8e1153cbb751e28c555dde49248f0d3f5c2c911c420be4bc4b6e1ffed2e0ab3c55220ead4a7dc677411c6c0ca8cee129230e791735b1e6166a0c47248a59120411a3bce442bed856fd37f9c5b4fffe9d14600f099bdabcb79f19c05c517d4dde820f09856806b756e08c615741b80e4db0935937fba3656c51343723999d74db8bd5a163f3d49787fd9b04660895b4845824baa085bb5ae3850c57f2ac632409c39546ac7ba462956a7f483c01d6094cb876f5d9cb0855163879a61c5b543f25a6efefba3339cc753ea5cb05f79aa741a1ab8925655f90eaf4b55abfb8d0db506eb2aa2ff02c0d110a862eddc9bbcba72a7941e6a169410889028d251ef54bf27a8148708969ce8b5de42e71454ca4f0ae8c7d5b6270215b75b6432d9e051e371cc7d365821541b252277fa579901c1503050a9aa0a74b376224f9ac03823a04249135331bda0055aaf38280c6d876fe9bfb59bdf17485c8f75a1832c7c2376df50535eb8d8cb0903a1d9102a550d4b9824b0e7df9077e274bd4792384ff22421c36ac55733793e1f28e511d790a3a00160c4d38e9abb528f2b1ee0b9dfed9adbb77af4c02bbf64ce8a7c2d2c721b024ae246cf411de3a8fab4e2d3c4ec8ad3641dc5ff4ec9421de138926ec456b838b4b91874191374285f407e3453ee672e27a4303aee6f194884314eff29f396edf4945d651b8c47d225418d4bfccdde252f6d605c56cccb2eff0e8b56db97f5242542350fc0a727063ce565c0396fd30b01a3062690567c61eab7f0ec474288e505e25519108d4f4743a9595345d1ea38e9e8c7486f24902922941fe6847a802eed98e4982ef20c40614695a3456ce866e8b2ddcd7bfae4ee1cd7e9c774925e6a6d609e92a45d93f22fd6b2015580536890d7fe8f482fccc0135372fe7a45459898e43c4eb374dae6eb86bf2dd516807efc6948ef612a51ce4e186f62375287070756d4c1bc20a0c0ad7a50cb4a2e0ef2bf2dec55b1fca79076f1f3d18fa2ede2459a4db0537c746dab90578fc86a41062b5f067743ff04a66b6b40689feb4e3ec1d83bc7093de3f9b9478744b0d86f729195a42573ed5b1b1649967514b0e9cb195f384d44fc3e2da00c932e41a8498fb12fda9364b088d7e9318949b90e86dcbd8d6831b94a7b459b55abeb259d5c03a58a0c5f70f0acb0408f7b963256e9b5d192c8212c04577b0921fefdc99e4514d804243d8e093b575ec49e64bd0b8a6cbab480a12ebc32dae58b8cbb80a83662e8b1e842030c5d4e5c0771ca2b23c6ecbc02a79a41f0a9570771155720e67665c4b360ac0ba4cb504ea1840f96b45a116bc97697fc8e428c96f7f86e3c8a2101c1ade2bea3206a2df9df7ab3abf502a9986f607aa41a9070f84c337edc42ceba4478d18bf4d48337763a0e23ec673fc6053754f894232f8e089c8d50a6e9968320cdba5bdf51b5fbf515cc11ac9da4ccc74a072b0684e9107a32d58287a83587461415ffd6ebdc64360c80c2d4a6c64747502534dd2bbfc5a8c148ee389ef5ab50e256af4756d667433c03fd9e290614dd26fd11251a0f580ae50f154a54f7cdd17af61a992d73c2e70434cc6431e504eca4f9b9d887f24d09eea30206e8a2a86b4bf6ec1c0a00bae1b628795a50ead9a71853eea7bb35101b92aeefa1c407bfc704b43528c97babf6135c87c53b0f8064b3df4507798029d8f6104a6b54fbd322ac023f4df55e0ce7868abb5edceac2a23d71550b2081f4b342c1e6ecacb9372b281fc064c198a1280bb49db9206377d28c30d0d5219b9eea58ce196c584449b197ac9a4b266870f4fba1a7507fd34a0448bef8c8841f74dcaf0f1c3d64cbcef8b04ae9c3b6899bb9c859a82897692004040e5b79fe7404da62382e8511d84dec8932a0f5117b0a4feb35fb913d26d71d2263c7e10bc59bb3e96d7c5fd375e614720e7eb2b902428b2005dcf641d1c21f41529787743640fbf2f235df83698c44a3c5ce8a40009036b230fefdbd09560dc9bb25bc4b54258d9436689638e45dec1210d5f2b538703e7d900809826674bef281cd1a474690c0ad4d6233b5a93a395d25a2c460fd5485993cf10c4f48c70e25752e5c60e98b7435dafb6a4f104a7d9d50ffc43e2c3bd8dda3295f1c9400570ed24e06cdb5bc83a36ce79b536e0cb813cc7e0610110072b89f88751fedbf0b96a0a7389a1c31e4901aa9b29056ae514998d418bdf889545fda927db125d521fe1b2e6b43dd912affaaee0841e2c442edc807102b1131f054017d1659d602caa2421b66d8a3f42a4a49f3026837912122886427f49e692caf0e5815ebc9e42c50e68d051914b681af244e51a4fb6b2833a732861a2fe111d00141b6bebb34fb9608f569dad2fca759ecdbd8c0d09dad848570a3e01f8cae33beabf01d2bc6a5800992ce1b9fc9ddd3b993bf424e9328923ea86499593622f438693ee09377d51371d6068412767bbcd870c5812d141c97d8f1ea068febd27b7fef3e558497b8f49ca3cb8ad5f84fa358d253bb5b02ab77dd7bfe865f475c846512d20e30980f39550082dbfb17cc903198c040a2a552d8fc2a2ac15b9687c6b6128a0f3a8d4d210535832d25948300f349f03340b4b6122be9396b9d5997f3d32337022fdc3ae79dbdfa1b91e32076c431df86d913c68901a0321aa631c032ab12d137f4fd4265f616f834a56905590f07c6df19297a9fc542c9740b59e3cd38813b294611f56ad0c6ae6c2c68a53a3c76d76a3772ce3adc0e97682957c9449c62fec7eac2fb3f711079126be5d7943b67772987f2a2131b23c72a0855923bb107acf422e43d8a3bd3ca8837b1d35a05b413432c660512af8ee06848d909e4ba5b56e0ae9989e69608c825a3b3ef79984edbf33cda553ea47982c7af6bb0904380073c8e06824d91e9caa1d10652d64c6d9936af31111d0b10ecf52e92152978f5b37d4137d51e111109807d534bbbb5529aaf2efebd9ab6873cdbb0026836726cd99400ecafe7e9dcb13c15002b0031dc99c17e67b3eb84fa39e7170bdcbb85cdd38ae7e42bcd602fe5a4a266d44c46147150cf0a37c0ba33c814c7408a260cac35949581319850467efb5d0ade83213b94a004ae37abcca97e3b082503c744e48fc7e0d375fa4389d167e5b16b163810fd70be3921b7b09eafa0978cf2f8c1d9302050996b74c5d936f1538c240f600124aa9a889e015cd8345f48f0c88aab7e126cf4ba0fbe5c9e365200e8c8d18f82368723b121d4440ffb7938c7a60f0be4691e34ebdc4d5a5da843fb4929d33b448b830cf6faa0250f7db2fe805cdb98f2b6166c98855c5d2ca0d8a58e955ed39a13e0a3c5600f67393bf477972ecdc249609186a13c61a5924f901cdb719899811ea2841311a836acdc52ad5f4cc39b5c6884a65363237d37e54a2565134aa8c825e96846a0d48a02092dcc12d83991fe136be922c5bfbb8999374dc447077586d42fa6f2cd6cd40768b6a542391163536a077ab3299b5a8230136cf4fbfb51af0c2928a27508e6ea428650998aca446eadcfeb1ce758367ccb7b4355b30ba87769d1b1b049370a925a46ad3fbfd58627d50eec392650ec8163f35aee751b647422e367b5c9e39fbb5532b71eacfa7364dc79b9b298dee7ab80f338dcf428aa039dee9ada215f459b57b2651171363ff5bda57d5d220c51a666e5fbf6cc35b90af8594e446ad3e13ee36e4b838bdb19674f22b509f591128d2fdcff04a787440707795610865996120aeb78e42887f8c590101630a77b3f4c44859350a0507425d3ef634739b86a0a43ff6b5bd0e2e171cb5d2e496710ca32b1cd6e82157d86cd901025e4dab898ae541edf7b5e92c4dd7e8fa78bdb64a88f3b82428e88bd36137d08644fd7481be4d0533cc2306856e798fd053ac4e24ec58d317d91f53b8c104577d5a896b76781581db80b183787569457ead264b0e61ab255cbd803b6ce04472cef1aa4a32032c51c3ccc6eb9964dede885f5b735675b017a866b3ca1a4854e83203250d9be16683e884c3e0e52abb269770d8684f3a91514060df20788a2ffd53f8203926b27dda9dc4b197187f26e653fd5221ac3549a5b431ba0ea3dd100a35c05757dd4d8c247668fe9a230fab53032e6e87af9dbd7944be42871f285894df340f83276eb12cfd947384d30cdc53d52cf5c1328f710202d6f2682839328592c70f26f9b1de0aa29a332c781f6e0975769ff0e5120e29ad98fef68f70232091cd1e8aa3d75b22875bbbd905cbc5f31089b6ab0ce84bcafe413bcee1d25202537ec96d0b26866032a7fd5dda7c0e52f6efb9b8df248b580f2dcddc15a680959bc24c0afb98c407fe9682d54da6a9d9f7f1b449302dc4c584d3a2363d48a295b2279026d7d93d119187232f1c41ad22b585bfd12f52945ffd657ef0064d099369debc2e2ec04a778c23c2aa35f4d090fa8c4c03f822e9471993514005c6598522e29bdc1209a12acf1f5061609919826952db00439c6e80a8627de78e4d246f6efccb6a6b4ea96f9adc85f1a12f2f9047b24109fabe56d378a42d115273e1abed445204028b0574f14ce05953d290c02f0f7019a17872e59e2afb0d573faf74f440b4cb6b95235422dc2cc1527e8dc60cfce826aadbdda1d0cd35430fa9bd8779cfbf178b611baece44484966d76cb273b368d196bf80b2b528443dfe43dafd95aff8f3ba11b69899eb3fdc6f2d02a17da677fe162653f98adf3cab83c697bc168eb4568d7e28bfabc2808802b7f9a21d6f1eac4a2b759241605eff0240266d284724be04d698a44ab040d3438de98b58369e97e0bbb81d25dcb11efbdef418652674e3ef8202a480bc0029d4530b07f015ed323d7a41bd05eae6cffb57aae22be50be19276f8d6476a08935699b82c317f8cef1097213afa95f64560d0c9d63d33e22fb093ee36fbff6febe7145d44d0ba14204183925b22591d2d610073eeda8971623b9e068c4e9d7c1d8ee192dc46ca9bddeed3ad8c444eaf322a75426ecbfb29cebd57f2995798ca6df1c47b5cc6569d8fd02fd796488a1e2da901d174212c642cf6863f4e0c3d5997085b13f49326957a53a2049dcea4dae389a670684763847095df7ec074d92ea5fb773ae4968c8ca3a7e227b24ef2aa67aafb30adb70ceb444b17db8270fab2c87ea73b59112cb9d323389adbf370d6299190f1b8048bf5402051d56fcfc574f61aef9fdc2a47e2e17326d47da52ad5895ddb4a2bda0cb1114d1dc510991c25eb12b01960539b427d869e1bf6fad781627be89cf1337fb6d67b5a625b0bcd4491fd62242265fcfb6921ce83c4f61cc84d0d847764db2838081a5fc51dccb2ed1e362e4856032bb726c08a0de2fbf50244426f385437054160813238e1035ff99f7d2162177b84e51ea24e295638b72e26854ceec61d805841f193bc41f2fe0dbe572d2e63f7801ede0ba71d63b7a566f19eb80b53075e8e218599d1c079ca323ddb9f4ec4e84ae189287fc4818e6191530313ced40c78a80b9bffe6ebb938e5089285cd8fcf83b1a5a158c50a486c217c76621e5d0d92b1a305cc0fd290d39f65880081b7e5df2fa62bea23d5301b543a610061ad13ac9d1bab9b774afd12708a8f6c3cbff878d37dc86b84e4b5541faf9893da9bf4eb6c81408517d80036717c067b6cb0b83680f9f466982fb0eb147ca08e2a39b06ae412751673a8234c019003ad67703e2d498a6b5d2c4b3ae2ec4f993c9619b96ff099047d2877b5a4f141d79f8c0dbdb29a4716f120c4ae4f340d0406c7fa06c3198560fcb39efe0dbe12997f793d1a101b166521b5481d648ad7483f38c580ab75f596c59fa32f60f0990c8c76cb1b562f1ea2246547cecb357074554b9d0a3401a0744b4c20d30e161c8254637730caefa4cda42f9d665940a50f83e7e286e0810ac18633ec8b83bd940f33b33feb6e23b28f9527756b227f57cc0b6da236940bc0dc10c851ebd568a4f52f9d09c58079ca30f6c60897cacd4860d7ba3840a479223c9af788aa8e1adcbe92bacc7e5e4a58e72db37a8e6a2e27002b18a1a83c8555760ffbdbdcef7452f439ebc4d5e657ef175e418a3271f3535f1eca709868d221aca431edece17542653463999933f29b7e5561e58986aa89bc6e7fe037263bcffbfb42ebde2012cff02f40b0052c862bb1fb7b9ea35ef3f2da9c2de8974947fb3bb6942a161623ba0bc4f9f5a8b39dc4a687e87055f37a9398694835c4e2dc202ec1b93ffd4e2de0d1cf8447d5c328bd49a914be21f0e760baff036d4a1e46c3af93556f8683b2cf42b6d146c654afd0e714993c2208a74ae35affe3c2db639f499d82371813451e569728b360b81f921e294b41e09f23b252707322aaf044fbbdd067a8c7dcdc777ea81015bf0ef29c99ccc9022d15419f64298a355f2a237a00eb009ebffdbdabdff66d03c80763b6480bcbd3a67eff7bce9b8f03fd80b514994108a17322be112912f71b3677f8441db195083751b69c27ff17b9450282a93692e62475c40b733412d74b066b56bfa5faf68aad0b937c80e4ecbafb36232954cb17f348620e4eceb62fcb3e46825be169571592ebc71666e02f20239e20928bf0633bd61b251b430e1d7545894720de315ce069b6741bd610dc890a249ae66d7ce09cb605d1db377b3eea3e1cdc02c6fa094ae6366bf782213b3a638e3d7d96c0eb5de9f7328fb9aaab90dab35bf2db5a682980ad337b936651d4fcbd9082fe196a1344e6cefee738604c8dc5562d1102385b5f4fd23cef113c32abf3c9dc1032936e12f8a71287685d8f0ab72fa4bd997df18cc4d6a983746a6aa107a31587463a4467531225aa3c3ff7d28c00a6d9b3e8bda4fd21d5b55d5e4a6c134f31d71cdb4ff76f8649e1daaaaa663240a42c47eae123f3c376dd4e39bc2e35aa88e957090e328567ce902607db8550347eec7e5e5cd17f988e13c2c842c79a1680281357a18ecde987f42ad9004be7819776568c2b79edf5697a31048f5c3840876fe51c6086cb6f14f59578ff2d6c1d3805759fc3a183f32ca488bcc3efdf2b79ad7a62d939d964354252c01a8574a1bb72a315b6045fb213b9f450a2efd2c54b05e6c1768eec6935acba2a80ae9260505bf4c5dc778748450e970737e6224c6b0b1a0d5133da86374baad00b8853a1eeccfc5bc4503c79a6b6940f73ce862e5739d53a355e166deb6281d29ec7e5ba1bef80bc1bff9118ebf0c611d104f522cff532832154d99937727d4c8f177baeb127e50de1d7ee5809ce55279124e981a519a5edad39302231256fe1da3337edee9d8b6d757b550435847effba9c3f3307590c161fb28e1474e4bc8aea46b879b79742abb47aa6c71b2f54c0b6969c70aef28144fc0ec63470e48a5081faaff9549c43bf7ef5d9cbe03c322e390af14f6a00ed2a80f51b906acbf0e395c17ccdab253add447e61a7de02d7a91c7dda4d16f5d7e5b2b251e75bb4e4f43aa7f44fb3fbb5ceeff15b9c402e6ac9a0a0d67d0c8dea4a460c92f5fe19779ad6719206e4bcac70be61d6ac9b0dbd2b61fe700215992c2ea3569dc49c62e5c973f030fb6026fc598c239c34cb75fc373325a05f7b7697657d3fdee64d77007dd4e3941ff72c909ff09b30d00aa851d31ea158abf1901b5d20a909bf0f4a3b3f7c1e0bc02e5eabef132f00fae910c3a65376e6cbf50da67d7918b274f50a4a55b2066fc59cfa4e741c9974a1619d741b7258c5be7c802917a7f59d80dbbf4acf7bb657c56f9634234740768fe71384b855103d44115d8cca5d347761eebd73767937bc5cb70b353656eeb1c5efbc9f68d364ed3ca6fb00c5df7901192ea2a8081dc9a3e1479ac4f332cfd5209d3bf770d9faac3f00331e54ba1c046abb9a4b522dfde3857bd2ababdc0e23122616a188bdcda5d8945ea2bd611972810babacedcaf1c1b0cc318a53a38f6e38343e3b4ab4355f69924a421087c038a471461017d55b3bcff56f8d3b9188e5b3218757522038064bd78f9b743278225ead0d73851868808e183110636ae8173d5957a1210f43227325f204b608cd2489fac026819e2bb8ec6b9684810f7739375a717742baed5bb7e6109ff20b59548b6ed72053e830b1dac6e536754fe536accd2958f9d2691ff095a681a96c85cb9cee7f16a7a79901ddc0555edd1b4167caf4ae83b7c191b85f81cbbca8b944c91078f75d46620420894f058691288d8bb1248608fe936ac661298dcae5ff885981376a1d9568001c54c02f3e02b9f4d092551451e2d50443b91d9d2e20a2bd0ece2e50fe3d8c56ae46ca0ca73c30a05f8c4fb676f8b4b5dfa266ecadc2ac39de92c278d6da70e3cc74c00a8a1b7a7c2a7e17b5b9cfd65be3021c2eeeedd9906322f7c50eea899fdcc9ac4ff0a0b7ed80839df862f2d5e48d334fde05b3300153ea3e7e8513d4ff935c410058ad4efb755301e15a539283800ca2d96c7032eaefa788306738d38dc01231f8da961e2cf73f9162b9e1d7c58f5765f43772707a0000043816dc33d40bf7c38740a4770cce2b108033e6a08f691b5d6ecee26a47523dd4448c80e3c0b690baf0b91c76990d480398e9892fae402bbd9dc9b9d6e096a2df3346df6ea0a336186f06e33544e97f08a48d594a5a82473674db030567813595cba21a968bee909ead45a2d34ead4ddf360a74beb2ef7ab15a2a3fc73b76747a2ebf2075eae78f80ccd225ca2f886cca2b364c7aea8b5eca16b5bcb3e121dbbbd31a35f93052d0b5b16de66288f7619ddd1515050b0c70a83e1d268f4110a0ab646a3d75aefd5334219a1a45c976bca2deb29f5a25bb75e641de5ca0a539d759165a558960e2aa7bc46d71497eb51ae75d14df990666b59663fb7777448b3232caa529465fd7ab6ca6ad549fd82ff7c742afb8cfea98101a1a0a03cc665145c4a790acaeb51529ebd26df8d268b9e7251acd10ddd55d1e8d66451e873eb039ad19efacc8c1efbf5eaaf47b11a6b72655116454daa9a9f7735282cf3e80fa6288202ad4dd3e51c7d523402a837758a82b0a9f71af38e3484198f9dd1c9374db03261e1df15f00c0f44be1bc8bb8f89fb6e5a9b0e6b606bf2f407e4e6316115d02e323205235377ad4da71a42f862743cf955ea9aa64f30b66744d34e323241bc3d20cf486b33b09b5b92a7ed1a689718c7811987e4081ab7448abc3d1f3972c09767a48d5435d81cede21e307d0822da057efae10bf5a2702dd3b390a75b5dc8d324863c3d23cec574236d83e5f4157dfe12fd82b523cd6eadfd0c2997b2ec99b515751565bdbf0ce7c4de93ce3b51fbf7de6748393b84c970c9dadb77bccdf429cdae9ed62895dd4d890c29c6de9762a7b78fd10ad35508e72847412ccbde56b531b3fd955d99ecf6f843655685b1d7d6a139b3ec9f6b5db631a6823e51d151a0488a44a3d1689472d005bad7536ef56b9a52deed43d69e68dbeb4a89b50e5374bd47ba7cf846965db8f4ac3febf6d63fd5455dbd22bb89b28cf463b3ebeadbbfdb0f3a6b6b0dfddd7e765d46b91dbdeaee8001e12b0557a7ad499437b29f8f28cb3e19d6418942ef59c8da8c62cf2efcbb941e3b4cb52acc8e7afa18534f0f7ab706a4349022ecd6fbd6a4ac73c84e298515a6de5afb18972d2e7d2e633fffb19fb7789e7a4d7e34f9fd73edcd5e766bf2c3e89bbe06ac146347625161511d269e22d15331429cd48a32cd58acae75b9d64a293d46dfebbf6ae3c2f1954515b1f3d6658cd75e7aa713ec2692138c844c2ec7b2419c1cdd74e7ac3bb05b0b09d25a04d21a8e943dadc4f7e3f9a0e883ddd80605bb3510d1d6f3a21b5f77b0759006f204bbbd1e39fef5c079345e8e4082d81a4350a0887e6920dd12dfc3c439c1c9d1451777a0c82992412fa263f5f8670237e3f368d8cf1ecb84e4e4c91044f48be8d6a456a4f15cc60623c7defe5003c1b978b7b783a0d52bbaef567585e457e43d1c9b2704a7b5778863bb1232ed3b6cf897f1755def5a5faf0b57f4aee964a57dd6c1679f21e112c4376412ad658fad658fd4390982efc8ce0f5385424c9305c53abdc6d05c33a43c65ee374ee2571dc2e50997fa3254c5605f49f2f5685f6a840e4660bd32f5d7f15403d6f90be6c2e9b3d680b526bf6a83fe7a99a597dd0113c2f378ca2e4ca25e5807b52991af77bd46bf6b8af7e2c1f75e55981dd65f8da962acbf3b5bb3750e3942729c5558f8be7d3606d78b4f2256d160e10f1f0f03c88b0cdd31e65c9861c3328c7119860dac6eb09b2847117c4309a30c9a58117c1526be4884cbb16445ecfcf478583f13a56ebd83953f827a9225455190aa76b0d75485c0dc67aa307dec73ac2b4c76501fd47dfa9a4cdd8d5677a3c9d541d7ded5aab2d829ec53de620f4876a7d7052fcbbab37e3a170198e55b932cb03731e1aa6e205d8e252b62e32721b7264ff70d29922fd8350230cf1eeb943817ee3c8850122289bb4c6118130c87ef60dbe0ba9e7d596d62fb0ee2588525cc905d06a6cd2f9ccbf584a3035f1ed4eca765affd7c563ebf7e414bed21b5ac5f0e73622f77b9cc097b511a2f897d6c6b552412954c91e3afca056b6fd55c57ccf54fa4ae1895e05e607c428e318a1c63167274f6be9cd6e29027a485401f393e2142b0f454d770335c7eae45e5aee269956ff148ab6c335b3bed121f8f00f1f84824dac7c789c42a69202211aaeeb071b3c55a6b2a67f9e5ee27c3425cfffc837f5942d4640bb3b4a6f20bd2d754e556456d1122598ead3e5f55c1d5e1595cfcd8d6e8e1fbe567032729a824ed42b168d323c3eba27c957c780a5e261cedb2d73fbfaeebbd0af3c39fcda3c1f2f877828702e702c48bf66de6919d31ba732f946bb93e3a10173aed3acbcdeef596ebda75eb7a9ffbd9f9bcfab99ebdba5b75966399005a040004109fb3e0ede5cc018144ccd67564d902405b78fbfcbacce7982500bfa824949294005c1601dcaea2b5f896db4fba25c6d6ae5b77b6763d8976f9e07896fbf27d399f27e409794222103bfda2f1481193f470233922c9315e36128944e24e869188f9ba8e2c5f1800df261c1cf71746e2e5cf5d15e2737c94ecf1934ebb5c44261cf8127360122ccf6402709a9781380b7e2cb05bcc09c005e2c62119dd692d52229148d684ed611a926366f50ecf74a45d7a884472911c8de4f8cf1f0b2c96f91c5f26eab41687b416e3272191e54c6e37e99698934945dece2392131f00bccd9859f013e2c35abf229176617954297de5d7455ddfccc982279ce9c6dee4f8ea026bfdfa0f807b446bf1f8d2bc7c318d739f0967c2899f62bccd2c4899c59d63f11b776291d6228c0907cef9c136ee071c89b4163f74c2b1b926215c7f38e0af479c7611d22e39d72b245eeee1b2b89b8da5096713a910c9f1f309d91ecf46512e4e8e1fdd1d940d14e1086ad131ba54a7e8cb842d0af87c8b18d7af0c5b18bb6fed59b13579a96d2c93912baac8d48dad4d1b96d650e0a4c84162901ca1d041915c1f8b7ac8a456204d60ec866ba83506f4e924c844e4609376893d5d526bef089882854e4299fa73ce27dddd5341277305aee1d1b83ea71e306c92e3ababe3f5194916250213c335e0a9647d5a1f9efd703ad24473aa2ad864d21ad3c3fb8af3476c33abdcf58bca0f3e6016789b2ce6644d558da987c9a2846966670c725997059bc7343dc99b8c95fc3c64f268c44fe864ea6fb0095c831561932c4fd3b9a75b74b2b04cbffaf46d92734eb08a97852393f7427ee5569755ee76f91a9384b799e1cda6e0cd52bc91483fdeb4bc391eed537daaf8b952365972e16d86462c43fd37a8c7cf0797e8b3971ffe08f8726c713200befddf48f79bc5df2600f0c3399ec70eb6f465752c8b555563e265aa8963218c35c3f0d64b72f58d54e19e7671b99eaa3095a29735ab53971445ab1f7169e64d8207847f3eb65e92fb4ee4e01a1e8d172fe7af18eff61c8df83ca192a76864ae305cc37bd124bfdad859d824cb7bc4a549a2ca23e6ac0f03143a39b97f0821bc8b9fec10d0410a37318fc43cf7c42cddd28d6d6f2d92c1ba23393e3fe00d3236775360e1db490e133efac55f523e476bf2d9eeee86f9cdb426e324e539d09a8c87f28f89769193a65d625c123ca47836f2af87bcc9f20246b4cb74b784082d4b2988d0a6065f4020a5fcd4308d7321cfc4f6a73f1cfbb13b89d6a47455e050489826225a9b86680d1e6658446b9313439ece90a736e4690e79aa806b9928e05c4cd3347d8a71cf47bbfc68971275973767e4ddf48b0b627a383656e424784c0f686dfa7b9ea6074cdf26357ff8f252e05aa6bf204fd3abe9e92093f2c4af877331bd46e7cac44e772c1396793a3bd3c59a939cd6c4ac5b13e7684deb73ce6759b7e6acf4f5dd0d2184f0125eca48e905a95593ada9bec6d6aceb8ea2284a29c5a57a197af84a0f4f699d77a38f265baf975a35d9ba333457b872e2bd983ebd06a4823c20930b985022e525a5942143b66cd92d2fa594527e93e15cc85734d8386118adc9cb333816097bf06c5a682cad5dc6682dde252047072383c2c2f706c325ca1ba1011a1eefd12571f2e42e6e5a96d82fd260064fc6705530b02e01ae255e0ad60a32cc2003b6c4cf69032f2f0848d339944367d1a81a4de3aad0022bae09fafc6a41936c2360ff91992500ce25c4e266c48a83a55d76f4ab37581e8d1d2fc35f37dc1557e4104cc9c61322745d86feb9a50b7ff2e730217cbdcfe72e40af42ca6ba29f8b44e7cf8e0f086471c4e734d067b521b3cd1ff8c1ceb90061225acb01f3664f446b395e76a2432bba33c64979d99b04c88acf37160bba4d880eba4df810dd1e44b00745eb4ce4c04841b704fab3bc2590bd25107e19ba310cd12ef12c125f7bd89a2d855e0a81b0fb80fe8864ea33346b180b2c4bbb487ad85d61e4596a8b0c371819c6c8508602dae573583faf1808047a8ccb20d0e5432050c8397b379a6c1fba5b9cd96577d5dacc6131eab42c07a9d76891731445e1e93e3d92038c31c6e85a0a90dd1390dd6f3bea5c220b8b6fa49eb1b1c03732308cec360094be69b984fb06b6c0eb68347e4bde0b7807380dfe097d1ff684224ee89e68dfc09718d7b2e4d1a8f15ec0c331e47c2143b8850c83702ee0b787860c2fba5e8d79a010aeaf70fb80797a8d7e4bdc8ca9c2cd04f684b56a74bccd846b42e8ef3ce771df3817f0d88e753d31cebbe381ee16e55db2e3dd9bad5f85b98e729f92d660c49860f3d5d25db65eb7b770f416a9804e7acaca53a66b05c80d7c1906b9511d91a94841a02677fc404d9e18043fe4c6a5d065e6fb21dc476031f488371d362351cad5e32471854bd565e6a957f8f3044b51b72e2b11a0cfcb3ac4cba037feecd8aafb56a00a7f766cbb8a03f4c632a04f2cb3f29e304dcc202c576e5cef77b5b182636b2af83525a58aee6a04502e42b99b125924ea2b92940845249a28d14503b3088fbaf61de14d4a29e53f2dfbf3c69800fac3251b8f32d5ed757bddda5fb7f6953c22c7d07c69961e4ba0c7bbd144eabab578ab3e852050334d38f479458f979a9789a73e45320bc947f998411a0814c232d5af982b6c6fbd06fc5c9b1bb35e55985a61a88d51bef0eb99c209f6c11bd133f01c6817246e7b498e641863e7fd7051c48049863f026eef05193e1a64f87490e1034210dbb349b24d19315e7c78e9db64d1830fb807ec1c0b8c6338172d2486c1a2350fa90b2084f82c74b86d0f224c7c81d68c6804bcbb53b70825b8ec43c80b42245e0abc209de30d96c2afc7b399701235868824d8cd297941a02817015f68b7bcbf39d94822fd9a0603c62683881ced22ff9e2d42766c5cba91212ed99864a60c2dbc11adbd778c480d58a38dc09260379adfdfa988058c18fd721b1b1b13bcb820de1fe0728582c718236d1779986486c1b5b8bc65314b48e15a5c8e33057620378c6f789a92fbed0326983c813c3992727c4e9c3811a227dd0133e7dd73025f5a8912252eb712184f224d27b0257e4e6b1f90f79c3879cfc9bb4d58fc92545745df7db9959048d6d626f6aa6060dfb77ed2b1b1ed21e99c26d2393da49fb819ce52053ce9da7f77c7cb0ab89b02727c02dc4b3f712df130ed62042730d4a091e1602071c15a21c7c6837b79405ac5c11882f683e7803403eb821cef1c0a72bc39b6e458801cdfad247e2ac95192d3039d1d6c054e9e7492ee1cf8d24a604bfc9cdd52b486a4b524f005de00f64008f00839beb1927eb2023b5b8a7641823d292ff96622ba3ae4f8b83d24d97bf2acb0e91e3f1aa75d90cc89a4ed90e313e722ba274a9e4bc519f274e60ecf3c529fdd18f7ee249e447242822ffd04b6c4cf49ca5105762359e08a20ec7c32a7b5fd24471bdbc40bd22d7d3bbb8e7f4edc93e7a45daa784f7a10611ebbb0ee076b764f727c08dc0c7898aaaaafa60a736118f61897315cca322c7b77a37d379a48eb0ccdf4dd20756216ad917a6c633bc5e929b09047050a9763d9a2931c7f479de5941c812fb37b5a498edf1ac99cd69248bfa69162bcf56a249d9a854192711eed480f2490894e28a5a47207595cd35a07be40267dc3026f3056f0e690a84026ee48096f27e1cdf188f026a3f1666184b0860449139448a1271e43428e100cc9448204097c8137178e427286c01bf8d247702df14d90428e9fb8ad8004bb451c1c2131a75d5caec9fd58fb51a00826178827426b012346bb5c97383efe01434caf89136845b4893ee24d046259f0889b01a7b8247d2997ef1969971a7fd17649c292d69d8dadbd8f0a62ebb7175341dda38f60b777044b41fc3be2c337183d7cd3587cfbca3792cafb06860f78837116783bca57f046b2f6c6b9171862c28454dada49dfc0978863e1bec13738382297a5a8304d91589c1c577034128fb416239258c2dbc422124cc76e90498e8f3cd148bb7c3e97d5b5f6e9c70dde30d12e5bbf21066917264da01358057c02ad8836edd2c347bba83cae3c1e1e8950de51df3817958975ad91b053d237edc2c421907e7941c44321ede2260a0a4adb1f8e427ae9c6b86c7de56e2e499657b925eb2ebb4a52417cbfc1cd80f3ce3823e52925bd46537a0c234d6c52f914cbb2e4279596b4e4ad8650cb923727bf8afd70ef4d8e5bdff411727ce86e04c8f1a0ecc6b8ea95d622cf888ff7a35f5e90ee27a4df10b93d2297f53e850cc9efe5e9a293520300be702df073bec8f3050a6c3f56a7f4b4aaaaf9c3eba4a3dcde2d744b22552b071dfb0ccda4bb15d2491fbd3ae9d2d6441f5d516ba263d7b626a24f39e9a11b4349f791cea35d42a1a3a05014145c0aa11c855294cf136c0ade62261d9230fde79392f22c0b65d953525294c82495eb7246e95d256d2fa3644739bdd95148b72b4c86725dce32151229cb48580795555450b2932e3dca55111d74379b45b335518d165df6860eba29bf9c0b9bfd825474eb1d6cf52368955515cd6446b3ed82af525e7db2904824229148245c52b90ce9d95548cf4ec2d93f28285721a5a0d4649451e8346455d92bd02b0b64fd931dbbb5d8d92cb31976555ad1aab2aacbb22cab3a32b10cbbdbf50abb76d43f6d1569b522f44d74b7d1af50689ef4cf513e437348e6d0434f117d7e3e74532eca7d445ab32eba9f1d5b8d6205ab0a8b6696556f5455b17e9e6045788b39f47ea8ba48740c1b61d84522257208ab42a00c7bf6ea62cfaa57d5b31086bdaa4055750c0b814019f6d0ad9e5decd7659045245bd67a425ab36e8dab6af537612afca6f5695996855d5f8fc28c657ede8cc3e558b6d6c9d6acf2aa3bb097ec4bba819e4e538c415ab34af03519ced75bba6a13bb13a735a435ebd7906cbd5eeaf509a1d6651502070ad6b26e84d5356065b17636966cbddf4e6bd6b327d8b61eff47c365eba46be5b363afd3d7ebbaf02d2cd33ad41ca018b224bba4946f092bb7d89303ce3d897112d24d4fbe4b52a69eb0ae344def494e3209f844566199cbeef9a0f1730af16bc571e58ad698eb3e5af07e5c158652bcc58adeb22c0bc8ab300c575007c43218cd0e691ab32c8cbdfa36436730c5db83b8145f4f55a778b3519d56aff4d0faec58aa66a75756ab2cab31d565605555b3081629a5d566336c1e10422079a32a5aff7c3c1ad52ba520bd85e1adaaa730fc1c9e1ea3f4d1a214fe5cfbd7026a5916f63e27f6e86b342ebdd753f414f66de6d3d432d118ec32134fd85f0b1e0d8c7eaa7772cacf6ac1a341a98cf5798a236059d6e98df9bd46bb4ce9cbf4fd2ca55e6badb8845da61e1eab87af15a3f496455fef3633ad2e4c4dac44d7600d6202e4aa2986e42b83772c1bb499d3af79c55f100a79093d571f27ce540d691707e3559dbaf5f66ef052788aa22c0b3b8b65acca8947e37367a10541d590ecfed9669cbb054fb9433c1d2ecdbf57ee106f36dca1fb8314ac5e0ce8b0821ea5f055e50ea235c65d266247e3b10b7278fb4065559829b225270b4248c1e6b1c5b893b7ca59d5dfab9c47c3fd553a79aba28565e02b550dc9d57b45b96a48868fa71eb1938195a856105687af6a4c75d84537747babd78a27ce0aa5d6b36cde399cb938b18cbcf5181fad2cc3a5f9eab072e2d188db56bf4d21f9baacf0f662c541b3156fec96ea18ae9513f114febaa829cfca8947a32757df665c8f5555d6145239f1f818ef2e1c925f5c574e4c9c6a488eeed066f4858b88e770337238178e243a0b8d05868c18b45fec8b0143d40083e599babbbbbb45d30cb028f46b75fdfa75adb55e53f4b5a44ef56e36c3e6d1b5dbc2baabbba680b5bbc7c32816218635a5e2a2e2a2e2a24205cec5ab87a2288aaae151b9ead714d42bca65aaa2ee1ca41ca41ca4204d3f8a7a5c5255d50427dd328cb2be426158866118cea87feee7a087401f9b6114de2aa6179e71564c223aab88efc526cd24537149bc7aacb556c66b89bd7aae9e8b8acd66d83ce214b18975d714dbb5245e3dcfc7f3d13d9e8f8c464a2f2a2e2a2e2a2e2a2e2a94e0c4aba786c7d573cd39a95bf5d55fd36b05a51803bdede7a0982d86dd0af66d5aaf28ae2ecb077d1715f4a24244f9a056e623c3dbcb9a64f065a73d30363555d6adeb9d655966615956ab759aced995756d8b9a248d30a3583746b3faabb1a66d611727dea8293b96a67c40a4e77af7749a3ec2ce116e32112459cbae0a44728800c906c8ae0a4958b235de6a782891fbeda304b94fb58c73d23aa0ac42d44417b18b0e6fd4214de7beba1fe1a3fa1445515fa19e619fded557ae77d3ebfa65af7a9d5ed7754aebe9f5f9157a5fdda2675776d1ed874019de303c43cad5a7ae783a0bcff469194434eb6aa7481e40765558c24d5e824d7e4b645705224e72f6d92eb4fa057a14086f30bf534eba49a62413bcc54b2b46494df32b9f1dabaad42fd83c4020d0f63ecf9ef63c1aef96b22050c58181e25fa4b6fe91ab3ff979763f786b2b9f04e1f72c9e8fd7e5b11bf38537ab9a6819de0bd184317d365415145d52b50fda53512774095de2ea3120b085fa9c177c7936967aebf436d35476ca826c3e55f5cfb577e2ada5a2784e0c5ba7b8baf00c2953d6a798ad46c6c2f11dbecb2942ac539ba2020f131445614b61179da02e3904bb75cea4726475bd2769cf7b41d132bcf69133442767888e1072789c88140f2dc37b4151269410727488ec14e1d1c9b1ef491d223b4578681972748ae40c2142cb407b64fbe81c0ba949517052148996c1492fd13f7a891b9a6e1b1b1b1b9afe820feb615286d7a4457817f587adc808766b1c8b0db132f3f2a22afa4b3ebcd55077f5c2cfdd8879e21a50e28723e4e5e03c21392e4aac082e47792dc9ef1811ecf4f77672b021f6e5ad71a81ed22e950e91deb9a8782f2a8caba023c50687348e8e1121432e2ade0b0bcb2c7d58dd0347b87d00e6381d2a2e237688028f123664110b27efd909c3b1eff2a57e5e4614f17e8157fdfaabd661a4f8b363fb16f15e6f8e10d23927f08924499abe279a3922439a24328f2c7bc70ed15a536a45d4ab7913f5a6fe82dd34175b64adb57e1aedf9523f2309bee4a852d81cf0a545b7342419e10373c0882fd8f7cdf5bc0a06ee4108217c2cb17483e6e507bd60e4ae75e0cbc48d036395c2e2c0174804eac03fa8f374f22bc1ebe4b4f6b6d6b142e7e626e6eddde4be7c7fbd03a4b160df8f24fc98c2f55d9cc0e5fac5f18cac404213f7e101a2136d6484bfaaeabaae0ba316adb5caa12accac168414428b52eb75be5e7a552f48654d872209413a26524f48ee27cf467aa125ece9b138cb05dc5c629b64f77e025f5a098494d6dd556544df886ee9deb125ea35998240de33a20776eb27aee791723f812fcf8a49b5154facc8f01335f5d48d674803e882135de820adc18ef9bd572bd8f728eabd2bd8ed5981f5c06ecf8a67d3c3c78febd05d4082d0c36338767b4494e46eaadbf5f4cd99de7bdd4278606d70b01dd8cdf548966c047c794aba057e4e253d4f8990ce796259cb7a7ed22dd0ea7a83c50e1cccf0a43518b37b8da14dc5c20eecf6943c794f7a8a1ed9c4c9ab02d381853e5a833ab0d437e823430ac31eadf59327b06dda481f7940aa123bbd22c24ee68011ede2a020824e86d74013ca481268d39ae37947fa496b48dac5c26d4589823d7e64f75a090ee4c199388df3492423203b28867045bede63a25be0df1092339237d7f382e0c017f821dd026f84542443088964a8644e6b49a45fc341817db90fff248eb7466b0f5e4f65054ea2c82e0a1ae4649c5e22bb286ab084edd7c0e6471fe9914276503811243bf1233b2884d0236fafc7eb23b92722da25879bf172381773561405ef2af5e82084d510274f5df878a5ecbf9de7c4cda8ceb9a85ab05b8bfc1e0b0b52d4220b29a2e2145d13165108a16dedf5c06860e3bb2d28c0085f8c31eec83723cafd4e723b8916a4c84e8a9af71e912ae2ab2994ca2929e10c29671546ba7ed1ae5dd803618dc620863d105ea5a67c967e89e20f8f18468cd59800bc87c71e8ec1b370994509922e80fbc3479774202ef5778657507ea0c8110a8acafb874a33215146584665450281a2822280a3ac0800050505058fe2e5caa993604fc8874849141494930270b7970370acc6c8c32adf4b904e915070f4b40fbd0445b278545656aecb2a1005368f28650751219d8a2495d123894445126974791200be8958a48d8b004687273daaac8c4838f68ff762f4c381b8a407e006e0baf6216de0cbcb61c1db740100fee12f07bef43d7e39199694a4507a604bfbf0dbf0387e74d2ca4717fd87eb5630e913ecf1a1a9d1439824125d5618118a8aca48e521958f42afd12a2a8f376614ec315a51ac3128107ee5d25518d048253e95214824124945e59242b8976071d1ed01976e29e52eb3d052282d27774f0ecae9925088e79289bc499b1e9dfe216de08b464d40b4ebba45d29ef6f18496a10a2b74604fb7f46113497a94d0322411d132944270d444cf68898a88c54baf1ea9e62caecba5bbc11c3a554b2b2b948ca5f895a3dcb50b85b71a94eb5a5b5959e95cfaab2938f60f958f46a38b6e0abcca45418937e592eeaa04b2ec54a67215780ac38356aecae82ab726935246387e2eb5a2d62296d178f5f454c8a4070b82dd62cf466a6923ea89935a1189c55974806802e42ca902a65213f4d181602f1331076648a04bd33022d2b70991c0968e33a41c0ae152c41009ec51291eba7c548ad83dc99d8f60936f7655d099224995c2c2b780b77a43dc23ccc708ce858e8fbc45263e20e92d9dc096ebba85e6889948ea304e11238e4aa274025f20926ee9374462041eb9a8780780ef43239802fd033539c2b829916ba010bbb511accb2223b819eea17c7a2929a1cf632dc5d6a0c8ee90717437ba144ea2350893a830150ff61049c324ed92894446c0c9af0bd941418423a2db1ad02f38fa28c66c14aac9d2da0fb64d901e49d8750be65ec54a5a6b88a4b57e0bec366b400a91e8e47ed542ba0c212ec153a2ec2240446beea51bd205a56c503af4031b2c06d6e52399ab306e5ad590693aaa929573d49c1475a58e375f5d98f92952310ec7ed05c918bb1112b770f51dcb4abdc35bc2e435794feadf95e44891a1180293eca070c24996911d1443b8c9580cec73cff268ed552bd88d25bf37456b52496bd0b22c8aa228eaf218fe3cc156afc9f0560ac6681d5ad6750fbbb1afca1992e32960050b317e3f5e8f1ed7ab3142dee1151e9049318905bccb0ebbb12f6f4f48766f1b1c5cd812d6ba1ccb66f38b7d7515a650457651c4c0c93c0ef71aed6e138e32e2233fbb2a40c1245f6e034a704cb9659df45959b241fdd43451b889795795a04110213ede88f1700b4dc8c1f5a37be4f7ee91fb477efd6e9c36c3ea73c23764a6103e08a173b1a57cbb4f9374ceb96a88bccec907646acc0516be549287f23247899f4e7e3bf911c1ae7a131516d21bea3df9caa24d9cf2d3d590fb541c97bbad31d6e523743d598571f23a68759c60f348a26a7255d514940c45c5a3815d56f6eac9f272aae4aba9aa20bea8a066686982f00e07fc74b972746635c6de6176ba5308fad41a032f23b13d85202a5fef8742774b2f7a434d54059b07944df24621e5e6af291e0df8792dc91b9532ae82749e56f0eac95462f96d46ba5b971595d2cd8a52d3bda6b06a8cf5ea140bfdbaf3d68d543c1a19cea4941496192e4d9f8712fb5463a8cb50bc3d893dfa9829796bceea8ae2346d22a0d436e3f0fcdb66689e24768717158fc683f6eac91d418d6283a95f445ab7c0d03f87d7e7b6b81a4be82f84a3cd30167489007d4207dd213eb7c7f1c132f6203c44a8055364fb21e00b8b85436c76e5fa16b20f7d63c958e6737b99d059b6cf4136742f96ebceb984be5dd765aeb3b468976babf5d5eb647489dd5bd3a8df42a77e856e0bad7328d4b988bfee8437ba8fbdd9dd483f648a77bc6c5d516bd3b15b61d25b9b86c0e06037118f7621a2b5e9d36b0d6c093e962065d12e4cf2f4e95b0f306254f79203b64c8fd5cd6819d34976b00efbabf98d89873866226e2df5696396d6a6bfb5e939e0cbe8d33637bb91f2483467083b07c27152408c18ad6d77b351423961252532c45413c1d864e4294f9513358b08c039e79c30c73945ea238ae24792bc3924eed373b4cbe4261cdad4063e72b65d8d4d61bbfb38dc13c37578b1c0be3bfac9aecac04e7fcf7c58f87ef512c437b40949d1b57cbc3437e3cdd0f19ccc6f2d993a4bbbc01901f8ebede2583437c365eac2a5f989b579245e9eb8458e38b1c39ad8e9d2f1c424fc309263c8287e148959be450a8e6479185246967fcfbd59a0fc3abf3f37e315211fb173129d0b79cc88955b8b2c61b4cb365bb8199de57350c0cd7059de3917efefc11d543da7b524127452b6689716adb59bb1a3aac91bcc854b0f5fa7feaeebee86a7aa5f4feb928e2c57b82b8ef80a23f15e2cddc8342f470d82e1da6236bfd160191cdfa38c4ccb404cbf84ad91efc98045bbd044c7138f5bd218fa7a45081f9d5d2feaca50979092126e9de12155035235f9f4be2caf6b629a78a301f2314bab8a91d4a5ac282931455115e5f2342739639ca80af3a6384d719a9efc7b943e0b0b4d3edda4489ef37a3ab1c82302faf676b27e02d3e99d22d159d87dffbc21de66f398a6c9e9f48e9baa271e8d2c7ebaeb221ffc72aca6a99f9895c3a50a06f5e2346dd67b9d3e8758063a8be1adf7aca6b0557593594dd83c5cef3c1aee48deac47e7ace6b1e6d445acf713d6d445328c2e5a2b0b4dd6acacf7ce7b013f6b4cfd74eb3afad0051dbbd8d3b1f0c57dba593f2dabba552dabc2fdc47b31ad12f563f71101ddd82d146f154f189026f613b89f783ad74599a91c310d4dfcf41927dc4fc8081bbe7ee2d1785d24c74baded141f543002051446a0b0c211f8ecfa95c934a18443120411268415bc131edd0ac68fee7439d0da055a7346b4e6269b0c8f55c1968498d93917304f8ec745b1800c1190e15b6c2e327cca45b9a38b8b90c2ce4f70073e2b7e6686c21b896427dcc145b4467d2696402413adc1d8ec748bcb30363cadb9bccd9b03e2e89eadd00974d20f420c9bc81bf8128964b7b204d78b76477cf579695e9e87b7baf3b1c8255f55d72b998ac967c571f315fb5df4ed875ca554947b893c87ce391a71c97bf15ee1e74ff0b9884526cec57b6c1297d05b21bc597a505c226f221379e36654cf0a6ec64dbb94ae6387a5eb17864b5aab1c54a12a98ab0c67fde76e3f640aef78994626d3e55f13a36ff29212474e55e188456121907e21b919d553363b827803b888d6261c5b4b79030e4a1d46f88a31dc00992e236524229f8358f51a2d1f9b40b137ee4cb188c571c7c783181521d2029b7d8b44a6f72c7b25188510c9ef5148bb6c32d6871ce1e198266ba220c401d25a1089238574cb7b04726157b070a789d16b349ca27e84e1ceab31b08ab8348fe1c93de2b40bc470a7b5d704b6c1bdf91fae9237d8e49337d8a477aabcc126d31685e4f72e856058b0f02ebb198e67abda9b75be496ffb8a541b2d192ea95c8052486bd2487e6f69a43189e35cbc4fc1ca4ca7794d601327ed2233ab804fece06654d791cdea167c055f55f0154f3482c4cb138e475a7bc7ae60b79879f2fb7be4d91161916864497e7f3cd22e70471a9147240e7c7972702def0f0f1305d605a49e41c31d4dde48262490695f86b19feb25ad35c1b5bc57f363a10ae987fc98f48b0bc2e5656c0a76833b15fc7b2e4aac6443c7bb226f3c72f5d8daeb1de7e25d73c69c11afc8dbab262c53b2319fe1351652b09345d62a08712ccd50190979012338b0f2d1b1ef8adcf6c3d21afdd63b70a75d4ad6b7e7a348bb942c7c43cbd6adf7a3351e280537e329c1b978395abb4e2febcf75efc097d93f8934a7b5538abcf58ea30177de8b778a7252e4ea1d25476ec915e65113c408268e2e0a46e75113c468c76521577f5bc8d52fbc53e1ad46276f330e49964102e6264630bacb30c7088f5edd098f2ebc1b096cf2347a4ac8efa38b821a1b1e9c1b1f3d4e60029b20525013447432ba5fe0021289a85dd8e0722cd79b60e4e90dc341479d8b493b9ddee202cec5f4225a9b8e69c16e742a69988124797a91015b8e01478302efc5f4e946b819d4a769b3970c0a4cd3e4bc90a738797a08c98ea7071352d0c9ae0a52c099ba4e3a6fd4c1236f57965b123636362e18c265e966c07793821839c68811a35b628b69df512c0001f9ddb9166ec6cbef1c8014ee5f904619b20837c1fc700ce7223a0d3817f14664c16e3136c7e488191920727c7c07e204710cad058c182cf13da880fcde3720f2d4c2b978bf99d240bd5c71fab3d675e3297c443422f691f7de9b3c36fe92af91a7f6f66e4ed6bd300cfb0cc9ba93c68a61ef599665d9f969a7697af3ba288df1650fc7cc937cad75e78a5d94dea2a777b9ab10f0f47f39ce2ccbb21a4df3f8928dcd03a4fc6846e91d764a2bb5515cc22c4a3f27a5749ad464599ff7dd9a71fabb734ed5ed8cdd193d40ca32140b31d5e479a9e9d69c60ad26ed7ed3a52cad691683c2e5582cabd4afc98d3b93aeada63a04e8979bc0bbf591ed3f8e2763788b19fbf5b9f6d7b316fc4a16ebaf7a99ab9e946bad78abdbeb9df59547bbbcd67a4ad5acfeaa9802568629c16e3322222870e3ddbeab8d7a8bb7cfeb86c92ccbb28c443a096f312eeb785764b73b678f93841d8997b15f15b5b7a93bfa75d1eb8e9eddce16b537e5d98599745dbe2ab542c07c597becf6ddb2dbdba75c18fb586360ce5e6b8cb331129f6b2cc3251b9db177c6aeb922fafc7c11ed321f7fd51847c37ec3322cb323c6e5f9685b288a24c9623ac532b5aa8505e38a416554056039c6e51aadc5d36439c6e507b48649271dc474bc2ba6e93d59281695dd2793e95042de3aca2dd9e863df917d749d7361fde5becfcff6fe80e53e86cd795d9b9d734ea403203959be4611e48973617f6f13055945d8d917015b282abad543f765d07d3cd9ded7670003f2ab1576b6880b6778be4653cccee40cbb9b28eb7857e4ebb2e28076c364b0c9de78d8070b415f8388f31a0c1939f264eb6e7deb1d45102619c35675ec83d55fd8bc349dab67dfac3dacb2efa6e3e57a245ebe2e5fade918765863b23bddba9d2376e55f1502e6ecee78ce05769a98afbb2991eb658ccb18266b8cc3f375ceeea68409f2b3a9c24d4f77aeaf62b5a7deafe8a28398bdbd3ade15996e4a64ebd67d0fab578712d9dedd1dd9eb2fe7026b800fd9de071fb2bb2267b7648301d99e01d9deba0cc8f3cf3afad8314cca9f7f0e2bcca7bacf16c330ecd867bee2b879629f58bfeb8d7efd85eb2dd9a8c75eedaf98ec98b3614fbfcd88eaa5ceba1e10e56d264ff87df44a4c1c8e9dfcf2cb979b4015850e8ee42965e02b05b4f62076b1b2b4cb83d346a06a31d148c4be36c3cd7befbdf7a494f2bd185f4fcf63b284d743e486404b8031157142778a6b81f6c5130164f81f98cc003917f0db5b42869fde0b853ec7d843b7c270083f25a14704c36f098c6989fb3cc6183350cc0e0ae1d7833df40d46c66e087477bc98bd9ea784cac9a13e512d1dce90a733293d6643efbf7723f598bc26a1f77644ce5ef6407f0f813efd4f1f0402bd6ccbe2e70f0bbd71c7528621509331d033d0b383b27efcdc2dfb640fb26f1c3f31cc868e85dea7b50765211b27aa7aaf5eac428fd97be8b10a6578aba8573dacaab1fe61fb874b3630ec34748a9dfe0add0f754a8fc55802bd745fdcacd0e3e929deb087fe0985f0e7dd0c822ef39e1d240a65bf3e0f852e13ff1e7ad61e643f58063b758b615aa75b5335290a3f9d21d812725e5c10cf07ce057ed4100224c31b888407deb9171fbe393164e8cee0da90a19b838cb8058c9b174ec0a07059d5a40ec385de9f8ff0595ca9a5a16befeafb7c3e8f71f9f3b9fc5cfe83e5a9b5a08fbd99ed27de8b7a58af73b1888b93be2871ae9aa844cd55e5510b1991060000b313000030100c07c482c150382ed9663d1e14800d9eb25670501887418e21630c2100000000000000000000000000c06606080bd671306782279cbe1a578ce152abd4b863a05c6fd9efc7af0623790058111d1b3679a2fd7e7e223d34685e45d31aa43cbc03210bc41697b37066994e535681ec1b51ab0cb3902d1e80f330a10eeb1591592063c1abd4a7806b31a7ba6a5e67528b644d7f0b7a93f36f1f28fcd27f13e8a0f65fcb08dc8c5da3107bf3266c2210cfcce0246fc602978f8ea4f856e319c55836b1f010497dcb3817868be1d0b07149f9a2c08075ee76779aa1e520b1101fab5546ee489cbd139ed7d28ecbbeccfbd4bda6bba9d1d1190b1f4c83453164d716f4cc98940e62fce6c18c743a860e7dc252557408740fbc431abc10f0ff81f7720f2c3bab97f5abcb7ecb8e1023f751cf1e8852ea976b5a80d86ee66aedfabbaf2c7a6484b9d7f41250bb274dc59727321afdfdfb7164f71e6efe7d0e47c61104e9ddf8b14d07a1d8e748dcd0da1da86c0e594365ab667dd5f184b64538c25ed02f559a59e9a65c747be30a309d1d32cc5f0651f47cfcd01377a96e8c1f276c2c32c6388553b392c1154caba546833fc5c0d4ef0245f82df0916a3c8626483e940f49c7d7c3d6a50fb8c7a5903939209e490807448de70d11ce31b5a2b5762be3e7ff37d90e7de474c51a50a2a5a50238d7866b98a807c91721cb2a913d8229299e638d8271c4a6145d18d0b237f91030e47eb9217c9ed7cef550c7e0b94990f39e4c8b9afb7da20bf33f17a5487ad2c33bba03eeed6d127c9e2891164a59177bb5dfe57ec28f7c4059b2c960bb8db33a28f83252c4d24e8dd6aec72765b7b3ad1dbd5f38c024ba81a9bba94b95676f6811accf1d5673d318895a9c2f9a080fc4f210c78da23adbfa4debf0d13c040ba92fa6a9c8149d733bf268668baa0b9d37eb49bff0085fd7ad7197a3e98bb550f5db8115f7f7da4a791b9b211b9c1ce36d370e844d7390747b868af4148efef3ab4069d7efc351bf86e9f80021139ca2837a0eba429f98a538da059f30aadaf10c689d262345f131d1f13a465e8bbd9f32e34246860c2f0b12aa1e18863d9b0b28a4576224b9cce3d941ebaaf6ad574e97a35b80148d3db5ad3fd6e4807c23d547260266c87a4e35bb5474d1607717d0f6e1c8dcc8e836a0029458447f23a4f22590d561dfde22339730cc32ecfa2b842327d88ca9967f7e154bd96e29a0199f4e5777ffa3857289f540d9594fc961a0815b310d89887bd7154f3e2d0a4c6b42cb16ca5423ce008a06d94532a71b50b8949ec2ae70d6017ca08d5a2df1f6c6777ec53ac1960575e25a8192dfd589ddbfd213adc17d4e80e28ce1a6260848c163ebb1c7c04180e954f7a41033eb4b1c95782ca442577a1545dc3ce1a334fd074da475fea4aaf0d3e4243fef499e6decb49f29224a0c610b4585813173a2d2a900cbfe12e44d1f63de5b083825da3cf287f392510947ef1ea10fd0109fb00918c16262f3a9c9a6acc99767d92ebc9c4941da3e0cf1e0be4f54401961485820ebb6e424101e1d4fb086f376e6fcf2f61a69a54fe78fbc1aa42439c97aae6afb606255149d27f2cc35a61f86db818b08b6a7619d8d6a079260376266c46db4c59f9fb8456442d7127626e2b22db750005610c93c6cb682fe09c414e6d08a93c01ceb8f18d7951bfaf0ea50b6223377b67a735f1d8483cbf21394def9e1b17fe4e4179f71d49be853c633a691c1ec42503c849561f012f6fdb96bf2e0a8138f4ced59fc0e82d931a58409b783d7b4e94493125a4b6350fd2d19b07a853612c7b39bc7ea47f0f092ef95af4b413425e82526b5a5a032fdf6b43027b9defa8442779403efec885a543e4fc77e86d9c98052a2d560ee3de0f6e6c9811405e09fe50d7c51788e4166af8227610ab4a6c1c4038a880ed5806d164783c19169b7c0f21c12b48d2d56f4d5ec18bb4e04e1a7931e1e08babc29a5804ab8f268325e981321c565a7473ddc2414f4d45ca658e90d1946a513717ae64942e0ee039dc59cc7b3c5c9291517a7290e00e58bdef8233e33dffbf7e0bcdc643f0d1c1c8478374b753cf02d9a762ad14ea8c28f28ac15f35e75d8e71165c3d9c0f3a182216cca9f02546e184a1570e9e9a837003e5a7d9c23fbc70ec78f264479ef127effba65f3cef266cf1521069ae87ef59451f3f7832233585d1f0edad7914242796a28f1e6db64942414876f7c23f610836ea0214b4ee3bc3cd859b23f5819100be051b698f05ed3013ef024ddc35c5b6134b08b245607abd1109fc91682de1e6fd95d757231560c9c62b02348e979ec045a193a60171405097bb953d102e5102023344e92d90bf0e30afdfaf6e0c8a4bf49c2c951650e68785182c5993a365944a25c2763862bd11e631793efa1bc442eaf6552c9c74253f727803740b696c7f766627cdd39189c2e397fef31ffb149068060803db59554f648e76ccc681e23a936da21e90c0588e2cfee227c386822c8bd27b19f516eeec8f8c07b65d5de427519d98ddf6eef3c380643cb90e74240f06089ca1ca9b6bc070a5e0baf966525c7a0b5ae80702fd04b1211b60adf5e86b21132bed07f8fdf1bd9f5d6c12289776bc63cca3cf84851424bcd830381d2d9cb6d798f11d4e3f57eb50c2fd22c68ae39115ccd18c3219197269407995b2027145abbce00d0760af7ea52b196aa1c28c6ee4599f9623162f7ea7e816eeb3aea7ddc14958edd9b1a237350d49fcf792d453514f893c44b100477271c58aeb63d560d5123626cbae3df91dc68c53974804e3ea76fad9fdbb185cdb740e4221c13ace3b4a340441b72b8f864505c3d8180454a8185e82464c96ab8094c83f2c7b1d60d7c3d762eda73b34d64b7178084b687bf06ae5fc8dcdc415dbbd61e8082891281670d6ae06d74223d376a5cdb7a2a5a2dcff692e76c741eb6a95dabf25f746acc8323bda83c1ad7b21bb79010332eec41e6cb75682fd6ab3dbc4ac193be915aa89b46a80f27ad3dac69b966079533078a9a4c6090cba8c93ef7d8d37bead79424eb7334db80d6daeba9349d2f32d63252a02336359b7ea6bdb52ecca08f69efe292e6097ed8245d1fad6f39b0c278cde3c3e46100f28df44aa0bc45947f0f8cc70024ff0f4363c8dec4a7525629e0470898197b775a5cb5d324b04a3160b11485d0ab12f46a96cf7c1e0a2e458a25badcba53fa8b1a40568b172d7ef5995e44b926acfa882e5ddc187be57177b659cdd32f46519868e16b5c653f12a441a223b77dcb1777ea5e0a217c3404c36e7de0b35284b6602658b7bc7b9cec8c4b8c8be4b038622c4fa424265098e9630610e35afe97540d8fe7db585db540d5ce3d09bafddb797ad2f60ed6157300724de21f8475ace0d93c1f7cfbe3abc3f040d4027d92365e1aac9f5ac41fd0b540ed837467f27674646c48cf9c295fac2fc7f438124c9303ea2db193101ba46d21fbf1fd067a3b5cf9f85e7a775efefcb48ca49cbdec51358f12cf5ab378a5e65d18fc2fc457f10b275074ea1529ddcfca4308e2fbdb42cad9a1ff4b9a5aa69a77af943222781b8989b6556185b65d24e84cc59cc9b0218641a83e607dba3ae57dc093a9870e55af8e11343454784bc5096a20bfadbc6e0f8de56baef6b417453c05281a8aec27df8d1eb00859897b0553fd1e05fe4dfb4e0239ddcc9d07eeb6d9026e19917a745600e40adddd89b8e72176d6f99e510414d31ef0433a6272a7f958ded7a112afa25a439ccc0053480e42c5b56cf301b78fad74b740503832f2e9843fc6b55ed444a2f7bec3e77fc4d080ed80ae5fcda09d768d697b9676f4c593013703d63e101546f6440cd1a4f9f89093f99f2e317fcd210ea34f2811a0447c0218a6ad252418d2815b4814ce327af3227c0c6b7ba7d8c5e954f57ad0b7c273f5f953aff85c7fbb45179ac35573b394f7384e672fb68bb7acbd7025b05dbf005f2301147462a59ba956ee77a043f6937c2b842be43f1cd8c976c847dd0a63d0eff5a37b4134f2c7f21a3652d8f9e252b5ac450afd050cbfdbdf1454fea2a6130f01b066116336c1968ebd55749c8871d35b4839d16846767260a2b42f830a75aa902a0d0253f1928a0071c60a7ff808625f90916507f34c3616125f510d1e3b3c444c45b3c83007c55d6958fdfdc9e39e1ed318ad750bbe8fc393d4cb1ffafb77d36d94922a0b8bddc023720212a6df3f36128e2b419565a1b6e821a2177865570630d6ca404c0d780e2087888adb88f3e5ef3140e44142415a4d2640ebdf8523a14fa9995951527fd355c3f514e1728aa94c6165cfbc50b147460518f80150339dfa8dd3237bdf3257e08dbea28a407d8ccaaa9a39a438250b629e282905747817f5cbf6faa2f7ff4e98b32300a3500ab8119cdbb1740479198caf74c4ad20c85c607200b8d8d3973f7320c90d14b0077043034c16f9cd87a2cad166d4075d40ad1d99dc2a08a9d9085a1c0f5730fb3681bac4fa6bca1bdffcb4a7d88d63d30561b2a0870bd97aa8a80774459b2596657c8a16663a345526b138b57fad237b31ebece0d2ac04abf28a459063def787366350f56f90b755e9f1cd7818ebd9af4b843690c14beab38209155d71dcb53e1a1b0d4277ee6c8c9090ab1f5bae39eb1453778e316e4191ce28d243e7bf8a9f404a9ae9fcfeee08de8c84782688928bbdddccbde271b1b98f48ed520ed0f882437393aa418b29bdc5c376df18aa3a126453386b5c6acaab60787f37fe403956461d214ef00ea92bd5aad2acb538873c27df004166a7dac83d1ad74357bbd35f597cf70a34ca60bfbb345ddd8444b17c0e3654fedae13907530e7afcadebdd788436cb7b9476035faffa883badaeb9c8b93ddd14e48bf9d0a48493a5d07f68b46ad8a60583ddc0b5c728079afe7b3192ad410af8f46b6610c2f347dfff434f3c0f9796fa9d1689fad5fccd8af0722776de7949e1d4d92be11589e67a222f2f6c6283d026478841f09b221304fe0def19b91d97b27f82b9e96445da2418cac327411fb7c194caa304bdc9b6d52083301a7ead2307290dbef593e8a2bd6f391229ceb94c211859f23dc6a83af66db7ad8ecd7826fa11b0fe56e888b49f2d07f17c6164107a3ebee982864429c159f3fa2b126dcb3e016d2f7c186008c61e8fcf8323503832862295720b82eb7d005df4d14cf3ee1d5e286a2cde10191fa010d29fecd4b779c12a1978cc5da5b985dc4d5ee288b1cbacefefc7b2723a2718028efba20260f9517a61a924100c02dcc75c980d868f88dce0c64b55030494b56f42f050a829b456400f040885654932aabaeb9755287a1cafd98205effe6c050ab1b023fb2094532416b0af0e229b994c95d7ba54c78d7a6eef0527c26e2a61a50d1c61b3e9e0186257e0a44884a3722b0c315987ae9276d73f0796ad999a403873b97068e0d81290df0c5e4663b409b8f0c4e47af70c4e6939cc577e813991e6fb24e97fb7a9c195d8fdf367d5cf5a5045a4c239e693a24a8377430161a53463ff7221f04030b829a9d5fd46674334f379c83485a4437cec39b9c4c8ffff7faa8c3acc25f998e5a88b60e04d86c822c9d117a42721455d9add4e076de26382a1993b3623f5f996e1c00d4e55431de9324d95a4b9dc636ca7a60353257154dddde97cfd977fa30e2b2b8d955f7d8cd69159656166ed18b05275f5627e66fa00e11fec077af8fb772473c0448aa8bb06206aa866c50a40ed6f7f9f0988c302ca7b8ea25a2145309a115c7272c7ac548821eea80ee9feb9fc38ba223d09481215b7ea2ec99e04903aa84b4d9bf159aaaeb60415ba51222526f16b5f9f993b03dfe3cc3eaf3ff52f559d43c86ff2c135ba7e61a98a7399833813b7d7300fc049515d3f535ea15d4670961f81e87ac33bca122645da754667fbf6578428ab92675df22cd19e0eaa836148f442b2a0d46b8bd6fdfb1c432a8f13497c217e7eb017b68fd20b7d98a9cd19ce959673c45e848ed64e57a78ff53eb50b4cf7ec166864c1a89de11d0139cd363d789830f8adc6d6af195f4d7bcef7abd8e05d542f617e6767846c9af30dc6048a4f853203e562816af6829851e1c8d8ac27f3a5ddeb6b113f5c94195fa01e14637bb005248bbcf05e2092fd64f07dad239558173b98201fbae2e63e7909dbcbb8df19c75bc374f0a2b59d952acfd8960fb88c394e4ce182fd067f24c5114f04bae66354a70a6879ef8ea1a0e6f23a2fa675ccd9d60036f27c1062659ada4fe0821b544e4c77e954807ad2bab11657a5aeca32ad002694e48b82e02d7ac6424a0d6de1c1f36fa0a4fe558558c317319e0bf7e457ed7752dd0f782b549f80778373108a69d3acfa8100f97d2b4a339cfe4494ff3a75d7680fb6e5e703203d728da5301e7b31a4d3704f07d51a51b80f4a73ec592910326a4a6664582f7dd859059913d6e55fc69a7aa83c66c7f20b1e4b63c868867d3dced4062adfe3dae406f5d5a89a106acc91ad56fdf446cdc73e1170bd201a321b68f04ca51f5ac619b1dbd736f65233620ceecac5eb04b87e2324b40f44602cc2baaef9c5484824e83606b2868ba005dd34eb0d17737a9432ca02be33f71840e5e74de21be2b9c18dbf98ae887b24b159c6b1e3bfd65879dffc61eb19cb0c9d6e8b6a2c3696e262a28bf092c27389bd017df495e9d95252b35f693aa79180989b102076bc23244aa059c19f736b8444d7ebad5a03cca2c2a1e7cbd95fa5a8a455310e2b753140914af4e0ca13aa2039902a1110fe9c89493e437d73cb1a2914a75b784e1e519d5d6dc0b301196254ce1322c3eb6bade772b56b3c2935256b5e23f247aab2688671d10fcf93a754a7d4dcc3f1b60c78d45d360ec3ce91bb824fdaf3bbaf997b76a78aa809d6681ae8a3cd13a1881acfd9ba6032aee7c2c56661c5a1707a95954d6792b4667cf6cdacf2748962056d740533d9ad4fe55e3e932c37a4ece8f4e21641dc6228703ec270c420d1ca35a5db35a938a26663139481187b402e780ba81541427d6b1d772f0cd811242e62b78257c3cd208ad15642a7b875acadd032def697976b12c4252d17a6ddb528fba02d2c07b4be7a24033cb2added4e6fcad1c32562d14687066ce14b4cfa21d9b7abe34a037ac31bda14704b612c85e431fd0502d58a575e714aae7138aaaf0d6f08ce03ee78b234d13fb3f39705a92cc780edecc55fd9c57e81b403e997965997b5081d07a7d21fe9a125fb209d900a91cae1a4f18fef46ed18897210c3333101da7ab82959a6b5be8326a786cd5de30cd7e9072baba3660e39695bc45446ffd25721963be3f43c8a859feb0dda5d9719100b95ee3df84455ab78df2d7821c7b520e73e719b7dd1223037c515d83b1075e7ec347480caa1231849be71f5de6e46ae5c4d601b3f99334259f5828b29dea57ab13cec80fd213596fd8595c52de9d1ddcf17f0cbc2667de85c1324873db4c9cc04a332e902850440dc59f633d3ed16a4db36cc27e6e2031504c6b0b1eb230240e23376f4491ded4acd188b428347f5688a368d0012e0841c5a0440488f019069d17a00372c08d5ab1f696e62d1b983924f301156c6a0620618505bdb07b1b119e414caccc21810c8d4b6654597ada14b4d1e7f60ab3a6d230b1037a2c92d893c9d7051f9c08abb0395a7a37caa63cbce0a43ca5d286c8af31a05b359454637064197af22b9f37752e590918bc3583bc25f77ac8971f76f1b8eb8483c59f21ee6d1fe03e08cf8f51b0b30c3e73680e6502b1b2081550cbedd61f3d0cc6801d626d535188c6dec0fa03400fe4744581cc73295dff56781e1b5518f5c01dc59111ba12ec217df3bde18b75c7c981a7ce1c3831fc32ea2b564c28e2856780712362b67ee93efa0b3d556ecbb8f4da5ecbb037c53d178f640394f2c7f1f2f5d8e2fda1a5e3a418e20f7c29bb20a06e0e77487437d321eb4ace0ee1f7387db120426417bd1e77f86a12a95c527fa0cd78c11435334214a5b3c66965eca30939f0937de29c30ef538c29aa78cfbdf57eabb08465b6b9571d069678cbd4f632b88c1653621866c0fe53038f24363d22e6e337f19065d4b3ea0e938df66187d03451201e320c4f49236532ae6d0aa46590406163060b1a53828f1a2c1578653889c7822c5cfe20d93e3d122f00c409a453f72d691e20d599aec6b1064f13dae29828a8cabafebc178c3d5453cbf1a371210a59f9672675aa4844086a47621d5fa89d38b315020b84923b452dbb088c34412a5a5acdd23ff618a8bf25ee28a12d3638d7b84b459eb29c0617a42286a87001832192cf03a2eb78fd21df5da56e711246bd1c46bc99c42731a55999f1159527549ccc9660e6b6615e78dc4bf84e7b19aa38e0f5b1a901973aa845d911d7d94c0eaab75db10200728eb73e3507afda075dc92bca2031ed4518b7a7126bf6177b00cbeceff35ef4e13f73ac8fb005b787460c5a6e51919d16b68d5e76d0160f710446b1fb515a2dbf91792848f2958a687e2e725352e7ef69fded61f7bfa3261a589fa286772749a68e764c339007f98a81b6715d0ba12420b34d5272a9362965df84c9a05307ca1576459710b7b2f67f4eeaf3a6431024f967b88ee94ac3a9573e3ef4567d51ce23a4edd41b39da1dc9f9c031723a9191b8665384b1282b5f92a3171a11db60a49a03d33b347cbc787c2018cb1748cc5b616320d67d4df993c6b49fe7a196b7d551c3f074b7745b239d444665959408e2234f034a485ff53a8081a77f9780d45060da525ae70fb1e7b5d21298535c57e11b47b3a947b8415e1aa4fb5a7ab87b45a68d885ad07eb43cafef4b3747131a7c8f6532da4322a0cfe7daf181811b3e441cd4b1d46e1aff21d05e7ab46224da7f461cc2407f2422c9387afda12089f099d1f989cffff82ca5476c6c2fc0ecda6c0ceb54a9d42e64009d19cb5a9338e88f6a8cc72d42c81ac5490a93cae08078a1e3fa9268ce3bab464bcb02ff8bafe44d4a4f558f7826b657b6c54be2397e441b650106a80557b64b22704a58dc9e9ba300288487490c5d9a8a77a2ebd24f03d6c010e2c88001693389dc17f85305610d44939f5ce6d044c6bbdad13299f5c8c8c94e4ba06d14394da2210849067cd49290630b2310fa09a9a94974d5ac9f4ede8f3b05c999858454e503d0405195090e2aca913e00b594c703be82634106edd10a67f63edfe178d2fd77d77da048408fe03d741e3450b4029d2898f269e24f8c0449447910fc919ead4c60ade4b24fbe81624a3596835716076ea0c8ce84474eacdc883c82b8fd40d18a76ca7e7674b60c143e708d6f717c84c1a4bd77f653e0d011b3ea0fd823408c83301828b215614a84f29647068ac16e9417c758dafe31dc1ceb78324f5fa30af40e1d1842d2e5cbe98df2590afd7de661d18b93e6f5c79f5e03c5fb86e121d6a9f8fcdc91e46618182f50e2bf0d149fab4c652bcad851a6bf25f433df87028980d727d632509c0dc23c4d80df7d4ad3191a28f20d7f4023c800fa0f0112cf232624ac2d3e23e93f5a1e4e1c88d1ff99130b54dc5a3f80e2517a2a0709fd15e35443f285ac0b0e05687f97081d2826314b15f69ea3a93f503c3ae2b02f7370b8f06aa2915f2352ea6a44dd011438dd3e2d3d49d412be9f7290a00d19cc99213117899d6fea81a2b384f2a3c263a9686b295b6f031e0ab0026977a0884f3b4ae30c148fc307e30482e57b73332a2c81cf3817f797ab394d516a27cad7a1a514097e263edc65575271c915e94a1f00c21556ecb388866141ceed9f71396168721ff6bbabe786b844b8ae37c2c38aa688241863c543dfb794cb8a5f86a4ecd98a3fb7d566d757bfde265a8ccbbbe202c93f1fde2fedf5812c73f8dedb3351f865463c14830d5d01cf5bb7fc67fcb54e79d99607fea454cb5171b3c7e1465990d08743f30bccd13796cf80d388ff2f33d960769db1113b7e9b92b308562db4a98908a29899090d93a766c02fa7bcdbe3dede2934c267540950319e1708fccee254981c21161b56c212c58e8a589753898b5a4774c55af0863009e6eb681aa26c1f426adb1b6456179444ac621d61de55d5ac8b5e26d3fed2cc0489ed707f99606c2536c0e4a7ea7e2c8313b0d5fc04419036c4108c62f6114785b3902f9d2e5f999ba7319062e24648244ac4a330fe244d83ad36eae1308f3cf4d12a1be6438ec297a3c30c3dae1e7d4854b4118c7d8888e9322038be796d0af31331e7973d290640999d9121e6d05ba35be0ab1e158167929629548baf289027ed79411202aa1a2e5dfe44c27192825d64553bfac553a0ed6034d1231eb25b59ed8adb50c767028cc29f8235dec6cdc6c97711e0e073714af09ac3083080a6802b17660846c7bc5d1842a01d9894842930b627a6904a4290eeb906063a059a36801a03a1f5fc7df8c3c4037f92988211817edc377cfa5b300c07e009618547f0c17feed0eaa0d24e07a2c90f2efc3ae6d387189ed4e97774e178269a6632fc69eb36c4058687572e89979692cc9459980ca7dfd5d606e11473bb4d5b3fdc6a7d281df6e26d3c9ac022415e3c7989fb45cbff7f0a4b0bc103423db24128be62bc86ea0b10108253b88cc6e5bf4716bda5020c7697313ecbb507603cf2afb7e2c046ce91c425c005ad8ff183f6fb22cbbea2deb70e51454ac5c0e97d93d538664f940cf6bec645bc4b96a1102de112031c2680d1fba6dc5269f34d306156f734824089e2457193f0db806acd69c486ffce2e1343222709c53f798a4fec57355de36fa2c9b9f88ff3a58368f56b629d80c2214a057993df25af5bf113105a26f271063ae9bf75e59f11d171e5dbb59ba98e71517bdb203c1ab1d9f24e44d789431c89def9e95444ed38f380f96a6c717822650d5cef0e3cda45f53ae363db0d9f80fbf92479978d8d55e698fc872ba3c3c6a7cbc714f3da3a2c7e63f5db44fd43c9f04387bf98302421a2f142e14a97ca5f2f91bfdc3fb1612ffc9a8cb9f74c007c6cc3f0b197bf14cf626f8f5675e911ecf1b393c6f7268dcb4ff23eebc84bad04f8332a1b3e2a0569d51d68d5128a6e7fc4389d02356198b8b7d9fc4862463a9648dd62287202b7c42ddcb60eae1d62556dd3e08a36b28dbc629c0a09426783fbf7d5dcf05a8d51ea413695ad4a5c7ec704ea846aa2f3cb0ebf3b0cfee86a02eec02a263988044e741cca5e757e6494d0d0d8d7b1c0b3c1729c6dbbc1f6447b0050746ebe00ab67270be3cbe0e8d0aa2e9f910066c8811512b59375231b463311b45ef3d5626421a032c8823317f4c31de86b6138530ea62ad290286b3fd43d8521e597399d41d1092238938ea8b56fbe81dd7d7e0c08f1b899962464d81e2dc5fc982ed8681071b5d5d3e8199aaa2dd94cfa9d9d5e83ce46ca72fa77ca78f17d21423ae6a0217031d2f3d01c406cecf7929c41a04138e56c01088b4c0c06b99da614c812b1ab6285a21f04661b9f248cf997fdf46829cf2bfa4531a50b41b92e1bb76f6eff56891d0210896371f5827deeddf1b503fb124155f75927313dace82eceecbb0c7823a6c12a111b58f24615a6711b6f34b444ac57af46b7d3c32b8049f0d67ec5a0c2cc2ba226d49bc85918bfa70b877c05c0185e1b0ebf59a5e1874bc55461ce95a141462c12aa0604b4f99037c13f00aa825a19e9ad156ef0c2fa259201bd4963d387e46fc2015baa275067a26f63321eb383a6e2e3404e57b4467e2fbd42fce93ac305bb53ea0ab045da4b42c38802d9c9e7f4bb1a968e3761805ab255d152a4cfde2fcc361866839defb0e1930b7301aeb3dc0b3e20c3c46017839f3c59f0d0ac2d0dd52834c046470a8b7e31702903e6219e2ce79e516a023632e0b5c963e0b24c1bbea6ac3c2f9059529653a5e1f5455b8564f27e9b9920aea3159fb8d341d09c6d4888bf771d6d61116039b0a54de59e005ae161d71ab72107af3504b81cc23a7681a3d20ff113cb508c1ba25aeda77a14ad1b7d54fafc7181c10eba03604c85e25932e15acb37b0095ffff196420710c6d34641966c8b1cfda63d70d2a8724c3b32f301fcafe07bfb1d9a5bfab85e1b47432b092303f621c160e9c0b0d0fd9638b3cb739e9fe09d0e64f10cf67f8215c47276ab52e4666e968ca7ce8a063233068c6a29b0c50d01c64e02060744608a2465d59ddcadc8f253aff80be564cd89ba601c2cf16a8f961cb8850ada1ccb044ec6b37c625a32e520b8936bff758c5d92ce78e660128b2a6141c799b45db3b45cf93ab609e379a9d14ad973fd352739b83ed0e56fa928a2dd74cd1a751cb929cd167b4157cec4138e51106a2fe4f5e1552dd6e48845faf8ca4c75a6a7a02ff581502cd8c5105e685c8b724909c97d8508e9a42ce10554d8e0de5e68a91165ddf83ac5d09eeb10f432a4d9636dfbaec293a8e855b47ae463e46f94f1c59e4fbe414102b9f072380c987808e5bbd8f1e1e5a884944b135cf30df452fae0b731dfde08b112839719a83ea422e2be944a57a5d6e0b68c22bdfb013475dc14014c22de311d7ce7c8540b4ac0179609fa56927b299587efd9cb9537d6ffd26b3e22058162ba22c0cc8a5f7e5349ee11dbbc69afdc242b23edc5c0230ceeaf2f6a31aa7f73348a044d4491e215e8d881aa32114e4360bce47b425546d2de92cd24ca8136d363c441036c69fed028fb90199b0307ca7eaf05f8d765a00405da19986004051f2ccb586ddbbdacca41caea5aca2a08b29b6e83b8ce9e772551d8d3d400c3e65a917a1262414ba30cbd2eeeb0f94ff8291caee4721ce4a270e3fbcae2b0c6c4ec2d73c5b0821d0afac772e03cee54348dd85e4078fdd0ff62212c93665a234e45f54651d57eef0facfdba42590ba3d9fb7f0daed0ef57886b2c4cb792e5c6eff1c08cc9367f258410f605c4b75ae70d2d0aa85804348426eb6817cfc90822b2dc40a9d5a0138b78f8b343356f94231682433b7904a098055547028b78456339b08268d099351c221f2c61020ec3c4b603d0091f0e919569314e6218acc0b08d54553c44cc860579af50613752fc025988a612c511781270496c6ebed37cd3286491196268c957640b57d058cd10f66830ffd315b9c9031c4949b8e4e5316b11efb60fc1e61c881ee38a56b04c134514ee8a5549dc1fe802f85f021071789b87914fb5d6629f2076d067e4891364207a6f55b017fd903c8e09d42d2df272af07fc0bfc05f1131cd5eb78c2e19cdfdcfb37a49cccf67ed4ff00cd02fd8a45cf10c5878a18805ec1136236a096e14e6657072ec870dea61f90852bcd1200c6b19b822d8c2c45356ce00bf19990c4267852e411d5f152e1f0e58c0971f3ab8a8417b75b5a548cf1eb421e6003a70c2142f5e7e881576e9ea33f7867185b01a84d953f4940d1fd32d690ed890de62964207ac33b4cd073a03071c27b69af3f4741a3e8323e58d05eaabe06cef15b60e276158adba7e16b107c02720dad309c13b39aeeb1bb08012eaa1b95a977b522555b8a90e128b59ad1b52cb7c872396e272d9049712cd606df4e780da8bb11c4db96df45811c8f79aee842e4a7c477cb653a0650befe62e32fb620f3cecedf9dae4e0e449854aeed928390b79c180a259a2fbd0aa06f3ef938169384c7d5602513c8d23d2d9507568cb3c747d96792abc90cc9af7b09a50a26e8c82eb6878b96e7bc392f4223a018a73ebcdef16ee5f5954ae1bd9a0b8857eac28574473b65f2eb3595d2ef3798d191363250832409227185236fddb66f1a08fb7b754ffbd21a3a40bb2710365cffc254655a1a5bd604e4b78f318fb37be3a2403c53f1c52d2d8d635da048df5b103671f65cdc44c026a11e4ac694b828e1d7ecfca6b936dccf137061206d3901326578fa8bf935ad6f6b2bc2958215a1f47915aecd8e522b726d8d129970f360e0507fa7c246d5612a34551e78870d02fb5b443f015a2f7beaf3a6acc8d622a7d904218e329c9da94419c2d52cf49905c293f0b44c8d8d1da3b50b1dc8e40b3cba6e336ff9bd3c4570e6617abbe1885afc60c289cadedc09ed11073adf29e3df3d83e3eb7499672f8da76123450457937b1ece91a5a46dc320f12a9df32581d13722409e1743fe73e07b0f69b909e5d1bef4260302231014209fa871bb7cbba6a416b930311dfee72ccb80408ff60b36185e38576dcc7d6693ce12ef76b99200e5a2b50ebb61c3c9cc910725abc1d983d823a6952f85c2ac1ea4b6906ced0a7356a726764a10a5d44248dfa58155e1be09851343a367ade7d39c5f72d2e0eea6cd2e85ea55d2176847306fa8123de9bbf7083d36b3f7d7d500c0878921fe29ba03b642135dd3781febcc6e7e08d731d468d3b19e32ad090ac8e21c968d8fd211d750e9f52907f445ca5e6bbc9afd09d16f2286f1f07cbe063dfa7062b7238259f3177af8f85187fc6d895ddcf3c14383a9a6d20789cf92ecc446fe3b8f9ab501580e2303d703de36c4342560858dc24fcc329ae736c5b3d5a552646abe8375f9b068c0245d0ad86bd06dd5cbb8400a92c16dfb75623da729e04e741daf88bf8a0ffef4673fae91e544d32656a0f9231626f5d35495504907ad74d73a7d80387057369a443616cbec9be6fbaa3e192742f8bbc86718ff6c393bb3d1d69873e901b86b1cab63edef228eba8484b1c7e2209c899fc0131a8fadbfd41f23033bb4db00733a56446284fadc774978c23a2f3c14a4fe4364505d6cd5356c6193e177e6b558bd6e1b01dcb45698868e66704ae1f55161dbe50d377cc431cc442ab74ac27bad6760ada194ec41bb3b709f036fb0ecac6e7cf1ec35469dce571456d1716a3711379eba07190cd21a181003070b96a74a6af67c98cb53bd4a786315b78e5d4726df14130fc3ca75600ad5f15b5bdee2a9ec0447b73a8a46388495f11711817d81e4a99f0496ec57cc309efa5879446684d4b4f8632d72e5a9729332a9b9d83ee1a878a0b54c9e852b951fb460fb02e609dd2692ad29ba215698945ac41d8197e8c9ddbcc732423fc0dc17141cbfc5cb185de6703df359b849a13dd149e5b665f9b7e8041d933986bc1c569322093e545aab0ca83aef98ff6ae92495c4508ebf3e3dbafe896c65862185c9358f2ad882bd35d1b179486a72c6c9cd2375a8f0c50f071f1062c18d0adb0b76704a4e929cc68af0f597490376c7fa10c446c9a103d3d5e7cb0608654da3c835668ffccc48707e29ac1bec94690184567c1ba7206a8e9da27317b5f5e39831f42f911d7282ca6d972ccc5f9d874897e239e04e5c532a0038a5f830f191004544923062a30ff902fdaaee216f8ce38d559519508784c748847600f6d36bdcf07e017953fb75f0ae286d22c612ea84acc4559ad051a7d0233124d2f47e617bc71eb528e5279e8f53b08006d9ce3fd2d67422ccafb40d879e337855b1cb6b25985735145a9b521f10ff9604e3ccb2ada72971e484817647484bf2af6f7266ea973c68785647201cc225594771e55a68764af4d04f53419aedc990d65babba7c655b85534760739c8fcacd4b0f685e82a500ff88232ee1777b44e08e8e6a68efa486dc68fa755d5406d0bd89b6db80fcfa737cad53c15ee8e053e1b21e5b2515891c5eb68edbb0801440bdc01f5161cd38ec3ea836c288c8a771ac34684499a243847f78b8ab9cfb3a3b300bed17385600bc7aa865fa46ab718810febf8f0a7655d4ebbddb52240a83cbc81d81eb9ba39a580f0e3b692a7d83d319f7f36317ec777739535c74678ea5393442aa420d8cccb5d826a821b3544c1ecb845add57e58b5f182ec914a6007e551185efcdc9e94a9d95b5cd15860f967e7914515977108e62e72a6c7049547f09b7697bab96ad8412088cee72eb6a5030f66c7f75e2560143afd4bc7f1a0085cd032029c8c504ccae783b1627280d5779ee10e1a0e24063843ff7871713a0eab7c671a4d34e088f557b59b4b9cba37c71e174f349b2e83879d4c1d45f444e1d59e78c2e3f1f8cd04da1cf774a2cb7611116ed618d2886f6458f51ab8c45c004a81d480006b9194a3dead807929b8664383bdc8b5c20421d4eda33ec244f07a03850c56c6738b821a872ece0bf57f78f37a3f00a6939f012d0501ec09a3a568664e476407458e7247a00d4787edb051e9e1929b937a4734ea84d8b3a236990854049c6c5061520a82682756c27733abd4220989604915ac1a27a760931c55b5479db7251a3b8b49b7e08cb76dc7d0a43838aad52935ccc618d33f5c16066a63687d9812b16b69662fe5f81ef034528e1c234a13953daa11f62de8f6c43d0af8863bea6a70b5eadf6d84bf851de2860624c25d5a5f2712cf8d3688d99c95ec5e16e96be0e24c43b3319242aa25e313d3802c020b9ca990000ec6d53141e01c131f6a9fe0aeb19ec24bd27794d7586d0e3b81e166ee5888b47fa99658af98dcd55f8f2279c36984b4a2d4e6b6722fba25e93ceabfb4acc76be7c56581ac6096f99688f21b438635d17ed33570a0ca4e6a62bc34a78676842134be15e63eed0cd1b9a00b0618ef1c06ddc3f45d9280f7c120ae897fc56b17c18c778bea846f3bfc02805a90101c28b8b86f32c30900602dd9ccf04a54b7b9ed977c183fc72aee48a2680f8e635a352754d8e3111094ff1af8ba6bf2b37146567bafc28ca416d77c662ec27cd513e9bf72d74ab7ce38f3acdfcaf85a3849890eb77bcbfd18caaffc4dca53690a0f6d28919796be81e07cf5b31b82eed7efa45d507c157022092f96536de3f6c179544f45a43c7393770c840684c6420ffe7bce7b4e8f2ad35f9fd6555f650e49b3d65ee2177d876daebd0552b3ed8e77c13d12859220f07577c9d1552a118216346de5c0338adf532b32ba6dad6738c95056e56fafb4174152dcc9cca65b0dde591ef7b0b35370abef0dbfffab64af644a954599020ba0ea2466b1688588aadbee22c494b4266fa8a3199c1548a2b74d036e3d490efa7543041b44a2d32ffbbe6802c0a4e583e1fd038f0f7b81f16d311666db02b42b417299f6591bc06908433b2e144634a2fae0624c3c6bdd025210c0d053990de6ecb065a75566f88e08d09ead8af2521ba3f4fa5f9c65535681469b9efee80c6408419f6431b2eaa3da31a319d5e660799e3f0fb1145874b8c6d450211dc51b2e4b7d2c9e9dcc5aaa6c3b68dc1d1b16cf3b32d48080cbb76b80058bd7c847424ce3e81357fdeffad7d395cd6e7cffe001262219e36e4d645e1af4cebce7b03bdf10068418bd2550a71b059a1327a65bb7fdcbf64ef5ac072892bcdc5cba9373b4e4b217208cb257f71a0be8e353492fc2fa766c4d4956c08ecc0af46e9751c3f2e61b0a5e4a81e29dfd2afdf99e227af42862d776d05a282d71385000d812d27d4ed26e2cfa13fbe77070159665c429ccd2505757d15f66a2593cd3009d7786718ec37ac16b557d46289169b6df2373ba3ee0b292877205db9745838501b18f04d6cd2a2104b48d9aea89a8ae23a83436e6b5f8dffccebfdf580b97224220ddc3e216010d335210a2e7942979010f49388c9263e2bafb210143c2c836a8eeafc6fcd0388cd3083bf7b74a158a43a52fa92155d189fa15e4797d7ed33b95761d50c820173729e997b5ea2732ddb51c7fe4d4ae07d04031bd6f83ee81d7e330186d2246ed7893eb16dbd8cc3cdd881010897ed15c614865aa6eab4a62d2ace73f15953cc9bf9ca2102d2d27839c41ae60f0f55943cd32f85bd0f1ceddf95992a8372b69cb65e12201ec1040b40eb1716b4952b2f2ab28635b4e95ccea5438c98b721d883820b0fcdeb2948fb2cb30d012f97e6d9be048d8a1e75e036cb4a8d6ac1e94049f63dd7a67ce7c4a985a451b2d643977043c55bae0543f5fc16af05e61053f699e4f8e1a5497a76f2a994113a5094faa87a25b8e1f24e1f94003a51c036ff5011b85a40a7eb666abe861768f702dda9f3f7488a5db37476c1e2d721c0078315f570817308323ba222aa10701f1099c04011d9b4f2eeece79018d0200931aa24075aa44aaf7832ed5f298002535b1d9b944a8a298cf62478e5652627deb3caa536c622f488033e40a012447b7cbdef7a2fc91eea4097a3d2754ad4b638ab634859ee201c8be619bc7662a9f76e628d942d3c18256b768f7e105842b3d085d9e4be3c390c40ba26918a8004fd5fd5d38fdfe2d6b245d43e672ef4e4e0b216f15ca070e141050c4e2f0c9e24333244ffb8a2571029f19dde053d519a37a32179fee36187139a76ccbd48f95851b268510ab14948171162be7cd61cb598857f0aab6c62031285827070c166202c78244740e9bff2b10e97138dd5246754c23cfa639c6f3c55bf74112620359a5cfdef0c29e9b699492583bb7d627995f50ffc5056e022bbd38b1e33854e5599d63451dbbd2c9f007faa2481514826a082735d902caac739ea29f1b2dec0ebe12ca3478536582e09a75ee11c80d580b87e1e3591792bfc490cbea1261d5dede4630239e44222246ea39e81705686433f4a11d44f56343948aeb2a891d91c5ee47f6ced4946dd735525deedd7b89618a787000dc96f7ccdf9f6b364120e220a8c42707dc4aabffea5e7fd0bf183fc09daea20fb37639904a16c39c1bfa8517138d49e58739bbff137c55a23a251b888e1495ac71e42a2feab5c8fa08f4bbe42a4fcfa07289db43ab476d15f9a9f9be90a49bb0ed8c737dac1210fad3cb239f09e694bb8e00bf8dde2eae0c6aefa6c66a0b2f2283612985c545180d2567852debe7061336f7a3f6a06c594b512a8dbe1df244690fec71444e1f19a7575bf65c6edffac176a353b0b631a88276f738863ec590181b9bef4d0993a04268499f09615458e8509e24b747f317a6356cc75c49bbfb2df339baf211fe6043017811f9bd41996f999220f2f2c95c838129699082f43f7132550b396f7e6d84aa18f473f05a8821de3ea673468c7594556205bd03bb0a5f4541266f80264d4c737e3181b6f36b4d739af326fc776c14e07d20c11d750ad002f0524ffcc0cb1bd7862054499b91859ad6bc0fd3431923d1a2834271018045840cda5d349ef8285299a8e185b6e27611ca4b1c87aeeeae6dc589bca667db5a356dbf66271e7e033649d01ac0238baf3e914748191ebfc2aacd26a5776b9c79d53d0b503b644162e603d166ac3747db1b3206b03e14ab03905dd8929a4bd0ee26834eab6b56e455a5a9dc99451b1a10356f29e1b1ef67f60d564d6760bf0d6fa806f2b57ba65a0cccba510e327ecb3296d53607fdeda588054005c3c6023f4ec0f2261434785644d6ccd8480e3fe827a879d51f548a8d5f74581edc7b5332c336dada185659bbc3bd80d3d4815f907d6c201ad56ca7091cfc3b3d64cb64f0b33a8212e84b898382b175cb0f500e580e16f4ce773ab82822dac0e02659e5d79110a3ca30fb041f7a8ef552260711edeab66e1407eaf59786ba16927ccd388e3ef01d8081857c51beb338de886c9c0a70c03ac6156f55c0667a11a3bdd40ea75c285b1ee3ff4eca259f3cb9845024981f781109b436589a3691b03ec6854baba6355311d6ebb30ade01eddcaea03ffaa66fe2e2f0be3e44a6af7b0b499fcb9ecdbd54ebaf731d35d444f42804630eef0d693e35110a5b4452926a53a3ae70c68d6214ead48be3cade3b41f516abb431bb26528621e32b6f34e4955c2bafd03474bececd0394e15919d8150c82e4ad17d2d696e0b3995791504ff51b1fab2176330af55c7a3d30dc06488c93852749f2c8ad1faba11e08abe2d6f0a64b15035f4e60023c21a4f2431181213d2d0cb5f15fc75c305dfa8d5aec4611bc4282d5259116b4586552ee6fe9f50c4da0d936f040ef728012904dc5715708a1247d4436fb0ed16b891ca1ac9aa2c998e8ab98d855d2426babe7f46c2caece3daf9ec3038743b397de2d3b4653d64055d4d92b9fd3649678729dc6bd343a2df5aafbcbb83e07520f4dc795517ff9be65a8ff7bebcac358b09babbcbefc0fc78a72ce4dd3d980e34bd09c5991248de41434e56c8c6d133f1b18b6ed83ff227373f8c44b72e41dd197b3f53117642229fafed26a10b3f2fcee5c2bb7343d7ddfdc302a1f31b8abe017fea6aaa125e029242fe191372918e7bc45d16c74b270820be81e289f03cfd12b0627cc4aa62d064127dc00444f124138021cc668a9ea0f3070572976518f4ea29b5ead181171fc27e350e484fa3cc66801a133c89b900c72db956e3562fa403782114df18f752ddfa0a6036e7c50d7c272c1fe9cff0dfb5a63ce72cccfc7a6ebae3cc3564b20c73a3905184bc0c2f9e1b763200dd95a4892a4e93d1e9b7a827a66fbc83b6c8b795c6727d96ef0e273f811d7f6a5a2003f532cdc7089bc3e1124fddd50b82e78126f2839f3265b90b5891c8369a19dbfc8fc12e2f24b108de6b2a52632e5c2cac5bd1a8f2f6468443036f2abee753707695d2e87c93bbb9b2bef647473d44bcc4d748df47214950f30772c43eb3b2df6063a98f2f3d4b6c695319fc5afb621126b13b3f549b75d25c9f4e41fce956bc634fa3dc46193af12d3f07e4ab921bc268742aa8d39d8dbfba6fe9c20ad5a98aacefeffa4f5fe0b451daf9ee3b7ffc80c7f145c1f13cd55175c848c0461bc7ad45d178bc60f67fad6ce541de867ddbeeb1ffab288be3615214fa357d0701f904da728a97337bfb9ebdb6b8001627aa2f1d4b1a73bde398d566c3cbee38926506cc4329b8d4b6c4830a774a8b5a4e39f36c300cf849029b92836dfda43e52cf9d92e21a1fc9216397d0bd8239fcd13d05cda4dea5cfc84954481de5a391d46724558832944a06990379b8f942a5af6de1653ed39384085b852b3d022a068f217498e2a4996db6ade602ad55e10a4140cb1959da14a754164bf38a30757a5f0f8617e803bd89c8048435b1dab9722cd1296e47cca93eeb85535d762da07c4df03b364964acc870c6d3e6b107a9566435405bf1d180cb8ba62d7172a786379c1e494b0a87ec22dbae85d073a2382254420b8592823a9150d1da4fa8c34da346ac4549bb9d375c6fc5576d03823b86bc7bb17ac6553a8fefe2f1d33321dee6d7e4029ae52c941f6a9d639a5231d373f64a9961fae6039b617e4c3051cba39c34f8c619749ab44d0237ce7c53df5b8cf6575211f587834b5d5619df83b64d4536702da05398335400b1d5431e630c1f058f0eee3bd6601d853ddeaa0ea6572bd185876a98e19acf1fb4fa21bef13bc56cf5215c56588c16639674ec9350629efd4f375463598d85bfbde1b80edc6be5ba9df2a06f302a0c30cacba68aa50e960167eca7aba1fc09484e0ecab27203f19ba9a8e66a7b2e9311f880358f9d9ed14ed74154cad93740ae4b3d782ebca9bdbc502f318e05b32e8c99bffb8bb7b2e11b055bb80b105d877fa855712e956bed1ca843abc3d481aa1fe75ef8e0e6c0ab28f7520277c523e775e0acf17ed0914aa05438f81ce87fc9d3e67d72dbaf006f8068aba9998010807715680b18361cc433d7d85504e8e081a960c933e73bf91fda06c2b9dd36116af10543993ed8909f6e6a1b16f9b4278eb74dbca6ac8a4818397a66fa369620bf170dcfd34711aef8c863cd00c9f864c894e76f9f541018b8f941b22966939767a35b1f7bba9ad2d889908c8d308ba8955f589aa0ca7123e5c20de8b0134b938250d1d5d3dd5ed01ee22ef6acdfe8d215d965a3e3c08ffd4e3265c2f1d1a349c0c24f2285ab2c6a86a8dda515a0077fcd03089297038be45177fa22b5b1ea4fa893814b16fd46f5fc5d40db7d23d804ddb0e9d2bea6564d178b7bc9df1083aa4370c1e5d4b187801eae9f32bf5eea46be3c24067cfa1acf1cee2f000a77d507c8ea22784e428c247d9688ba54874472f7dedb5e6b9c1a0607920dd7a5740694b7059408f839c82f92ce12da5ba21a2a177d3b2c83d6c0fa0bd9b867532d40153bb82a22ef13d7c985aad0b976ee62f3c33431dbac51709f9d63159f99cf09ad34ffe9822b1426a5b434de6d3b83c2855d8542949fb84eccdb29069d9185bf814468885041bb88046a242476e740e14ffeb6e350c9f50fb4d99e4424284cad5f68f97816128d2d64aeee54c4237af68e09192f51b5778193f30ec24705c80e8fa697c5e030929b2d7da415fa140297083860bd1ccd22abbe9e757723f3760bc80b8e978c56233b4a930579b83cfb8db0ac01c22ae75021cb9d3193eb5253a633de0da99aa747b52da3088039baa3f1aaa427b9d7d44ed72ef685672482cd2d04218101798ede5e3870ba9fb31a43520deb0fb2bc892af2ed2203b51558453a177c4f512038646cbe34d952b9b1156d71489d19ac2a9322769a2d0f9b23da1d984107552dc867e688958e4f10baa38b3a178116e4da202fb52fb1a4c3462aea0e0726e9a174db6e37a0d7602a02544434da948b64ab957dc8f853f6581fb3835c5b0f28ff4a4e1a198aef92d28e0a767c1c2a316a8ac308a987eb22cd66aab62ce2d50ea10deca600a1091a7c3e842036a60c23775213b75093652b581c7616b900e73c8145ea3696bbbaffbf4a50831a798346bfa8c6415d83927d7b29c05b5c784b61dbe87880abc016c82ccee68f966bc49d91cc821d941ac8b9abc7daf950ede0fb177b7316e73b7b8ca865abfc359dd5d4da11458304afccdb3314d3b5a708e3642cfcc3dc929c6819e7e2662b851a89485c7fa3a3df869dfe1212ed98225f493c07596c68b6b8053bde98bce4d5a236d9d47b4593aae5422f2c0833ad607b6001e6fcbdfeba8004a1cc7aca43e7f72adcfce9dbf0b74200b05efe56de04ef4736481a91ac85917867a096367187a9829124ebc42740adad4ab2c85e481d718e0a565072aced38a77e612788d072dd1b88a0e8ba6d0228db6d64ac589e251809663efb9b6a6aae7e42198686a898f04f7c460d55887bfda557f3beaa3fd9d95dc19c2d56bc901d7e98223d29b64c5bf4581f3dad0a95ac537fe98d00aafae3ccdf113a939e5ce21b5e2985d06ddcf06c92cd09bd56af7d069dffa11d33b0ef971c9b7d14b3e2d6371c68f509b3fb4ef7aadaa49e20ad181e84b7890a1f7c9472194f013b21430887d03155e0adf747c5cc5fbca64f58f9f45a04280e74a5a624d941371f1cdc5b3fe080da8fd59b3e6d734e605d210781b7feb82302f800a8230f9c9a1092617731f48c3a0be162bb5e50c74c472652ced3f76be2aee9b0dfa0c09af07ad0b50664adb9a9595a1333e99d4d64dcc2314f1da1192efff76be724656df819943d6c4184582f667ec8fb5c0a24aed73c9b7d728974acd788586444ee823cb8dc121d1eea39986ab85e63da26d233e4bb66133c659859848720b23ec696a56f952717237be176a116cf538e56bdafee6e0d13e3aa53585f6f71eccba76279bf5575fa8b95e08cb0cc8ec1b53906d4657b07a03e6d2f83ee7c5b0eb8dd1e10130da86fd589eb332b42784c22ba8e2b9be64a1d0fe3609c76f8c6b8e381b6d3532e84d170243ce8ba36c3c69f564de5930216a762aca93045077c2ba3915fbc3f8ac8f30e90a8cfcd2559e18e85be3abc906130bf7e311dfc1381942e1dfd431c2058d30a3f8f340ad93dd6f87cc5e735fceda6dfb76fff3fd011e8a222a5296cca50a560e0cc0787dc96a22f39c1c98e7709cd705e295b4762a36401fe9fa190e1c0c6fe090654f70a4b9329fba88aaef1ccf35c5033b368830fc9d818a624eaadd61cf29beee94e9c0aec0b3885f8438647458526521d795c4e05932c160b0b96cf59a5793aa2f396bbf2be84b872e05ceab9ccc9ed77bcd14983988a398fff5a9d64a9d37ec53121423029c35ddf75e30839997af966ed2f1de84e0d9b954e30511e69570d925462cf32a6eca1d3825759b417e824425cf9965a87d54f43bec725e1a3581520a5b41d114134e01a29cffa07e70737013b79359f41802e650d733b32c61c729b498e2803680c008ae09fb716f62e9c4d571efe25fd7647eef29697cba454ff95637b934cd03a237083e705d28dca89c95b5e10dff2072bbd277f9972c638bba9fa07509bb56e15f640c208c40248e5db701fc85ebf75d43825b5fc33ece15f13af078a8858f105f36e259970bdb4398cda27c0f95742255e59a3792e005355d4398ad35b0502f0af6d3d7683a47e5164dbf900b2617b5ddf26cd30edefbab8d884debc5a7e4824611ddf9d3d89359e484bacc6f6070efa6cc67cb93bf9e5f2dee90461b44a0883ed759b66aef163b7084103301a28a0c55ae1495319544fa805609c94939a9d7b76d8c87e2d087718fa66b196b43deb250010d85ecba55e6e710b80a704a62800fb6c2660c1b8813830d85edf6cef00b84234a99ad69a2c924b1a143e1c6a66cbeae75f5aa290f1e6c665ca13a055cf0d143e1e1383c840e0d2bb5a9a38be1e4498ed6d9d89e4ba16253a483dbb99f131c99592cb3e5399812b18db9d886a402b315591aff084d28708bf84e32b65e8269df0f2b41665ee11a0bbe026392525ef3bd11fbc8e672ba576483331cf04a1c5292bb7e8002739ef54260824f0fa37e49e8602546b3ff2d549d3f5645c1fe4e16ca1f594dd29b8822c0af6a09818d7efaff66bd1173ef0bff6332dd62069ea6111806f0db274fa3a09d520ede6f651fcf4087783013270ab60d7a2a458080fd7b750265a9c8f0525434affa63ef6109fab4e422ef2b62378869df7e77e9335ee562357b51e0a9a698c26119b92a96a98a43c1a884a3a236099946182904947a59d2fc559954e8574933e308d588045307b413f546ffc4fde864956ee69840a49fc7f5c9cf1dc3e57a9998e6ccc7917ad8f243325395de893aa3f4045754d74e5de32f9310b836f17504605b78c8e8ef47aaeaa32bf419cd415183aeede8e3281b98726b6f739084f3bbdf4926e10b3abdc094f27f0b92cacfd0b22f171f59b819ed434710525499e365ca77e3aee8d9a82dce91d176fbf3a55196be3d0f55911e5276266b599e958b9ac9e5050b86a200193a8eb47a7d1f35169fc6c80a0f435cbbbc4dfb005a6f6eb59f27cdfee5806a70c1e1a03ce113959b8282247a9022f469e3238758b52e1446ac138f5673463701170fd898349560003f29139ae1457abe85f9e848bb06559388643c7f80d978dc7bd78803726fced1149e110d4bffb8609ab3daea02e3f47743f15f2ac48795579ab6d46b9c3d2e1b58a8c6cb37f7fc17fd05c9c264a4e52a6e146f10e1d0d62de0e5ad03dd59ad780b0488380368735d5ebcba4d0365b439df6190ef8720dd912a57b121b2714575bcde67901c9035caa655d0abf9e0a9f51e10d239151c928fcc1f32977aa197a767a9d943210d6906009de90d045c7cd26e2241078b67170d618c1906e60b56d5d0c3eb6dcceea993fe9688fe128222baa682f8563f74843539a06f200966675274e26143ede4746f3291e8071b4f6eccf5004c85aa13809e6664afb640dd6af7274221febb9d152df2d8fe319f1e1466e5b572e01c6865b5b1a6a15d995d86664fc35c3a62339e300b1b925e899f00d607399ae832732d10266ed9542296eb20f7580b7a87a3f43053431ef3a48d9785fef9ebf97f9c066c62fdb3e888f7ef81bbb15da3a192717195d077036c56f948efd951c4354c38013ff91c2ac510d9507c44a4d30bd80998daaa158735fee67ec2f0683b89e56552baedd7e9a38b24cb47fb3103fac3d76fded6be38056c095310c204520ee230432665dc5ca1615013947b3a4447a995423447e926f0152b821c8d038ea2d678494929aff9229829b977d20800e42e72262eb0345f01cfbc0cf3768cddcc047d2d0f086cef5fdea4040583aba3c52c39c390477a7b65e2676aed81f378612120d408f48d092bc6366292bba68b9fac3addb40f533af85f9f3561f9c69112f1d016e097f1d274871a7604aae75ac694fb31e7292d0d19596af2985947704b7b480c6b768596971fe609f552bf6da9ccf1468b02d5d006aca4293c11ef484e63853025c2dff70e936661acd674075aac3d0c9c2db2312c44b37775e9b4b6ea03eb24705ab916ea85a72867db63f3f551ed9dfab934ea52253fbd3718f89f1ffba8bed7b31d20d4903dc18344c844336b7d0b263739c6d20ab5732103f7691e4a2af3f14ce91b0046490023aa7bca115efe7b55554c9c6866c77dbb2b1820908a67ab141539cdb9ca68e8496f8b5926448dc371bca2e50fa1db1b0ff25d0297a86547fb7dcb08b4692b3c10f74e29db1ea66fe79eb4a9a11a84e2933f18443c596a82e65be0b452447309a7a952e69612a9bd61db9ed39b2cf411eac912d6853a4e13b3d24f9ebb6bdc074d2fcbeb1bc7b84280b114e50accbb211ae057e3678b0113a2b3c28432af8e9431385d10057d8116fc823a1576a84530ce262238514a6f32b16ecc8d43dcf6ae992ec1c7ae945258ddd48ca1fdf7eee01967fa32facaa9638dae08adb77945ce09943aa82af7b1cea37661b1966abffb9265ed3df062c46600166db8431fdeaeedf087b47e9493dfe7ba3a84f3135ba2174d701b2608c754616617596c74ea030f58aa3a3daf1c937b25c6da44e714bd63623b79a628910de5f1481f2564bb65c1208c66cfe016dbc629ddb8f1d7fe3f6efeb863562a8996428c8ec67affad88d18bdefbd088620b9eeadfa4cc1d130004402b28184ed4f3edf7536a973c351ffa9763c0cc04a5e197086462932a1e27107dadb5bf0f89d2177eab25024131dda4f64d9e8d03816619d4cb8d7c2fbdb560538c1162eb2a3fabdfd18fea1e83201669e0875277c2edea19152dbbc2c598d843dfb3df791863f090957d86d0424f21632bad6c866098a2b5f5fc38660fec55c06ceb5954761393169b88b5b365e77a272d2f118b82068425db581612c951b107580e71232ea0cc81564333b9843d2fef9701d77115130123e377d62fa4af03de56ecd9250ad03e6f870e1d44e2375610d340b01567d27c0be030b7d44ad4d7f094c0c3a9b756390fff1af6f28197d50caf4b0a15aef5234a90a7f49539b666e54e3ddcef5eb5eae06fb9c64ec29e6484689bfae17db91a5ef80046344151c0d8589207d393e881867a15fc1a5f08c2fd59824b214de2620b332530b9e364688f5031fcd7c0a7a75286fbd3c68856deb02ff4bc374c50ee2132a2d024348ad71a15f869911673cb7b3f983c3d7a97e5f873ffbf965bd941baa3934cef45f439f48abb0f131125e5c584522ec57a60e1b3ca58cb34e665e2f6402c8fed64057ccd1528d01dc1f7998c4585b51ec382449cf3da58c6f24bdc74ab849b1db1605c3337e9ea176fabc8974e7168e4084d4048687e6cdbeabd44a9f75dbc4188764425890a10919e39a97910544555aaefca6b804f1f38758253b62466499588948e7020b967fa6b8b8a77b45838dfc33d8be88092f5a38bd652af6a19c86c6f1cdb2edc215d2bd5df21cce91414a4eb38a6bc1c072b64abd49affb6481741ddccaeb8289dad928381ee846f579b7993518ca8cb76dc11cf86d4d4e8f7a04482129dcc2b791aaa427a029a9aa1228582a10aaee15e0f18f3ba41178d22515ac657dd8e4c380ef54e1a6921091f00788b3d685382332c1b0dafabb10cbdb7d11082898284a59a1dcb1e2f41c0978a9470c6a83ad1e9fa2e31e79ac6fcc062c6cd7b590a96f1cdc422f7688ced1e7f487142a6d80b4840039e2aab9a4d886b2ab1064d0aa5b7d95696c479e1881a5d54fc0bbde4d5d9145b2a4c0d4c30660ea0a9422c4bc4fda1a1afee9ad0fab8526aa39ec085fff6eac76baaa29b942bb3d31a6bd595c8a11f302ef973641d404e463121d639b4902ddff92e14f38bddf719923c16f988886070947088c32523152ae405ae88efdf0b865b45308748f9ea7321d5ea1ec82dcfa1c87bfe16515eb86bf1528303b03e110eee5fcb8efa91367bba1f4534ad51ff33b08bd98f69f8544ec7bfef547367c4cddb20a433607722dbe14395058b1d405c9d46c739d0a8a0eda84680ee6ed3537acd4dc5398050558a275d3608b5e242d021b81b0be3cb2b3e988822cdb6d5ecbeab2ce6e9846b4d3138b93127cbc720dbb98f7732c83108c123515c551a1038d19e4cbb1718c90e91d3e2bc507769884d51582e54845dd56951260e0d6abf87a2e1145581e5251f3e97a125bc13e159fe8f2cc7d527bd5832eabe9069c284e24aaed9a55c4db4ec54161a56b0c60916859ff8af7b081b97582e828bd38158dfbf7b2f6cace23c1eb655dbe9ee2fdc7ae2d7270ef3164601f226cc2f1896ee142d1a85473b81f1a3f55a50cbea9689f1f09a2918900e251a6602fca4eb5aa4be28cb53dfddb0dec785113be055b79bad784bf7d5d6cb9d6c02a5746a719c76b2383e0642ffd457e027788ea28648fb2cabfa07621d47ecfb8612c9d6005bdae2cfc583b04fa3d32bda48c246dc915c12e3354f15fa8c33d68988748308917e019abc3eb8a71ce66859e0e2224bfc1f6f16e0a3d8ce2d26c51a356a3889f3bf0493b9e1915413a1e06a16927b81ca7ffe5be2099bac66cf54e3d07fe192108966b9a25c392d75864f6afc2da6a38c6b9d65852b253f3cad6ffa9d690254b9cba537eb97c6e17fc84bacc5bf5130b66e430ce61b87c3b08ab403ddd62715bc52d9bd662d92ae467a0467501c6513659172c28aa130204ee006309d157c3b5d6414eb04a4aad935aa3967776f2a863b359985b2f8c0dabf98fbe7ab4b52d8598020b1cb47c10f474e741079716e7534689299a5a00a3303c4f73d9092ff9b9b80c8315684100c33659756befd7ffeacf0ea39e7666390314239dee6c1890880beb392d603cd38c92400eaa8d4a864ed49372354c032ef8589439e098d5f9fd052b2a944658c900c98d4c0f1ba3070ac2a2d11d966ec81486d6d01a5dc072d578ec78f03dfbd0ec29f0ab774c54edd58e8c7efcc2eb2d63845fd31df72d8dd50bc05fbe0b5375215f5356b47710647126413a69955838ccf1c4c17af5089ca3558dd9c440b1606861cd0a7b45b2a9014f56505c62faae3f8f7574b45d15073e33027769f49904d4b302bec086156592de218e8b6154a2942f46f3240bc8e4b307c84ec01d38e0caeda5827d6da08f0cf7aa9db635482e3bbbd512945dbae78ef4fb99306383b8b3a9b619b2ef07e2eb92a95691cb3eeb3d9f1131f1ee9f3d96040326d41d761aaec89222c284d197ed71125a6468a44c82d29dba61ae390445589c8d46b78c5a8229a90e22dc9a50bfe85730c20d80ab9896adae5fa83250f7f30568186c11e8e2d2a999a13931154dd41e6c3d2dd4331f1c65bc07b9bc2347185e70aacccf987aadd0b4fbc7f68c461d831fa16c43740d5d79f0419c9002d16a19ea205a1c9de0271561214f9d5c2414c9c2ea2201cd020a408c96f35722f462e74b2412c9f034add40a4405a1d570ba7ccd4087c8bba83fbeffa42c5922044258865a1fffcec429d791fe44b83b9e8d4743dfb1814321316e55ef71c00198f49c1c67fee4846304e2f2d3e7eb33d467c7b30482960920f191e8ce51dd3d854e5b32c979602ac1ae38b209db432acb18108bb339151260f627a4d0e04ee7f78963eae76ed232b8f5b7e52ef4a486baf97864318b745dfb5e9262e267160308136bd7ba79765b0d64aec269e0f2cc527389d6a3ae83d6d557ce4e15a39553a22d86ac38039420542e2cb4bf43874fa79378b15a94ec879574a27a83f9f15f3d8aed45c6dec340a0d4ac557120c87dd1e6cc05960416180505318c7428cbfc39c5eaa1c3ce2430c4db1bd29ff7d8e49387b9f5d87a339d9a70e117e8f77164493caa7816f392b67fb20b13bd2dc2aa1217333f9404911b0a64eea2186600ba0c3897fdc2841f5c953df39b1ebb109503e296ed891838e824c4267dab9bda0e27038380964e920f53bcc239794440759a9dfbaa88cba44287777de40fe4674f8c83934e61781d37197ab5857d47da9a107e38013a98ec35b9d8db4a8ea7bfa742e99069d3696457c19d2c8ff0cf6e489438899bd1511459e930e69dbac3f5d365ae012e975106e47cb48461c20efe1b5795a54877306a2c2e5527a81b56c227c58a18850fc63efb24c7750b11cee1a05e4dfd7908ccc72e80ddb45e12b19384f1bad58aaea29636949532ade4e34736f1f09120f965f10f9306d993becb5e1ff994605b351494bee70173e81abefdfdebe66aee780c2db139cedb585645c1d28818b1ba1beb4d5416dd40da58039dc787999d21c439fc196159f3a5b870bd3cf102c1c7a6c8b21b6ff2ef54ddc746aad7f9851bccf7ec23d605f96ed98a1e523757d1304070a2f702b682fbc3499a3cbda0a69af6948237902684afbdfa713cb6e9eb8d1c7721b22bff637d2490d02478a853a7c60ec38414faed1a1a025ae7317c2148eaf0eb24a5472fdff186799648af4a195015b22fb03e7a91ae49212051aeafe58b80f5efc94e5a75060e7d454af4309c1bf7c62597170ae81c8e912ea2afc0ba7d33efa8b88ef992c93723955400d808afe1ebb40a7eb6338c004b420aa1933d480c7b49f143cc4db748a55f28fae13625478150fe3b191b343c28ac616f9df5942f8deebaa54ae1035a9f74444578ef8ac51f59fcaab599053ec6f615256707d0c7da3e273c140d64120a38c41a9628cd7ae22232a460ad3af355f1e5fe00f8012bbe6f026b7374a38c6207db0dec270a4c8c7c25502b7dc651b9bfa1f644d4ba00f89dc7f440d7054ca88c07e6466d4f9cdf0bbb76a5fd16ce415194175d8004e018a8ad978205f35bedd2eec1369e05f60aa4f3c8e7df65fad1aba9bbe1aff94e1778648fa1209be604da98813f4f2fca5a00d84a3536a089ba5e6e6cbd5e8c594dd400f259fc149b35bf3ad377f742d6ffe7dd082dc54f8cb8e00c397ee0ce9572ca272a9f9a22c9116716870c5c7de4ad512c53cd84e5da596bae20dd67db0cc7f199777575de484e6bb497295fdd5d87a640828fa9269c698c16a6774747335a48b549eb3641b051011e3168a713f6ee03fc5d6b4fc6507058a0fc4cdba7418b11b236995d696e24d64e871baec953a1deb23228e9c57a83718f00543df7bef4ad5d217b29840d4ac338dd39fd19992773de85d9b02823a941bbfcd94115c6d03f2d987eb680abc2414960acb2d5d857b999b037b34b37685a1e6b64ce7d71657b12d8df74276ee74a888e7697389e7a45ba5e45b94585f469652d5ab8fc323080e46f25eab1822fde31b6188d6bc35be0ad8bf6b679d756a694fbad213bb0c3b39c449dbebe9f397860f5d929b1569fd09844cef26c135fb9ea584305015f1e7b1096739fd6251354e9aa836030003c002b6b9a698a7203918500fa4d22e70da02f603ce2fd37ed813e024018bea86ff09a34258c47e15503e82170ab410bac775fcbb17722bebb11f972df721acf26be6f7999bb8fbfba737362e77d261906f3238df7fb826b516576a422637862020e54e2f18efd04c055885ebda499bbf2871aa8917acbc9dc5a1e709bf18bdfb43d04a5f912f69b7a70cb4eba131923114d6641c299605bb366951b3896759ad3c276935f336c03eaf7c5baff285325bd56a331391b8a7517e19aa77711fc3127d7ab7935ebbfb64cef6fffb4e70258cc016678c3192fe5d59d726c02603b0ddf519ab10e1998060006498898edf9637a83f5cc646e3888ea2dbfcc3ea18ce9b11985561bdac2926e00df11382f37a6e92fd284c85b12a60c5c189ef324e8d54846845928a61113e40f40804757f909cfd8d8ee78318ee104d934150cf3fc9fcc02991aaf1d3ff18ef76857eaad08736434a9055b3f86e965877c6ccdacd3c03f3bf1f74dfd1d8ae01de6b0501ae9b604595fd01ce35f5e16790072ad84b38584a4e5b19ce6ce31d6f6017e93fd0ec6d79cb8967ca9207033e40fe4fa36539bb28e5ef2edf62090ddd3d9d355851bc8c2fd2fc7618aeaefb6df5b64479caf4fb088bcef49c466eba2029452594c9bf603203131817568c32e3fb420c2712d858d0de8e3c1bf6a83064ed6493164bcaab5c0e5b3caa515d4fb69f48722aa39ab4dfc6938513edde32a1796ea1b09a7bb149b0db9f3c6d4424031ed50fe9f475ff3bae99cc819e6835a1d61388d01e70b97ed8c98425e32620c0e643bf35e27d0b82125b2f702320334ca0ea4b46c8bc0c6d3392f781cc763801161e4372c211fedede5e6d07689521487f4e90ce3f3c86979a509d93490fc8d48d8eed900924975a0a00f4ffd7b169b23b285261e0e021518436d52b4804a17dc67ed268d4681140fa3321e6964d0e5c08e1193bd2f5404b3b2f620395cae3114e64ee0017cdbfc94edab4bd3f8f561ec2cbdfb0bfd54cc7f8bad577ed5563bba082d9850acd97678facc4b6923c390eea66a4c4a9f1d4fd696dd5478ea04968a31c49cfcf9599ecc8c07fb2157a2d0ac8fcb2e087baef0fa4c84b0983aba38fae219af7673bb1f7ae67c4a7245950536c8bfbfb31a0ebd171080b3c1008d6511c1c39c2ce366fd704b10787efc86174519e0f7d91de470304b7ec89dc25ee892796e3eb8090cf24e81397852e2b543bd5440ff06e6ad6859c9d83ec882c3b5f3d99b16454143141e86f17456a1302287f0f440b79f5219aac451d58edb30d2bbe4a556a12fa1446e42a7a3331425b07f0c93be6045ff40aba453dee18e96b414360f803409e2d5c7c48c9562a2c5736a32515e79f9dce0175db18d891bfb7eb07cba8e288045dde202924f1c4002b8cba772648ea4c508b236ce7ea1d60eb8d9126437571220c347e667f97d4aaa24dd2c9a4bf0039ee9c11c175a214a6e16f690dc45ae0b4c97b9638b40ce281969f930a0c58483a0494f9925492d367c117867503e1455467ae94de18f1a122bcf45f45bd5525d9548622e6df3617dc975261068e6e9d097d8e0d0fde23947c6570461209160b25f5d6de721a60c061a255fc8b30e5d6539e54536c7b12d73edf5e0fabea6287248c357bdc6660db66a511508a26cc768698ad9cc306090801e7a76467efee463cc6b4a52821e3e3c979b0c24537d5886faa79945eb20848c67b63be7771d4546180393e14911141921ab43867510498e1f140923a118836baf30c77c93693e3404ef8a8c99dc61e267986559e13cc559633ce843f28f404e1e095cb817364386c8e7ed0553e0b6503b0a7a88da9f8e6ec1dae898ba845c03b70d4cabcc0bd58517458cb06806f3c35cecff9e7fd67b2c830bbd56b011561541a4cb6fcf7d3bb69a94cfa51313ee43d86a366bdcd31bd564de6631a7a3f92a33595b81986a8e0b77ddc781392e6a1a860078c4519d8f1098c8c6a8bed79a307c497043e057c591ef8fe012da87d81f17824f3f03f2dabf72ca0e9227f37cb6c2b276bbc37604db3f0561dde2f9e909a07be2291eb75d8cb91a1795a281a6c6fd01560a9d1f1959c95d237521d80b75364001d8977a37bf41afe688fae9335e4a20a2e7de490af4bdf76f6cfe674afd4e6595077594b9f250269c0d80c5560ada9347cf96db538c59d6ef01cdb3d8e8a6995df7775c121bd7f025797998769afbb040d2929d26a380c9dba64dd8679776e601bbd2520f50108006a6ac294a309117465b70f03c6a174398234ae68fdfda05ee66c1d770dff9aeb70c29e936918003c469c20240aa72e2417f9e182f332e1a990f6e2c7cbf1ebd4251d24e425b0500918418a2607fbd4da2ea512054cdaefa05ac91f175b03334a41af897c95ee8321c1e53a1ade80ec9890f0edd0021ce4999f05e30cf5303027f0a98f8a703d8234f62aa86009430fbe66083a11a57d474988e0cca855fda965ab96e7949524444392efbd2307b058d44d4ba4af8bdaf4eed3f674b198d4251b794d5826351fb37675da99cbb572b300a7f480a253d47245181702f68299b0da09f2d6e8d74d07a8eff7cc1ecd824d62c80222dac2edbca97aa723eaa43088e238ae711d5c7ecf631fcebb3608234e13326f815d8b606d17b92de241d3320b27e58fbe99020e4f7567f4ed91144b720bc55fd77123bdd02c98908abc38b460e162bd7a5c565068465299b943441c63e7174ee6003bdd5b1d8ec7814d7bfc8ad5239a78f545438dc286b39e572c1562b508af4f6394cb4e6d581080c55f156bb1efae078e022e0bc273c2fa5a764e4aa46a74b0ddb3417feb07034a9cd038e4bc2611723d42d83963b5a94b17b0965d21a6167e0358e2a1da53f2d1ff2f613d2f9a44d5cd67a1fe118aa7180d4094c167da29c61e405823d71ca1b0d6e9fba6bd94b0b5dc5c3ca46089a4340e4cfc0bdff2945a05ebccf02150a65c2ec448efb744ea04c7e96534076fd5d419dd695160a25c0a5c3398e2f6dc37be7a3d0f89cfb0c500046e01685e689cb6c5684e631a4c85da5736e9708e90118b072268c09e16797a588d1befd008a360a7adca5b1fc2e8aa92a3f7beeb8962d5abe6cfff001d0b6ec26cefbde0320c8d46e6fc834849642f8278d6f843bfdbf92b6f4406ca79d95295031dc37fe8033fdcab45ffbdeccd349ebdb05290271ecfcd090e55162b767e7bc9c71bfe9a8ced55d2f6f36c816aeebb16013c655c8dd0c2ace9d204a5e9dad247172e0b3e0415025d88baca29204bdcd99af3aea5895cc4d0b285bda13de8b2fdc6a059ed917d5478a7a51268561a4d592090a54144bacd2be30ff2539a3be85c8d3d966282b069abd48ecb734ae885a3d39b8e878df0992b322ec23313e0699c36f16ef0da5436bbf8d6bec2742eb1f7ad304d501ad98ce946d3757eb7fe655c612d880c3c8579e5659a11e4530c43cbef56aa383f9509b3e7f8752d722227ebdeb3fcc68795a704a0ea568eaca8082dc15bfcc3a2e10376ec93ae0b3bc901132d6a14ce89d22dd70f8610dbe8fe485310ec93e1cd9a6452c9337163df137c25b892344c44ac664c4acc396170e4e252542d26684d00cb680b92d4c18c202c685dacd2de993ecbd97bee82350485867b8c77975329a14e38193c80a467f93e857a8d30fa7902205de4a051ca5ff14c0d92954a048a8c2ae56523ff7426e5f79b17433efac78736b6795644163185e6d5c6abd358dce274fbd19cb3c73b0bee225b4aa255497d434873f8ccc8ac5182783fce2cb62483fe3c0c8e78d0e70d6ec3ca7fcfb00b97d72d0519cc70eb61425828a55ff8e17e8f78173ffbc50d2d8eef571fb08835d4622a567e390ac5fd9abbdac922cfc3f5604d3ca85281a55c582636c8c08e283af89eae5a3e38874dfc4a80fbdeb682a59b4c48d8838a1728b24426786eb7654f1328e5710d154ee1bf5705a58da9f001832440ff78d1b84af11a03beb5f44a7536b0b06d8c8fc03c56440a517d550fc6a0266f0e3910902d00b9c4a6fffbf1d40eb3569218f3616c40d2d3e2c4844a1ea6726f7cf1728c5c87c0d84c46a931c0ba378f11067a32fc32d9dfe8a1770d51e0e6db67c380cda9da1e4be4d459e17949c1b944282ae7742aa53588ef94451188596067276aa7bc5b4314792af41f7d1b8fa7f01321c1743a19b43675f0e44067fbaeb92ac60c9b6482e562d0217222a356a7e8b3f3dd7f72ccbb948f7fdad01e0e2454804b67868c43b12355ace82ff5b9de386b0a9e157049ce2e4bd2e33dfcd8b4760dca79880a85f597a064815b18cce06952156cf104222f82f0c1d5aed7dc3ea50092c4c1a3d49d0bfa228a837405d56b11931852f6845fb6e5b41330a9a522c4dc96988cdc25cc159d77964e74ffffaaf3029379ec1bb046298f1d576e17c2463ce4ee500dcc3a9b3a46724d80b0e76324ecdf74bdefbc04057392e8b0134707ad9f3cf78a888f5c11b70765dc27ce70f108b8f2c5a3d33c77d404de66a525276eb10cdc62a85d0a0b6d98a94a4f2b98ee6ff176138b287a8e2f242b4451ab243c528dab4419a58f9982debb0fe168e598c9c92d64ca3eebd8f82361a4d966f65f23321c80f44411b29396b9fcc7594e6e906636e93fc3c5034ac98b2791b3c4952287738c12944c7235b638a30de22f29d84e5c4238b02be2ac4029aae482b8c916302b4218d38c496cf51d95eccdb6510c777af40f57081eaf5719fb57689f63f1f39b28e754aa289d5fb5900c23dd3b054d3ecbc2b73e0569133b11b15258f844d0270f40f826a0a269a384c5274e4476b7a9a82e472f751129e95b6d155d2cc0441e7c63a57a63dc23dabcffa999c6c84ecc7fc2d39f737c999f57d1f7cc32c548008a49e4641adb27aa4ed3105c0864b1d8e18d57cfd71da9902334330394ece014ba082f6e219ce85506c11d6d96c5edba9a7cd9f90c350d998f42fd64fa47eef0d911892bc649547ccd5cab8001cbf2442238b25936d6932c081b5a717004809d048024dadd99f83262944eb5ad9371260d1bfb9c8a357584882a403b7adea8e67987b2a618e80186d983d8e78156fedf1f6e61bd29717e2659b7711af37690f9b5927e94ba076d5d9d2cf32e90b5578900bd91f55634a11601c546636ec239df463159751a49824b931be9cb8b66db701de9e39e6bdce1fda54f406a84230a13742678e6ecd0db732840c88d1a6717e6e7270707a1685254134b6f5b2955310db69e25bcf8de0cd42fcda21c2b5b163b2e07e1b992c9064e1496a71f79b3c335c2cb255f25f47f63c4bd8861ca8496c24d19e2bb2b2e3e5393789a24fb69a45bdd0bffbd083e76bc21d1935790ab72dab981ddb28fe8b311f6819efd1c42ac9c8932eba3fd40237657f4174ca414c9832d76a25e96a4d6bab5c5eae8a46d34723b06bd7d6def406a05ed56b05e2748dadda49b5dafac7219089a2a42436eab316ab6564bac3f34a080bb8b36b0458e262916e18e2d274f4648d18935b006f510f895e5c7cb4afa52fcdbcc18bc0e7297dfca65eaa4d1ef5e867992ec77e61fc98e104a825cec032ca60105b55acf8636020377105a6010399ee07c47de8c9593946c8c7c7afd5b37cfd21e2aa90c27c4210d148328df7cc2317a2efcd7fdbe2e86d29c924c6f38bfef37ea70a719c844b1b2732c3799f39896759fc130a58e921f93b5067579512669e4b6acf07046db011327299636ae9c9bec67367a29ce4eebd1c8f8610214899d8f6b2658e75e7372bc163f6d40f30e833a116008c87f6d6fe81b600c75184170d42b2a9d7b77000079a6dbe4b2645818e09981a16123702607d4fec20033b10d3cf1beae3c3cb0613c73572a3db5bdf245a526d1e8384d8e22039d044b0432759a710a3da43c128b1d96af33f919525209fb9a73eaf7ccb743038002664510866bb4edd118f0c6296ccdf0b582c28331ae53611dd7e8b57731d5cc544b9799fe5a60e39872688e2eb8f70e9c283116ada9245fafbdd78bb15683c01b6d89939e42d41ff06548d758f509b0002f867a0276f722371b1ba422e870870997978ee5ca7283bba862c89161f4b89e765191af0b80f9fcfe8acbbb9488304aeff5a23627439aaeeae9e216d785e9d1621b8b13c6d35f38aecf2b29041dba3dce6dd4929fdee82897ddd5932dbc8e4d2b260a762db08e5514e1e7e1830813ca334fd7b52b9d12c4307024579cd82dd728ed7698fac3584877dacfe831c2e4cc88f4d8c3de5d5ff5fd7636f1fa3827b8190cdb225cbd00fb0b70a0fe795572a54d866a1ad0c85760c3a09d8d007b12ba79eea1b5cdeabba65bea1f4171e802edafcadf50c50d111bbff9fa0657e7a0f4be2c7e8472897604b7b97f33266f6fa978730edaaf90c3de69548045ec34d2c43483ef520b6632d495fe4d433ef5de896a937538b49a2ff1bbc0c2215797e416fdedfb4abef9ea32ed76dd2a9449d4b8541fabbadff3e880df775bda619e7fb4e6a3c55571a902275f99730e349e61bf25972ec96b2dd7ae736f1c1c4eadfdf38bff2a6add7af26f1e53647f7179d0392163b03a43fa3746f6f75764243e48d210292c2a2aa9bf27f5795325785975ec75ede631bdf30dbe3c05906ce4a773ecf5f671e94e57f8daedbd31fdd9b2c407648e30418334ba5607ae170f050036642ab4aac3b89a16df5179404f8f379096ef7a6398ed6f6d3b597d14d044255c968258b16f4538b16a410583df27cbce976bbc8d126ae41de0263a8ed685f83392229f6978b8d94b69fc6cb9dc3873e3f37524f4f30cefc636d15f255990780fb1637b2f561d7ddcc575da42fa4d436b8c4d6b1a6065ea4aae5cca713096efa618444550aa7cb2404847a7fd054f69a2eebfdc27421bccf3d6d88a30655793e5c8265e5dfe00f97eb7f9cf1446abb1b3778941c185d62cff1c2cab1c32e7a6e2a2760a0552db6a605d41f3220eb13efbf0c7d023d376546eb3a6c2c292aa4f9d37c84a1493a839a36a085873716ee3117d81d86dd855d4ccb8fb4a0e3ff029508b0dc76eefe4ba886da2600248c9a2120483cd8c1452d3293209abf8aa8148cdc46443a37cbc28c48eddeaff6a481b00cd468e1508bcf5b2dce74084a5ff9886ef94411a47fa3314b002e6d525d5bd47a6fdeb715645a2d7d0e8ab444c05600f3e025f41db49d2dfdc290eb9295c4bd9bda6cc188d9b29c87709a86b1c6d59be275b7b30cbcff41f70c086163580f35b7bf6244978f598c1e309dad6efc6ace847625e3cea036f432b50c3265de7f2ffd70b7221dea789513d174233a3920d1a714ecd2aff4e9501025afe5be7709656fac797d13fa70257b2c86b9f4a8d5f70cf4e91e419f2da13d425cdc59d90b6f17bcf5919279854643ac61703518c17cb0725149d21ec1d59180adcf3b151c2506abff11e02e00ac5cc6b41347f275ceabcd2c3369b6e52112f7c3cf2f81d61c0c1621468e27bd2b1eec3569d917e905820a2d7ed65432ac98600d29affb25b7a6565329b55f1e47f68112a02dd58628bbfc6f04082266de262a984184f392a87ae985e441fe7974b609d6aef42ec3b1792b90467a9c3aa239a10051eac3936a2aaa5305fc9c65aaaf0a5c85f6348e2a880ae0a2c27f5c76051f06ff154bbcc0010cea76c01f4b91080eb52e1ab715f2e5b099de4f07d05f6146bdbaad1d13dc617a20916e3a5204585f18a3f7bd4226a71952c69bbffce8a58e9aa8ecee4657a55a853940384f6c3540a4d838c49262ba9b202c54f10b272c68554ab2097a6b23f9eb1744ea090b7937c65853f15bc81863887069f3cb468dcc7fd11727815b1ba94ee7055006bd81741c7301cb4740ee110623857d0f29945bb5a92270d53bcf03a011093d8ada9a711daa84e953b7d6b43d4458127a16f671483e7cedd398682e15c225c711acc6244eed45f61720822c626c12a6ab549542f761333a644b7c67d086cd7432a443c6c0a57174d961037ff4945c0bf6509b878db5280b93e052346c70814e951a28183b7f48ec3e728f1bc315f9c12eb4c4a944b92c5640a1e583b6a94220a55fc2952df86e293124ce7e69ac2472fc26951341c30e70884e78502581d03f5e30c28dbd688090a02e7a2a75ea710cd107ffb0e08a13719af0bb205e7958f81c4e53e855c8a0c49989b035f8c48ea495ccf8b0d70c1202ccb165cf2146bbec9a25ed0102028288ba6002dd3086158d62fa8752ae1496a6df86ad072d2e364669f5f52c64fe46d252242e74611e2e7a73c137a6cf94a42a1a9183490b97a75e47348148177063d4422e036b3be7a273a38d75e94aab8813cad7427b025f0728d9606f3a1a512db2520c5b9c06036c5628671722c86951c1f262fe588b950d937299125b052b255de8de2d8f49c88ec5c621033d058141d1c06edfb19c9437820144ec4bc6b2ea3e1f8bb5fb7ad344c55d0838aa5c6a819b41dfe84bd324ea31429fa8ab5f820f491aab445e808b0c17cb3c8f415e80e088cef796a21a6f572e635916cccccd9ee9429223a0c419e1d336aa7729e63b072bbd875590ca1ea7873eaad6e21365e78e35f9be4c0670bb1a80a6836a0b07797a99cad0f04e70c3b1c2e50c7cd16aba7ab24e6e628f30e6a500c0b59fe03181a57d6145cbfe03284a3ee108e28550992a5ae79b9c385eb13cb75c6a0ef181294fae967147ec4223b3ab032a3cd5d378a878372322681bc203c7b438c70d67e14b8a23ccdce4f2df1f5b9a6d8ef257bef4490be96aaa0fa9bef8c7cbca1620617100c3b20586b363aad17e8bed17ad892a35d1e3020e2b328c7c6be79cb15fc8ab2dfa3a40f238ec8209d169c64578176533420ac84720be9e3fbee8fe801661b80558680122877fdf151dcaf2b96c5c4ca3112600d4d4164b5dba6ca8ac30c0e1141c9a52a51c510d35cc30cdfd0eede32db8dfca6b1999016c83081f2489034db5ad46db7fa53a19a0dc9ec35f00fb4553a0df265b6366c7dc17f932ebe9d5212aeba71776afdb6a3ca0044e7630f32d9a174dd2e0e6238a148d5e0b949dea1fcb4d551f78d345eda94a7c61f21c90869ba02a2addbcfa25d4b461baa310e9abd023350dc918d41b26dd79d896a3670a599dd275a31153cbfe9a91a70b0d0d70cea5b18b6a60fff9b13088d67678b93687212cc294368a902d11295f5791d09789178866fa0eccc993098beee9be432a9dc689458470e80f955a2bc6f3d8e152577fc67082bce1fdf171d19c14379f933cd7f20bf8b86807e9b268b1a978358af0fb31b16bafc285338ea4860c04e8a5635873c4e46d34555c730eef4ef07aee4c5e3b226dd6b5d4e53bc9c810facc0786f410da0f6afca7116d06695783a037b3a169fa846f03fcce22a159c3579b4164e6b7b2c562b388be057ac1b0ddd8ee04ccc085662a6742aee70469349cc0551e2ee85a2ad42c6b1c3e408c409c688909b3307c5f3ae4f232308cbf21d4076e7cd82056962c582ebb99ed619d2ceca3e35e2503916f0b64154907cb7c074b8225848c46a612506fe7c6c4a9d40d81d646235590f53df1aa52282a1ec44b55b1aa29aacc4894c836e41d4d71e78adffa36c4eaa0e45b58f31072cdc3238073a30af3d2e40d16cb4bfa1b02079ca814902f35a769ac80e7d72b348e91bcd4afbc73c448fcc38e24dcb35799bc931a3fd9aca1cbbcc2e803e13721826ba4835dd5899cdbc256ca3a99dee67dce936cf5bb2581d3418ab8687c86ec9eac929b5bba8dd1c4b072e44195063b3e33b963a17663b1be8c66c1b795b29d29a4479c4756498dc144bbdd4d136920e27b0a49db0575bda145d3d93d8339d614bb15c42842637cceab13b41de0d8db1d289c7fadfcc43ce181310b9426db3c5949303adbf65a742ae46464266da2dcf1197ab870c53eaef6a3513ea6dc37ce469785d73cf1e62d0cfc8f9d2a6bd7ca3307672c717f278f799d74b41f8cc938d4882a7e75aa8d76ea33c3463e74338553e1219a3b7b4c08b29153616ab81affaa46e9c4e33edbbaf54d24db5912183e4a181ae8a0a82a40a1529b068c2c8044f4b2b302094170034c01b198aa52e2adbc441c00022f84c690145ac193874a15ad8a8d0834ce6f2c09fc8c11ecd0d635adc220831094b043bc896288a2cce93a85953e9108b8212ae5ab06d57b408d4a0202b074ea69277b7d4f01a1849cadd681ae991c28a7f84b938c1744c5710a6b468e0aa480d9f10b4f857f388f15527cca1ec709b6fe6a8dd17daf613dcce6e1620f3c0ca31bf4309bd89544362a5e4000b81dd8adc58564aee831f61a3f1fb60130d3203529cca91f08142cf1306e8b7a9709174e1c72727ce145e087762d5ea07c73e059543ba780f287465b938b9491a445681aa4a27a49213763fd13e1fa8e41c4e5deb7c1860261d84f9f2b8fd27abf70e65b9320414ddb6f783b13a2bd7f39d61cc047f60fcd01cd36b72436e6a021aea4e1166929f2e1fce730e6cf7d74f8affccc54db3ae143d9a459723e7f8e0d5d801845b1124c835d09f93ff0ed1eb4967e37154fbc74231b6cd10aa37856aa886d93423eafafa196f6d1d075ba35265b61fa486d718447dc81e93357109a6201fca01fb43b36c98038493c274e4c2dfc0c043a7e17b057305e514d07a95302531d24bca04b7a30247993401b5b02b071aa1860f1662007a3ea59c5f58fc1ad825bcfad908700169158a6f3738ac5f9e638f2c8f8fb00e2aa5631cbb664e2e790616351ecb6f7de7b4bb9a54c49cace0a710bf70a4e5d3393457dee8bab688beacc15ff1c7c08077128859ac935c4d1748348434411a9fc992c1f1afa792cb3d8f37866b1c7c787aa100afa69429e3f3a195050788062404040b1ec79060ec633cfc0c98902f672dd4014458c3b3feedc59978fcbe704cb1ce304cf1c83c650193ac48612a1345404ffa26de9d8966dd9964e965946100c3cb38c20d9156643598811439452a5f3c9ccd2cc66334b63c232bf78bdf0970fe1c787c78b7072e245624431221758e6930b3cf3c989788db7c05d9ee337fe82172fc4d9d9a4b97c3497e6d25c3e252c738bd9cc2d664566701a97711834984c445a4b476be964cf263e339bf8c4ac1892013da1450bb127cfcea59946339bcd6626e99cd6691cf0ec7491d641a9d43831a2582c46949d44c23dd34edc744db79a042424e208ee1c56974f75555775f9c8660665425a802922e242188ab5a5535bb5555b3ad9473ba3b93361538a093463b3671e0154e9eccd2acd6c36ab34dcacb1993028a2833363e079628c28168b111515cd9734ccd69c99316be03871d6b9a32e1f97cbe593fd6d4cfe5c41241414857bc596abee8b539dc992a6a6366c78cfe4214f2bb24895d999f35e4eee8ba7b1bc7a50f725bf804f08fb61b2f77d416965bf339ee78f160ba321a14b8b057b6f84affb62816a9eaafbd229961c8044cd97ae22804c01d5f72fbb5c429ef54199eb8d3c7f34e4257b7d25b6972c6708c1c09c29184327512cedc9f3b907b2fdf8813cca1fe05f28487eacff7ddff7f96f227d014e219412c8cc20163dc5092153c62a823eb6079fcbf5c19ba54c8da008c471f4fc12205d6a1219ac3f1a89e3fd72f86862ba841fe6f031223231f249087119f94efb80a8df55ed4f231f193c8d441ea83c024520db8fdf8ff81811994842892c8a600531a0610d6cc8c265e4870871191187903efc4420dbd7e7fcabc8f4df95982e4cc82c5c48c418172e23a213233f448921425cc2919191919191916fe286cbc82b3122c2c0c0c4dc70093f06e5123e4c8cc925fc98eb123e0c4c13d78589d1ece5c5e4c2842d7a7971091fa609940b13de861797f09bb8e1128aa0144257a1c4400a56c4e040e68927b8f49b5c4592c1c214402f90620b3b2e426c60980033039ea22cf4b85c1610e10926c00210b070c2a51f6c0e0ddf13da8d56993c65bf8150e4a3ba65764b07e129fb752befe5739335aa92253d4abb5dd6efc71b93edcb0d1c3d90511e7d3fa1857ea29fe827fa09999be616799dc6c9d61219bdef463b3c71dcc1fd489cdc37f795fbca7dfd6ef33c2c3b10cfb1bec6fa1aeb6bacafa0fb01d1b9a75f3de4aafa6aa16ee9bf3d0b5f2658bfbcbec67ed9ad5ffdda5eafeeeeeeeeeeeeeefe72747d7df763ddd9d122f71fd08ee987e5a651f64f55e481ca2e3acf7f23ed67addcd7ca3df73d188590fbae31e530c542ae64d14881b235814dc621cb294a30cbdd6844e2cdd06d1a95cadbf7f6bdbdcd1e96198c7dafdd8c1e457b7b4d6f3426555e72d55529680daa6fc1d61ef4eeb9eeb9eeb9ee4720f8ddf7fda984f4956137343c8a43e9f555fd1d0890519eaf7d44556c91055a11fed8de9b9e78bf1ddbe8678f061dd5fdf8a61b72f5e5e2c8fd145bf4be11ea0f6494fd351491a731c9841acc8429ca16a6892a4fb6d527db4dd3344dd3344dd3344dd334edc32f87863dd4b723952b4ca3402cc2fedb281eae5a4fb9d2cfed849d6a9384b93bc77de00ef0d32af813067cffee477fefc719b3c3c571147ef79d0d71fd0ed30763e1585fda1141420e7b238c4498e97715c6bdff58a9c8af6ef11edd73b5c2481f8fee394f741960a78154b137587846dffd380abf1d23118999c3efa210b6d7c8d527ca40aea44db750dfe91658b73c8a6903a1c0715fa7cef401c74d1d6eea705387738efbb6f136eaf618899e88c4cc9f38721f36ca723f3cf147f841b83f82d29f4eac30509052586ed05957a36bf97957c3fbb0cd1da6318a059502109d15bd34ca064189625428dbefb65a89b2ad54f0d4a1b17facb36c458a83972b17529e86094658525fb21e41a2bef059304d217cc2589790edf64dfd025235656a7bfb44c815f8db2681b61f47b61f37bb214133f840467e7b80df89a40f88203383a227a3f585a5c4a398fe98781d508c06d1188d8d344677c02bc2edc74963f9e69f46d15811f8f67df6612dd39a6e41319dcc284c8a7d6d6be1515c774c1e872b511d6a94505759854915fb1eae544815fb235c953057786a0f46e2e64fac3b41d87fb931e14cb65a4bab417935aa47ae6cb65f63ba65f3fca1a9be3c65bf9f4ec9a2b12250f209099ac30732cae16f3faaaffa92ab9bedd71db9d2b20f0599a8105ee15664fb63ad225b2bea14d9befbc8b10a119984c2a0d17f86b27dfb721a33bd3c501c6bee8f65fb83fb0e258822667462b3a866a76532393e3e232257af1c62efebd7e3fbcdc507840bafcb20cee1bfe1cae10ae3783a653f88e5c7a7dfdbdea4ee4815fb14d717c804f095eddf46e9f8c17df7db8c7d9e78dafe139d27db8782e42d274241a252a57f4412512c37e7e57af5bcf88068f107f84166e6fe13a713e1d8309d78dadef31ad18a5ed328ebde2d8527a6ef1f51f6bdc6552c9dea57e8353535d97e97f2c0fae19abd99797caecf6193abea4ea7ecf3bc0fea27db1a94ada90ae51ffd3b9b1836cabedd9ee6ed8a52eb9a47083adadf2f13a87bca86e88469145d42aec8d56442aa50205e409f700cf324c2fddeb069cbb54f08e988d728edbba5fe0d7bd6d09d2ce7497b4f61029ddc1ac01b6814edf952c54944a951fe531b3135ca8846cd7fa9d38601ec6902b88526c8c03080605802ca4867b2fd6ec61c71f2a7b73f65e64cb7bc78fb93a65b5cbcfdd9aae996166f7fdacc9b6e29bdfd89d32da4b7246f7fea4cd72c325f7367c226cfec993e33367fa6fd299b42adea184fd99f9944ada25c0393adc97726dfddef7beff777765a713f4663184f37acfd87b79313ee18bf378c798163986053d7b0b6dcdb7e0165dbae58cfcd3e93adedfef4630765fb9e099ef9e4f4dbd7c3e4bbbf1f0f93ef4cbe3331f1bc18d8755c4560600a13d329fbb3d3804cc9d595565a698f98f9844ddcb1cc277cb3bfb0efc2bec9be89fd16f64bec97ec93ec9360f7f118f61fec4020f620fb9b7dcd7eb545f4a551f665600ad329fb1ea63258c7cceea2e3bcecb88dd7f84d4ab67f1f4773f71ba2ff727faf38de7bb98ddbaee3d807b3b0383cf6fed855e4d764bfe571afb596ce987a7485e9ddf4ae7d6bdfda771c8d39c2ffe4f42ebe7e1331f9dae26bc9d7d257d25792af235fbfebe8ebf74eb7805fbf61cdd33dedd3b16eb15fbf7fbae57efd066a958cafdf329f216aefa25c6b72addf759a16e33718f63bccbd87bbffbe90048f9430e94b70e95be092373179aac44bd6fe047b8cdf1bc6e4138ef12ff0e95de0176fc22edeb19421e341278432adba9eaa6f536ba53ef48a5c1fb422f43fa9bfc9306120469cfcf7f530bde9dd954def3c4cdbf631b0e3e4e8c0c05e445f62e44a3b62e613d36c77d0ff045fed84fd05f69c46d577815da751f54dd85d8daa6f82bd48a3eab7c0fe6a54fd12ec3b8daa5fc20e6b547d12769e46d527c1ded3a8fa23d87d3c86fdc7813cc865d8857cc8897cd6a8fa32b01775aafe8629cca889d0699050b7c87ef2e8396b9f8a82085769a0bb6755e96f08b7c17e934538d29818b799a9f489fc2d436744da33a6d6d9cab52b8fee39e79cd6ceeea7432f9a6407ddec1667c83243f9d3c76f4665d920952a9f1512374aa3e4cf30a551d24696de9352f0b4638afe844e4bcd8f7e4737ee4647a5489b45fa8dec8d9aef415a4522475ecaf0a51ca59060964ed1bf382dc59336c4a9089b351109cf35c7484c17bacaddbd8a2cdfadb556ca1d46c993e5dbef3a71342273db468dc8e366e94b991a3fd02f656a0b2ba5946a9aa659777777774d1c425ffbeeee1e7a1893c8e3f69c943c6caf6129771885e4717317a5dc61fbf9e998d2c579cccce3666efb24b41fa2844a11b4108511c460c50c622e550921504421046ab8c10b6cb084135cdcddc5219a88030ee5a2d75a6badf59bb8e1527f4812f79d307119a28466adb5d6da6fe2868bfd2149703190810f5aa082222ca1c625892b2a2163376c18e21374451b70e0127a6ade7befbdf75a3a247c4dd3344dd3b42a0e919d12afa7a6bbbbbb7f13375c5c1c220a71256c9770d075b3e50441cf9e73a2a04c2784f47faef84b1865f956105259f1d8b9bf4985e4fa67e864ee4639240aca444995295572cccea31c234308fb1b25e99cb3a79d7eff4891982dee900aa86f61d9be5661ae7c5fabdf7f59585872274f3c503925df8ca34772100299b96d00a139258f2cef43e98e539ab57754a629fa3796e2ee2c637e40b7f4882b6c54a65efdb19ff6475bfca1fdfd8a47ede95ffbed00329198d9ce1f736a3ea3d94eab66efc675de078ec2111252a9a48589c9c58bd32b5694ed7fee60788efae677313c6d047e2f5f3fef63923cad968499466bc3619e72f99dc382463d73a5beecc689a92455ea7338942a5f32ea99ac11b9529f251cf558999559a156ad60ed29780358034481a907411a20ca839d2c4606e207bd1870c6831d0c068381e2835d5010087637373737208c07bb9d1d50c6835d8ca76a0c0882311eec6c6c409093c96432d0c5831d0c089e1ee46030180c7cf12017140482dccd4dce8d0bfcb6e17676409307b9181004c1160f72363620b8c964b22110e4604090f4e00683c16020c9835bd05ca94120b8dddc80db0db8dd80dbef80db0eb8c580200882cf01c9da6cec836f4411723582c160e0fb68d58579aa0681bf43b26ed0cdcd0df829adba37a03fb8033e0dc9ba3b1fca8e016f0c084ec9ba36207d100453a81a37d04011b5108e70e7c578339d0c7732991793ebc798018a1dac0b023b18ee60b0a05c1fc67f30ba9b6e07ec6e607437373bb9fe890c2f4617d3d9805d0c8c2ea68bb1c9f54f279d0b4ed6c1809ccc0527937530b9fe8b13f782837141200773c1c16041b9be0bd356c2dd703b207753c2dddcece4fa2693db828be16c402ea6848be1626c727d93921dd9641c0cb8c94636998c83c9f55b9034920db605811b6c6483c18272fd92b06edbcdb6e3e5984ce176b3ede4fa25ab852d66b3d962b6982d66b3c9f5bb11067f7ae204419a5c9de6c28260305850ae3f72ecef4df166e7e6e666a77357729b1de6aad0ad6caed40f430f6f0762cfe5e9606fc6551e112bc3c9d5c67a21d70783c2f1ca6457a8553a7cfd6e8667d32a2bc321071a5fca7f1726f5a1fe7bfad22a3b03e586afc67f36267e3fadb2ad56504be8fbaccef7ae5669b3d96b06fb3e4bf37def34add262312712b3f93e8de83b196a95e672cd5cfef27d9acff77df3b44afb5a3fdfa7e97cdf3b7265faafce663933d7f76934dff70dd3aa1a8bb54cac69beaf127d25a05655974be61afabeeaf31569556db57678be9fdf4f1fc8fafdd491abf0bf9fad56d1d96cd6cc6e3efb5fa529fa9e03924589be37a25b46ff7d1172355d3217d0f73e5a455d9eaadfef902ceab3f343cb46fe3ea555b4f57d107245ff7b54b774638dfc3d0dc9a23adfdf56f9cc53f5bffca1c815f8dff79f48d710d24c5f39c5ca2e0c0dd9e7205a190eb2947861727d89ca6016c2510d6b633788a3898688225ad70c5114eb933018c35adbaa4ff29f8c99a599c598cdea8fc0f05ec488622f62b1fae14977d25c9acf8bfa23175c0bada5e9d4074d9bc94ca399b598d5ff4a2e498c2846128bd5f74a96545d3e24aefadd88766babead4e7c26a67aef25a95c634fbc4994747344689bc9c5c4db13056ff6621f43cda1feaf271b95c3eef77563086b67468ab3ea6df0d593a7e4533be1da90c12913fb5fce16ff611792d8fa6a85395487f43de02695a20119786a35dc8879ca85bec5714736d6e4ccc35d191cde8a6553a7c45f49b758b9d2b780675aa7ee75e5f9927633285e195554f06c4fd147f451e8dcc555eab6526cb7b22c7640abba640aad41f3d13e4fa9c378385d01bf5843294a11cf5d41ff5e4fad32de3376483baa55aa06e99dfd047d42a95afff15812f204ccdde7287b9ca9b710f9aac70aed4776f06e6de0c2ce8de3034995eb672fd4fe53bcda595a87e6fc6555dd81e0c7225b572e53e1d9fadbc4268412b422854fefe14c78f28d7ef6e4f97b782fef575c033d6a9fa17971a555f059b3a559fe2476954ad137cf1a1fa1535a78b618c47d32a6fb9e7cd94bc995cdf5beeaa8fa85335cc3553f11b6a547d1284df50aeef8d8050fdc3059ddc5eb2b707545259204ff95717b8dbd65cf1b740ae92adc9b22e576b76722451d375fa84d028a552ca2058595d2c2f5d936581e60a50c523497aa1ef25a0144b4df362f28de996979617bf32197ba61ffdd19070a4421ac80006502e3083080b5440a4c00424108187808c0738a0013118b0000524e00401271f3d0ef06208217818c0b4c324081d40b4c8510002b8943209c70004301200921f58abd087d10d55cbd7030078b0b103e8752c2b3aa8e09043cac6dd14aac60d3434ab810c60e0024458a002149880042200810738a0010c5880021280001f3d0e3084103c0cb023081d40e42800015c328e010820003fb0563edc50b5f460830700ecc0b2a2834a4a0e38a450356ea03103cb8cc283c2d343850c28b6041a3460e28d788353839d223a50a0a0d8cc9081657e181978e6878959a2a635c3c48c192f318062000551c18b8884acf0ff23e384653e2972c2339f14790121d60313820c19ae17ad172d222ad0c1b161c1c909cdc94434b389683686999897329c4e432d7a5af4f8542114f4d3049389c744e6124e0927270ad8cb750313931b122cf348cc488ccc101b22342228956048706792cc61d0cc6190ec0a2fb3a12c904840ad56eb7b7daf9d21cc1f1f9e22741ec9ec11f188d4b4c09573f382d1a8359bc92233d0c8c0a0c1f38838dcb9bb3ed72766c5900ce8095dd7c3a2b1d850e1d949b1d4f38fda48154b067ea43818f891ea5ce06b6020594210f1238dc14b950f0bfc48632af0239da140bf1775cb8ceff73448561113f8d1d790fb7d2657f8fbfd47aa8c90c08f1e14811f5d08023f3a518c2b246bca3ce0478f828f5c9db8a46ace38e0477f35e0478731e047efc93226ce02607cbfd348d5cc51c08f4e24013fba0d02fa7dc64b205993c7c78f7e82dcef3272651a92aad9d3e3c79e1de0477f19a24f5d90ac2924c48ffd05995cb9e091aa39c4e3c7f631c08ffdb3a3bf7b0ac9ea207eec24e4fedee91ba9ea191dddae1c6dd33290acc629c08f4d83dcdf357255f2fd0d23559d43801f5bc6e5c7a6c9246c90ace6c1f1e3cca248ae4220a9ea9e01fc386502f8710e05e0495848560bfdf0e39c424cae468a48550fb17e9c3bab1f278f0f3f5dd30792e53273c56ffc387f90db932a9f51fd386b6e7af8d1dbf871a620f7cf2724cb71824895e778ca475904001e587e9462c8fd1c902ce79991abeffb8d2842aeeeca8f52a6c38f1248e57d4895f778ca537e944bc8fd3b24cb85e68a7fea47b9f3430e3fdac8fd291e845c6ddf8faa91bb51355e8ea64c03e547f74c43b2e80c8a5c554ad36f6506c4f162401cc37c017134652126cbfe10e1c35516c8023d15e8a180389a7211936563139042d94a20021090992cebf300716cdb728038de06cc30600667b2acce0270725ca5cd149093801c04e4f04c96a5f1c1d3e32a2dd6a3e7003d4388a3690a4d9646248438b6ff1cf2e7211a40dc218ea6acf904a1b57488e3056226c70cce64693a05c0c95e6704c871c9c9393c93a5d1f8e3e0a9314f0da047003d01e8c9fe2d3459f507a1ec2e3359d5675c551d67b22aab87563de4430ff964ff1b3257258eb7451cc31e70725c4567ce33599586c65c68b228d15cf1e7210700393be4b0f0ac88a34907710c559c28fba788630778f41ae4fa00c0a34791ebf38047c741ae6fa37e0f78741fe4fa2d787420e4fa2a3cfa1072fd1b787429469f62742a46af22d7978147b762f42b46c722572ae42a24e3a719d39a5a63aa797cb3074d167dcd95fa4e05c9d26c6cacf02357242c244bbbb99942ae2dbe6a3838b5b342b2b49c9c27f4c8d5568564693a3a4de0912b8e0ac9d25cae25c0e48a4e21595a912249d8912b1fa4902cedf53ac24baebc214896b6b353842272758120591a0c26845cdf5dee03c9d278e64a7d9e1fe4faaea3f5f4541c4896e613856469b11a4896f62303c9d28070e4aae446ae4a367265522357261f1dc46ef003457d87816469412d902c4d3657aa0a244b139a2b4f48963634572a11b93a9dc478191f1403d90b845850bfbe33519fa5cde64ab55fdf874896563457aa5ce1afef4b4896cbeacc49e022c8f5bb1818c6cbc0319e845f7c8b16ff58c66fb87b0e6f4f31f73ebc28ce9881824283c60d37d4a88142a55238e090430e29292a2a3ae8b0b2c2c2b2030078b0d1430f30fe844fde844f6f62d2d8c593e0920731c96b187c8cdbc3f77dc0de5b8cbfd6d8afd27e4eae2e51a42f9b19336c6e50506e7068d0c0c9b9e1861c9d1a35745c2894ab482a55e485030eaf9d1c72d881a5a4c0785454787a74d0a1c76765458bb13ccb8fadfdec000480afaf05f120b321d4c3eff00300a0cc43900d590f42b9be36d442a49addf0a16548457463e6c3bbf0018f5885c72fdb6fc13de0b124dbb78179c0238c6c1f0078c4d9fe0e78a491edb3e0153caa64fb3ae071876c5f058f3d64fb2978f421dbcf018f01c8f671b09fc2a39c22db47e1515291edd7c0a3ac22dbbf018fd20a7945b68f82478945b63f038f920ad9be884779856c5f4a15a9621fe32b55ec3ff6a48a7d1938942af663e09254b10f039ba48afd137c2255ec9ff04b15fb268c2255ec9b609454b15fc22952c57e0966912af649b00da9621fc437a48a7d0dff2055ec5f8ca300414815fb1c1642aad8dfb00fa962bfc30b902af65be0074815fb243c01a962ff052642aa584f366d0a2621f4dc71342b8d43995cdcbb33637925cb294c10943b5ae94e0ab573d2190517233667a751a91601eab1c945de26904c552f0b52357b2053f567cc389d48a43c4ea02e8f1348e52f9daa2fc71be1cb04f317fa6a54107da1841efc42a8cdf24caec0afa2cbe0740bc99754a7c9537495cb64370c4da6d7142798c9967252701492edfb8bbf5e42cf31dd78bd78bc8aeda5bdc4bc549e46d59e4e5519c854fd196ae86b6ac2b1d64471771002c12445ae393652a5baac06b97e2d227a2193acf244618a1f82c907210eac586b402f849d54004c76025846c9728a13d864ed5bfbd6be3bd626f0c9d26422f9197216fc72d057a376ba05c663e4ca09b962c14cc19c992cad68ea6066423163906b91a4d603bf21acf516dec2b638fd864ff4ed6fdf999cb4df3428861842ac355d2467c7555fa2c96fdf6d26db6b4f5dbcc9e6c2848f00b7a79a6f1a487bc476d8b72fa91d7f947c10922779d2f78cfdfa5a919d99b1b628db22504846bc92bfd12d249237f974dfc91f9aa404c4a33c410c82f803b107e20ec41c8837105f105b106bb10a623a673c1701b610418e857423f7cf0fb97f6be1cd90936f43aee8d7677940a3e6cbcf86aafd310053e46adfb2cc1e72fd8edaa7b67b6ed2924f878937430e8442adb1f9b22cc912469634b2dc7e4c919dec4c9ef4de620b040dca54c4e116178192ed771687b9c3a33c894815ee47b9c3e00ccc1dfe7cbedc612fc7cb1dee5ca6cb1de6645ceef0b6b3e50edfaeb9b9c3b6488b75b8ea609ae78c54a1b9c39eb9c7d1414815ee51a40af7de0c67100c9946b54ef54e5f0e7798fa23df3292abf0ebd728e48a0b350bb2c59bacc6c9020d3362c8152857181f0fefade8fdb0d6366d6a4f1d6220f3d48f4ffddab7cefdc9f55d786c1d7ff154bdf9a9f1a96914ec5b41d82ffd23df10fd5af8ede8d72815775e7225855cf58f0bcb404619ecfe9e40a7ae3c3c8da2f77b221c6b0da52a047c9dfde3e3c7f6e9f163f31c60888a00b1d688281fff3d4ca60384e110a2ec54ad358db2a94278a20d52f008fa408cc8dab782d03ef763ade9ec274ff76bcde9fe8802e2743bb1a2320f903994ef7f2c08ebd3d764c95c9fee740b67bf7e85b54aba5423b2942aa4af07c9104dc57ecba3dff65b4b3190513e1d41f338839098a30784d40ff2e5b0afe1d3c554ced46f9cee9a835c519deaaeb502e5caa26db8b39a9ce28966ab552141741248e8244a37657a038daaf55d4a71c648da2d448a5d53d9a07c293a056fd41aca9e2c63a815125d966f23c4e1a94a1a1151428267ee66ae15ec42e8df6993a651617ddd70b1a06aa954223d09e949484f527a5a7a3a0262116a241e9697f4deaed28f0d845cbf754aa552e7944a2591d40e6bef698fb503b5cbbe1c5e6832851875a954718a49a4ef40effb74509d46b5804dd8abbbfb65e150a92bf1e650916e19f197fb8cdfd0f4281910e93b13cfbfca157f1c28ee2f4fc464618124bcd6bd091b9a5448955c8dbef425a49221d28491268c3461a4091b91462412e925494462e69138965e2b69f2d341127f8c3ec8cca42f89d3897044124fa42f91441ea85c1247f09c6994ec140909090909c9a4f1b0ec6ef48be7ea33de2279d28fde825c9f24ca467d3d484fe23334de922bc983249248c4dba2593aa773729cc6e65afa4a242c994e508a94e4f037e592efa889c4e17df5bc59826d097bee7ca30d8e4a64179da65f7a09a96af1f5fb45aefcebb7c053a64abeb3efa2e4c791927e2929297920a35c52f2520afdc8cc28877ad82ff97694ccb0611aa72bf148301237938488726da9ad03d43f1d6b57a36a112226ab775079ba07120bf9e612b173b8104ab9d25cadea174fd5bfaf1066eaf958f69916386d53a9d34895fa33558473c24a4ff2b25b4a222cc4fdd2301da3651c55c674d22ffd52f2232f3f207cc65b4ed32d24e2a9f424a752e3e4fa4750542d19e917199a5cfbc5a65f70fa45a723cd507e3d52d98b34aa3e180b3ba6d22ff9b19dc83d4a4f5fba05a663e4eae3517a4a7bb003c922f9faedea30962357a4afa39ecee9b03e2d29615af24a70cd38c2fa5dd225253f7ec9639f6994f6d389b0fe3861dbff287d909949fc49264fb758f164df7b285a7c3dd9920885c9d727e10d7ca10b41d2449c342d4422d726c431e97c91aec47bca920a8222f834839fa801a952df9b79eec8152702b1894166ad9a787d68a40500839c49e7f4ff8c67feecdfb4566f56ef1f90a026875dd828f73caf412c84b251fe2c2693bb6c548ffa95e5c95ca15e4569546399277d191416962bf4c739648654a13f4e11e429feecdc9372f6d36e9728eda5abacf654d3eab7ac3778316b1d656f5a6977ff74b1410a2940c15deb11435112a44043fee4ea8a2109525821971a355f7eb27b098972fbeede7cefdc7b31e20a6fbfbd4fbfb3d3fefc0e20b3951f10fdf62b3ed59f8fcafd9a886ad47cff42107b5f5e5e825894f1eb7bdf5521ec645b21d4bae5c777ddf77df5ea21c96791c3ef68be9ab7739c26deff84e46479c76eeb1e08dd44245c642ca50a10fa1ef871df3bdad1d7bebb7fbfbb22906da4fb2284e48c5e7215fd3bef7ed4d5ef7ebcf5bbafbe29912f8c6c43162ea46722c6ba0c11e24212a538fa778fc31d88679145166dd080ccac8d3a640662e9e7cf01419ffbcee37e149293c7fb4508c979209b88848b0cfee8d735d2dfedb13b4913818022144e907e48a9542a954aa552894422914824d23771c385f44a90c4d053b3542a954aa5d23771c3a5249a402984f3b997f99b734e295346ee3d6e1492932b0affe83fedd8b2fbe784dbcf2cf278b534ecd8c42b4241fafea08879179278da41b3f637d3dc019bb507b3267a239811cc88891113a3108c42d09a7767f77d5acfeebb9c77bd30bce0bdf7deefb71fbfd9772212d3fb6d13b9f7bc3f4febd97d77f472efbdf77a9bfd76b4f7e7756bbd39e749cebbf7d2b7b9dbeebdf77a93e55dbff7dead73cff3fe82dfe1dfb96d1f6adebddb76c5d1fbbb79e1779fd67de09d3704bf4e0bc3300cc3300cc3300cc3300c3f6d761ff871dc58893ccf03bd7b3f0fa4dd772ff7f7727f3bee7623f0deffae37591e159ee7819ee7791ee879df0809c9c876b1cdb3fb5af3ee055289366fdbb66ddbb67ba9b8debdf77af77a9ee7ddeb6db3a975dcbd1dc7719c177a5acfeebba3970b6e7f41eee3388ef3428edbfebbf7de7befbdf7de7befbda1f777dbfed3b28773b4b6f9874d05d76dff7d4783ccecfd8c754b289eee7b239b0805c9db1f812423def6dcbdff6dd7bb5ebd325f1fd4e57a4714464b78a2cd527e06e826bc9fde4fefa7f65d1842d928edf3ea4b3084f4fd4ff3347bce4fd33c4debe4bcf435542aff10f3bdef978f8292abae13537c504cbb41a1b03e45d1a0d0c9f9293628a594527777ea943ea5d429a594524a2925d2cdf6ac08bb5fcaa0bd93a32cb2c4a3124bece897f927faf847154f54dc219fbe7c2a2201248b2c91d075339492d6502245b3988f4e8ecfb88c900cb663d335fd52f41373e94c9a393354044f10283de1045f723f11964ce7acf6a512a1c9414dcd10fee491d2b446bdb2b84abaf44f2057ddbe28209a964793fbbf21f79e74fa952ea70ca97defb66a52201284604e3743f93dfa7a4299442751c60a64f2f12b77dabb25d44dadc95d5bd7bb370c296ca6d157ca250a6951963018990c156a158575aae9ccef6dcd6acba9b7a6fd142190d596adad9a536f7c6277f3898d3c0a04ab9f8eff40589eaff1e409cec2f1e6eeee0c6fa39aa5519987c47203a6a1984e286c0952a57fb4b4a7534da9902bed201ac231cca011408feae869d47c1bca4c3f1d9d7dd2d76797edab1f9d557fa6f6f584206d79fd99acea3357dad472b536f127f75797abe8acfa4c568d99a6466152a59f6716bb9c389a5c1c3b836808b5c7d11577be1896e22348abc80482b9e1e9211a57e7958d5c75d630ca9fc25c4565cabf4f647bd9c5edd3f1b9b65a7c9a89a751ccc92f048d108e347b05bf09030a9d4419ef906ce591e612bcb234429653c814e50e3c433845f73143387a59479d31e17c7f7ff90cea1ae4357bcc7d72bf0e9f46f54f91dea133741205240a472fb77c89d2a8aeeb7f65edb5cfc932f3d4e4cd2bb705a1d9fbec07a199bafb73eed7baf754d38e003287321274a47fc24066e6e6e6e3f6739baf7dbdbf5d0d8f287cf217531ae5cd6a05a99b1e388670943de0fbb8d7650ff7232a4b594b542c4e492fe5cb92af12db1f611df2ad7cfb56082140505bc2f547a31eb13889188a139c1ef8fde5b03f64f02df62f878d46598947afcaf63a2b06c910caf70c52a10ca232f81da593caa6e2a844b6228e7694aceef5e577166f2fb1a47e9228f9dc6ff251d94a54a6d947380812d78a29f5edd32aa240a9f2bd58ff645ffbef3d7cb2e21fd1598a477406a2c44bf6e47bf88819e466fb9d1447946945ed6b1128f9c423ccda87f471f4862f1e2790edc892e5a43d25a5b251d249b383c18b274b934f965926e1f593a5fc21ba97dcf395bbb1e7a73904d310ceef2c5f99caca83d1fbe8dd7f7e48c34cbb19721d95aa7e7d12e4095f3245ff13c72b6ae268a22eb3fde59e7a8ce9439378edc8ce4b46bb907f04d4d27f247a4aa35af47cb4543550cb8026504ef863fedc69d4145d26f446aff11af757a3a813a141ee8f90fc0c7f7efdf5d7e211dffb571c64e6faf57fd4dedfb577a7adedeb81b3f6b4c74d7a4c26d947d92d7d7f9792be8b39849f694baa504a648886f474c8d43ff3485fdaccf4691ac0efa046edb88cac811a55fae9a234bf6454226b79bed6d8fb123ccac825f1889949adf1e6ce85fc49461212ec422424ef418d6a12d183fca974507b1297b50b75cb147f447499078d200c3de871f4c4a1e8428deafc4911cef6f9fddd926bdab469b77d528494f33e29c2f6911c142fde5ffcc43ffcfb197d33df3a72184fa37aa84fa77a605d0349285e3c8e76986e89e916cf552f44a0066a20fca33f884fac5b7ed41fa02bc8957bf5cdddbd3d6be2497b50e4e996299e34ad0706b212914e448e64f188e9449ec6ba65749f4c27c88690becc3e041685429ecc651ca68868861df4ed48e523e8f469140a51a328ed912a74d27722dd32fed07ebed3f728e4aa9f6adf9cf37dc8db676b0847a7c9943e7d1f023a4d91072acf9f4dd42db36ef1be5f2053f469706f90690f32fd1642a641dd4032405d2494e96bd2899d86b6bc1a45dfc3b3c88c54a14fc8147d192e4c73a6e5310d34449fc264fa94d29fb94ca3684f1efdb51eb9b242ae268dcdd9a3dbf19cee3f9ebc9b78cec874cb26a6b4377d236848ddb5aa55771c500064d2b492b32c60949f15e1d521246b9a0eedab46e90ef25aa986f0e7670021b98a9752fa5bb59163136d784f2beda844a6a2dc445b82a03ca2c6520acbbd61c9b46d2cd9deefbbdd97404b74a3f912a54be916fbd65afbb6dbdad6ee8ffa415810d23adffee8dd99fbeb61edb41bad4f5d09ddfdd1b1f6ed5a3f2a6f2fc553dfb19f8e2959fe40822b4b24dc649965ee5aaad43fd16ff14447796757a135a73806b15294b95126d3e8f59c3646c014e01a49d922ed39733a8932da2484a30bc9fe2255b42cb39c22d460ae4cae34b9beb684645522443426727deda5b241d62c72fd5a54d320eb1a72fd3a932b33c88a865cbf12d531c85a865cbf0e5530c82a865cbf0ac9551764fd42ae5f65550bb27221d7af41f50ab27e05aa5490d50ab97efda958c8fa3556af90350ab97ef5a956c8fab5a75621599a8f5ca9b509b97ee5a954489616932bf5abc91492a5fdfcd424e4fab57e9542b23420b952bf1e21d71a5fbf0e41b2b420b9526b1172fd5a44ae6ef8fa150892a5c9e44afd2a845cbfbae48ac6d7af3e902c4d48aed4af3fc8f5ab8e5ca17cfdba03c9d286e44afdda835cbfe6c8d58caf5f7120591a91ac3ac8f56b143872257ead37c8f56b0d244b2b922bf5fb0a45ae5f6920932b7f59c21baf8e71e162e423fc210e65fc888c91180f23068cd3af4e3f765ebd9427cf3af9b133eba5fce18797320001782905208097720003782971e07829737e295d5c5e4a0210a0002f650172bc943980782981782975e8086287017808f15206f152ee78290df052f2782985f8cec33efcc51e88b527c1e09760922f956ad4781af88647c1347e06467911cff80f8bdff8fbc7fd42e0d1654533a221215910d04fcca78707b6f32ae2d2c9c1b9d16c884c531812c93574a1e64238b3ff586b34fa9275a7ca7205bf10be5a5cd6289926bb227dbde8ab5bad564b26f34b4fe02e93a9fad2bf20553405b95212982813b90e95e106676b4edb7dd578fd7bc3b0a66b8d159d108eb5a60a5530e4faf5d52aa7c116b20cea8bafb2076a594f9150e7569cd18f3c1db24f4da630b443b9be9abe9abe5a1c3d4708cc031b00efc041601d78d464b93e1078d48272fd1cb80078d47e727d0260179c310e3c002c001c00fc0366e1151e359d51d37046ed66d46cc64ae46617ff6187c11ee33252a53e0af619ec3452a52555ead7c08ec247cc9cc2a30fc9f571c0a33b91ebe780472f41ae9f82477f627415e4fa3ae0153c3a0c469741aebf43a52da8d46b576c8b205488460000000002d315000030100c064442d1601427c268db0114800d829a4e5c5a9e89c42486a19032c6208400001800001000000044040093c10e003ee68609e71937eead61dc3b318ec1c63e1de63d89e3336eec8ec1dc9b688fe1c67d3886bd13f3346fb0e48d32ff4f5e8cbff6f6d4fb8ff8dea2621c99ec23fb336ed01dc7dc3bd11ec30dfa700c7b26e631ded00f83b937e17cc68dbdb518f726c631d8b84fc7bc67e278cd0d957803c0798f8b01985e4f8bcda8f703db2b85bd83c1dc33839b647ba53675d571243e77e8cbcd422107ed6498fdb2f86a2202ab01c352d0af08930c3d7a9b98c9fb7bd3d00eab294c1acb522a3e79b2a7d798e88bd1470988b405d04009d35802e2002d6a7c4b688e2b8676fc3efa09608e4f786846c304f314f0c98540cd02074655f43349992640effff04d543d399a30896953cafe2d2ded70ca987dadfc144ec915f004f01e082134d623dcbbf04deda2096798528f81534001e7074f0a85aae69bda014c78b5ff6c93bb3e0a903e4ad689dd0135b553ebb6e3e8699752b6431fb1db371396df6ebb0f56c90d25bfce110884a2b02e1efc0c926d771767a4db653830f64a72071070e65646dcf5a2e287eaadcf76357c010fbe255c6b87aa1fae2903e5b3fa53f0ff7e7f473728b71897ee48ec401d7c8e5579d2edaa71832087a7dbc9f362c65c7071f51e14f6d56e1d92e12bb7ab4bd3709151e80ddaaec76daa41a506a8e6cda2c108d1b056004b6cdfed70fba286f021723a7b336fc720668c4d94b4397db6fb6c9b46eef410e989dbddc00c941d8a04773e13e73c7588523417395220d13003f92fb102dcd5e472eb1f1e4b2969603e627db78d4119c05dde67c17b11fac56a98efdc4a81381bc0c7ff3d1fcfc6aa75727a131470abffcf92d9900fe22eb51fc686ab836103bcafe6b63989e4d5c5f35479b64b8757c2e0cc90ef17b956a5a6ecf0b1948524e40eb55ff0f55a1a4375ffd9963f6cce88ec19dcef90bbb9e20e980e737f0da3261ee6d2a053dfb18db9d49fb6c38d622235d394d13e0957a42d53f6b506c95dcbdfcf52e373e6e2522c86d9bf3637f27e4397e40e05455868ef2ce80147e2f643c9350715db7fe63413af9308c91d6ec3b669e24617988657f6b5bd618890fa8027f32bc53e8119437fa3506f6751a0ecf8c891f70fe1f912ad3292bb4512ed294073d0301dca05247705928e24a8baa64c12f948854aaa80635dcbe4f6d081fdecd3d48a5cb5d92a8192dc61d01b605b8aea627a39c9dd8f613db955dabfb1af5dcc38a70a8b8df55633352a925ba180dba2489497ad6f0967aff962ee908b313910ee33c7d4ccf036351c0a3ca070c272c8cd2156a5c5e0128c143e3dc6d2a7c3b6fe4c774d932ce424fb7a54f778ab184e0e999093e191cf1388a91d6fabcb073c65680b2e9d9bbd28f3655608f24df7aab706403f635b7d98d73de039d3f86698b12089d1aa309366d48fb3d57940cf34a410a2cc5d19070109ec162b664192a99a64ad198da1704e9e80370a55d3dda8dc860f3fbabcac9f13d7787ca76a396ccaffbad520a4f5b999a959d3d6d8e608b686481952cd73ac7c3d8d8f13deae55acab79c0c33f704f7206d37917cfff94b47a78da0a306c768b5e8eda87c8940865757f337a7eba0f07abefac71f064caf4ff7d6aee83db91482fd7682cfd9ed4df770e6595e2758a5bc697bd555655c7350b0d50a7e7ee611e159b93a5a69a134a4d074ec0d098a12f77bf9da71afa79c34c767100d2a5136afbbe1685ac4f56e9b4be0297700702c9968a17a23968d7d75b5f277f7703012697fb220541ee94483f2e77f61c958786eaf5f90c065c88b103936fd46e11b4fe058ad6a9f006b9702dc4a1d067e11cbbbd4b610f853899b484f33709d79a84e424128bc76e23d9e4f40468525a665174c2eabd70189dc783bbe0a270cf75dfc676dafcc3e352ad68ed27f115356804116b7d14dee45c03f12834c75ba40703ca9a859a510b58a0d8f017ce15e3063c859a6f68232842274430b43035941b9cb81761b673057c5b814d6d25ae1df7ab73c005c920ac840e465501961f7bb61c4a1bface7ff993661b90e5c66a141aeb22f29ccb4f6885570cfa943165a92514782a8cfb816c2b27d1728a13f5f237a67956db76ce0efb5a508c70f449271fe2c3fb2c1df09f6230c20d978562a8194213e077a19015c60bb95fda0c068c6ef480249afc5a97532c6971900a347d5dfbed06c2b27966d4ea00642997e658a24cb777e6d7dbd2bbc575588e85764323bd2fec4c59e9e92d037a4c0a546196526196d3c6bae8a00e37195e80a390062bc173adf1c9de1150e304b8593aea3abb6fd9beb9c4dce6977e3832e1d83ec31d2aa2d79b4ff628bf634f9635ce579fb7776f4499531dbcdcfd8265ce7846dda11064873c7892c19ab1bc031094a1e3f4c99610e959451b1317b96d9cd2c1165a6f93f535d9a69c74dec1516878c0d4c021449d7ba698131a66c78e4a454a3c8b17ec14323d6a65b91d21275cb73b35c67d2b77ddba7660821493fd03a3fa598a28629b0f81c79a0f457d88f595b71f078cbc0d69b4ce8205d51e34240606c06d6172bb104d373bec36b5eb6a1b6f331a83ed7f1b00b882785c8377e9c9236b4c79b842255870b56182388b916e764714a83d715c1829fea5955a2a125856d218f098b1c37f3346ce923f078246ac0b51b7a6a9c9c6a451040c45a8fbbfb679a05c826837a3c4e5e150c5f45dfa90ac98bcb01f79438c76690fdd450b3671441fe65e41325da414c99eb1521d29dea9f1bf86e2bb8671bad0c2efcb99ffcc464bfcb0e22010ee9b406b1964a00436da92fb7b913302fb5ab1340838294f18ef767a72ced7b29fe5b4ad29c3575374564d1a53c1f5acd8804d73e913c1017b4e78498ac0d1cfb6e0c61277fa22fb07e259709b20500e84265801faf8a09823831a4ddfaf64e17469d0ea49a70a71e573dded4ba6481da1f39aa243c5f54a1a7fbe1b233f3a63631299230f0cbc1831caf7c52805914caeb877d5df2e36d4e1914894d8fbbe70b3c92d253fbde537dae48e72e2ae7f20f548c8544852e8dc0226023d791e179dcebba42458860a5920ea3f15c34ba882b245956ef49730475a4a258a54b85fff75450f0b1e192b835ff825249208bc1552474256f7cb681a038b465d23576e252acc9a3ea648684b5ad9615793fc186c8a2bae33562dddbc337ba3465551483699f7d4eb92192fb206c77613efb04c635f5d2369b76ded3bf274e09ed85f362747b8c7b1adc8c6cdeeeb21f32af2f57712c57176b7912b84c4995f5308148244d1b5969ee2a07cb8373a6b3bcaad8cb2e724658f5cd454a97f584a50deaa27fa7d4755d2d51a893061a7211f6c5ee2e9b9d383c8f21aa9bae6732fc0221a169eb3432ad24ad81116c47485dfad0c23af2b8ab3255f849628d0879838aa497e82092744d8d0b97544084de6d7499adebb784990f592a612176dbe876e66fca9d9b15a70e554d713271e0dbb95aaa6639a14cef725e6b5200bf941a614011d5883c4c969653f4882b9d0f03609c2c32fb314244807586fc6ed1ba35f59332e28017e44f573f179f175db420d30438f83d903f04b0b496b7f0d66eb92dd678a65d5c417ab232740f73eb253fc611be931d9aba3af5bdbad5457b633dfa416fb7e16381abe7ca6f93a6c56e4d010583eebc6c3f3064424a3009419a98610e532f53b3769865e6fa2b0dadf2ff3656cdbdcba2d5dc69c77f8a13d691fbb40641a6902711788b0d3568c5c64b71d40793a5bf0b0a138d3f020619bdf05624abc8edc2801392d15668b598ce8d6a51c328287d1e4d1d5780a230f9d4f873d18033a66e66f228d284ec69f1be65067dcb615800dd198514711a11b3a53a3dbf510914d2626c80a7d2b39a942aa303d3dec953cd24d2b2af744e6cbbbcadf7ae6dcaf6d3f1980802d9765387a3eddc164307f2e370ac6ae43ec87a95470448d7550cf06ba861db913f7411d4629a2f08b117da63a19730cfe4d81446e0ca3b7b7483517bdfd68a0fbe87d8bb6e9c77c43955a0a39d0d80da5cac27d14485221682ffdaff91f79f484c79eec4cce3cd545ff2b81ef5a231054d70abf91f374a540a22573f2800a0f3188e2ebea384a1f2f1fdbde45244282b893c00e32adcac50a0116e87919826256dd9524aa21b3a44f016d1a4b1d59a5095250437a2b2f169a43087a29c659f4bbd47a22d5b13bd9a185ac874028788a7e481b46c4f5f090e6d447a8fd1f16b1c3c1036688888266b49025115214c722587c0df29d2818f581eab85dbdbe528adc5cf0a8172b403f77ce192570c5d139091e174894b5faf02564cd758eecd1dc4f7cf57ba22a29cfa8b95f355c76e5021a9eb6289169f3d634dc5e57339c40f75a0fe846957827715ef5045d871cdb728379983411106e931e1d13baeadd86b7e6f2cd10d165b9e630a2b110a9bff8127eaf3daba0a15844b69d41e2b7fe93a8338e0e4f8f2141b3e8b00e3ee0288b286dfb7015f776a14d0e2d341c9c9077e5e4fcd98a6c63b3ba3bf0ef32f924a0fd7ef42953ccb17664388cde92e9746a2542eec3970bb12e659e24821c5934387918acd03a26c74428a52834359c6bd95dc44b257ab26db0dd07e688a6cbae0e0741735fd98f9ebd80dcc701e234cf0721350037917ab24fa235b0d67b6543cc1efa897534ceb6e26c13ed07ddd6b68a8c39e90311493b4f493d9c37f3ac0b845b40725ff5fa89f830bd501f3fec2a38e42af2e8ed2c7f7821e581986ad6d7b581e59aa21ca2452071fd237887c457216006beeb8eefd831b896c487f1bce5f4776f58952c592dc1c78025eadc9199571fcaf864d5446be44f7c511ff682439b5c3e9622a8b7963acded73af460a60f7a14377766df4a4ab01cd1f7fe24662c398833f4cd8b808054f0cc69a3c506aab1df4bd242e7e533dc0cb0fc14dec69831ef9eb22cd94ab13b0520915852666430f05051a240f8102f758c177fc252472555d07a3b77b7e79305878eedb417e3a17d5202da54bb674b2758710fc3c5ec7f0502a90f02e2849d2c800b4bfd7950a0dbcf97e262c751e635d27c7fd22d9ee10c5bcaa60eb0bcac6b6619d74594c3cebf55a897eed6dcb56f444beefcbaf8fe6667464f1c0b97d88131b5d708a3aab462b2c6aa31b7e4dee08c3ebbe2f68d12c89c8b98e9e18d9e8069a4d197440512280280edd0f621201d0e21d189dfd53c877418d6fc258d4d9d8265d20b3d8ffa9040421bc2156425d9bbe71e201df063fdc5e49c49df1ddaaea06ae11633dbe52926256409cb9beab1e94a7a4428078283f8308b72e1a0aff6e878f457e5189905520ac9e8d6e8bc5c9d0bf81da3ee9931c25ac9d66d79243931ca90261c991ce3b60bf1d0526f92777330f2da955f2155bd3725ad50e8fa8dc1fc08935f15a0af580104a7e179e4b239017191e62cfbd41ef5b2f957f589703064e49aec01345010ba21b97f4c443c295cbac99ef3ad4528e707a884b544c607a5318e236bdf1975009db3b0c5ac2573471115437efd165130e731830b2fec723ce5f1cfc24de6d4961ae9bf81948e724eba0f471a29b837c4c552e8f567677adec85c8021cf214ae1bbeff7f257912c8c8b3021f7c062d88ff96d334a67f38e7ec0456b931c96ed103c2e1a8d7f21aeed88bc25a14c4f60c68dbd59eed22db28cba1d504d7df91d8a14d3a95190b3dd5d3da312cb70e612e974ee3d3e66d437b135386e586887c417dfa840aa08934e71d2f4cd2c468997dd75ccc31d1424e0b8ba438464eeda410d1aaaddb552e38acc4c91fcc7c6fe16fbb2ddd554b42279bad0066f8aec4ecf8c451e29be8e656d51427849e772afdd3330bcd2d504444260bb7dd6deee99f5c4f66c714f60c67ca85842f2b3d443a62c947473e5abb9ce0b21b8018292c2e7b5df3cb174c5f5ce84bd4d6c34f6b65fb66e2b1ad0680bf94cfcc797a6e513e0280287d63593e3bfaa1e5b0df0b0ea6669998df9d6bde00b7acf29da6609198ca648b43e6badc885465201d7938fcbbc10d34debb16629177d934576506a4f12337cdcd3651db6896178e2ed050a4e32cc69dece4571458a8aea28f48bb747d162d2e91fc7db83cff8b10300f71c373eff903800e468b48a1d668ab45925da13ef002d55dd0cf84eae1175ffe1226dc78a5a76588c3e05b4d04288af12f6c9c2ba549454b1b580135ecaeb743d98507f422660ac0494305c44fba28c80b6616a93fec0d4e4095d285a2985a9414a3602874741678b7ce779bdb273299a05172461a1555c614b96c870fb992d8bae69a4573cc904d3a3091e7f9ee0d492c3d24290247cbcbdb8f9410271e08b3664f6f8c20c52c6bfb60ce2d76b05a70c33a434e2627c46383ea7f516230fb0683508c36f771facb8363539d77d22b9d1150ed0a046610bd1a0414cd5659c16bfba11df600cfad50699632b10ae8dcd50abb7f5caf0bb979931293f3f554c901ba47779b486c1b7c17731155b61d05d49d75b383956619a35d38f6cc231246fb9532b7fa5d31ba9d271b802c3783cc910420404740a4743f66366c5be6813f29631c8071a1bdcafa3b45dd3e1cb09f4bea4a52f10b3363fd30dab22bdc508bc344bc448933d85435e3edfcbf37887aad4e0a2621f402575a003d8700ab8526ae44b2d40de834edb227133aec47200642aa62e9d934302884d5e78d4ff411ac56b12a54261dd4392cccdd2e362cc79ddebfe120cba62e5fb334beacfd176766731e0966aba995b059234eadfc75895cf76db330edf12de0dc5a28d1cc8340d48fa94062c539577e929899ea4aef014a1049f0bc7b12dd7792c548cda66ed9ca82197aa4d20b6e633f14ae6afc121c04fdaceed5ff88a0aea93ee18e945db75bcd9054c251196c2a9631a155a3762e95d1f026609ef6feadfcfa11a3322425a09d2961ade5b4bfedf90877439c4ce88aaf31e494cafe71d22739765fa0366581aad7209178ac052953671eb5f326e88e51309bd0c8a881b30c34d2e1ea3e904c06d9fc40bb42721c55a8f7a626a3ff395bce403170eba29ca2a4cc748a12785de61f0c740e39e0cf9f14d20ad298ace36391c62e6a6c31c103f7cb84a27b142178fdd5fc2177a6d34e47a12663c80bdf45a050013d19dfaa22584bd9da9d65907455bd65793a931f6cd2158f86f654c232912b75b3f1110b55d9ea06dfe30d6bcca7d5ddc3d298aab4c7a2cfb40f4bcce0859b119b72bcad5b17bc93e098faf93f35b8f2c38dfb13a79755a13a040e8f347a0c99b69f267aa441f07e6720c864eb36a07f2158e3d375e1fe6caf0ee1a0c110bd07c0f53f20541d424bb6e04566667a54ed55d6560c9ddaaf6a0bc91d718da80b198ba151800afc7bda0bbffbefcbd8a8a1b5000fb88469160a904271e2de044c1da4a248cd3e2a4adf79d7ffdb71c5513aa89bfd6ef9829cefdfa8f98b239aa1ed0da9ab90937cb41d0aeefbbc61df600e0433c73c1a84fb2484cb9e345135d9f25c89b2fe44f992e0823e238a554148a553b20e96448fb051cf9351354961a0061a60b7f1c683360af2a57f02216b20b6b41d83b1551a1329406db0a17128bf71d96c023f272986317c951065ded26a3c4890ee4bd3023302763721ff84205e2566a08675636c1cd7247849b302a8c7da38dea0ea099bb46057084521ef00359862fa22c807a80cd068e94eef6bcd656b3600d80cc238d09cb65854905352b3814f1d86613ef13961f5178d065ea32ea67f2d264f693b004437e5a1923fb0ad0059eb4e5acea9ec3a3bc8f377243023e0b56e2e93784c0c638d4360d66378ac9b59fcd36eaebbcd23e9770eea41ff5dd3ea5b8e83d8930e14f98fa55e45004a3066a4ef050da1b090d818bc126df426b7b35cac7b70fbbf940bb50c2b788517ac11b6b32fc6b7940b7455c230be5c02c8a3cc2b352e3fcc2d2b6349cae53849c4085e2ea60a905728440e21b25c8e87dc8258cac5529ff10ac587214497cb6188bb17bf5c2cf529af50681442e4d3cb1ad001c6c33d2dc29b5d8a05218e60d0cd24c9fed463265e75b2ff13cbf82d9ac01dfe03cc4ac39f5dbc8b3fb688317ec452a07989894b65bf664c08e33fc9db388da0ce89698251171ae6041e5a5afe01bbbd2205aab037809de4cea2ef30e26e9af307e819caac0e06811e40c89fb234f8c3a6a0b4ae29b8bb79d44b507d056ba661fb45b8791983d6e22926b87da93d92a3f9b304794b80c5e7b97602b42eaf42dce286c91c8bcf2098380e3d4cb3870a368be7cc058b6a229dac40134c6cf387711418028d3da10a13bb3142b25450045a88fff010e81024a151a77211d58682db4c1128c82e08b0296c912416f33eb8451a0412fd2df8d93f7e70482f850ba3eaec894e7103e96eab48b63cc4b43c1f22a6c2c604ea699d33814e3b83347d5fcc07a2e300184c6635f7ec8a3375b99420bb49ca3b5d6d17241ee4dab713dc31f35d8b2f15f58ec8509d40316b725d24d3519a0550b2d424bdea36564de354324d133acdf61eff002590277277a5f38d89d49f606e644ed336322389e3d125235959de253532c535397b82a6a7045bf89586d83470c567fab3f96a5062ef2805c62fcd480530c44d4743e0b42884b6cf4188e88b2d6f625eac4a065e5d5a5c720a60d25b6eaeed00bba6a0110e816e0fa86ea3734abd57212b59b38c2b9aa914698d17423b981722cc3d8c4762a4e6965307425dbae4c8441a97d8ac90c5daeaf22074ba14eb725e9fb480b4e28eed065c6993feea2e2aa086946aab447e0260e86febbfe4b12073e6446154062409bfb7343a27e8cf40e7ab685f7e3788aed8fae910eb4d35b036733e9bf883710b9afa6280624b255798a35ebd05bcc4638019a935955cda31fc2da2f4a611eac084b47077d5d16956918b287057f21ca37460813a98b461127487b0895e4587a92e8bfefe0d4a3eee2092282a5048fc10d266d9bcf7a12d4aef1210c9693eca1cb2e0eaa4910f6fdba0a46073bec3949348d07d7e6eef083b5bfd3396c9e2ab5746e46e60ec698c15c7ce2883503799b8ff35ac299bc0f8805558836b0ac08eba6a0029c66385eb6411520eae413c3a83d0e540885cbb1ec70122cb5a8e6008eb33ebac0b7d6032259b677ab6368b6170f8279291152a5fe9697d53c22e1635de05042266b3989c20d928058edc0062f99db92b038a7ea038d83b35c56f15f7bf0b54b16b45ddd7ea7cb74f76417ce1ec9af63de982e8f677c7d567138fce9da8f0f184005d23fa280e44e84085fd914bbbc58c64c79944707a1bebbaed1552bc048010f3986fca684b2fefe831d7aaed87fea9362fc33040344bff61ae1e75cda49720c3f91f184b2ab6359e2d972d47bab1aea6226d67e8d9650ce2f811638799471ca9683b503142afe3c70a5c1e460470d033e3463053b639b0819350ed34e31b8b509ab8b35a4d472331b08b1c1b09d09f400c12e44a273f58ac09f24c51a22fb68470c93d02493f3bb35d2b7757395cf58251e2850828d13cf3b5f2bf5402050b24172c81cdb544b8ffb35584f00b92961fe023c7ffc1ebf4af851866abb4fe0c4e5bd2a23ff19cc982c2afab438181b4265c6b3402d327776bd204499bc2add51f4c6dc2b14e4720b2d9336360ccbb4d6dd27486d32097e55d273837a8863e33cfa395c94b6d63aa3e1eaa9edf0b086d6ff591f5ef4b6b5d0867d7bb2b0e9291642e16792d9c4ce6f8fb6c54fc4079d3214fbd12528d2e83c4e661a1413cce9260879cdab6ee829ec047cd6da404b35b839143e310ca893072c545a1b4147c444e6e0282119b10ef3552a92006e6555cf88c0046189b2fed7401bc8eda2343ecf330f5f8343c01313dd316699c8e12412627685760c9768ff9df31d5f7a3211708df4088c96f90b84d4f948b8da2d24d2a0af0d3a166abbf2a31aafd847ea834a8a79332c981a66303f32f08775ab66418b8073ec4704290667f2d2d93c2a2a430332a72558c42e635f0f36a5d216477d5870675d446ea5f7d25c01831ff1cdf73e55165fc6c44590de395f02092fcad0d0f2e07628350ac98c62638f01aa935ce81912c966500e079066b06dbe1618fe5383092ff91831ba3a11318a106d6f945703fdda94323c502bb08e4f455564d33cb2e63ccd1ca55e9116a2eaa88b9cfdfb88b480855181bc83cc561c484fb7bfccb4f3652657a7eafa8c8ebacee37841e1b38226f5f1b6fcbb7fa4ede2e88b0dd5e9ab363820c86bd7a584cd10f492065b28ba86a490cfc657ec1ab1d5b2384a1e5d513263bc70ba5a22b1c924a36f8429e43554189dc1a6e3d879359905eca5c788ada6a7eb945ac4475db7ee083b18726175661cc8fa9f9b6f84e365971f4c8ca9569ce249e43c9216c622e0d7049fa98b602474bfb29a9d29f1bd5803f9f22b37c7647885e20a56057fdae29848b0771e1d5edbdd73faddbf6dc60b3596ec5e3c74d57e621bd5e124dc8eb699ec40276c484bc033680504971238e0901c830c7de5a07f6a75c6bd60d331d3139e2a0d6f088d9221a00005f254909ebffc73504e513b280fd21531e7e353bb41622e6168ba344f6ff9736729be2cf66d1c003f0797082f4503caffe6b80384002b58dee7812237775bc5546bc4228f40a7ad7c5191e8168fd8608247af1123c13a90be952ab408a08340b5b58898b6a33e463a665611d1e6d69ed10610dbde1b55e7ee5ef28d2c1241e916ece2a1128145df80055563e6cd2d7b9311beaeb78c1bd87d3c2de996b343a08f7a99bca81f77b04abeb7d729f6e509345b8f5d7d059a567600190179113bdc9897f6bd9b92e8a8ca8e676cc64be08132378ee682815385293157549c78f63720410e4511ef7e525f91121d2aad13ebe1130f3bf4154660c4fa362e4c69caf109beda35f56f7ded188ee68135e9445fef23098921efb3f00e0b84b961459688bf29885af8d30eea45fbce53881deac8f671648d0eb1ad925c93157a0abf52aa1590adae53c8b3e04b58e889de41991687bb1f0a9fa61c05d5f0779b31494279d10d6f48b1f6c1dc9315175e9976e93353b85e26a653425923d473ac1eaad37dabbeab03e44769790a00a40f056fa75970035f56733ddc75d33e7b0eb5ab6631703b7620b1e04b652c9ec0631118ea9d89e8d086f387e8bf966aee2fbff5cfcb7c6c4b3e0c4b0a36ee02bec8e1d5fa4f7bce07a610a577f936b2a40065e37990452f0627001c32e084154776fbc483d8cf72ea48fb68c0f68146717b3bde0b18d4bf46b546775ebd13460757772426af5227b7a3eb2593a97ac1d8d5d764243295919fd252d52e7a86d1057890be175bd7d989354fa2e73b897d7abbc359271bedba18beaeaf0837e078c0fa841cbc7b233c1b359af96019615da8e9a41bb8a670ffec60e8b6c2e3c2b97bc8328d1cad15c70a3440dc15fac69a0727e056147ef0c2cd38382c283e44374a56b80608b841f67709676988e771be1cb72cef58adb5b0b4fa0ca094db73e9edd09a3555f33f5e1320d680b8f7feca6c52253e8ac1f553621887587f9fd81a8e66a1fb5985a5874a73d57adb4ae7877f63815f86526906068840a74c961fba0269af61c5bc02c95368716d0ef759a61d238019ada802f8f32ab66c13b128c9669586b130482ebd5190766a9b0fa8ae50d48e8d38dd0a60309051a5720831415d1d4f236c8c8e31b9453d666ba572d7e813c660b686826a6287be0add01d0b31ecac0d495ee9611f730231af6d5a2e969d3425d80191f25e55691a772152f21bb9a20c421eeaa6649da089c08c1c672683d4745a79d2c6575e392c634fe50c23ca32bb90c4ab5afb7ee4988bd70a9a5fd8619030d617e97a401a9094d311cced9e9f36b55910b1302fb0dff79c39bd20fbdecaf3c6164011f28946933bb6b1dfb1b7c5e7ce78ee16440d8c84eb1ed00559338be84ea76ff9045331874eea3b49c3f66449432924c3c4879cecd2fc23b3ab33fda4a51669cc6d1b1b9264d2c3064d5c8c8fdb00722bc9cfb9a483dd2e4e587b8e8d9de1cd417cbb405f324ccaf9df8e1667ecc3d769da267d60d0d6cbee35891bbc0ff781b08eef3c1fac5826eff67677dd83b703a4cd22c87c6caa551443a610567c0ecbaed54c85f8f3573396afac8d851827b72b0b3d662b306f6c9a1dc9627ee37f7017c4389fc1101e30155baf86d7206e306867534636a54e0254a19144b3fed9ff0a486f45597a4b5ba5d4c36d3e1b00a8063414db5e1048b958a991f8588a6a43e9f5469dfc74196fc09b33413ed63536d7ce69b147bebdf2b6482969ece0192c8e95a8a769d5f763593f579660a47b53096d066f21e2d1c07be93d7d981711168feba295d51e1f02683aeb2e31eb20c5457058db1ae41295153a8119089f1d9abd5bf48c235fc902f6860fccf7991003e8f747a7bd2e920daea457128ed84dba5c02889855cda83646a85fbf24bac04de7aea20472b8cc2dad1f99832950691cdb03523eb8189885cf7fca66045372ab3c726a122854cd9947d667b87e68e93ec10bf21e47c686a9eb51f261ffa4774f1a63528943b30536eced1395bc7bef7aac857bb0a94a745dcb8fc759fc83a3affd6d0f0b9f9121c0dc398b3156973d34785c3c40997a9c658107f58e1e9f7e816d77a9fa3c82aba167de8c27bea680e027c6a0d4b18b7b5ff62b01e653c82c0df590bb458280cfc87bfbc185a47f557370f8aced2f6921591d8c60583bd419b54c6b3dd9e6dc93ad8bcfc8e23d885fc61583e33ea4b8f7175f360662a4b291c64e25649e3574fbf79485f779f0fce3a3fc01fba12b72d83033c6e3aa53d5d98d583ae7fe706c053c05c1699043c1cd237dc0495784876ebf542a7f1d2c76b8701b55493f194574f3ba244ef1528231ebf62078141964c87004e42b53f527933b2c5d00c7442f52e5175db4e1431a37a60f47fc12877e757be7e906e49934702703de8055940537d9d233306adf6817bdd521760b1ccbef30b8583b811125fc2ae13fad643bd688053e05a1f88be8ec24767ae9c146c9815e314fde788365718e7a268eb7ca51a64c5434afb3d39fae2ddf231763f0cd6de148190a5286813b950b71ac31be747393ad871f6021dc9e7b2477a642046b84cbd8c1f153a0fcb568777c4c9c502e360a0e21e58c69323831bf0a5c6fc535ac1fdd6145d1190dc4927b74fda3112b67ca2e76444f9c1ddb872a970e15dc2934f37671a4e709da333cbc1c50599306bde8ca63632e8ece9daf3923991acfec1af006114c7e4a1dcbfce378219afccc9de7e9dd92350970e3b276ab7b020853e0e0978db96d755f99566f0a02599434919f2027a29ab2fdc161d3fc70ce3eb6229ab8c62dae85634dccf9a7d69fe0977a45e25599226bc71df14c00233cebbcc64c84c473bc97bee590b3b2d0cc6e4cde17da141d8695d04d3c5493dc553855e6147e893d196b1222cb3df89bebfeb1e74c1048a22de1563723a4b5565a914acc0df6c842eb2876b889185d10e02bcf8c2cdadf273df544727fc311324d537bb1f0c0c93aedd5ef233d87edd8e758a859b6d546477795d09d266a7c01f5c8a0b02baa12f8908969668c75299c0e14c4deb8bd28d2274c137af65564c7d6aecfcbcba4cf37ef0c6fde3ef046092f18225bd33ecb8a82f21cbdea89f1be662997172dc3bf432a04456b3adfc0023484199f69524b48d6bba7d8b9ad7f1a765d33a011c38828ddfadb184c22760c69b67b9cb1f87f65b332ca6379dfec702e5dc2197eb4b4d16106700d05e84cbe9253543d32cb88113af979c9ec1dc6366941ac68946738909a987da4b223f1fba39f92e7fe25024328a1322fdf1d7610fcc050178a8ebc13877d298644f8b5592d803d4827f175c36021540724e9da3cfd52a02f1de2f32cc25de6e8921411167a227907afec7a086b7ad7a51ce93007edbe01b63f0e8d758fe07c23f9c1bf56ceb48183d1c95b97c0c4ca1cb23ffa80997617adaa1762e62c6c73e056697dbddc9bc8c4e1c2ed963d40869cdd273303dfd4e8077b8c40e5a1a961369d1335a394b62b7ca5fffe28bbfbb626757cf876e04840f5f67c07aa6546450fe74a1f87448f1496b8c9a12324413fa9e07406fa863be1f4af6c6f5b000885815afff781434392a7c4614387e99876bbc3048b26fc4bedcb82aa48ef948eff14e9f0708966d81478c3f759f361423c87bf80fa93b85763d6c304acb49c9cfc20080c6d393b3c0c5ae12b56272c01ea8afb222bba814a564f654069bda202c1a1c78a0d52455a51e1507b3ae08557609a86932a6cc2161bbcad5e110a2393effea9e0e701bc5e38aa1e07e2568fd6eca0cf7b51fb4dfe49b51e83dadfb4010e031d8239f9ebf1087e2d1029e5b36248578cc38789e2e84042a7a0f29da0b0abf04a9bf4ee1584724e68034de81b3ee5069afd97fd570130aebacc12ed6c915a5a40bad524c2532f7725feb15170379924e791e70b87fa9adbc30d5c6dd0d8fcd3f52f40defcf6eab1f26267c204c555fb8fbce5aea7760a9f3a8d42df138ba94b09141bd9e9f438542d8c949f775b4ba0a292e0d30a09d252e3e4d110a19f4e6a9ed7930642e46141df4f0c99fc774ff2e13fae05a19ac5c0f19399c5888aef25a7c2c10837ed1f2fc88f083eda844ea48cb89dcf87a52f68aa006cbe82e165c587ad7988cb3def31490d07b7e76184816d8fa45f674aff0c0657b6ab564de5a2cb4dc11446e0f01bfe67d13b9313ca313fc85f9abaad9fa90cc5ef2ac061f11792ea43b4c24c318a169acfa2a4f599312c34b9ff1e83782a894161f5a129fe90a3ca7ee658188a5af37937f93bec5399eba3fe6a333be8b0a88f10b5e914dbd7bcf0c5365f037138630cb9f0f42098217ca9c231dabc62b23de8e1b99f23421f1c0d762a92bab817801878be1414653e526a03e16ac6f88251327ed6650ec8573600395e27e0dbb232a100d44f0ef2ff5637635a499c2308ec56ff1c1ab3932626385988a89a0697d12f74fc0f2d1ac6df2cc73822009bfcf66840554f10df9766b3854abf4395aa771474ce662c929b9a3d4de3d7ebefd1c92837e7d61ad868f5d0e3b9190d41993adfa709664658fbbf93f7685220d4f6d160945162be59e9cf54d64be840296d2efa9966f07ddc044fb8ceba4c06655b73d70b1724451543c74ffd5eab937742dcedfaddae94705b1dd183bccb4d8a6c93300f5d66f9121d00ada0982afe309087bae605351ec36a8d45f1bab2946f4018df06a6ae12a8c1dbec9edbb7178f3c4d3464bc121c2c7c4f30fa8a458d73cecee72746567e81e7467cba15146be85f9c33d1ce4d9baeade25679bd635a88f839f97df8d009dbb352092a67815a277f9bc90cd69aa6d52e33e611c06460c4c1a5fecf38739279a9a4b2ecc8aa672ebf528b4e5ef25c2c9bc2e03a49883a392822263a563cb292cc2eac22d08bda9959fa69be2d493e8f230fc1c63d12f3415b1ec73cd15016b32c4fd8c8c5fa59b9350e27f0cb810514cbe3f9a265bdc31d8cfe4efbbc85747e7e9cb845383e4e485e96aef0453f2e3a7d189d45ec0032853e419b0076644cf9ba0f0bd1bb50947a4be37477893d9f1571554c49482f01a5e456147ed0d3ddce08e47490824c8b259cdba2b8017085d94786201d10fcdd4f08dd34d98cedfe2e9f5c155ab75ff5fa7e3b4f9f41337d65cd679e7f36f23ce9ea048d58413a5f7bf120ae518b3866e7c5254671a0b378e02170245ae5cfa3e805bbf652171ac71a37d42885609f688e52d5e8a406c857dff3a7c3e8f5248f52eb8e3074ffffdbb846d0fc1b7c20a984a2c0364ee17d4bf8723a51d9c2db246d327eb3885b83dcfd19a5849878320a207f6d4319545ec5f0811456134ad876ded20c2b31f2f23ac1f8ed0856c3af33f6e69093bbdae12bf0cf680ba94f7dd06d91dc00a1fbe0580887269063a8eb9f20680bfc747873530b179292b248eb0a25ec2151703c902c87f9f0ebab124a7f7a931417f2aa9099a416befa5d6b34ef4089ab2ca450292db221c5d4bf2c054b266d7cb23424fc745d81632f3d02a1632c8eb46405fff7cea102394e3f9521f52c0f1eed572b7893441f98dc22bdd58eee56e01584d82d0637e3a1d1c52074d0f9e541832f305b2b8ea407a80518748f71ede3950cb5fb6906a605100de40c2f06007a739103135d29c60c7fe0e3685f59b861255ef016cf5a2a22c59638b6811f30dfcf087ddf8ee0970e955e806aa4b8b6eb8beb4c00152d8b3cf77fdd99a390dbdd043a851736061783fc45cc953c4b835f72f2c288c1f8a65f102194c857f4aafb26913c06cdbb8c3e28cfc8b7428d21e1d2f826dafd466c602b8597ee9c6e8e1769f6172cdaafbeeacc6d6c1461901ce4b69efbefdcda36441519ef3c5af7c636e72454eb01539d9b01eb5d3ac4a7f8d2c60a0cafb513d3d3058ff29875dbf9940e50001dd3f93101e84daa3ffc135ad7578afcf5384b0ebd8128c2d336006eda72a19c3765fa880cc942177ad81b15e534cb4a53a8d04673e3a30ecef95a6577f02d6b1553a8787b1f8583e1cb19e9824606e2f1b20438ee65d1e7ae098b8d9ee700fd6446b4c8fd5c699220aaa94cb8ec92e4de8c8e842aacf53c11a05e13d15345ecd7ebf5779a3d0514d90d4072ff4fbd717fc027afe553d9f948b133d62ea26920653424fcbcc369d598559c63b1ca1e8f9061c6e73472a4fbac4ceab88a15f1e98c5bf5620a95ea94cf97fcffb3997708131b1500615e90a2c3deb57507e598453c154384e7c01653d77a4beb1c32fd795e4a4830afbe1cac8fd746138652a2a0490b626cbf2a9211077cf4137bf9ac13b51fe8f54c72bc1a6906b797bc50a833d72d516466606faeeb57993d63215dd97fe511ddd1770933c602cffd628aa1a4ff5e02c9ce252bd42e17448599f55cdd40ed70ec5bb583e4e5cb7002c6afd28dbfea5d296a68620a80833a72eb8f3dd21c79a9f0ad325e5df1f588a12e0a43b0ce58596e49f084b83fbab1bd6a0e0a8e06b81a71593976befa8175f788c614ed398e4f433af3887011adddd3a88e1fcfe4ead0f4ee450b84a96384014731b6181ebbe39491f9409400bcf709b68810d8937e1186e82c9788036a01e19f4ed1a27419ebe1920d5650d6e392f33bfd667c14fb6fbcf5e46f66aa86463e9991a7892360585b23f7e0236faa165ee70b28d8f97512d595bf1180eac82ba6d036488f847cbabc475097fcae23bfa1e07af793c37e0c0f5763784ca557a46db740561ec9e5e35228f3f77146be124a3b7847bfeb3f2ca54532c0eb39e6e91018904080269899ed1cd1242dde787a1e4b2721cd8d5f6f69b69b1b9bbaa2229d63b59ac36f26ed24ca5b8b8b10918f689dff2515b6bf920d1d36a3a27852ea245bb85f6e5012938e8e6ab22f757135bca42310eec5f0b60c36d7c151db7f8a7ccc054105d8fb9c219f5488b2e8c2eecebfb08573f233c359575a65c5e6438c69e8452ab7c0e6c268c4cb2fb8eee2a25ebf35179b9afe69ee4ea0d8efbf13e97ebcb070742a0db27e423fa0154ec381eb194d02fd16d8bf3be83bcaee08b0b5f7d32b45abdbad8dd2db37abd664cbed1e65f553020aeeb1755a5317023a92d0f541a7742104beb90d64d18e9e5e38db1cf88c2e8d230ea0f9dde4e62dacaec4bd91bfab911e27991000b5107f34f827e47acee6356f47cf578f152c889fb6562c1cdcd949cfba8963b68653b3650b784b6e95f909b38f0623dde640372eb29fafb0a18248329a640bbcfb7cf0366f3464b61612111d44efede84fa6235bb50ef4789d670a3d474184a242efae6320f6b2b2a013eada26e6f40c021c3c158833a23b69d9e580c9dff881a92edb42e1b7ac82cc200ae0b2ea3388b237adb083e1348571611b23e169f2d5f21db7e75dea2c8f477a45d3b578175525f7d7e66b2179a86eb0ca59d8e55eb6d080e0b3cd25ed5adf1f9e00ab13b672e2564dc0da09ac31a1f513b67662564dd0ca84589fb0d5132c56f589c4aabd20db513348716b7200503bf30cd3949a9a1d1c0be97665e5188cf8d89b9105fd609073c98387f322d57e87f6af7afc3513bf4930064486f9e3684593b570db861c7692b23562235b374501dc02c3180e274033f1f4327351b09e8625ee2efd017f0887befa2213120414831993244806d572f0d58726d4274a25920e3259b151d952dad8295d7d30e78b1c43cdbdc128616f1f0571af1976db65eacb8f768c9d1445e449bc6aad4f5b0b20680df22e8f99d5d643a39ec7da325ba0f0ab0bc96396a6e8679a694665dec865c30e4ec89c110f1f7064f7bb96dcfb6fd24c8b6646d255c4ec6e17f9263852deffe94b48dd77b9620f2581219120e7f935fe646e2c885cff737dfb2778e4cf826b2e88cae5170d420b222afb9374fd4752f34ff06f17446ef1c7594d23881a01197f1d05e02d1268d041cd0b80f5682a88caf4f77e840c222ae1d734f07712ed2fe35ee89b922fa03c7605d1e7de3b06760fcde57ee7ff5f1071df5f9a891b4450a9f91ae72fb312c4b93f493bd9d52088e2f77f2b353903e6af48a482017193d8a2800e6e2f888ac82f49620b220afda3082282ee80db94e0e0f4204af16e5bb6871284ad20fa64ff8a837fdcd3fd2472eb07515199e5bd204144cdd848e43c40d33183c8095c801c9d35f8d96808bd680b8e3a30641605cea239202e41c439d87cb4e9a496f28aaeb29529b23d24195b4b1644e514b0511c44947fc8dc29ca07f5ed26e263cb2042d2af9cdbf1843dbc29a2114448b51506794a87eaa88f5a3a4a0c8a7a9127db42780e22d167f36461208db8a1f6d0b7548ee30aa51351d63f320d3de4d2a251bac97b353644bf2fb11525e1a73a9474544a9519c16285588e60a7a7117157a1b64b77a4c9ff883031cd62727d2629e265e249e82119b44f3812cad77fd80405e4323f4c3c1b28b99b1205f15abfd4725132cae24c3e9fef2de76db536fc540c15a78e0971b5abbc2905288ef918ef95804b6f46e501a5077e5b3626899afc808659023c36b810e251184862cc3807cf3def966a27661698d5468c0c77352a652b9881fbe5d3bcad0a1a7466f21d9c3be6657eda5b84b398913a8b8a4935b4311ac72f0321039b0743e08b6576c5e82eed46865cf28d360c338cb2711e13232bbf1b9093cbf04049447cb66d5e84188768e0aa076c2b3deda9d145c58880290896d2193ca529c1073296b936f70c44f27e9b04c9f52d900d189ada810af32a36c5bc597a43ac36ebe8d06cb72e8726a676c4792ef57a9668632f224694266628c9930a01d5003fdc41c0e59ee1fe2bc1056b6bfbb0845c10a9c0bb9cfe471b3c0f6f3f4ab2c4dd3810032c8db0d0fec2006bf19dffeb28a1121ce1c038e14a30a02e9dfe3df902e6ea18be265f8bcc37d5e4fa999f8fc8d2938099f83f917fbf84809a0e046c244f3f3bee03a8f81660eefcbf0b008fd82600b5759c6b1cbf4c0d6094ed11c0a6fd4f3180de15001c1cd2e765caf1bf5380ec9a5eff59e9471103927e75ff5773b7c4c0a8b511e75ff1714707dbbf2e33d838acec0f3e7f057cd049a53f80b3232dfb3e9da73f331d683cdade0fcaffaa57d8d5afb6bff0b424328ffe59cf8203610efd20f5574186a8a1f9233896b0e731ff78c000e2db14fedeff72f50129f0fb16f88d681a4c5d5a0a87c83ffe1f3027ed13aa8bc09d67f87496a008d93d625f760b5bc026767d43a40a9a7ed7ae34af202a1b7dadedb38374a0532d0ecfbae71d9ed68ddddbd880f35fc711ee8a8d98ffea80cc6d6cf02afff54fc46ff84f2991d1e1b6a401ab998f5605b7041570110f6fcce16bcaff3542405bb214280ac5a0b9cd24023c171f3780e60cbd292359fec0d0333baaf720c97650f3634053cdb6db6795b1ff406088c16f80e1365574df2c2956b1b7229d1a5edae8334092f648bd8d7f9a35da31b49f68aefe10a9c6d99ee1da197c554bbac228d4f488dbefefe461ccb2ecaca7d2d8e48890b6119e46d5bbd6cbec952abcc75b973f4cc3ad2ec99f277bf726495521c335c1447f79ca6f352c7c68022500c50272dc7c85fcb507814f6e21a3830190c086eff9b65159d4278fb2f0d597cab2c97a9aef2fe2757537bcc0cf40b8f2320a1bbda0b8ecf4a21c2879ed7c53e96cc6c8b2ab9ca560343a01fe13c3fefcd7d39086d9e36dafa0d075bd47ad4018371f4248e178cfec90993168260cb3f0103b1fa499a8b070713f69097bf8ecd2f6ebd79bc3ecf782839850f796e427c575d0304a377c05044d737c6f429fb369ce4ff85ea93f515e7868582e98b03e94568c59571fd2687d52b0d637348fb66f106610dccfe781f6697923e63fdf7d28a92a5dc975b8688df3ab261a8a4b128f39afd003a8d0df729d1a571a5ce8a3b600c8d036f15040f53f71ec9ecafdea52afacb7aac2a98caaca02089fa02b6094a6c672509ee9df71f718a7d047da8300b0aad128c91c5669d6bd881d20cd7a936501f7716a3f1082245a46b42f3eb9aa2d8949a78f1136aa62a77e4568aae44280328e9823bb9e507b0a446c5fbd5045ca59829abcc44dd214b8e908833626d1fcaa0a00fd560bd080dd5f973aed3ccfce792444400190d6e42c66e0405ad19c81bc129d48d3fb14de70a4648a46e0327860415c5897c818eb2ce56c5b1054d538c2453509fddcfbd4c1125fd745677fd8ab18267b9c2d5332670f8727cbfa7c8412bc48365e24390a0fb53ef49ff574994ff6c902d6438cba7a9323a072ebbe67f5c3dc06f3cb563d587c9350de106564153354255119784a0fa4e023e84e99d0dcfdbe70e3818fe5281b372a75ea0d8b45f42854be3b05259a76358c29e16b2651f02d055d657bf6d6916bd745bfda579c7dd2efb0080a47b593f85263c43fed0d222a942b61eec55568d3a57af03cb70b0dac4993651dfeed93fd23ceb1756bc88d6c3e9276b223511b555ee4457d90c6b58e38abedcf659e2ec8bac00e31ab04efd226253f041256102f87d70b09c34b19bdfc504776d2e2de1ff4abebd24fd79a50da4788f2adba632ea428b76f4eebd9b3277fbbef1064ac06ea4e1c84482e59b50e0da435fc34af1bdf490784b792d436e6282d81ec26a004afd7d09dd0f5ccef804863bda8a46fe46940dd3a80cde0033cb730087e34524af54ede8dccd969374cd63ff2f9009675405ab646678560dd6915446efaba2fdf369fdd6711d9f441c8b97a990fbabbf7494f7cb81e310bca078a2539f795a05fe64bcafd395c82910004c70cb0fd8c479f7a5b94f5c8e928cfef049db1fea31b801f29584a10d5f048a968f52bc229fec3c1c5c3960c6a7e88a19a1849b1a6d1b09a44c61e96ea2863ab47ba8da0464e9291073c6cba4efaec24c94118fd577291cbdff4102dc9de0a1dddfa2139c71ccab645e8c0a0e95ab4c781d91763b8bfc046d2e6f7b533f050057da1a5af8ad2ff2ab984ef3724a0a22e61921106e0fa151a1ec0afb83d03c58a8b8c53a2bfe3722d123153da059807c038785c7c12cdf20e189babccf9b8935e62dcdf82de33f75bcf105d773b10cea4dd649ced445eacce77169fab68a07ea4c1be9fab8d2b6f16b4b1dae772814a7d8a50c2e78251662ca991b4c02438ed6233e1bd04a7b6d8ccb8a5272e8d3abb91fb031d138a8fe68b43a57e77a45ec04685e40339e3a9a9dd8a9427a00121fa38ef782a6a3623e7037828c43e75ed500281c34dedce745050867a13831ee8f80509e92cc78ac9cb1daf9064734751ddf9049a594fd4ab276e70c77dbff7636e7effeef52137400fe8fdcc2da327ba3ee396e8051d1f722bfa8cee47dc043da2eb036e88bee8fd995b420f747ec62dd06be1fd30f7ccfac065a63e30e0fd91cb997f8a5b667e60e0f139f74cffc8a5cc3e914a9f9279b815ac9c2fd6a185dc102f4cd33d56b1e7332e942b1c90eadcf4743a2a7a964702378c4dbd2c42b2e21cdcdd5a3ad76a8aa148214ef4b626397e15bb22015ea7b7071772426e18ca76b74b4d55cde2525d882857d3d3492aeca0339f8a273cb23cd4e4cdc1851c903b86b2ddcd92795da3981457a28a65fa74520a22e1cdbc454f4541848c20fa6a0e4415167af06fb72f272be0acbcbf01a3d182af2eaa2370c919a31b6745fcb7ca67698dded2c804761dc29a0b0575c2cf43d144dab47b61c120cf217954fc44e042d5447fc2968602020c3d45300479cf892ccc4edddc3dba6f0080d5cc8da1c5cef83d45e99adf2f18bb40468ca2f328d0531a55f0d6473a04ca6247ec3ecd456fc525920a4b0fb46b8ae41288a579d7ce575d7430c85a28b0eaca2d5001186de5962b0ba043cca190728ad4e08b8ed290db64b331394e3dca5b58fd15651465d95126136328e90c4bea8c7fa1334f13721f819694fe1c01edf98f7bcb8cd18dd8a12fac63e30bd61cc9df7f61d5e3f705eeaa2ee4c8cefa342c37fe6855aaf99e917de123085bc71e274e8509e65ee77c03237194a861ec5d2aebb0a4c920f7add1bf1bb411cc4564cded905c3f3220fa77148b8a8a43cc802723e32813a02552d00572bc348182270eef0a8f4562cb1486ff67d5f82510fe7438e01febb1aeca66f645c95cee0b49f78409352aa615f94507315dad9dd9e99a3966cfaa4ab2fa9bb8244a8998aeb86f6be9950034e8645ff1f3c7df81482fa82707d1e8f1081032c88e567df295c98a766ca42c1cc4ae0514fecac8a2f609ba7d99f7e13d21087206310d20626f99667eb58dd32e562ab799552008ec85fe7c12136d5c1aa9535fa938dd851cc878dadb66f7300e709798240c4d086c535d34a4b6baca6ca7389b9ade97ae1c63562abadf763695c82a53c92365c80346566fe0143ac23b6463013bb582600280006a980708aaf5b9662760bca2b37448be04a81ea37d8378c41213750cfed86fe0036829ecc5b9dd1adc5bdf92e21dda1865017f2207e459d610989cb1741adb001be882c566b61af23200835a1a04786499c77c9b6aae766283d8005c30875c5e2b0c888ee136d1f7c1b29e83b146d3de90a57fd1d006da3415e97cd11e073869112e1bcb313ae898d4c01988d561043eccf2d2788f33c4361d86c410d48b118b1cf2c4b6c15b67d5459e6b473b19b89d30d6b1ecdcc183c2298ed3e09644ca0b3686d4b8da52cec52c0dc87b3aa76d4dea6ee6f332ba31ff6ec542c8878c6c8203981b74eee2c6211c76366eed465636d66760dd888811365db4dd3d9df8801e0b517822db6c858f25f9c58c23a75b88283100476b079703121df8a235397835f0d880d21513cf331deb06c03e113b295cfe948127761a0a3962bcf864489fb4c8606101c9f0f2c820bb76faffb18edf12c2fd67a36b35824709a06de93bcc35481d03060fc00e4e58e519950e5e4177afaa78b114f9c7b121a24a064a292c964551293d0a910cdd9ab1904634d246eaee21e8d799c3319e85f62fa00e304ec92f7c08bc8e7390169c7ad3584716909fc3ac516f1eb49798508b4d02368843bd1a595ea51ea37fa7f61edebc8fa48fb3560a7ad0d01e9758049a94ab3f2f6acd0a3f3f5c5293c1668a2a6f4ec119fd130821c03d4a21a828af48acf8f3dccd9616a50e39add5387ae3c2248d5ebc79f1b9377c6c0b3f0f6848603812352bdfbd73ec47d47d01ebc0d0e28e028d0a82efbf7f9fb954a0038df1c8e42698b41c1a993775eece1693876f6486469dd6dd4cf452aabe3f03af00a982e19e17c2395517982ac2c0e95c0d7a46f0466261e9274537573db7d0dc527f0f2434aa2b925d3ebe35e57574ca460bbf97e79b8880588bd96bf8682b7f0f6dda7dbc5d4edf7200ea251775cb33f307017703c29296173853fe59be9a8d487e0eb106be799a3401e0eba4ad06dfe6bee86670ccd64804e044fdece5f50fa47b94079f442ff830c2e8df400c70ba48cd5354e0e854d5a298dc0db8c0f95115ed56fa4d60fa4e6cde8d45bf947e2b903c903d196c3f50ef3d6bfa48d5644f2e02dfa6e6e0acb3f05317846673bd0514c17fbce9e8f6f2eb80860686b4ac82165e3ca670260ff138368d47a5b07f2eadc9b0de44d59b4f70c3df011bb006e63e2e17718308446fcf72e1fbb3cadf5b891e0b200c9c87c078fdbfe5bce587c3d1f03509669b849cf6c7024a9a70367be7207262ea3ecfc0266364b3968e1badb163f2b41f9f338c59b899b6e8488a1636de76ee03429005d5064c72a32c4984f7025eb951d6b06819d6dbb768cd2ea4b1e68307bce8cd43938fb6564f5478d17c5a6ff6b4d1f80de5e935e806b59bc22801afaf84d97803ec81ae84a40a894ad9d71f23101d6c749cda2c7069ef8df8a73b5a4554419d7c413410139dda68877349874e9b7617f90ba15c35a46a4da6224e867ab2c279b1ad5aef190984684799d3229f765f1cf7d53c9f7fa52377c85414455f7e7cfe33715136e7047ab6b05b9453388c5c913698095ed06e05865d43e9a55a124a27d5655b7daacec6a669012dd2fad0aeabe068cd76be9b539e8a66dad633218cbf3cceccc504231de67878f8850d003ede2561246161e37d333372670944e4255a1b69c7ec823127bbdd345673ff7d29b209139381d7b3f5431f5a9bc4de7003f3be7fdaeae844e68cdd9774462c3c88120effd68d15afe120dd87b800b30885b253fcf89f52537a484350b4d16e533d7a7673c8dd6e8ce8b53d5401d549a75e48765c0f362f10ef898471d04d630134cdd0d26e81c2f137a8ea83cab39580ee944f0eb1f5bcbe8fc36b6fdee39cb7e44ab0e7572b803bff7413fed3a81d3ab563af0f9f4972b4796b42540388d5a5995f86e1cc1c4babcaedfe449d5f149cf70e0f31d2c2c4e003b32e990dcdf7dacb10f6e4728cef1371ee404539e90ba29ef426814fea03ccf7b6fe2694dfeaeb0a1bb7d78e18a4f8886ddc62a2df25bb06d2ccbb99cbd83854f213855dcf2eae509880935e4aafc1465f0b0bf65aff752dd81434c270b19ea6770fb71efcca8fde6be0592e7499aab834cf8252ba7bbf5fdda8bda79632cc3377c63082bb5ae12c05e2b0cf528f09a8333df8f44c8514d6c436b3405abfc30eb7d77cf60d096160cffbf50edd8d527844d6708dd4cbdfc44731e3636218c46e9fdd95f672aaa0f49f3825fe87e96d7093d4b3d6d08ac527869b77e62ce9cc47be33f5e7b7fd2d6fbedd1d4efabeb80e15f9c3eee4c1fc182190aff03897997aa492b538188bc5e21c1a80cfe2c8c65ca3b3bb7590685f178dcdaaf3be9cd7f31d4285c02135f286d6652cb7a88d96695d0ef459e7743e01e7c37af78e7319efba01180ad9c2679975d16368bc64d66b6489d2a3c65c0b12ed681481ad654b5da3d91571b4625c2eacd2085cdc3d9f19422be13a693109185cedc6e0c29f86519e3023a18b912af1b034609600000a553742d4abb673373718546c1bab2d125f14f7ecd10d978fea583a52c85388ca17ceba92618dcf71b95830737d6ce30e3493a0b733e4ee3f0df2ed1c464c0677f08dea2d4debf756aaa3121284117d7d9bbcf3d8f2207ecf75c1df16aec0cd196f0b6bb4a693dba2dcb42b5889d8c01add25b593be682acf5abd099da94378f10f308d6fc54b993f56b837c4b7b3fd73071c048253692adbc6f4a790281e63beae5ba91049e1027d5693a9857683be059b67b1586f02730e2d1bf5348765d53340543bf5048dd99701daa54875c4c890e45944939a9921346196efd3ad54778b63149876af7f87e5328d98c5e4c99e446bb044f8bef52e5b2bb38102df886f2f06c803757fe621432a04b5fd8976792689ce99689f4004a228fba0e5324a02e552bd1896d63f28d7bbc81644132807516ed813ca00c9fd2a8588113bb66be4c19484f478733f51728af25ca50124a72e0e7c03132e549350ebe850231b458720dfc6ecc6b9a20e540fb1bf6bb7dcbb2f123eb590cd094c2520d080f3d96942011b5846afcd90b8719d0807272607909d73fe58db13ec565f05b55d64ba00883a5b463f2949af6f8111c9e1e821aaacdb425209f42c7e04afe6be0494878fe3c5380ad6ba4bc1ef43a8e083f69c0069380149e36408663edc400e68af5bc639665c9a2b413e89dfd43c50dc92b42f5a0cdc260ea03c760d0c1d4d9c893d100026de78eb65c6049b0539c324c50256279bb51ce487df3db5440222e46a8b2baac51d1d81ba252fe09266739dac72504987c7bf2b70da5575b3aa822ab9f31dfec0a2246ca46349467d807716b74eca467199622b0c406b8e307695e693afb98d76f401bf03d7314c60b7044c9a303c8ef6c4d4c3b94b8cb11e57e9bbb54baadf852f2884db132d0f5f54058e64a57902bbfd8a305073d68b4cb2fc03b1aad3bd271b91d9fb370812ec08d328375a0fc94204dd7a75d19dfe3f81d80d2278912cd9a6a4b7ba0956322895f608dc45a239ceb84d238aa2b75d2f66aa439814c72dfddb07dbecbf41ac9819f0a6f4f2b51bf87a2a5670ef1b0726a02c7f72a2f334e6a45b88e6dc49c7dd82c586f82aed202890d509429a4fcb0eca49aec87d41bce7b92925369be9cf09b123a70788bfbe1449c9c73359b453b2241a1985c8566f284f2dc3fac801b9c81652b86111b4a6f9ac5d80fec2d00da8a064f5e8976387640028b9f95e2112edf416797bb36483f6ea74ce10c8098ffd5bd4641ce6dea12a4c294895de6bcaf7ab198d53afcca111921b1e3e97ad077fefb4b048c3383aa5648de27c8468620fe7bff45f248b2966cb2d49369e6c1e2880102a658fd472c640b6bf80aa4d4101332497d4bd399784fc10b19a4ef5b6ca6ed121b704c72eb022bc60bd8a7d403eebfa10adbf7d0701c99dabd6df9f05e224d8e04c0a9e48a0b93b4f17236579b8cd3448c21fbe836b1051a13d223810c9e541363c3df1c6ba744479120ae0d863149023724c5dfc0f71bb3741616361a42909d9ec9862be54e36b60af1897e7390b77f70c295dc0c4fb91c9b2424b59198313e091ec5b93f5eb29b7b7834db97d6f45ac400ccef6764db57ceacaf594e6a993e565e11e255f404bda02032cb76b056c523667c6cd5361e4545aed67c1c39c2dd3c6f38de20f3e12ba7c8060502e58f24a0d7e96bec762126714725332fea2c68b74d02af0ce8de26e8777fba1e27144017a045d744e9ba4af31059d38827b9e24bee3621cfddca9b6103eea3b90f38e6f97b66c400e1411e1238553f85ad65e858e0c5e9e9da5a8e3b678ccfafa85006f286410a87421d3881082f745d0a5b4f6eb0a55a8c8d1e58d8638ff5b6e1fbd419c4ecd34305019ee4415574e68820ab536d0441100a1636690e59376a59fb14201850eb8c3945d99889041fffe6709b01ceb3fe541c4df0ac4733287e976ec586ebe70dec2e43f4d50b178a42c64c98e497eb3e904ea992efebc38d1473edcd9beb9ff0e27e03dc2794bbf5930daa200ab818b048d6e54e0c62bbb72e38167af6a2f13c85bae9fb835cf4fd0dbcf4fcd342245e601076e80991a91090a806a0c98793a98493629c36f5fe545801ad1bcbfb2d7595827148404258e7ba44d23409fc2ed86dd50b7ea5c0621b78e7ef3c51b34a26825d1ada89166e653ef15240ec43739fa95a37121c96d01b705b7d27e4ad9b02f06433739e742f4f0671a3bcbd8f5fb167477c00d0df6b6d9b03052b0c8ba9d74733f15d8e429e1d61858ade2664a883a618c73eefa9dd9cf8f082acb4daacb4279458ccc22568f1edbc9a76a242eb9be815dcd45dd7a2c0f0417ed9a8821d6c94ef8eb5b4b84296c21ef20c3ed5fa7bdabeba089e5b91621779b9645474d10b95526e870d1e0c955695f9d478b61d3eb871bcd50b3f07611d05aed674307c1f74f654be65413576c0d6e5ad561a2329c8926f9f02320286859969cb34ccafa135b7cc2711efde3c2d80b1a2a6d7236e18caa07b197a44102e32a1357ea88102538a1229709891cc4b9ee2d5b00db6865992be639589bc1b683eb01f33dfe702b23fce8aca4efee3802a3dbf1f73bdea0359d12aa41cfd09f3fd12624c6687f8d42e42cc148e1f7e05ba41c7a2df13225076d0353483cd02379c83dea38c44117d7c38f013a98dc8cf05932a76cdf7ac945d7e55b1db5d90209a6dac1c131fef3b815448ec9ca91c44606334138f64d59119fb6e31a6492f64d23d31d1f65b5ba34d4802a72ccbec53a4e630f705668a8fd4ef7030645f618ecb4f69c5b400d600cdb049a035ce05ff70d0ad6a5e42c3f5cfc436cce1853ea5e91452cbe72e80034841feaf24ec75c357638e34cb6f9531ec0245435a0e5a04f4e0262010ff33fd84a56a5bbd65cfe1038f84e6b4c45b4f71d13c7aa304c3a9fc4baa6ee87b684982c1608bff45d0783f5f358ecb4b8460d74f3e68c7052d987b9f2e2e1868edc28bba25f5d9034f4711e708e7e8d3c7189be1898b7787501f4862e0cc2a6d5db42b42d454658f0bc92b4ccc9bac7429a4a08287d043c7dd4c04e1e168b34350c20c849c63f2a63bb282f9b810bda4c1783600f3833dd76840eb1a3999275a05dcf9e66d16b3dd6a79acde8e17c8620e14cec8c1ef7e4fe14df74fa313d3f5c09741a4ce4c61f5dbc279f6786afd28be310e8be9612b467d2f6f6da66a11c6d70003ab0d26620e2d4840e32022053065f2899c40e401adab9f254dbfb42a93271dda8a6413f922b3dec5c2c8b70df75d3cd06c9201b28b7223e34d8d44ec2fbf11834e9a1e4a5102b7deeb1630a61c70a71f1baa62f2e72e3cfb7a94354ae74e091138003b35eecb0bb8102291c670f25e8d0965b27fba2d5e75545680cf41979d0a762243d2a3c418c31082b07413abc0f0d99b3e3ec21acd92fcb99b63006df117f48cc724dc45af4cfb68f7cd11d276f0ca6def81821ca04ba739dacbd71b1b1f9abc93a9bc6082b19ddd6f2d117db03e979177bdcf714f83e84b2158677a0fcde307b9f715f79af386a5f4333f06df26d87af1bbb57a0d7ceee85068981635f5f388fa32815011ed3631b931702181b27e9d3f9133437eab032ff7e5d572a4d434e5b2e675abc4681e67266f91ace52a3106b4e982f9a4f194b0d9e773cf02a82d317da2c815127aff486e79c6a86801543a8c648e7bb0536115f23c737a135c0594ae439ad2653e6add919332e9b08898ae5a9a629d54cd9492d5ed6da7a7eee4443f30157c4e340591a0af1f72f2dbe51e54bbe80308cccde668f4283e0421745e0152f05a1d2772abfee540a692183b387422a8b64f7bc51c3d7f06e89f1034540d69d046581540a5ea3b56b49d0f1afb3011209872cb01b9a5137edf2dceb670338e921ff0fef0491212ec78cc5fd37920f8dc5176939278e5902809c5a60b46a9d8441de747f089058cbb09aa2d859ce0be0be0848c03a4827082bc6411ef3dcc1a9057f9336aac6e1651471d44aafeb297d97e58e56a0d50754b047f49b398b837b0ca9c12b3c2d6e5e1b323bcf757310eab23800021f91c201d3e94800a366cc62f5d871c4b1aa4fa94f4fe0bb95560ada2aeb32bb64de0a2d5282d2c2a61d083b6f9f32db168d3d5d2506437420546c67a1a9eaa481c2a1b80f788b956c62e065585625f5f6a9daf63ae7bb85f7fc25d919c32dc89ccd00a0e13710b8003fd0b414b7186d568ddb395e2d5eab268505154df51698dee2df9fbb5a22b4e9c11001bb39366960eef3521fd521a83b586eba8187d471724b130b885b6ee68d3559c9e5bd14d01f780f8b3c56041a8f7e794e9d8cd4b3ba270edc3dcb413a98121a1cd70dcf0c928bc2b719a6b085560581c0f630656eb99647a45a58ddf683267edade2fd305b263502d7c725288acc273d0aa07569fad69296ca503246f27143cedd0eaaa79f6870d575fe9efd4298db5cba6b0e1e215461958ef048ce948ad4255c58d9b6c028f0b703d6d1714ec4c4cb7b9b385db5a5703f71cf2ab4bbd357e37d60668be62c17b118dd2914fff9af1a867f71b11080f81139bd9d48fef82708e5d906e6d0e63283bc02a0663b57d18473502748718b564b39f06ed774b7e370ada276a45a42974d270c1c0b8bb80f011e90db9f1ce3b557c7ae5d71beb769f367b2b50a24118bb970f6f9f979741211779773755187119902700ccedda8a620ca376959278305cd22c85635ea27509250a31011fa167d695c0ae99e8126e226fb311c411d5ceac94dd15eebb975cbf6644e17dda2f6f4c409cddaf395bb68a68fd602d396f7217c84752e326be8aaea1905b4ba38e40e56c189e4c8435ed1da37f55dc07a8f1151c7cb06ca536906d301aa0e508a0196426a20b0171b8a3c2fd80ba743eb3124aa2ac8544ddf2208d72421683a28d901d0a1d1f0aa0cd485d1b8755dbb7cb26ccc1e55eebdccdd8f11ef4264163b86f0b00da6d2f47c6e6e096e926dde4086437c3bd1ec039763b62100d975559d623582c79b6d02f2b6fe8eb9b20c794c8324c039231527bdda5011dbd8fbc997581ebc603f4631f015890c38bf2e21fc35a93db98dd43869fc5beb2340a7feb3b9bdd94b7d67c97d5061fca09f065cecbf12837d077bec28f220e5d4ff32a6f4cef7faa4e035123992404418e5a215290bc2b4effbf367d5489d9e7ed0f95c7b0cc80348f202a1a531c898ccbfed7c27ed046a2c87d9dff266a59014ffdc8f0b15d7a38e2f6110e0eb1b6447c801faeffc0f9f0daf0095d0cb474094851ea11fb04f65ff1af79a865108c6eb803dc60ee81501669e43b300e8dc7467e7ec42c81dea383160400eb2b5c33972ec9b510b51f3d13d526dcb120dff775cd3902e4c16d32154fb71706a74ceddb7cbbd9c09b490745dc59b26b6ec90424b2b43473d2b6433701bcad021ae049605a309a19a703cc07e256dcfda22e4770fdc243dc96c8e2ecafe8e8d79d234fa0bf434d8e88439d4d5f2b9d009d1b6dab00b7222dc7e48819fda1d47103f42e3f13f026c316869a94e01f4b7e814fb46477db5bee2df796522629039205b305d205f333b0f14c79cfe8f7ddf7cd1b17a70e627ab71bbd94228922bbce202aa270d428632e476599919d7d06e47b49b34fcb0f5801a15d3682347b21280e4907e128fa59f67ad121228f91428a0d38d9dbffbedb9d77de797fcecf7ad03b868edae656a9377ddcff71d415ba9789fbe334b2ddfb1e848bf7bebdf725bd39bf376d7b2ce5a893423deefbb8af6949f0931c47fedffb97e2602dbd66defb62df973357a726ab8a49a77fd3cb21e79c3faf8b73fcad8d42ec00fcf9d98fed992ec8e6cce675d1d6fbdb3bace5eebe5cc0b6f769966b97b73582e50c16f100c401a22285fef233db775bf653523b646bee3ea59c53ca6b7f661a54eb3a172b10ee87e47699adf485ada8de5052f8f233e28be9e5907be2ec7382f6b1bba761eaf56cef759f7da7b3bf187b1d9e9cf61c4c1bed6fd67d2c00fde76b05207d5995907d2b00c7996de78b3a8699b4dac118d01fc35affaf8bd3eb0dad82fb8db3f86381b7b3e3f6588f82408e7bb9396edcf48c6d725ffbfbd9a0377491e422bda0cb51fb4d6fdadfeb57d3fe5760bb6bf5af05a07b767998bb7391deda555abdfbf76edb6b3f64db2cf270e7a3db188a7d9f06e5b28bdac70230f47a84203431c5defefe563f148063bddddcb91ab73d2e8d5ae0e6db6f579b3309f2a50a76df3f646779fc9d0991fdacfed6ee3a75b0f2dd4fb1fd798e6cd36adb9758cba4c70ef3a7f3535ebbfb9ca0c703ef4e6bf3bbe701920e937b3ecf1147755ab76daf92fd3f9836fd83691a363fd8b6da7c8ee33a158e83f1b0b8fb1c8f137367e53b1e75a4798eeceebb5fc1f5efeceeec348f13a61a7aa2aeebdeb5cd3d1b2b3fbd150ff518b2e8d7a6fdcaf863e9779e8dee531aeeb495524cebfcd39ee6a6b875ce39bbaed394ec71fbca691a0fd0dce9de79587bdc341a5e3d1e578f23cf91bdfd76354d8f3c47f6f6f7b5eeb54d9bcfbdf6da762f086adafc6dce39bf729bee320f90c35680284ee9456becdf15a094a7e12b1c936dbff4a238a510044baf6d9f44f227a4c74f2201ad046dfba518c50155b4c67e189662a5d8b6cfe3c4974641fec4a94fffe68f4095f5f9a0e67182ced75eb5addda26c8b789c983bda9c53fbb047f637fab0473eff495fb32889ba9d44753f355cb78ffe64e3ec2bee5ca83e7e1e27e60ecc51f731c64f419e23397c7971f1da11c8e59b3b29823c47b6d67579e37eecde348f13d346abd2b4caab1a657e5db25d177befd17777777f3dfa7821ab7620f0cb255e14cc7d899b7f43439792e9a544bdbc6f528fe1ae8f7195200882ce42e968347a075944f5077387e5bd458e303c447af40d3e8cae4bb6bfe81f4349eb50b3887e445da453a3075fbeffc8b549f4f3b99f2bd30b4c8ccc7feefe5382dc147936e453cfe331bf97d1638b180da3c7f0459b74691464fa5152c1bdf72b593af8b996b9498f928afa038e8b32128d4620750c48595f40786522472d9cd7259b7b31bbdce894e4fbcb147d96972f97f01a837465a14afadccb4a65f6918885d3d555ca29ef42fa96ccf2659b5761b66515d740dcd09bd1cdae2f256a6cb1c79b9497144788160f0361558ee4684ec9f2a217a2c57f18ca17bdd8f3471f2ff6e85558f42808fcf9a11e157dcafcd448ce9735f4eb0df2a64f278bea5145f429de0361bd1e0ffc460b6cf007df8b5e6cf9a3a4a2480e740afcefe97f3f74832f029f7a386cdddff7d5714095a40f44fdc1dc999f00ede957b02e719fefd267c876cf5ac29074a37af4f162832f1289e69cf3b9d1cc63153df889f07bb9d3d5c52bb91ee9b6529d651f645e71e54c7d99a72760edeb77ef7d1b725f6ddab679373d62bbf46495f987ee4cd71f4c9b5ab510c65a4a9491234824c9677cd69ac4b7c457e45b7d1ef83ef07de0f3c0c78474207c20f8561f085e9f12577c4a5cc1e45382c9a704139f79515f6c1bbd75bb895e71ffd4213b8f406cfbf35fb4d83f756fb6ee4dea1451b7a98aa6fa828e3730d8018f1fa7a8d40df4a84ad414d412c8a1aaaa1aa8aad3a9aa4e5575fa31dc2c58fce969685ea52252e47efa471bfbeffb5c7fe5aa88d8189d79a771faefebe394939e4b80238dd1641a25bba891e1c70d65bd20c52a83b6609035f5ab0601900bad448dbe62d71a9b365d9030ea8f3686ff5e1bbfb9245e40e4cbf974eafbfc293a44a3a874d246a9a7a769f9d199a83070446cc6ee93eea1123a7ddd4aefe2b0d0c2c293b6310b3399fe5a988dc9bcce39f9350f0c8c8dd92147c97c7d6b85ab788a8ffc4526572245a8876dacaa6c4c3251d9300c556b63368a1dd240181b73c92369acaa5d3f1462c963b792c7b03e290fa1e57c37e8d54d341ae769c2fd3a02eba675307a6b076a58ca99ea5febed6a360d69ed7cd73ccb418098b20f5da4efda94d17091561db87f62db36079a8e24732452c79fbeb3207b22c897d55ab31d3dfc405f44a7c8ab681cb26f1401a58b3a38ea858bf56f3893d0c3ed1e094093a6c54cea46405b970978be283ead4f5f0a70bea4d9d61a7a2f088275fab894d2bbaf8b72eb269da9ee750a4c29a594ce37d9d0a61f09633e1144489db9271240b5d6eaee8d76006e7fdff504b2b1fd3cb2a3fee70267fdb9ea01c45126e9e4e78859c4ab6ad79a512b80638e1320acb5d5ff66944d7e905478444818f3b32bb0d77ae387888af3bdbcd9527cc2a23f502231f068f55a7588a9e769928b2f198645716ed01afa1704c37fd14ed6a6599665598db948b5101257e24fe04b6977e34614ffc310a47abcd3a7b7dcc9f67a32fdf500ac6fb1d665d9e3bcbd6603a87dd5ba9b9d7de7e9587981125eb0339daaaf693b5cecb4cbf2f833774a4c51bf2e729df4344dd3a63ff1335d898bf48aed554818f43323607dbb75d2ab557af6f6c6dc26ed539bc6f1fea4c73302ce212457fb1317298e0be5dcdc88e23f12243e0e130148ca5eb369ea6ebb0d698549c8891471203ab4a91bd9b4e629348f5ccf0aa0909c4e7ec282a6ea5e10a4d42f4829152f9427b289c3fc67eeb86a4b97e4b9e159af42d6d0b7c2a65cf0306cfa52fb9df465a52c1816785680f5a926ef7ccff344f6b50972ddb6e10b8731febeefd326f053df6b0f7eaffda73551f6f2f8b3bd07bfeea5e73d0d1fb2bdeca3db9de69e06a5e198d339734dd3b26aa4ee2560397384a36a18ca305cc2d9fcd4fef6f6b76a5fdb5edb326e07ed8a2baeb0c2c341c3e7f6d2e3b48eeb4952e46be0b73909f6b79e8fffe67fa7a52fec6a4205b7717780f9becc72cf29a9a42df8e69c5f0bc0f984e80b54d49a793df5b76ba975d916c59950e8f5df3c1b764f216d0a59d676e912dbb22c4af1a5dfa235501cc742b169dba25350262efa832d6a5b74896d653fd225416e71b06bcb5150c8fdb5e622e6be9da66fd5565a12f03703709338ddbdb404d8e55966a7cf2560397329a51aa5da270370fc9f719cf02ba992f4add509fcb3042829963ea64ebb8fa52e62bea5da679aa49432731f0ce1b5b9ef3c1b3fd77b4feb103b2afae037795e0e3277983cea6b936a1dd94b1a54fb6aba5af622d3295bbdc91339334e896787c32be50e478df786a37af82108fcf8c9c6186350ca4964684b285b4a4184898da777f5acb69b325c9c6ea5bd5ff795f8f14b6d44926203437be4d9f831b831ea7570943ffe1b4f6948717749a0a42fd83b0f09a0f6f73dbc736e7f03ff0eac3d7e929cc11916b2c71508c561e95e529c95c72c79259332b55f453130e53dfb76eada7b9eaf651bfe7307121207ccbc899db9097626c1ec41ad697ae38f29b6d6e77d5291994db3b7b7be265f145177ca07f9768a069f8a3e4517e19ff2d7b20a65ae44d7565fe25178b02fc5552a7a04b54a943b29d222f4ba0d9fd90e8a7eea223a9ac715caf53835bef709701467142e667f4371a6cb6bb2ff7006cd209afde702f0e6b31f67100ee9b38c8923e38d23719483365c027a14d98f32b28c947ba035d97b8e14e9cb262da025ac29349781b7ed830128851247762685124676ddd9bb2a7326a873e07e963da53a08396da52e03b4d6a0066dd1d736740570fea8a9b8965bf1a256fb9a54d1ae5c4fedab7a25c26893d39d65ad943a60c6caa0687554ea549c8d48d6a2acac4559598bb2b216655156d6a2ac4d95b57c6e2deb047f39aa88d4a93fdf9b380e488547d9d38aa92dd52c0c885e212840545e4a82cc02711990d700b958040e48cbb213d0160da250d04c658decf145b4278e26696b6b62b757b7ddbabda883996b5bb9b677af4c05aded4fe2017d2b65adb58a3b24c9cca9080bdb61deb6428e022d14c7b151bcc63f0a116b051344b6cc8c30b1e511235b5239b59d7e81b68d356955b1b1b6d72aa59492f200f4fbf262e7f692026548bcc6bfb2860066dac784e5931e719145815c542283b09f5d47594ebbd56587bbc5d6ae665d052fc591356a266d958d6f5773cac65b57f36863aeab19dc1b7ba28dbdae666f771b7f5dcd7863b0ab99db38a5bb59d6a879db776395ae666d63525773b6edc62c5d4b5733dd3834b5b0ac90545246e027f23a19964aa2aa4109c37fce5801f8d9d538ac69100576d751a6eb28992db7eb43ac674fbe2a2aca6660b535a7f509519b840dbe2bf80e9e3cb18215be21c45aba6f0b5ab05247ee2c40819b4eabcdb4bb71b8f3441f384a5121adb0b4842e25538ccc773096aab662605e4c2597cf3074c5b22f58d8c2b24252c9fac55d2cba52491981fa649aab2cf689bcee34539a2bcd15ebb4191a97f99a5bd1b008f785edad0563d95bab095bab65b3e0162cb525756238d50a0d54b4cbbaaf53b5286ce572815eb3cb99bc6fa4b292c3d24b0c8b7ca27121ba806173d3c5e86466742a67b9126f05c55c2e97cb455b2a7fa9542a95ca9dc084624331302fa652abd56ab55c54210b9491d81d527911d1815c4c5e4e602e97cbe572ad56abd56a45612d67b55aad56cb95b43cc85dce248cc562b1588bcbe572b95856abd56ab5426ab55aad96ca0b1c11b82693f972021372b956abd56ab5a2b0186cc8555ec4572a292e97cbe51aad56abd50aa4300aa3301a72423057170864854abe2584cbe572b95c2bd76ab55aad2693971398d02772b95c2e97b75aad56abd5f6ef66d8d08410526868aa6a2c168badaa4b7c573881266b2a99ad19d46197cbe57271393aab9b9bc372b198b0e48b55634288e27f185e213016be4a73aec6b4ccd618adb15a633a1d75813b20d8a320d05fdbdfb26e44073dc7e58b52f9bae0d563a8e931ccf4f87a14f7665f5800e78ff6b5fdf1ce07ee05c130a438a3e8830590c7035b3ebea1f397a33611a51dfe4c950308b84a39a59c330918bb6b9aa67de6f5689a96f7befbcb7ddffd7ad501fdbbd94d534a377aab0fb4d7aeb1ef823666553414c1bf9c9ea8f047a7f931d37ee44e3f8a4c3fa6a0b81f59b67c39716a7e2c61dc83e2c8f0b5e65b5c7c09bfcbcb80df05fe1a5cbb30cf3c975d1edb8a8444857a46d3684d9f386dd24462e0f21cf81a27ae9359763bca712a1512b2d2fc5893d07eac4b9c7eac1e30fd589b70f9b18e6057138495db43408e7beefbfe7ef3bfec5f4212d8dd19fcf75617bfc759265f68a7d3e94dcf23fc13f7df873f85ada5b1fae17f8f35cdf3b2cee299d74212d8891dfe30bedf07f9f6a74d8f7f7a3cc2ffa4e7c3e14c639c1e3ffd9c86bb2e89ceebc19ecf1cc2618c394c84e3f28d8b1c7e539612ff294b298a23cfc64f935d1b3f0e738e14f1cf68b2f1638efb3ecc392ee297e122be177fadb556263acc61fc9bd7c3619de362fdbeee4f8f19d8e3dc33df0909fc95a68586e6bf9e93be71f1d339b9762fa550e289fab54aa197a3c6174ddc89a346db83a6a482396ae62bc9c5ed6972929a07f3cfdca1dee16295bbc76dd1e3056b3457c33ca5f83d4dae52c4afe5db4911bf2983922445fc35399435f831c675cafaf57c40d911476d481cd58956bb3e911cfef0c53038763be92e9de04fe6a7d713f337e6cee9ebe7903adcd7d7215134352417a44b223dcde9baa8f93e7bffd4e27fb3f8df429bfbdff8034551146d8b162fb2a0a1f9ef4f234973398ea31e8f7feefb3e9f661e6b481c45f3f535258e53f3f52d7eee699453a6432dafa9cf227b50142efb9df2dc1f7bb4b1ed5f438c1972860c193031307428668d481ded5dd39605131343064aa266cc98539b1a0b981819cd124611850e742075b256f6440685d4a14b5c5486e7e36dd8ec028ec4a122130e6ac41e6d0ce5f5cca959e1a26faa6dcc45d7b28dd92876c85ae1a82866d00c729fe1f978dbb2604c6cdb8202a5ad12d6e68ff27cb60da36d1014c00eec3ba1c099ad1cb46a96984772bc09348190b0584f4c25337445562b193a4dc745a7254f1d6fc2e8645c3219bff3838b3d24010208adf1dff17aec783ae8a6d13b32313132313676f3cc6b796805f34d018ed91363164516858de22897f7b7313be49277dca03c37dce0f564313132b8864ed3a145e720cc3231370040c629cbadf3bbc8c4c0bc985842db324ba86c599206ff69f3362309486b5ca435f6c67c6cb655f2841c5ae30f00efc6451938cc0869b47c4740b9648bc445ffeca6e55972117787da2a71d17f7b9675047006182f647051935f06877e76b394dcf822f23accbd50278ea2c2515a134ef60d5b4ab1c2c1b65185d0b651056c63afd2c902420a2c67461a95b3a4e643fee721cb3c8f7c3f003f40820ce123e5430078e0f16301291f02c0030f4cbbcf3efcb458eb5eb2917d61e9b47c33e445eb1c813f6509fc0c19027f931ff036b9014f4376c0ef64068c8fca13f81ff9022f23f7f8185988d48f148d4ef2030236367b9c408f0b4820972200815c7a402e3920971a904b0cc8269510d944646606ce0ccde9477625499ce52c0ff296cbe9a21a6a085b4e9e0fedb43cc30d0d363b31668480d3c232e3f99c1690733e654d8af475c652a47f9355a4489f86dc2245fa36d92445fa3b5946c2a09f14a9d6b180bcb3a799e964d82d6c962c2b2d685ce49c59d46cad750b719f4e27b19b917b1e27e7002413f13f3ef2113f4436e2b5dc2236839ae9c961a6c6b6cb8f2b432a5a5384d6ac80663c1f4d28671c46fc8c5ce3513907216f23bf3c4da66f4386799d9cf5bc8f5cc40f9189782db3f89e9789b1274d8303f67d4a5620c78d462008822098226482a2d24303079a1c4a4230f4c5f3c1548027cf87653741cba7196c6c6c3a99ccc3dfccc3e69cc75ad65be769c51cf25cb513c36d98b8a1a18619dcc8aa8618316a48f948a57e50018c11c39b31173df6a528520063cc88828c4ee703fc2923e067c806f81b023c0db900bf930720809fc90a78544ec0ffc816781939888f917f308002b24c2b01598615840510700003005100020c209b543f6413119c1902c0c9a133e849a366e8b40c8363d369f92547cba54d434e22e46df464428508791bbc24d3456bfc85e4e9e4358526cc4598cbb649527a062599add9ca8fb96e0572dc686463b347eda5bdb457b85bb0d889c123e3062f68e7471672e3836423de46ce81e37572467d642254e80b06928f7823f2acf1936792b9dafe47e4a904df20a78b02f0d90723b2acd1e2575f84d6bc642921b4058f90542ae5638820407e7264622c49d35b080d1cb21c3c9f984db54c8b0a3b36d80080d10e3b74e4c07143871a6faf6603d5d1c1a1cbb9071d3b1e27ef9003c70d1d6abcfddbc30e3b74e4c07143871a40e07e7b8d28820821299d1a356ad448e90c8941080b9ff96813a5f485a7c3bef632783d9afe8c90fa51c3f3b17b065d12aa020fcfee72dee1473e224826e2816421ff93533c5e26f320f33eb2113f442ee2b52cda326f5f1e08c78f36e2872fed35fe0bc97612735fdb61878e1c1c2786d1d0087c1c7ab411c5ff3004c1074ad9d974443641f11a97c925211c0070034f4f0e5733a2082284a47874d041871c745e32dad319381af5314410203f3a7c55c821954af5b4a800f2a0b20ceb4502c14a91952329e048241289446289456939e5921094284326223e33b6ce18384295f364c29b456ee01c740ec21f20040eafc78f5c82e2a91f3f3e870c5d126281325cf4bff9916924c9a135393de4f06ee4f074d0edf33e302f3e43367d2d8fbeb3cfe1f9d07f79ece373e3471602f36253a9d447049927a92ce384d6f8d710c3d0a6f12978202c08d96cee71d0a30df7af4751468f1fa3c7f09e62db350d002137f04898172924754a504a319b1d3b7e86ef9351f2a314a534142397ac90a81a6e6cbc1e8dd21d3a7e640a5420f5e37d0c110448052a90f2f1c3470528904b503c9f983da365808440934b421286bf0c74fec833783ab2d71e86d7a369179e0f75e123bbf0c01d3c1f9b5d8a4d2195455ae3bf83f7dfd369d979f0e978dce8ec2997a0e85c8af5907549e8334249c807182f78f0d03c5a585678905478f0c872cbc464b92dcd1ee65f7c320dbee86b5299a2c834514529f60489254c8084295e4da63b0d3864023e5510038e521a9989a8442d7865b9648846040000284315002028100a0704a3a14894c4b030cf1e14800c83925464541ec8c22887611046410819640c00001000040c0c8ccc4c6d1000908d82ead7855cc99d30943253ab432f2362077e83dceb5186f532895ab1f6054da2e4c1481d282159699cb191d6d43cbc668bcbb0069a3911739416e40938a48f460a546c344776073096d10ecb8491d8d19dce8bcbf0d27a9d3433095dd16c15900ae30b0d55960990c4a0ec76e4c71dafa4fac047df5169e154506e2f28d80bb45307684e357db03d0dbdc12c48d6a0984270325688a2bd5773cf1d9b429e2d7b57c29c60254cc238e9d5d310dd3d23d1118cb87bdc21c3ebe15e2d35eb57dc120dd404e391f90c839b5c31ca5ef28d758ca3d0a9ebad27eb471c438a1cb1605bdc2731a71e07559314ba7cc1b673339bd9ef53de8139a5343c003bd1d06248ca7ea0c4fa425d50721919b2d2d0f617c05153ea0a2b6d932ddd982dae09499a4c38eb9a0bb3861c2a9257d31570d3cd8a21bc158fbb820a7fb52f431ac869e5ffce443a029b8eb427a60b987059281fd7c12117d2a1dd7b54669da28b88444da332824713c948c8e9caebabafa95f9a45233302bacbf378e1b77c41d7209b383d614a2e3d12b0c716c34ac092bfa43599dbc6db09476ad075d45863d80c55ad6b2078a040621d57a4686af30ed613faaaa862d4425fde5912bb6955172dd76fd645cf8334fa9c3f32236c8b9ef1d04e719d819f39330e00c70125915530e10dc2e460350d3ab1e44f00c298e1dd87a10c25a02d279d3c456ac6718e6c71d90453b140e0282851935181d58601c9bd3b2b830e62ae89924b86ea0cdc1b1d0f0470d11dc5a1e5dc4e67ca814f686c1345d50548fc1b7afc0994f59f9317ed0922e5d1468a2dcadab9c1e84d331b46dc25fc48611d5189749334c814fa4099e189effc9a7f2eec1a9bf646353819000ddcefe50cb5c4540d72bfe81084863c57cf6ca5103ac2f3afe6a974f9cacca99c9c8e497bb4fe2a67c07756901ec8b1db91199a95e8f3115423056a676995dd5e1ad2dc4c5461c64c22cd03521f3389a9aa260fd333c3e3db2a87c18f1f31aafc00ee55597d0c61762d25c4802db02a5d8df244abcc3a21965c5856b8185d5ec278c36ccf0d69f35c7c912971e2a929aab04569dfaa70125005d692689519fd9ae424abf2f2d87363bb85209e30602904f80832baf97c26b11cb13391f5a6ad14cd70a185cd66ae400338ed2841b03a6c2fb9a4c16aceb74e68fb7cd595e526addba76b2cc93b15bb7519776c7a09e590768bdd090bcbfde1fcb0cbca7005da3cf99c7eed6b9c6817212393a457a1eacb61510fd9bb5e62c66c704f3e90cecfbe4526d3e2c856e9e17496232df0f03083d2ccc1aaa74f6f1432361c09c546ecffe1e79cc4309e04eb930d98db4046d620ade22949966375e3462b104cb80f1160a7c32fbd0094c5e543223f01fc0b09c574bbdc903e86b10c570c0e80f36af60f0a509224bb6288ac5b4753d6f4959723b9b5a173648d78cd8a82da230aed492c5011c587f0ed977a20dfc1a440b70bfdfce5628283124abff77202fa2efaf027899d0e28050e6e2b97902c92d1ab615024bf6ba5fc2512ab9692a5a3c4ac0d626226dcec1c53752d08e085a913c1033174cc13738ec7150b2c1b7e029aaf629e98877e0eafa087597c996ee374a0cdd97403a4a907ba120f7d77732ac587f4aac139ef4f1522915d31ba08e6813a6b60de1efe01f460987c670333b1779ad8ed35ae8790a112af27c08158b14b46ac101d65040d1d2635471f4d6c19c53d91ea44fed034c14128489f372a4002ddee6666b87de92c1b40d001a9bb0ce9a2d24f586e9987febe4c1641ad4f220d9e93664570a2e561e365a8bf596288bb0428b19737528f7919ea40c0a8ddd5da16abc8db0e672f43dd46b48e6a752bc2e7a0ba10513abfeacb7041aa358e42c0af4ad9f0dd18834b04dd64fc328ca20a1ea7ca0bd90c4762feeee46fc463205eadf7512760b948bf0945adf9645e136b98f492e13b146365ea075e9cc00c9d04475d61fc54654655f41e98e1220337c7a207c6dbcddfb949664a8188bdac72caff0ffa0477e2716cd3788cf941e6f9880cf3912cf19b4cbe4ea68cb2c83c20e700ecb6547a7294ed2e003090b4d8eaac327bf41aa9725611102362de3f57046ea2b319cce5955e2fcb31a8b7f42dadd82370d28503fc03e23953d25b5ac92ea8ce37aab23f151b7d12bf2529768e1d2a8f31ecfd0099fcfeb4837a67a4e2ffdb417e07f156e1500f982f20427fec5cc06e35c626136b6c8c53ab9f7be576541150815343de18f09a143a9b28bd35f0a2355e94a99dbd30c37bf7398f958d1766a8858ec0cce3b94a84fcb02acc10cf5f043f7b7a173a8e001d9bdf4c6646dd6bae8109db861ccdb08694e1159b7f8619d20772a0dec055cdb60b2c893a8cfb1ee57bd2a5e13a42a67ad07f7ec01f638697ff1b04dff2bc9c41e0f67109789c15f6318433295c6062f79ec60c93445543876ccc50784f164e651b2a1e1bce166ae567b40c20a156e8102b09010d1cc9b8de92cc2ea29cbd0074b70eb28b9c4db0588c7e49f6144ad96fcd585d26224573974ed3698b08e1c83a5633b85c2471b01ec46c939cc24582a88c95b2e44cc627602053321f28fa40f62d596bcb4604c52e774b85ba5f86521cac476556e7cfc68c588988ceda8a3e18cea66797191e3858a2e50e99d1676e10be0552cd550ef49c7325400fb3371393bbd6aa5c6b70a1bf7b4371ac22f954f6633201dfb095192e1f1bbe4cdd0f873e3b7bb66583a0c5c8178ed5bfae919519f6bdee0e4f76fb87a91d3a5012a8cad14dec7f199e8897dfa79989da0663c953c93761c60daa57e327cdbe17455172e69e4f7b78a0520e7e17aae37157b7530a3be9232b6cb132c345f2ad8ae52c470e9f5e955558da445751d058832d0864864e7304098d7c61b4e4cd434697252fb66c6bc893f039142f84b61acc5f3ab038640941444832d8cd81061c7a40220a5a086a63f260699a19f6f72e74ea41fdaa3c697e74d270a68305caa68d1ae67d17dced85160ffc858a558d3e206cee30443e33d41962200c6cd3af8593faf05dd48cc1467e954facc7da7f6678779e1ebb875c41404a6b84271eeffa3fea13e0526803e7ccede0591987976c5285c8c648b90ca095babcc9e414b4cab8445460ea36f3192b5621a1d00cf5ee3c33bdc2082e785f4d105e06bc4a2f9a61659cfc187f877c267259a3f4c3f22e5f10d4caff6c28cdd065f69e5d9a61170b44949861d68a818f8db0bfa08ec2f8e40858889171a9a609451a494bfe9afd9aa59cb9c821514c2003e0e2a16a92a43e547bdcc820495615cfdc34b837949ae19dc6c790150a288916edc310faa03524bad73095ccd1fa823459ccc7f7590393ead3222108658146eb8d6446090d81c74c280d480895a49c2c9776e82cb4858a77ffa7e2e29a2199bd5b687b7556bbec36997448a2aa6253e641facf37867becb786417ade7bb40550ef9aa3b3b60a6338e330b8c5282d4e6022b91ea86a96e84f017fe961f093b0e04a50b4a11f42707344b9416b86ce4a6e23ac88a978bd97f84e0320dc3448751eefa8a92c6afc42c235430764433c85a5b32e59a062a286b47f47ffdc3aed2d9191adb1c5e0b7a4a6675d289e342d3323319314c71863d027c632d668d4f8894c515f3f2623d19c78822e344d5f4982d25b8c708e979d6a41ac16ddd4ef6d0463faaf7b0c8f8095d4ce93905ce487f984020b3226f2113e55dbbee8bb3db52d53cdbee002169a6103b55643f4276da0b0477cd8c0e504884459b5d632ee997310ba32d3ed7ee2fdad57deb88d091572f43c098699dfce6905bc806ea6c22ab3f387d397682cd3c521fe9cfd878511b3b8b16c626aff0b2a8c474f7b9905583842e1f192ee4157286fc62d99e163c1921874c9c6bf156d2e65a64bab8d93ffa101c4da3296fcb5eac5ced67461e9d11ab45d4375a517b75fefdba267962b1a1f1cd8d251f13c865e5d719c1691dc18e556e5214e0652302ff08444cae442f5548f9f79cb6c1a352af4c8ca86e57f4e0651274d084c2d5c9d5a25edbe6628821a9b447def20ca706ff3981208925a5421b78f2de5328873eb4c240364cd7a8aa221c6a404bee854442138f158598c0ab5720e9b984da141177a1fdbc61a19aa2476b3062a38f276664dcb54e4faf4b2c67e60d84b2cf02792ee4b764ce4f9105fc698467ccbe34898b5b857cbafaf6682b96149663a3a9d4295cc0a822dd43875a5871344006285bb396c99f7e6e1f572de44af77d1a362d2c49aee5e7be30ecc8d3fc3617c08350a13ce53f189847dfe379c86b48e25c88ab3d6de48c8cdf6ad020da2559eb3284b0ab17666241ac82cee4d0b3a4bbd3a8e72556aa015a28e692500e8ef03338cb2364c7102c68b2448d10890a6f528a2f58df20701df93d13f7202f00325c42593449501556fe64c9aa8908300ed6ae8af27f5c21e29891f90a0625abd37a74b810de36fd1ab38a085cfd3ba2464e417234894cde72223b39cc1c71b1565d691caf1d615b07bf64e04e140b3585e3e93d58be546c094af68381e1421565b266d012f245a6c328f3a283e81471c03e3cd8be726e249a924b326e739e5df9fb957e24f0f024fecbf99131f95a45fee00b9a6c07f2f7114404f47b4c6bf0b7c2239800bc57c0f3066b9b722d58222745118663749ea81902a2144258cf530147eea0f0940f25a3cbf4a950dabbea7eebaf825dc21a3b2475078888229ce20877edb91b1ba3749a56db84d4e7efabc5f3fbcc59d9f5d482f38371ebcea9247d8b26dc29b261ab31d4a91a0dc07e06cbc8d27a8c3f165110d5f8f61c0a22342c7cb6a77b2f2ec03dde3abce7037798512dc476c5c71fa3738658adff54d9b5b5c39ee4cd255daaf7a27b293402d1e05c1089c8c59a2e768725b9f133a919a8aa5cc81cc5a44d2024b001e8e84a48e3647688b2821a8b9ebad703898dda74e6ae58d3f5ded3bb2b10fd532796e05d13683507b6120c67d205658eb1d0864d08c5090884cba93e019054af05a7f1ad2d61f1879b55c21b9f34ad4dd712c7c8e6d291ab602f9a59240b25e44a4b2936204e41b37e530bf904bffa9e157c5fa072fb112eaec06b363389d5ba82b73e33e7bed3ea67c6abf583a81166259d20d685f40fc5b396c4ed7d7e9b7a1fe0f6f23cbcd1cc162fdca936f38596439950312ede3d0e63794d915d99649e0e35f606747cb16645b17195bbaf666f05dc6ed8716e9a9528aedaa05e1e4f40fd73c36cf1e965eb67816f02964efba060914990ebda8fe324c04ba27bbce5c62c2af37da3dbc2933c41693d7aefb8c6337c63152907faa9b3798b177a5158181dd30d375a65d076de875fcb6d69e69fb3dbc943e5c94ea9888f4becd75e692f00812fa11bc98a93ab6192628152aa447d53d871b10f6e2b462af50307788fb2ef5bcf2f623f38f122f9cf8cd1dc085c334473c472f192d85b588377badb0ecf87f67c195235e7c7b7e671b8811efbaf4df2c4e27628978ec727de520660a8233ba390b3220dee0e02dca610883937925008db0b3f644c384ff7580985de7101a8041831b758e596d936a7d907d15ea12b1692def60899df88847c4c596d858d6e1ec6439ce29e4c783cdd70909854104be920974a02ef09c072e84bf1ddc517a9c4917cd1c795d721f63ddac3938c46f62c110eb35943f1b49ece866dbb5db42411b3590285131183f25be81920c7c67dc4d01058e81bdfb6e1c61d56020083c7aa899c9f03bdb69f2ebd95311af7a2883746962ee8fbf29fc7d754d9a7f92a1ecfd1dfafe44bc405f95dc7f1265e82d55c0c9b82db1ed2334c890f7313a9a736866f2d8ccc87435ed914180bc25643fca9710b126ddbf1a24608c19c3541412b65dc427bcb59073b071f07785946225b654bc0a67a1b616fcbe51635a6d339a81fc96e6f45773c57fbb0ece2f6a7ac069f4dd05a49922ae0123b7d66472584099b1d8042eabe8678898c2693d4a161113f95ba0c9b6e193f283bda0fa2fd2b6641baa2d7ef09512138189bb625de107094492b4bdbeec97664f2a44449902676621abcc12439622c62874ca00ddf2bd85ecc602e4a204f7e4a937eccf905a1165a25052c65d17524e7e23ea8042a710d61dbfbb4a9900d45d80c95df7431c2ffec61ee7d1fbd5bbc8c96ab6c0e78dba8a351469af7411278d7d9d98836d8b3dc535257d7727a39910ae19bfc435e47d31b389d7c269e10994ba92e00a6528840d4cb2859b3439678df756b30f0a16c0ae3dd70f1b6cb13e9ffc81efabcfc1ad9c0f7ef8e2f47f330172c9319723066c7a78f3de3936e8714f9beed5197a87ba149d5e0dda4906b783c5882973665a75707acd28b6f7de272d262eab4974301e964c74329ad801bf4b1bfc9efb4ec304d69a0b0363f522b86ef0b929202791b7413bcedc2e33e0f7ee312d9359e27157afeb776c08af2d706e3fbed335a155c7424daae87e3c7594eef21d0918bbceb51fe7a840d7e9783c161db72ee93faae09f4bce1c8de844eb59849302b5a87d80151e5bcfef3d411a384c9a24fb5e29cc485ace6804ddc119450c7c915199df2fed26b0a8f61461947997d199488d815fbe34407d38c1c056e00fbc2ce33c0e8ec3c27dee2365546168cf78e041e6b8c8f83f6011f0a53bdb51e425ef42c3327b35ef8063dc9823d1af845da094adf1cf07be1c0fc48cb87aade198ada363203603d279943fbebb951c1e2fd6429689dee630238c86cc7432ae04a81f39f206c232b5671a4d6131a7e5fd6600934d4718f1260e525db246006d9f84891c9fa43e864a5c7fe724334126fdcf850a28ef4ca9cb04dd73df55563ab72d5955fb951b319b7f7a549ae04fed79aa8d0650172ddde837fef5d672091b2b5da9fc22445e0dd61e6f84aa85bddcae5361bfb17fd7eca6590c8133eabeccda9f86a658e6487eaa6bef68c3301ec3a33cc62c0294b69d7e361b4e475e4b2f1d78160830b754d60efc6b1597bc38ae53468fc91573c1e199824714e418123f29bae2c59fe2bb6bd8e0accc33c8d74c4392efae102bfb8ded1eae744da4eb52069951d88b1bbb118117483950274852f6f31ce37f4a1cdcb9499465c21995c21cbf5548537c4e92e6c46df710a8e72446779fcc591f83db5b69b85a6181b508016d15614855a3e6f82a5a75ca93569a0faab90e1a2074ce25cd0eee4e68da05efdb181bf4a8f58ed20ca933d22925ddbed9e2582445d850736e7d5879fd2ac32ec20c7b26974ea5dd03ab1512b744a25651611dd479abca21561fa490da0dc0b9d3c343d57b79e80d6324531f5c18d3b3ef749f0bbddca4ed5b826a0a4baf645a0ed2308ab9d88c68b0f15ac3ad74e0e02a8eac7d01d2e7d20b4a97faaa9781d57b10ee7d78b1de100068770da3d3814662bdce546fa05b8895b97919ff39a2257f3be8a3c44fcf7db96c8213a3eb33da9ae188be403bb1406d80fa480398e21378d4c678b9522078b39ffa06d3ce76ccb4ad3dc9e0b4ad50ddb8e77ba6619c952b7520ea6f87abb66a4c6a21708f111e44a36f5fcfb57219b631cee0030c22427ed8c12a33eefa1e7e52420c28615b13485976525c39b45d76ceff35e99c4102a2a20b11d0ccb4c3de3006f41c2b0b07ae7ebf2ac4d2bff7aa2bb578cbf91f64c2a492e0756474eb9ed5133dd0311fc880e8a1c96640208d7d366b885e4f82ef456c95f309d4e3a2c5a048e8368db3a4d644992d77751fd609d35f5dbf0673bdb9c85847ecc3eab64eec8ac86f380437d0f2bf0a2b8d96d86ec01013e28da154faace544024342dbeacc0201b2374fcc6f03ab49eab5a5aada270aa394499d2d7edf8c4cff120a9a335b64007dbf35af573c83b2597a5d050ea0f58e21c609f84684208c403893b8efd87314261e53c8a994b6fb5aa90541d82c3f5973a89581cfd14f02f92e2e0dc52200990eb358fbbd118e231a6b9f4d49f6d9272bdc239f2946df59c71b8eabbb125617b34db0a642b13af2c84355935c4f4480b96a62b0ea8bff86734cc4b13f33ceec9e0ba2122592f68d7413fb7221e311849102dd6400d5b54c3048a651333925bbfe666585f7819e4b6b7faf80439cd11159a7959d8c9dd50582b8b921a2cbf3173d6a4d68cd1e7c8ec5b2514aa9c771deff5b60aa4729a785a53b0f9079013d08b6a77e532f42ac9d7c52207fa9b8e5e94612f31f8a5209f387bd077c172a9f4decaba314ab375192a405f61817dffdab9bac005000bcceb3167cde73a1a709d46390230de56ff9886a913172c5db74ee9cc179c9793efe8c774713caa754f9fe59e4eeeacf31f64d759e2f4aa75d55c932fb81a0361283acc9e752bc1fc0e3c573c31a25871528a9e378580d8ed4fa2571b3bc86d53cacb43e4edad74e5f7378067c5865d7f36e66d313fd77d17e9131715875447d3d29ec5789528b63cb86fe1ad286fb7d269a81c31a729cffc3a1717de355b7dd15bdc85bd83e992dce94c72a4cc7c934d07cef93672a21f17dc5489a4e9d8dcfefbeda76b26aa3d7aa8f8e4500af137bfbad14ab101a5a536119ab82ad82a5f368e31a34dafff006fb02ba48732b3095ad6723567afb9e8edb21f5243f3b89bdb0f587436ebed58e516442b2d99d2da675e96bff06a5a7e44f5b3c29168b72a324f17697e8b187cf37fdcf75f1d91f89d184f4d133607cdad2110bd3a8ba8659b6847c2ee58994cf5841cd82a690a22eebd3ef8e4fc9e79839f39e9049fb2e803f067d5deef8789ea8911318355e5efc739135f50cd37eb1304577871c03430c8a53889bab5a777cf6bbdcea1dc29cc899d03c3eeac38f422877b10697ec5e200656fd86ec78397b7c6a0613fe6d395220f52f3cff31a1cb2e74f878fd2b01a84e4c8d03464b88da1f999b58d79e9b554e5a9f4f1ef1d02007df073eed9d4d46c011ae2455caf917db720f8ee0c34be5433ac80ed45f0e16c8f4c1ab69081e30e8737eadb46d3c4cb1f47f13197c60d5f8392c814fb1346f1af83822f46279af778c52a0ef0f6757e565ab9db0c960008eea082fdcb77b3ca1ee503f1c646965b82011c3f44d0ce63011b2734ab893119d7c904c1315a0c4b60a777c36979322b0ba261cb5af560ab914be35668edf34ca59d5499bb6db3df42913a8e4a537e97fe0a7fa8a8036244513ca1e890b654dec2303bf070a4901267a10bd6b061f90d4bed03a437ad83a39dea4dbde59acacea0d53a0d7f61a62eb97b3690242a54cd7d3d340a9bc4af470f7eeb67ae2d2bdffa363424f212192d506f0e5db3ece7047246ebfe36292c52551231267f2edd8aa468a0aff3eeaf4e7aeb0ffc47c545c30b6d57abff092a14494f32fcbe049e6ddcf34982bf96c6c9de8da43914ddf0c9e8df704127524b0bd08fec4747d20f87072f398d0234143e57b346727749ee47d4d7524a69e709fbff68056e938319a17fd831637a8b385975644d4d74538db276c0f8adea5bf52840abaab54ac8697d52298c84b5383319dc678eb5f69bfd409e87b8c192b04ef1da80388c3e4817e0a4aa54a1842d81e0dedb50e2bad442008538da963d67413015868fb5d9ab33e3f67efa7f2c3b1f212f4a1744b0d124299baaa0bb8cde4f6dccc3af029f27030a5209e3878f616c0330b4b6c8f98c90262ee0b37f0d9628807412ec8af91f854db231f7357d5993df7b2c17b755dda1e7c30c5407f9dd73828504e78b6c4e11e3ad963b1e6ed2a9ededdf231ae55bacd7cf59b1d3ad850b79ef3fd88ebb110e69e987dab7c69ee5141de6f7714204c6caef243490c11874d262a3c3857b9b1aa5b4d72d91a160062d33da1fc52ea9475b09ad7d8747defb7a2dde364f056cbf890748a4140bd18a85632bc9c5cb708b5b809a2cdb4724e8f9127a93ba673e1501306cddff2393a6441832a5c8e2f18af46174e2c1a5bb0b5e11462c3449c51989134b9b4249cafecea70a9d843c5767105ffbfd679d455efb457a2ff4643220f3267f1c93edd6588681ac4c88d8e88ef05357a4dd9ba382c0d312ef767c189fb1b2aaa53604c7a7251c1ddea0122bcae32c39cb65726376ca8c1396cb41f2ab12426d3d66cda56226361b22ba3302b899dd74cc8bd75e539f8ca45cfe8e1b4365adb8e2184db68f2fc26e2c66d445d0e7ce9304d06ca3131185a1911d49173abb93afcb3b6a94285c36fccf9e1611cb69ba2b0bdac397ddbf6e2ad9013750be904098bb9169c1caf01876cc77702268f0932e6ebd1823e0de609e753c0ffbc2252cfbca85b882d0699bda322590b4e3b5173488930901015f6f3b7edd134f554324856687ca0c68020fb38307d8023b3f4f1a3d7649b8692cd11d3a736184e053f2e894526a5c64b855905d8f653e521a197a2b7fc23c605e37d3392808f4f4c359e5946d79d1a8fb92809a639f43dc2a2101db0faa082ab6ada2d0a7938c54b791a0fdb4744e903656a9f3d9d61085bb5ad7b37aff6f316a91c963ffff9a1665cc9fd4911ea07db31f7ab26c30e3cfb29f154ed9566f1d8b89664645b7b9d1ce85d2babf7f6b28ff2acd5a88ca9ea88638223100790ef8f6de48d4a7d5e59c309ed7017aa8ac45af1685dcc99f374151baa28793f113d35ebcb4a61c0ae89aa3d2681a18d49d0618e1e03dd50ba35f67c3f98b117b31341941a5fc6b8e03e4af147544a6ab6e6dff00507015c8d0c40a105c457ad5bcf8006140b9fb29f7d105318e1de4abccc3535cbfdfdc23dc1f26ca7d041f01fca2cb9d501b4f2a437c946804015cf48d2022101035029ad3e60040bd55b6012e9c0c4aad1d7588cb71631ba56a272264aca8644542c5e3f6a4502dc29be4c7c7ca7b93f82d08b4a01d07fb5754c1c72358f6acc8d903d79069ad64eca2f422071a85a9c5f8744c73706d1052e7dc22c89f82b94d661085a0b45bf2e48263b107a869eb0a6ca4a26a5c7b95c9cb35908622b5093dc1e43783d360e5d1d739bb5b93b847c3c5996dabffcad78a0abdba9341b63905ed9d7c50e9d58689aed40de3625e6ebe10e341c888b1d6261bad5a865bce5f59239349eb72b8739348fadbb810aa48b280e04f4294d3bb10e9ed1ec4328a98c4baec1fbe7f0d4661e0b44cde2a5a3bc0d3d47f36cb60a3b514021e3d599a7be4343e7c5eb6611b8098904e1d6d8a50b91b8b396ca5a91d70594338dec6a5a71fb396cf9ad76d87ced032435488acc4d5b5af99742f663180c9b8a3411491e27416a84279d10824419cd17a92427ebb7b5080d83f039493665b7b510235385f6e3a6b6d0a17dbb22fac11ae79ba8aad6a77fb05654570a2577c901a9f784271a18c3a3a1c2faf9bd12926fb7232a0dfd4e5b0a08b38c73c4c66c46625440dc65c10b5464faea7246893613d97a46a6d8d683cc49ee68154d373be97993b751c9351111ea7e61eded33f4f38a4be9761c93f9b86b9d38807a13bc92043f618ac94fa47e882000ea6c10e4ab60cf0d2fa078f46d77bf88128540bb98a8941c345bac3b12c0532ad016b693e332d607b44fc12e64154423277af32793698b4e825c135bdd0cf499bc437043ffe74c860b9272066cf950c9a25004d1e285ebf6517f155d30e70a45e82ce7d3679f2b098226ec3687e46b10c48f28bbf4e03379fd5948ea751e145bb3fa2ec381e525dd454ed028ef17580cef60b62519485cf22170b734bb4213ee05ef7d314ca358998404f5d0f85e842e70026864aab54f692dab34cef2ae9bd768f2cbd59fef6efcf9ae8e1ca9614fd4960ecb9d09714b1eee9192c6b1696af123d350613fe22a2ea33922193dac26b70b9399bd0dc6d81be5070c24a9c1de824f67261e19edd10abfe47e0d151b6098afb9db03ba010d08e5b8855bebebf37a044001d02b15b2a23b568f2e060c1a7d149ec94f19373f9fe215045b64534bb0c03e741855c1377979b09242ba09beb0401a8d3463f03ea61886801e3c542e6880b553e278138ed7f8c5f42d17e1dccde16081872f8f96bd2b7de66fa61af75f942b3a879fb47501efa4b3ea99d03ec2f630d40f1e765b137c7b6d0fa7289c27ce97c92a6f90a7a7d42f8f23cac6740d3f9a1151345dac863c84fdcd2c1cd35424909df8c276c9575d73899b83d3db39d0b54f9edcfeee00eb057df4563213afe8026a1520a4d4df50cdf684b152e556233e3cca3f13b45feaa32f1d8aeb30b967c7e6eece68a706071ac665636cc342d420631604446dccddf06210327d7c4e560e5a1843c9f0e3204c53a99f225732e3581648070dbafa9c6733033c7698759c9054f34129ab4ea5f08d5d1ec7bbf3e0fcf37509ab773cf7e5e4f71d09d193cf09a81de3a924d59c9ef20bab208f2456c1d8e4d2d3e369af630d1504d0299edf08ad13a92c2cba562f8ea268598cd9cc8aca8df70714ee2361d0fc0144ad78f9907c349a3821407de28067b290202cb7111fa5a925d960639d4a6ee201cccf2327c89aa10463d11eda4e4565382c4b3e63fd81ef7f3568e64e940072eb9a830723040531e1f9941afb71a9f4b78481c815451348af7d9abd588dd81b3a925a3d56649b6c948c3f4a5fd5e0ceb28a1e2b0b43159d49cb1104ec3d90cecb1cec7120862ede5a543dec279d2838c53e578a576b5f5b843e49815dc6af83791f72aba38c8cb76b0dc186ac83281e12923544004d45c8d441158c211b7fe12bac471ceb04017523b34bbf728c8e447033f48b82a06ef28e0e262b08ba4969614dbb230f6441003ebaf77fdf45e7387fb0dc79375a3b64757a658b67e5db81b2a9156d620f542fea8474c5bf772d5a34370583459a93bfdfeae1013f596369c3f0e37e7f085f91cf8b916f53b8f780039ab71865d172397d834d2660883383106acdf75ff2255323c00c03ebf159c03d814ce2d6fb6c801876d74d630e3042bd16ec28018495039c73af755fb28c0990233ba07c2fd71029a134eab3c4127f0b59bc49969b89efe400a2389cd17285f2ab289e7ba62b48f840d469e5cb8e5d944b985e7827c9c9aa278663deee96dd7f5b3520fe21afe8a4123db607eb93762a9ae3f9a3be4d2528ba32027de21fe5cff23d2ccc8718bfa832154b39a7ff03459da55abb357edd12b4444245ec3191fb5dae804cfe252c681862ffc206cd93dd9ad18980643500d92320651b96e58e3b4c947e3d0bd6823a3e4d186aafeb85f3403028268d8dcceba1da2361ffb7823ab2c98eb8fdbe58df280c69f661cc4834026629a052e6c16fa64c1f31e88dd09b94155ef162fbb10e18eaf6cfd971bd06c7acf64715009f74196d5b7cc0683fe8be8355c001d4dc49265e4f32b0c303f494b07fb8cd10a421566aa332b288b74ec4d55fadb7f2bf8028f05cf62f5c416edf455d03d6eef00ea85255706a94d35a4f5b0c0b92a9ec67715c794f1993b66a52f2130b6017350580ea1e6beee794199c6c9fafb8679340301383730fa39c31fdf6949baa07d2ad42846c8eadc8ccff9e24ba58a03ed0a2f075bc108325d43864b727fcdb796c7a1002f8baf1412f257e6571248df6bae06a475a770e808ea4fbb21e050e457d24e5a8a3944d8fe15bf877cef5d32d97b2ff141e4efa328b08768b6a44074551b8981ccaa2401125aaa9468ffafb948ad8368f7ecab30c06333794e8e5c9c1032b2247f786a29479bee4da8ff4db45745acef8c366722ec93fafe3fa5dc3e4ff681cba83eef9a0a160915da0f548129ad7f56d17c62e77407f58a7d6feaa6322e365611e70a8d9e0efdb7dfae1a6a27ff3a5fcecb957366217192e370911e738f0b644a725f7c4307473dc2f221189af9e170fed23570d945517a8b7fd3c667f5b5b8d367b601a8cd8985e4a158640abbb79f4650c6e9e6aca022bf8704ae1fb18c9ea53811b3dbd6405e65dd815c7a85a28b7fbc509651e409f42e2dcbd67058d34db05545ba585b9f74e4da615a6af32bf29aa9c773bee2f3e241bc92e01c313ab39613b995ed8baba868f4592bbb8cbedca93caac8cac1a6e36143828f45dd2f7ad88cffd87cecee9bdb90e68f8e119cd5e553941f287f22c1452908cc48adb360628eee8346565cc4c1ac686699798257e07cf1c124b9a30252b29161ff61b5be589b02192354c2f3c87a41cce4d3128dfa30e0ac5453d14fd8dd42863d8610d52d756c1660aa3c65bc5c2954b4948ef608c6b2dbcf5dc1b58e9d31019bdc0ecb1d529b55c16c4372788a224e51f40f1b77af1478e9d4194a9a85e67bf917f5e0f7669ca89fb12c489b91caff22e923fc7cfe15db41c3a7e3b938a0950748f87c7c92884bc97c018ff589e07bfe2c372ad8c1fc7afc2c01a664dbb1eb44c42843d48da248dc578e1fb3af84e1a44c2637c3fe8fd75fbd79b12aecc6dde834345ee5acec7ce3d6cb4002d8e6593cfeaf774fd0a296129008dc28af0630c852abb085974b0459cbc295d54958c6d8faa6f8defe3480e91af5b5a2bd4a039169934c2f84288f9ed6f2e826de42d385c881978744f0389690433395bcb0eb7abd30dab6796f80b92522aebf08ff0b8960ff5b2707e041ebdae870909f023fe1c22164187e8e808e8ff038a7cab592228f9ede81744fd9e55462d09a98d6fc0fdcd74a896cb3873dc88ce81bbf873c45e81d49403c09074bcb75a6074d919c83452de6713ab3dfa4ae00f9c97c52bc9f18445b782434725d28c19ac170948c995593407f72193ffa59505e2f4f88a0f5fd857d932e1e29b640a8400ec379704c6737f16eedbafa6361795d10ca4211f753482b85ef96d416338920ed1e2eb5f4a3b3f0e98d4970bdfb3be43974b77424c1c0c9c3ed074434687b71f5147e22690371bded966eb400330a4a2c485d7e06e036e540c70d3bb12a0cb21712a701e93f4759b5209ffa83806a4de5121553c75f2bba1e6d122dc6c916a930cc842dcf77f7b4d2383fd0aa470b25247255fb730536cbb6d50d642e66afdf6288b71c06a73db7f0335185df57f46b11d809fc06479955bad09012b30086c0e68c88f61b6488b3c67f8e31a8d322dcb9bfb041af7e47e6790fa5f3cabeaf627ea2a7bc63f232cb8a4c749a9eb4373bc66e168b04687c9a63dbf81375bb25c01c470e340dbfa70694e3aa0690c76346f00ea0c820efa2d43906984dc3b429ae646a7e30fe77e4466c3af4721d4083e77051c521ca34c339e54298851d8ee6c62b565db604f038e60a1fb13809154e8ba61a3e48a269f71a0742518c9f44b55c69aacc8905152bc7fc3d9aa9212e7451332086c5566039fc3ae6e6827f189b97b4c2574c35b667ee6338b5bacf2fc93f8e08426aff8a1aa871e8230e7c5008733b10ff0ac832575ec6d64e26cc395811736438b28f6594381f1a9b19911c6e83cd88cee3c28e4b96d50f83ca9b054cb7bb36a0ac497f31304b46b143a0ea3691da654ee360095a482b93c894db0154acb805f68381288fc3c35547909ee550509272b9cd7302de3b3f110ab2e860077c66b4761a29d504d96e1f9be67e53a59cdcc0d71076bcc776afa55441b42f122eaaf2ec01bc8baa2d818a52b0b600c54f65455cd5f04ee18ba0316361b6782c4465d7a8f6eb7503438a23835bc0aa132e42f2e6f3b777a0fb114bdc7a85906624a19b59fe6e9199ec6a37c6c181fc2dca0fe88d6dcc137182a7632b17b05ef3bd9bc7fc943bd4f816d2ef4a2b8c1deae56dd919ecffd9f327c0fd32ec5eb9ea97898a880e62139e4fbc6798b26786f6f57502be825f283607dd6a9cc1283b1b97d4dcb0a02270cd2025e509f409738479d4af7041927b89267412db4b9be045835be41197389a9b045b707698bea99ca3771ebcc2aa274985426ad1ebd54ed63b5efbd6f1ab3635b889f0d45dfd0b43d78e77c0c9bc8dce38c0bcde6636804db6aa2bceae9671a7871b8a14d72de4c0d1d9f4f408fe1b8a1af02f0616a7578d54f83f40829e14d4f25aa7c093ca14e1069d004a82ce38c777a480cf1b76b1548c39a330998a46b4094fc7c268bb9e8e99b093f223616fc6c9acf6ee4117823550a2f14b1ea9870e807fda4a8985993331234091f17c0e79335af5dc9098c00a491b68b2b5c0d52bfa8dc95e84c4461032a613d230d93df3c2bbc2a82b61068fcf7a6d0e478dc47ae9f4d3e10f7589123f8d560a2dc082463f9998be4a1c6a2a06c162dafa71d54a4403d2487200a73cbcd6b7c769502d4f1733f89dac33b4a948e62839dd1c6976548f4335ebea1c927f809c4584f7d9997330c1f497ecd3440f1225d484967723c932a1e1083a49f014e84fcce70d9cffc8aa553c04c06e51e8fdfd9458b464f6678a965634c8de0f20e35d1fb3c384545597937721801d31d200d4ece19159fdb40dc3cb8d19fd8757d537e680b1cdad083e2e44cf622c592897d292d92124fc4bba3688168dbe3db2d661bab8d45a4bcfc09846e03b8ee5236edaa3dee2fd30864f5cd8c11dafb582955c677bbb2241ac76c798a9c1b624c6e0d7effa589a9a6fcefcb41005c40814abb8a3124382683b0a4c9cafd79bd4f0958dbe4f7ecb4ea64a8304b35faacd5aa3ea9ff904b8430e608cb36f6e1995c61ba2de11f74a01a87af1a4489b2630becb123c490c47946ce28058239baed74af82958db0d3b8472a92d24df3f125b96196ae13e69617945dfb695e8ecdc2f7dbc55fb7e904f004cb7069a73edf936c36b3817c4b49911f087c5be6def27ea82c622c46894382e978c45a31d52f474f58d1f2044d210de0d4d49d1f447b2965974098c84c562eb2e08e2a18ecce15142749731aae97a49835922f5c808c06b24bc969a437f5b943903dcf7028c0432ad787afa5970f203108ed3b09ee32c7f825b07f6b7674c90931ec68c659c88d776af86f6fcb73f7ade5975b43134aee60015988ffaa24a1f6f20a6c5d89b9dd880c12165912250410bd9b4e3dcada28daa72a05e4026756c7123a72ae0e023874af50a3cf02bcb3bc7d3621979a2c3b584af5944a3827d1f4973a89182a6a0e60883dda13c00f07a24335d200d90aa54785c1dd3108fdb82658fb5e2d5ad3272d52df21297e8e1455c3b2bfbfccbe6e07db90fdc5ed17e2bf48786b904d987fa3c275ef5875fb8af3be6fd255ce00cb7ce4ddd7e28e5be2f3537a0cebe7d31498662c6b11683566c8479364fe9642eb9564584a23eb5d4dcc3906eb35affcd00469293a8257d6dd836381fcac4f3201b280e3851cffdd41ccb1dc5229b2c388d6a946b764df33897bde8bc42df8846d6a8d71789e236cbc18b23e298e3d47d60d0e1c4de73dfb8772a9523b27c478b68a7e176204376b885320bd18ee5fce3993f10b00db98d760500f7d3cb217510ff661018135210f88e6cca09f61b28c4bbcf507a94c865aac33750b28e52d116b98ad1208a74a64f30fcbcdffc0733152c857930f2864609aa56f7d71ac5fcc3c2f4c717ed506d1eb6c06e131a6a7725670becb942423686651295433e24a36e2620682c829dc306ad8e1b837f3ab6cda95408eb0b48f149aa420c56423f7234530339a004790b579f20fb4423e90a470f1ab4ab3c7c7e340e9790e976c143d6f7dcf86b018b3fdfbb41d7ebd1226c483f3e6a91764f97daf247ac5ac9b6e92e284b969433e0f471de347a9c2f5f38b2a4aeb375e2adc92553039713e08719de00c2fd6fa86f31f4cc4c184d27236a25052cfb0a6e43520211f7f9dafc2840320d7b6c973cba1b2f3fe7f964942353a60bce1e835c6fb88d1a2301149313091c768a754716cc3703a2f9559cdf376a833118213304c60e3e72c95af43838817bd804b656381cf6daec1e05b70364566d5ce4b5b910aa37163c2f6b75c84f51a126f62a4955d910177c50cce9e6f418fe325c1a81d88c196def46f2bc018cc0160f3798449759df4f8da80df66f7fd19e56be807ec36dea5c443cfc2c600ecd2677968984b01d7448bbb6f5f1a7fc334cd95c123f3c15ed52fcee4148572f806d54fe4aeaaecac65872eb97181a0cfde4c316f6441a557b8721e0f3b328f0f0f5cdc195291159b972abe44737c11a6144c3fe4c69178cf474dfc16e2201452a1265e1a1a88269f17e05810c67d2c0f95a21a9821ff16786336a0d8c95a2e7cfeb36c1da9a8803305f80d5382c73758a4ed4daa061896b9ed044396e6738e464493c259835a3ef39fd75ea35ffadff49f26c787fe85ab4665b7092c48cdc6654668fc771cdeadcf440358500626e170b2841b67c8297e0a0c25773ae99d2f55011347c8d2903bc1951407cd77485674c507d88e197da50ae4680935b39fa856f301f45732df37ae851624fa5a80986e51b686679d0302525ba4a4a9049f10cc925f2c1a0106aaf1b53f795f76f6646ef1f012b20720cdc5a4f6906b8ec4de667f1547fd57f9963057c6791a0cf8ed1103a45bc94965caedc12b97364db3ed11ed76b0d3d03e32d438230e17d4a1f7beb032918b4cdc7e74641ec93d7951ccf0e40ebc7b9f66a98771c045f8011991afd5a1b2569ff3514f3c946cab67c99928616e285780ed3042e80aefc36871abd5dc052a8d4dfdf0554cbf752c66a70e213f4e4ae077acf57f95330041e7ec342c15d1ac1ec2c3bd9ec2240392d47caa3bd72cb50916753ca16dafd432523bc00accfa629b62e4df88e7fa629b65b2f45d5f3d4de9dc3d90deea1108ebb8d019009f0eec094994e1d704dbac6ba626294159e40262e9308485617c668414494dbe7be7d0949d0a88cc1fbec502f631d4c2723b00dcc4e26e6a216047890987b7aece5e540dfc48ed5c75d6bdf8a15435d0a35a0e41f92dfe04f7668e7f5820ecf6a754c069cbee02e0e2430c980c7a1851d61c43af64315132815c63c58c2f2aaf4650b420b7ef82edaa16e861612fc9cb260d35083aa8464c617b20946858a5bbfbf8053ef0718f010ca1cd0e33a83fde613f0f851af2f71dd8be2cc275c0ba1e874a99f65cf11779315b3c9fb820810a066a1c716ed284f29757a9378c1945e1f3daa6989fc33ad51d954ab6356a075aafabb23747d1e7e39efa616beaef2fe0ffe2a4da8956df2aed90284b3793698ad04615e4966f25467ba68d989aaff1149cd00466f73424634e75df6e101ce4ee55b99b0d958f040dfa35e24c9d6b769ee8fca88cb4c50bfb53fa032d4609415bc51acca90f4032be1cb043bb73d0872903811f63dd943e5783601399e103500346be0d4183661c1611d925bc82ead8d46a60935c38ef6a1462e2fed235aea411507f35cb7038ce9070d06097b4ea4a56be52d43f07a706d4a4c95f38f2736a613b9ca0d93935b731b0926283c785557b9ab4736a31666bfcfcfdb8baccedfbff1305f39488eb4b53adb9fc26e9ff4b665872982da3f6b7388e501b9e3251ead07f2632ed4372dc14277d7ad38aa2430831459392cc1c237addec628963d4c06c8c15fa349e65db651b917c2d714a2f580b6a4bc4b3a11d9d910ec7e11ad2f8d84963303c04b2f381cf205a0aaab05b8d1857bcb78402c12c7d2cc4ee6132385d1282643529202bbc5e455518efea872f141db4f9fa0c6e17c29e10bd97de7f0a90aa8d5888530b122ae238c0a55f1d20fa949e0a8720e205a44a484023d0ce8207d33c991a453871aedb85d3955d490dd0e79b92e452f59b0fc3581d95e58f1288c4af62629145ed904e6471d64527ad0d372a746e72c21e15531c1b9a468f5cd8807fda04de0fe38caaa697650f1ce3973496a362ad4a66fa188f6a510ebdc0ed0e6c44d01ac7209cfd7e313ed6e89acb9f53d7b876264f97bf9aff51be1873375608ea8d1ffcd8426288d4eb9775be0e53ec73258d6e5c9a1558731c028c18c824c9ec8f59f8956234b04714ade34b5bf2ba80046dd02f6ce51944f3d9018c3eba35b36b2a2009dd08b03fb554cfa1e2d2b2b9fdecda60eb0a5954316e79fc43ef1c409ca1725ab00ba562dc8fe6d947697cc450862a5c975d940797196ea78c0030597942fb38aede05491420334742248c309d11bb2d15f4030e1d7fcec2ae6b81b96149942b153c0e4a49f6697c285464cd4408295b714bb696be1742ae59c226a7243a5b269071d491f5beb0011c52a102ea23c9585874636a63878462bfbaca34dc908dc8283c0cc18132f4395d5069490a8f71932526a9001c2e6e4c2e85f4fcdde96a475c229ec87c04ca882b1c99ca7a7b10dd856d14bb516783cd5b7e8dd9058f1fb5b884cd44669120a0a087b304705fb4b81d766374a4d4015458a483a0ecfc822e94e7cd7a92c424ac46c25ddccf0f485e0f87b5468b0dd3fdbcfc896698152bd30a013641b6d65dfb7febdc679445c8d365a033dcbdd4112f7ca9cb013398fac6bb57db039d746b87dd8298f7bb49d5eea555fcd539385b9d8ee01ccc270c1cba0d8f6eea83543bfa811154b8a8b4a79ae12200453a3b786b0eaf6c6555b547fe8893408dada444226cf35e7b78aae34286b78b6e552bc874cd30575a6954ef851acc407a563d4cb1d7094c37f752455ffff2dbc6dd7a2fd656335d5972968f594a656c45b263d087165d5eaa35280bec5a658f64ba5ba36f84057c6bac822d316ec61837dfc6b20b76f7bd9e7ed3d2332cb944b4d1d15acf8d048035e5318672eccc4aa14b5a29dd7d617ac17a2c09fc7f43159fdc4578bc0b33a5bc137b534ac24075c482d75330a686bc96871065d5f3a1261abdbd88ffd1406b3c78a37896d6098819db8cb6275eaa36746642a6b601b65b20e88333183cab5ed1474c6fd268d01b7c5ef7ac0df4a653b245f38f9e75d3cefc91acfeac8ea4b86f371d527be9406a51d82783469e8743240319225e084894092e88ecee01d05c24f811732b39a2248789f24bdaf96a42a697a7c0a33659bc201b567559dd48bdf90d6fbdcda837ba89d9382cc6393878f0f428228141d2a9295e48973cc7ac8ff53563dd4e8950b104b75716ade38d9c38c2aebce572bc9b91b379b00684ddeb758637b13a9747238ef530a961db676b218631940f52f902b34d47d0a1986ac87176e5b71409450e871fee866a4fc3e517d464e0e5e602a5f2da37d65c0ac038a65c9e43ec0ad6e1ddab5c00e34ba33fe117ce260307ada3afb82b1440857798a9224b0f3216f9f63f5492150160059822ed81a09390a82a9acc76f422531ae1764d3873cab714827de54c321a1546b5b31def0f2ae62625f37b3acf6a60148e9fbd9512339204431a03954190dea4bb39729cf73d7bbed208b1aec40b9e123a2eb4e91de3d53754ceb1d708da19d4254a03a0b7f58d2385776ed2b8c8c2baf17ba70367203a728050daee9a9a6e935dfb609330c875fe2935698f3c7090319a3caaec40d3efe52713a922cbdac878d70ea4107ca5519d9f1bde143ed9e187283de520501ee5f6b8a71c603ce12b03dd07d11e58655f28c1429901b6efa34913f46dd81722390d44410a0fcc884d9a46cef079c6e440ae6029da627a11a901443c9f4c70d4ed49f24b64e409f41a84b121c5c808eb22b9eea9b30a8794f938747484a4d0bdd6e05cf53e6bc86e5dc8939c4926dfb3f1dd5e23a72b94a1f7cf46d805a7c3c908a567beb2ec18bc6897333481c7cac289227d001e3fba08bbc797b9634521dcd08f871da6e3ba4fe5a979980a7e900df27158f49791bb06b1d566922b2f2e0d1518bfce901121ceda75799f1f9dc1e9e7882a72bc28177f421b331903b140d33292f269e20972f7859f734332fa0dd2415f1ad3b48260f13dbd463afbce8dde40ce4a72434f3eea990b4c4f85f0ef15af0c1bb58969c701f6aef01dc0cd48f6ba9abdc4ebf67fcc06a007a55c7f09917e19c5fec5e83ddaad579353a231eb7f81108b2fd26f80bc32c3f4320afd0da4c636877a3ca5ff62f70ad28d12a21ad02e85305548608159d53f2d710b339b7da72ed6e172317fdaa3cfdb653f3637ca2a3a6348607b1b4f8c98595fcd0290fd32e8ebcd61f8c750093d2df8c30ae51edeaec0a00a6b336e7778eab1a8acc926d04f565de90bd2759fc537083e3c3068400ad6eb72e2d3a3d9a1bd124eaf57b091c66fe5cbf916cd7b678747f0d825815c085650f5abe07e385046f867effabf2daca098a2cb3d8bcf6222d8503bbdacd228d5e2dac3916cf08aa0670561c817683f840d886d8f6364fa789ec2fc45aff2a6837636d82c7df06d488037e4613d334cc29d6ff779669232178ab2f2da233016e1591e7e26dbe9a1cb633e690ba67717fb02be02dc92036ad16a93572092b29a0e17907fbb2b74b487d5596efcabcee0eb35d251563ecfec91cefa5b11dd5c913c7b034ca47937a2d66eeeeeee46a9deb838f1b0abafd5b4b7f7bb9346bbdcea561c360d4db8167b49db5bee2db79432499902600929090e0998c803c142feb10abf838b605c535f07db08b1a9c1460df8d6cceb9000042000b1d7b752282282fed8d13c0031228a04c0944600ae911f45707e727e7e346c73c49640c9218006bc090ef81becc4e61768e4800f6acd7a8c8a3420c883418641de11cf2c3c0b36bfe31da979ed8104793ffe357f7f7e5ad002865b43425ab3d6ac35d4220272e4c8179a16203a38b845b403e4c80040131e8bd6ac356bcdfe01f873007e566b86d49a21b56648593e01bc1f20b945c483061040c3b200d605a0cebed09ac1a0e3c305175ca09991716115e3820b0dc01db33635353958b4a8d420e7084442b460091f80b1854b09e655a221a78563e2b67063704ccec335f96b8b84715e643846c3383638a62c35aec979b8277f7991b04b2443361a7639ee5eeec979ee2592b07ba334ec5eee5e1964f917490a69bf4ab0707f47a9998e9ca76767a7c7793a5634ed2d92b09d9d9d7b37ebb3d21daa34a5b84ada19a9992f758d524a279e46360d771b77649d1659eb49d1c9d877a2a64b9a67e694e08e9a3ba279ec4b0bb2b826328b8b4e9351a26a9d9e425a0389697693a97d70a8656a1f2a2760913bcebeea9b1912493ab83521a5c1050e563dc6f41f7f9fe326072606a7c5c2349f63874b874d4d09218eeab1ccaf9e069bbfcf819bd060b37dfc571aa056eb527cb289a4029259aff717c88307c8e3ef0b0f59f1225eef5ef4f22971cc3cb02319f9911fb9927b9e345bf2fb916d95393ffc6f7de49b1cec66b477e91e74b846b3d170f497d60142bbd1a17cea5efcc933216bee9afd7a4c9122c56eaa170f44441b0713fa1077633a15c6790d97c0a4654b131a494a56c8389ee4d3e501536323dbe866e0a58d1991f773b9ac3a0def981149a15265ce237f79dea4611da832e2c7fa9467a4f5377e34a0ccf21db39a691a2e2c99540b0dd924d5f83ecf080cce2dec4d8e86abe14fdfaa8dcf0aa9c452793f9e61c02e1ace7982f17e5eb905bad31938d9f6e8f1b7071eb222a570fd4a26b9563231ad1cab9b1b190ddbbc4029c54812f94b12c9222a32945424d28c278f8e62b091eb5d05ca597c8a4f2c162bb611bd7861ddd4e48851b90d4c2a4b4b474c8b45b3c3a5e38a1253161c7388e3162dfe8a4e4d4d3660ebc6d5691826ebc0530bd31547430d2f48df4a8a1b7fca91d3393838aa2c4c4c3970be3f27e7d366702211be88ff3b4ce5169e48576478e34d30390f3688b11a3bf0f4225f52b0a8cc548289230e38e0985ea61ab30d2966c09894f4de8475b40e108c518b5a097422cd2b530a192ac97026b5cc4aca1f2f37c5606f722757a30d3c67fef22243e9713ca970e79b637044221e1df550b92b568171e1d80c83230f3e401e313c60787416e7780dd73c43831d0d1536220addc99bbc85664a80110c3c4af09a28c13be2f906f412c290f56127d889cd33e04c92a1f42c715c91b0d5cb9f483369a585f18bf9976704266647c5ea9637c5bc54463cbe858dc0df8127920bcf243c95e6ccc2e359343a7ec66223a230e692018d74fc879dd8bc028d5c7f79e0212b73c7f780017b07f6a63e417e0f139a60f0965f4dedd39ff5d7b358483f40b23b91b1138628481352883e4ed01c0d9537fd30e1252414922384664646c82a4688904f93ee9a83a1f596ebc50c82e87a8b33d1d926f4f20525a6ecac75d6c723719627585d46476de93ee719da9eb32c0e77ec4e5c028f1daebce1271c98cd2a57756430e3cfc1c971936fd74ddcb2c91795faae2a66e3c050260c6356323334ac9acea6759303a7cbf96e5eb09b73ce39c16e9d8e6db86342b4aa55a73386d22b9d4255d63528d59e0891666249d8023a6cc17920e02fc901b98086cd40842f94b02d370c43db6b2f3da06a1f071bdb1e02cef3017fc9483443c362940ea351bf94e813e47fc07962910ca3342c12d1a1fced8a0cb2fc882485c88f47528c56a2bbc8f263191f95a296b8c5bfc81495fc356dc762918445a56dfba844f36c2f3f1a6dd88845a44dd03b427f3ee74fffc60d13d99805dba567d4d2e7242280203d03a7934a4b86e7b3fbdac712c1379a47e974ed5fc3374fbcb2def745227cb22059622e6f9848186a1aeee62663d3a97193038304c912e6699506e1b64bd65a60db2440fb4c2232dcb2833d3d534a2a6ebb80d41f45a477f9ac84e9e4a6807cc9db1798a9a7df7dabef29a5f45d12860a2f4081237cf365dd0401d4e538d9514c01285e67f4fdc719a504205f45e8ef640a864164b853c42140810b4870499869989578475a293b486403c2f9a86dbf22feca2d9c71bb548fdc0f01e7498145e44bfe4bc28068d5935b19d7e70cb2b343a4a7675277fdfb08432a572c7ba9bbd51c0c6aefc671dbb59dc5b6bb7d6ab70f75097363c2ff2cee7ec1a85e41da110fe42dcf146ad575fbdccb5d94f75db9edf2adf3954cee9df0f59855b301354ff7b27b80922d46fe5ed65d7ca04d811f0a64792018defc81d6e13233f3a91ae6df588a04a079baeec00fc8977c2df2d30e9ea6081a3641225ca4942d391405573132de4f4c6f30b91fb70f7d8a65561aa8bd6b41dabb56d3ced359f73a6cf41fdba7737f0c4cabdb27d5b3e2f20613f3a55437393a550d7ef5384ff776ebbe4f85f25239daaa6a7078b722ced3b10bca2c072a6d4af9034f474f474f477ef4f401e7c95878419403296650716241968f2aa294baddf5bc1f9c9caedb67e66e56e3bc8e933454d0ff81675cae1d3ac01b9b6ffda8c9c1c9a1c3e572b9306be67fd0502948f8c75bec427201798b5d7fe7adae1c9c19d6ca8f84ac6472e02dc7ac5632312bacf049acf035d8575ee445ab89c4cc3b4fc79032edba23324dcb9d86858a41152a54583529184c9122a5c6e63be28188c8c60c556774836b15b016f94b3e7949a5867cd6c22dd40cfef13407e6f136d8c783f8f537b8c7e7e0f07170095f834d781afc2d1d332c1a96c023c50506eb9861511a9ad6dbdc80353938397278ab9cafe6df33429343d359ec62e5e0d4b09e460d193a39c936a4172f187b46c0bf342d688ce91106415a944532311549efc2aac9c1c931c3a2343acea8e954c0432a3c6c6605449e858d6020d1c7887cbd44f0901569c50ea9a4b483474789a2c15b760dd9d145abf3c14f38e0f3557c78d0cc58eccaa9c1110206f9d0339252fc050b3d892443241c2160a0247a79467236ebd123a7d3701c4fac1e36b8c60758c3d2a1f1a0c801e46b70679cd37a9b1b30078e8e19560c8e718b130dc862fd87e1ce0e1026227cdf5f1e9d863136827d0e5c89ea900d02d2272fa9d40da645d8608ae46590f55ba649659c80fa1b53e814504041c70f6068f11350f0fec6201d2485145c52b230317d0146dd1771ef8db88edb1ee5bde3ee29666284fe2831427de7254eb21107a65efb22de3dc7c550bf8133ce7113ff1852bffd757c643ac94649406fc6c53ad04b8007ceb858ea3970c6c5b897d9f19113b2cca8fb254255b2d1d675cf759214ea3970d668c4bc2c99649e8d8858886d47bcd13a9d6572c8cf114f0da47383b2e941f57bdb365cc3f6508462df08ac7848aec4380e86fbde0bd54b400a4264896da00d0448a30921b2a4d184105bc4a2506e0f4889d1f69d9788201bcd686c7b6126d7f730047ac75f5f4391ad5bcb87fa0ff58156fc5f852c731293977416467491eba73e05d6c001efa6ef58f7e485bb02075e325572c473bf1398bc643ad520f76402c37d7f0f8fe0be07c3132842311cacd0178a6defde9115327d4f4a54f217f79e16ae4969d3d2148b62919497c5a21aa008c5acf8ab98f81a64d25fb28c4856e224262fc97122074bd4600549f7a89fd52067a0b725834332b67dc738b0fda5a4411a66aea0ac9f824a808472bf93555e62001740c9fdbd44022db9c156bf07b2649907b4c8fd24c6b8df300e32c68143967bc74d8264ee97a1635c3ff74c525f72ff656a1f9d2cff7a1745e4563b6e511006ee7b69893872abc10308c5b6efa5259e722f2d51846c808e6d3f8d8882c4b66f2f8627fde56936dbbe88e4f013edcb972f1b6869452da17945d8140ab64e076e42b9bd84744367dff0506aa0badc4b4a34a5bac64b491421af3e992d51f24ca94a29c1cc59cc97222c06f2c924d3aa48c2a42c42c23c09794909a22c5f4a30b27ca9d43ed16a5de96c971106e5df91a26423e89756489338635c24df6c993b5739b775befbd56a31f6f8788fef4f3193787fce153ed5cbbacc924e7cddefccefadfd3e7fa1ac87bf2f187e97e20bd24047f0e5cb17a64c393cf3a6819e4c41251325a7917cb72c096bf71cd44a330ca7b34bdd97ad72ea26a740194dfdf6a84b5333e5fdf4bc2f7a3fee200dd98b928ccb8a9e91f64219d6aa2d7165fa319461ff4739670b6951a6d10353041627e86135b5b457deef90859ca73ec6583fd6d457d4bd1ed6aa773b72ecdec633c2799e7724761c9ed93d779893b9c3a88b65ae7c35d8e7cfc9ac607ef515cb5c9e91954ad56960c5df3af561700a8e4ff6b16458ff43793ff7511773607fa84f2d71e5ee53de919ba42174c95d7378c67c539d873b77f8c32b19c2f1b545b95a277ec5b24fa6fe7c196ce5cb3f7a3ff5b98d7be7b6cde2586db533fb66c48db163126974ab722f251146124b431edf3d3618f495d0a720280019d6220290610b41ed1327561261b8880c6d37ffc2e0f9aee8a97ee2cedbcffbad23f3efcf7bdfce57927afbc27dd97cfb57ebaa6744f513a3fe46c2ecc7eedd7be13e0565f685ed27281342dd48d80465ab148d7999ed637e4b3dcca7fe46c22c28dbdecefc8c120fec406eb3334a47cd541b72fe4e7b14fc9179ae6435c1953135ad9cd9e77b509cb80993f6329b651a60f2ea9d862eaf38906713262c64d93ab4c9f634d4bcfaf68e3c608599e4306121c7d66112bfe4f9dded838232f9f4b112f933752361add81e015ebeffdf1496ef3aa24a9edf3a227fc6fc5c42820723aa9732f929ee056a44f58ebb1b096bef677bf75ea02f08519784f58f50febe880c9212a37e855baa87f9cebf8af9156e1dd13ee6b58f015baa6f1d8179144af5def946c2ee47197f4a1f067fafc23f42f973597f452528f03dacc45ffb0ec4328df6c810cc787e0529787b035f2f218184f5062044857c3bdb6786981d44e5186999aecc862c85e283321bdce7945856037d49410d341abf4468092fd9410d7c0d0e1a696f438e3504394e97d590230539e0a0510dfd36a4b41c4d318b69e00c88183698c5fa657b0af85ccbed6fd7a473d632ff5610971d6492cafd2d46de01fd657fc92dc306427b1991a69527ceda038263f55d7103a71820ccf015c608a28b1af8a0051662c448914417252d44434e3c725f71031b6498dc57dc00c90bd519329e0186110e44edaa653e9d746a404c9f3e507bbbaf53a9b81cc1195ec22abd15cf6c238dd94a2a65b64e7d563016b58e8cedd33a10d16ee2da59c7b18acd6673e3149b16c7a160a2ac76884520816125b3713a14d97a7a7a6054333333345d4bd8fc561169e5eeab203b3b3229d4474343639d67636df861dc1dc64718c678de918ec5f29804cd1cc119589e91f912365f5bc95c3916c5586441593c8a483926cd1bfd73f78fa264b1c8687bedf5a964ec79b9ae664a581ceaa1bb514993302cb844a6f8643d44f249c260758c0ee5cb66ad5b6428ab1b5dbff409d58b0cc7685865a343f9d50d2cb9ab681e6d4a2c92efda14d786341cb27c6d569f6a93f3b8185fbc8b2ca79292962dce443f67aa5ebcdaea45c25c73af5ba59a4ba5941a2f28da02462501972d120c19caef07947d35f608667665e7dd0d0e80aca9d16af0ffd871813a6492aba344e9e8b06840dcfd781d58ecd0cc801d0b32e4c8c131c1478f20372f9b1a970e1e2c58dc33323c5c3dfe7f870e4ee181608c79c0c080a0e6f403dbfc0eae3901d747017b090ff0a2c3a6468717073c40865b45474849210f21360fa03284d33ff14844510070d3a2d6a5c28ed98e591c71101982ca109ca3d43a47518800e074e3d472a24ed64925a487670598abc6d59aed20b24761f8efeea335d3a1f33f7efce82836f216ff7c037005708688640fb035932754a142a5085984020a27a4b42d296d8b0ab766326442218ef8f4d4fa160f32f49ca30b0a34e7955f608b2805dca2d2026e5581fd0082f1fc701da0101dd80f1e1f393d7a3ca3c8e42fa6d8b44586714bf4e22f279eee06776ee5e024f92bc987eb8eb6a4829042c457f4a5b6a4b6a4b6a4b694c0c3078521291079279fee07ee79201800ffd8e777f0909700c6c09f80893c0a58854f01fb07c135ef030bf91ed8a67e0ee6791cbcc253005be027802fa0836feab71c0343bc268e64784464d63a1203b86325bc05f017f94b0522437c3000704e520fce4172fa271e29260a47c4c1bcd33bbdd33bfdaa352443221e704b8a0ca750695571fa817dbcc8a780eb07c136ef03c3be0716f226e015fe856b3e07f73c8e0ebe69ddf014b9b1e14963484f8f0a140ff1b969512d175181c8109f9b16d57a880000002b20edf06107d18e21be97bf83ca977a22e023a57e08f848a9f779a41bb0854401103f1f9f3d23267c7ee5e4f89b75b051039e36e06d0a40c2f09fc5fa3e2b67a4d8a32cff8605f72934bfc021438614e972e0fc3f02ab1b272c2220a264c741336b5dae78d24e9b75e676c94dda2a6e903f7da118a5ecba20495d8231ffd0761929d8f4e9aa8bd739ae155f49bf7f74e901d5560cdad747b2bd7d4d28bb07445b0768ceaeb3767a40de42a27d7d1934903a90ccee5e3d075bfe123bc991afc43d0803f9d31650cf6c3df77eb8e628d80ada662b68b3610a4d798fb8377e524a19a39431ca30cb1ff91a70a4ac448213ec2212f2a7f862fca60cdb5b6ac96ea4bf2c3e59981ba85bc767ad1367f871f0477b922ea7d33929a5b5d65ab568f996bc78515232f22d7db1005adbf936cf5650966c64a94586548a3bbf3b4669ad74075b1671e5dfd4870510fdf992de9085327d25524583f9526edcc7350ff395f4c78e3b746c08caf6f6a1dc560cdbdb47b281482e2775f0d6691d27f2e6b7d0cd39670e326c483610b4feaade748136f580bcf95e0b9d27487fde181f088c5fb2e601d58fde0b156c054d6df38062b679b35bc70d4533fd92db7b4103b7353a5aeb01fda05cfe955386ee01d99e4031ccd5ca592cf9adb2377dcef97353300c4179414919e9bad487e5934d0f482604243f66b9f516a54f5ab50d45bf82948b19e78dd22928317739ae15c4a5e6d4a2c7389d4787d93eb375e2f747f9719d9dd6796037c618e50d5276b81594dd3f355b415b9e1fb3108d9c134d68f7fd2ec9e37dbe92c34356e4bbfd3be7adf549ec6add0db1bbe1f031ee65e31d2924fe0d9289f886679ef8deb859993a44229983e3d03d894322d88486cf092b6b2f6f682032994c9323cf502b5989dfaafea6e6792be8b3fdcff63b3ebe1d87676c1d6b3994cc861c41db3a11f7e06b5156ab5cebc4bfd8724c6c98650bcefad1b9c55cc128565a2cb725cf8c75cc67050386b002208ee082042f404307a11500014a9726b218a208478891a8d2d96f84b154049425907428c12422e3073994e068882a4b5c786e2c2610c24d208497715be7fb1871ad747e58a60cf95bdf01f2f9b840bfcc212bed5044964eb983c0128507eb2ef38c6cdbb6812dee956c4f9fdbb8d75e28472ceb72a421d7b7160b654d09fd39bbf265326f2f6bddaaa6fde4521ea56fe9574db359c353c34259ce18cb98b4ba3b9113d9dd6505110c5c444108319bd617e4004b0e6d64d71173772888c8be5ab1c0a82e6dbabbbbfb74874245cc9cf38951e71f46978bc321142b59e6dad9247d818552c4c6ad589f15dff67483f243cc5669b51b1428dd534abba12f559b736a619e7326e7dbe9754808aa6d1bda816adb86c2b0db36a4856edb501675db86aad0b66d888a6961726319eaa183826ad5e79c3a74c953cb737ac48167973e2d8a5b9da81406f36b15789ef3fb81a503942e669715734e2c4445c8f3cbd365450e44642e3796276db40e8c20e2074c1801c90b21e01003920aae80a2043ee0c044acbf972ce9c288411847745eb7e8da1b36bb82f4ec58b1e33bd6b522d09d70ee54ff8630e96a82ac8fa5b9d34a296da76ddad6dc977840065777641a841134cb7de5c09da5344ea0a21f4486f173dc69a59d20f215df89be56ee251e5491b9dc4b3c8022cb7672b4d2038294d267fff8e2f712b7dfeba9826108ca08c880a2450a142c64a0116b7f41c95e3071822c4e4770a306b16e55045b86a19451dac873863e76e24ba5285a3ccc92c85455b093210595a23865bfe1eef8845c3a40fcd107e59413fccf81ecf7d7afe8cbf9b41fb2426b121cebc69723c7fd89f9a6a54d6abb147cadaf554116f8fed23ef497a669df946b53f3f5bc2cd65d41f27c5182345ffc22d2861855b83331472f886a9a5674db356588bba24fe6a36fddf85631de5df6ef1d7c19fa3b115f6c9dd6fc56ca614a6ea51c8ab24f504ad0a876fedfea26ca0ac67c4df72766986fc84aabaeeaeba9f94f9a5b734ac12611348a2fff63498994fa9c275a59973d362ce6d9604b1691421e630e3b994aa34ab1fd52f07d5f6b822cf0fd453ff417fd212b51884ff67dabb8c34d7da88b861412df1bbf88fa86ac44d04a21f287ac74fcfe11e6f8394e9961f28bdf08b8010bcc08a208072a3892130a01baaca103204001c71a2b88f5b71229e750092c80028412185c68f1825835c2155b4a30c529092ee28e2cebc9fedd5740a91204367e2842ea414c16e6087401042b547890c10f49b176cafe33fbbf0fb2bff597ad948dc4a4cfe6336c6e8ad3054f283d5142e8072580f0c1172450638a2e1b404195192481441c447861c11703d9971b16e6cefd30788f6f91c40a7eb041183f883146acbf67f8aad31b96ce98e5e437c6a0f2451240c8410c76a63019b1851b5b9061052af792193ec89b1b8f97b890925732542a81093293996f5ac7bf3daf75a49561742f4b29b03c91945732048b6efddb5776b4ab57c32c3b96cd9e6630c53ccbfd4998e4799e8fc96f41c26cf62cbb9bcfd5adb07d92676b59a2f47b22d7dc4b6674c182b24b634cb179b997c65822a77263799204ef96b8b5754b6bd596524a99ea7af83ac7ee1e7cdce374e79edbac16279dde59e6e0fa6b9ae65e446aeeda9409e5d965194651a69d8c4364fe34cc2cbb34bcf713bf64e7deeff5ecf7dbd60bca8062e6c0d611aac48bc8eb71488bd6cf45bc3d23b106cbfdb593d398d4a051fad67ec9db92184a5a17c03b229bd9655dba19f856cd5a62424b96b152fd4176b8989265962428225ff295be279facb36409010220b90003962c3131cb457ae96e71e526f7d21654b68092c50d57eea52c5f2c65310a927b490b3696b4286385dc4b5ab4408b1c62da4803b5a5cb32050a490531b997b2d8a14b420d0f6cb468e55ec20269090b2a79e90b2d5d83aa3b2c3151246552292f7531254b293c46d91ebda34ce6b69a05bb89cc4e7232fd7e27395bee017497dc7f95b48f4ed6fe6a9d63fa321b726b0099fe4e96c901c8dc3da4b92065cdca526c7cb206653db76e4a22cb9cfe4ed6be3d17fcd9f83450269bdf5bb7d099824d6436da5ee6d33cc89a6c525026945b50659751dc4ab2c5b68f5976896ddf49b41ec4b6ef24cd850fb1ed3b49ed8105b1ed3b890a435468b9bd24f30c24bec4727b49808851832db797c4b900e1045c6e2fc98e2225b05cd946156374d1e5f692e4e8e1055358e0e5f692482286d8c8828a2433642cf1c42995db4b12bb28f1032384f8f225b67de32fb797446506194624e1490d56fcb12a532cab4d8ecc167dffd60ffd160c4f626c631203f7db3791a163f74789457518c5e1cedbbc93daaadd3c8b35ad46b5d9355d59cc41f1eb97fd2e9572ffa4b128f7cb3e227c1f11be8ef823c2d7ad201b41599e48add3ef4df815bf92fded1791cbd2a3597a9e657ce54bdd5dc618636c7a5138df94cc9df864d369fe5a27e24ce78380be2ad34927a5ab1863ec016debb8bc393aae39e6883df7c8d7a594ed17251f949b8c6db5229e0843fb410350fc5085192d68220aa5f86d4570c516659081c589085c6cb094c4952cfb729cac1b57dcb827a498b1294b0aeb594f24cdc99a2921bc5862888b10829086942f8a2f8630c41b5c52f005f5a26eb48a123135b58f349675ad0a103034954e19a352aff2246686e3869832fdb90f2e2930c10a8ee8e28317c4a61a4b48d0c1071e884e30041bdd8a0731617c305850aa28ba6f092e35c4d1869af19020d30101e67249715864b61978f688949602176c35054436d40dd5e48420a3c669a5ac3c57b55621a0f0e2744ba5ed55151bb484b01b9d938a0fe606dacf87fc0496998acd79c6162886900419dcf00320627325c51082d8a1c90a1fc8884d168bce39e79c73fa745149c3432a5bb6b8d66505152c9c06fd9d81a4356e0992bc2671dc808b1a284082135954a00936da30411533b4c021a907b5d65aeb4d814fbb518152ad4f9f9bd75a6bad4e8340826d2a3d785a6e2c4f6411c49559a78b1a41735aa1d0e88d7d16cbdddd9d096d722104db587831042a92a0c11551d8a07a51c50741306305570c8184dfd867b1967ae051185165c7b2ae26cd2bbd71964b4e11c40dd9dfe51e850a362f37962092506b248501336f58fe5663398fb542e51debb3f6bb126774fa152b6f28eb65e854f8d809c30b0691c229ed01db938eb490b513e630881294524aa48748e83c419288a03d619020417a6c96054145b1332d4d1ac22be80aff937a40d9241c342d09b6b271e9f7039feefe8419d9fddf45c37f2e54da1ee253c04124061a4e387125661347952a9ac2f0a1063784da3b75a771e5feb5babbbb7b2861fd4f7831c3f8fdbfab66d9ef1461de74e8846fb362990117d7db3fbe11f7f98a65c47d5d29128db3e9fc348d524a29a55aa5148b0aac500a7edf6acbb2ef6b14252e6e5e8550575f0f6ecc2090b0423854e1830d74c084920f94a8a2cb0e7ce8428b1454a1f1208330a2d6608232b82ce1c5131c7c0104082450b1850c4ec0021cde3aadb5ce5a6bd5a20481c32720871e86a664f1061b5fa2a871821abce19445125b4ca7d3afa0412678056ca71305b5d65a61b9d65a6bad730720d0d89814ad51822ee078dac11442242042891be460e8074fa400c1c4f2e1ca629e31cb6ebcdd9df42ee256d0742f28ce66b91db431c6281b01d7f9a6642d193a56bf86568a81803e08eaabe66c36bff3f45a0dc2503bb74cf6f708ca6a7210288b91d28f14b45ff61c6531b706d0fa918f5b41329a5bb62337686568656c6d43c56c83149ad246b9dadfdbad2503711c68258d91765af758db693df97217487bed39cf9b1d0aa5a5bc202ec8e3342da569cf719e06b6b8e7501e120d48d3522c56caf38022675fb6717f5332954aa552b12d8a03f2acdd82bce75ec3409e7dee72dc6b9cbd9a26f380b4cf7e5e90671f7b1e50fd3aad1543ea518f0489ea03a2aab9ad384e46e676b1ebbaae8b5979dd6fdff564be0f859a61b16650290fe88bdff77d1fb7f280b6e7b897f1baf73ccfe3369049fcd2813f3773e055794052d5a53c23dd8c8704c603d272f717a6e3305067ee69bc163a73a07dd917bf641a4f86d4a31490b2771557abd56ad5d2a2643c20eebb6ec6f35ee571ddd6bdc6813f37771e50cc401c077a2babadc00e6fa0acbe6ccd07f28f2f94636e4d30c83fbe3f27615470653657d957bfb60565ec81795b9fab8f721505651fe67027ef380cee1d7c1594b590690b49c9b2fe253d9e92130951ba4f3ae7a494d25a6bad3f4edbf8ac9353762a4ee5e9291eb9e619a16d7cfdf2fb29122efd4bf1d32f4feb797ef7f49f1a9d4041d16b21e13624567b23330001d559ad8d9a266b754ae79cd4bd4aa975146b3b7c31cbec46c35086fdf5bdbec4fef4a76626f14bcdb5d621bce2f657f4987cfeb28392064e548eb2cd35cfdc3f51f0c9bf51becd57765173cab146273acb333e6539a596a71ce77b7cfa8939cb8f475e22d75b6467b1f1a712ea0d4b679488126933a936393951a732a592648a5e7294f229b7278ddc56503f7da0ee39e7ec397b0ae5abb9774f2a29a5944a6b83802608ae2876393f0fc8764fea3533895f80a8d66d378ee3eeb671d603eaf11e7f6d1cbd2cd64542bb6da39c07c9a797ce39a99cd4b64eecbe9c272596418bddf7759e0cdad7ce43323dd0e75f8b9a40f37a41f4e7bd3300dd3cdf6fa62093f8e5e7c68c81625fef67cb4ce217eb511af204bf2837ce7ce720f78d8203374986f2354d8c0bc8308a8629e950fe962ce52c01ce7393fc252f9354d2b0abc54dda822b15fd923f83eb13fd927fb568586da243f915498654d429dae7befc4a83f6e9b8ede5d71954286a52fb3c719364d03e304eb44fccaa89f64131d13ea925da07a97d549f1455207a2b8810edc4645e5697b2fcaa24579079294416491089ec11b27ced0df95b1c593e8784247cc9f27d853bd03af263b093d6910f833d80559849ebc8ff70133c030dd388682736f3171b11f5c4669edb66de3af99cb0f2048d66c04e4116a1e490e54712b410f997d2ff00963af26be6cc8830c8b25af964910a9284c5973ee4cbdb8358fb7d0eebae961879d5c0c195a13efd963fbf6fc6287fca7fe90d74b33fd0cdf26595d6b2cbb86d6e51feed59ca99652af9b54e7c097eadd32be9054d10e3d681b1af3d14ae15837ded91588d032d68fda59a314e0fe893b227a764b0af7df59058b047037baacc02a1bace9af723231fa8b30437097e5e7c9c83978b96931c6a32895f822a05c1160d364c212a351ec42083071463f4ffd1b2cf39a78c16e51f5f8af7b87d6c0fcb795e7bd4f7dfa1ee71b0b1212b4d9ad0f051eebd8f9fdd624cc3dd3a16cbd6b11fb18c7918878f59b973c2640e3fc6ada343f9285c024fbf58c8d2865afbb28fdf8cfd3287a7b6cd8cb7d8ad5d876d4c8b5ddb75b8c668ec725d8767cc63b7d33a0eb535c6ab8cc2edaa8cf2702abbf6f98b95a7f598005d14f6d88d1d0acbd895b1a59ca8960606cd7bb9cebebc40ff0aa0eea8446cd9a97a14325523000000040316000020100c878422b158960552a2d91e14000f73b64c60509608644912e330088214320019430801001063c04ccd0c15002140bf32b94354e9cef9ca09c11388f6dabc4bb9d37844dc08dd67f7dd8cdf71f300822fca21b5f12af2d402e0afdfa2e1e3b2f8d2ddf87b2db62853c81d3477701c19a744df5333b8e0ece04be68816ffc1520e27e23469c2a40cfe4c1992234b15286fc1bb6db912056982f376d942c82b24b8eb672c3db5cb771d29d8455ba4e4abb90023bfc23482da7beb4b0226df717dd8538cf34d01132492b07ada2bfaf747c5641e886ef97bb371e829ba05b7f40670523bca8598db9334004f4f711f3ba993f439fa7bf84e573e74ed33688bf3cd8c8db435149a07ca7d9471611568fd6050e02a2a8532461dcf02f05f4f19aab1593fc3d5d7332e150e741d1f9f0fe1974ef911b2219f14de9c44e7b8c2153c24d955333a84630a650e3d25ad864bbd89153392e0890a9f3a9508417dd8de48eae70eb0fae935615d74c75b8709c9c4c2903481d56fea2ef06e9fa0bcb2a129d04d3fca4658e0db530b0b084cede8e3650f7ff2f4b6dcdcb33aad90a5f559d5550dc55d6842c7fb2e6239416fc022a397ec995c82473d92360802345df98bdfa842733581bbbbd8ef5b9fb8d9f3309996547f71a674c484bfe2dbfa64e05c155ae08f15f3930a9ce97961363e125e1976de844253024df49562da58183a4a5ff15dba24d4fbd1be8204f0144a029626dec07c5f8ecb5429b0ed1429451cf8de6c9f635f33f1050bb3b3fdf0a57f0bef8a027cca498654c3675c592ed4fb3b7b7fdddb901d12b8d565dd9081772d75f4e32c5352e7226cc8e6ee8ceb25d898be97c104b4414e9b0d6c38073f76e1e6c097ee42422fab0e9898daab4cd5836ff05d4842a610bdfe67ef8707d11652577c3698b583cf063dbb4810854afc9416920ef4b7d982eef085995a16d4862f1ed4f221ddc3a5e716847870368730518b02d970450bb420f8045f18a065d12db806166c71c80cf0c2ceaa75ebbb8cc9fd88e37141d444e3f29dfd588c78dc0027983f11366aea10fbc54b212a852610f446adde19068f05d83800311a7a515134b7fcd183f243247475c42392b9c274f3fc21a94f92898639ba3c868c499213266df8eadc980b760c334f5db4c8c4d6e15ee254a9e20eff052858695bcc1a472fe126555f9c40333033bd854979865524a508488119f323cc9a5fda31474748fa44158a1ce77462abfb853b6c40de5a5214e4456a7c07a59eb61e738e5ba684df1054c3c9bbff960514ce3a0e85a7bb7df18990e2df256a9cbfe2661dc667a7b1221b759bd36c2daba01bcacf6d9d0fd1e7670373877f0a90da8aa174ed73857113c582435813408fc4f2faa91c60a9f80023c23ae35bb82164c6f1ad32c3abe3d24faddc001784c7168a19b19dbf4050ed97a3cd779d422f9a11ac0c0f48016cfcae54690881481fcf7e20e84efcb4a1f00f42853b5f4015aaab71ef98ecb55a10cf05132bdc0b38ec3bbc0aa211f2aa2f541e38b608aea179d5a41c039b25a1cb682abefdb4796035d96b4a4fb2c8de7b8c1f313db9ee2704b08e9e0c0000ca58e241cc8c5b42aa0df932e7edcd5e64384ac4ad7136061d9b41f8489659c7826e89fc2be340daaccb3ff12b7bbf5c098b1234fd4b93880207ae7561a18f9aa3e6998a149b5388ea2a7edcd579c557849d984217827b76f238c47d4a22698f0c0efbfcdcb624d6f659d01cba30110defed84820d588164b3a54ffcdb7b0a311d32036e1e3f91a8d809e1a6aea93dbf629d8185c6234bc85ead1caf6fd562540cf02051b73cc6928ac7af45892d21153231ae9c81b3044ac04294a8357e5dcfcf91f77e03bb586b60d6ceb6d268b8aeed1ebbf3b60bb939c605d2973e5feceaae4bd5c5f5422b5ead45550cfb444d1fa6734f666d845a7b3a32a6aab3703f0640277fc26412feaef79f7c67d3b0e59c930869022d0b3fc1171b98968acf0bb7625dd2624219e1d843e1583bbfd1492f7c0aeb9d124beefa37e176731453a584408492d83dbfe5abc21690a1347120aebf7e8324432e31b411b203cef35017e6410b6491730c163ab32271f7de7ae868e825fbf71f84f51285774d0ec2df8b3c34be1ce9f6f776630cf575e410e17cf15872ea2a1498fcdf709789a08ce41eaa0a74bb5f1f54b6da48a045613e97ceb7efd261dbf0589aec82bb060782c70ce706e0f783a8cb317821147cd6e56f350c0352d26482aec4b51f65b105fa62eb4db179b2648c240b1b15894080086ffd0b02c87330808212aa5b6fd26a525d61d9d69bb0eee931559229af08811c5a8f886802f403e0ff7b229e05480840b56e34950d14233819b94e546999459517c21c7ed6df12a401dcbb2720a6a44bc1cd44592e218bf4ce5f740096959febf49851d6aa00b80706c4d3cff3bb0cc84b2807f26a79d197bb45f0796d51a8bf0b767fd7814af582b7a2a70a442685e3fdad104999b9aa7337944dc0c1997ae9d1e78c53c0135cc3bee16e57af8a6bf2f617eba18541ec86831d36c08840885f35ad9eb5b41eaf9a02f47a9f836634fae621bc69a138dd437c0d5398dc4857b16ef1afab8257d8436974aba84c0a6861671623e02d3f917463458b19b251e5d3b246522c4d46003f9802eb5ddca2e429a6eb5d57cb6f19f9a6a6191a71c8c614d26eab8dc75bde503113235acec1055869438a8fb9cdffa015a3e5483a07d5ee47ded016f8ab3ef42cd24d5d1056e5b9b674c90595896a00b73357867c54b2c1f675af9f7229673fc52a97fb97c2d0f0d862167a3b66f5d112e016a404c5b4b920fdf7a11b7b05f553a2b6d8e22c01d6575df7c84d27bef465f64a241eea9cbbb87ca780954a2eafbef4932b937c9da3ba6705034921720af300d15ac8c620ddd0febd6c30603f465e88af81452e4e2c1b37ffa3b51c01617059706bf7ac15b2450abef66c98d9de7d866e3fd458d0666010df03c5cbf92a7f81b4c0d3606624fbac0701cd897e5f6d793d195386c1cd264e719b4ffba6afadba0f7dc8312a2c7b10d8deb997829ce12543e2b41714da9affdaf5978da23ed998b3ca192082617484f24d8eb381773e7ee7748f45f446ca454bd75dac8fd51ffcaea2d66e3f0c9280b1673b58c5f31826b69ea36e61d36601087401c9b9ec48c613ef96b432c284f528fbc7912a92e76e7004d63de70f9323af15fc2d1ac86254b4d0743b2d46e7bcebb58bda2de36dc1c346e24eb345c7acdc1d180685e9b081039ca38c970d65aeba00dab0b645726a0d7fc26bacf30a246e5d07552dc2f769d7e2d43e258879e4d0aa9ab572faf2b94036a4a134186d5a4eba0bdeea069c372fb09b95999c1488b98446648e944f8ea29d9e84373729477f31a4467dc19996849934bca1e6ed6c0028336fe61f05f2bbc418e128bf1c8490290a23f790f9dfb45fd3d33231e3369158a0a9fbebfcd55565624fa126e817e438e052f6840c6585b3009446252d8881330ddf53ddaffdf1d4cf9563bd5d70add50ef575353bad066a2556af885982f2edd1ce6333572f631d11041bd10198a01ad126f47461d725ead27ff6c6bbaf561231f8d08b10ea794e6d07c3622c18f3053add5f7fe17726460f6addcfc5954be09e90b85107d79d3120d060b64e1aebe669d3cd3100932b138c62382cba0b40c0406481e82d55391ed8a0b4795f1586e5a5b83351d72b0e9e09f009f2a0eab35613dfeb4cd1eedfa33f35b8fdd7460c6449fe11d6bc009e21479b43ed9df6174e6aa42465c7e5142a2123735ad691449c8ed94121f9f992fd8b6f2246ca52148725aa74cc0d751e24578179ddf9371e302f00a15ad6df97bd2accfd451cec96589cd3432cad74674cf029485f00a2fdafb08299b5de4a0c64700983301ac946e24b964117d079ebade7330d44f53f9ac6df50d12d8abf56308f2e86413d8e68b97ba7113f88378144843da2643d4b6ff075acb42b3651fb750899c86a7fab4ffbbf805216bfa90e85a3a397a476eeeb9e005f4218d4cadd9ae2bcfcd0a5ec3bf501aadf294f14d6555bbc748095dab2ad15e47b7a9c6e15aeed5a0979f2ba4adb1ab015dc423547754917c904cd0621e78f0cc561c0349ae99238ebb7ba3d25780584723bd7bf177882f0453274ffeb069cf85f22ab83c772c2dc4b1a195472cab48d9695387d7005474e8eb9524ea6e55f1a1804a8fe5d19136aa27122077aa50b18b3da8920da78141f4215b84fa689317e6273fc82d8a0a40747d723196ebb760967ed79d5776e7b12d31a646507817e7baa871e17021534de5b523c644731bb8366d91906664c5f133099fb39ed0eba5f861c239cb22f59e64428d5fd8a8961fe1f22579bd07ffd824e4984feb973b701243d25da7cb7942b40d844ecdb0e045c261062009ade08b3b5e119db2dfe4323be25d30366872dc3bb1a40bf045797caee8a08cddd36b2c7fe71641db62de4eb7ef9d108a27e7b689fb34b72f3ddd96d02f75b46ea1f89193d469d9aa947a62f7f2e89e954f322e8121918a02fd29650eea9e5998d004f77ff68eaba06cc04da07162a41c83a4ad173011777ea5725594929281b0a2c755cfcb4f155ce624529181a85c4abde160370021e9c6189a6bf041c54304b999ba7a7983fd962bbc6af2e8e836f43a9dc78bccd6d608b0d3e697ca98c3bbcd468354c50dbcdeb714650ab5e469913e966db313f4f3167844737a30ea12803f964d025199054a042b67c4f39396491255fd9435c7fc92c0493c01ed541466592d8a96a3220914c76c3101b805e69ee2e92ef7eb6bb6f2d29965c0c4a2b7c984f13c84182b02cae7c32ac42aed81db276caf18e058b5a3abeb8a0a715717fe9a9558d7cc19e28708f45b74e5a382c05f385bd4030fdf517d3f8caa60d8d1d410e9b8edec0f3c33c1d615999a25f41c23ee29bbeeecc52de728bf9c450ecd1a5e3da697d20a1a8910cee6c01e4eee05f8b109c0aba4e59bbedf9f28ee67d5368ea8c46f43092ec7d7538017c9514e18dd717f0afb9ec9c7c3cf491b9f8e03eb3efbb796331715010780103339a4026d6e4fd5e25810502de214ef8959a0e61bbe8765f19a4a7ee84ef9c04c3ffa7e58c017cca79a819ae1e7bf07b6552832b84114a4fd85c77288dbf1d37066e1bfe8520472dbbcb5bd7be96beb73591a3d2426a3019430408c9865e1f6754e1142b3a6e1340eaf761ed6e18189835ceba3d02d488dddbec1df25fe57b30d778adf8ca4ffa08992624f0d0e30aca2f2f1f775af64cbd44871160c80bd26206d746fa9a902b821ea64c128fda13708c235ba2e0885b2f937f7eb5866ed33bbb416c2a5851da03b91a28feb5b6b47535dcdcaa7223ba2e701d57c3b4f5443627d50d78ec1a920924e3b86e20ce2eecb67df6107167bdc4ee1853290958060b07c439feae50fecc626574fda22d27d3ad7b4479050f300cd3cbcf06906853e47e8b47952feeeb2ae38d3c4425d5550139a9c09fe68e121a0595ab2ef067e71c78c2da228e0f86944d381dd44025b8490e75f9b2a3e61b04840dac8c684be0be405cb81733ff842478df00ea752bd48ec2f59cf083e03ae79934e965823dc9320586a96c28d95c5e3b2c58631000d97224f6c1e285b67696e25e3f966d1b8ef6d8cc9432a3053221f722d3f0d042adb82d5746941468ff770ab4c2c20e90c0f7c57309ebd5adab612d01294b71dc190dbb65c068b6af127333d071cf78edaa9e8a6e79b8a87750044a46471866d7712d5245ae7d204810f96c43048a4b3ab5c0d0080ad84e5f7f12d124a318c8cfc202dcaf09bdf1a9d31c22718c85e5f055bab0f5d4e2bb37ea85f7dd0369bf960461986932595cf853658d0d267ef74da2b8857423b7a7c290bff1047f5e81b6ef494e0e3c5c49b2a09d28c860f1cd4e9abd16afce2b7bd72bc23799661473aa3668051e2a1943f9462321f6876d02c2dee02125131ff4a11ff72f326a41dbfcf061a6b6c7dcdc30ab218f9461b3e7d284da4176284be3a3c2fae49ba4bc4f667b70975e3141841312b3365eb748e4ae394428729222520ea3df91741b72fcd060dbfb99f5274b80b0a6c24fc022131e66db12e0089e15bfded883a284d6d05417d7488815184ffa8ff68869f6ce377f2551164e463fa20233f64bf12d289d01a1339ac242e5d00f1e0c74836aada5b9adad2b18921a28570032bf3cb5e3e603dcbcdca53b85a481d84b1e3f2e9f2fef175d65cfa2ef4c3aaadb5250eab0aa132cbfbfd3e41e469576940e58744ba730287f76e597568c75a7b30f16610a06f3e82ffd81cfb12e206b3573e7e6073f1301303149f9a945373996e89879a3ef87151ef0d0b148860e219bf8ac7b18fe9c9511764001504b01b98ff6318e48f1381026b8c38f87de71fe4dea353d72f65405fe569e57b2974685e322f3589158b2683949318eced21632b43f13bf3880ff0f3a73ef37d592c5ebb905b61bb7bbc9b07321223239183fa8fb9b4cacee17b42f990ee5dc17ace15b62d572630685812671fc275534446aa1009dcc5ba6a5a433f6b3c4adbbc95a3579b2dbf45ef3d2072c1d167799379c9730ee183a02ff454d479cd7cdd7155de48350e9da614257c85b262a30478fdfa1597712bf854e47341807e6889b44a43118982aa5f5c2035109ae71eab90cc1b1d54f53d801981e9d17284b00a03d9519c5764191faa8788f971655e4eba1fc739149c8b2e32431739699b910c1f030a46c5dc95a7010429c29441d0a43c54605c56ae65591fbb4b2990ede48c75171f821ae018e0fd15b424483e3ff5600abc67280afc3cd1c4ffe697d1cf9a6208a472b372283e8f0b2f33fa510a6f264effb31aea43edcc7001900a85aa0f6330f55bec8ce97c6aa5c0453d5010c767152bce625ee77f73a0e80005da8f7d9164828a654d1d69edc769c0d1388ae174742b806877e68a8ded7459d0a7777d2ab1552a279d94d1d37521711bf61b3304ad3475d0071cc792f3a1fb44e98211396e3fd3f875571af3aaf9112060044e814704000eab4e1ca9129485b395eb691d0e7715787de4e7339a4d06c30e638a2b651eaadcfb8c52d6911e36441874fa9f35762782e1771e445275df0c4080db8ac5c9d4e81a1050e6a866ec7de6e440bd204cb33a75ee06ef6f7d1b8d163665de6e57509bcefa0c40013e9235d39c245c86c0d3960ef149d8219da04a3e3dfc84edbf4e93cf7862000ceb10f7b8800b6426fe6b458d695c9443b070db89005e71bcf70cd31f323638a0c69c6ea1267278953829e0774bacc4b9baa95b572a353d56841daa5adf5130a21a2c90f7acc0d5a27581381caaafbdfbde42e3fb8f1b9b466093415f4b06583755c964254626962f4ad4b06ce08d7704d0535d79c718c219ee2cb14448e77c89757ffa09b78e14432dd683856e3648536251d47aaa1f0888e5459fa46cde70ae4ca40c26903e9d7ad7af2bb792f6320346816fb127e2ae41c42b025a6bcaff01b90a20ad115e587cefb6e774383ddb6c2938880364b1a191bc9ff6d532b17f8cef64b42faa1d6901e588842f219441e6d2058af0a234a8affd84ce5bfdd0cbcaa50244842792b2a3e2288a42fff39050c18622791ffa944068c188eba669b44a9f80b89340bf2bab5d9f2db1c5129ee2bca52f362e47dc668b0bc70b4417934c9525c194b7363aa826254cbf4de338655a506f45b8880dc5d31495e7ba63c32897f1bfdc6b93e73dcbf3c98a0d78650913763cc634cb5cec203874cac17766fc0f7073eef9c1ef952cbaa6aadac319dddbc4140d5696e3ac2410ec192d14881dd877d51411d4a391ca083e0501efd79ebb7e47d102d6ae08e501420473816943bb4f730293443b9f213f68578e7b98515748d810e8cb5f817ab747ef60eaa61c903d867b5dd0bfdd7b5587a3885a8cd823c34b48bda3d2cc24dcb89108d340170594b4110a90cd7afd066dcb182252689b141b9ce78ccd7845609fd99f2710aead56b00887f755c61f82f84f8f4428c0f07a0cff0fed7c768410630092acb38ef203c89bf6bf096536a0115d191e2c58c5be47022d7753333f70aa92547207f7360eca0a14e62fc896b9ceaaf2d066383dc4bc8e6e913c6684f4bc55f8e756f6eb8ddd79b1d10f4be8b5429117e770ae3091fc687728bd41a951c0b2dd5828f1bf62ede448a56119aa7867fbb6b2081a363bed29ed670cdea02db641e49c446ab83e146d90e9e19c4c8c89aaa5145d2cd7e3702cc754ab7d573c10a454d61b0c69f8532667584d97bb23793c22a646ca312cdf3ef0f82d3b9e9f6a3c6e88e9d160df47f06a943765fa3c23ac9b0fb829a8774cb200adaad7a6f229c5058c31883fb8d6a97cf3133f004e2802d9c4ef0da14e615745d86fccab054843485db67d45ff85b5f696f34a16095fe32efaf8893efed67424619a847c2fdf8e58c0be8f57f57e376a90045dbdb5aa50ac027400ef5616bfd90105c887912d77394662fdb8dd71ef6e06d3df64563744799bb99bd92e22e78b0837073ded2e0fc547d91b4732335e0079f481ec1bec60db0b6e48968a2d48d5437b74681bcc6971fd46fff8c54c325748e85d4eb891ea315e27ce38124667ee6f325a6801eb6e74f2895cbd6b5e24accf70725d371d71cc7e2f2001dea30493c4d80d8a7715a0e5b0b6bbe7b57a894159d5473eeaf14005672ac6d5b5fc3e5a6592dd300c965eea1a0e958248fd86796c49bd524c68f716848f78a97a396cd6ad9717e1d2ad81d7c1da2618ba1ca354bf7417b1c00a12a96615a4eb09f20c7a8e764a33a8435eca85f9ce04b611a72bddf2e9475eeaacf73933ac154b8dd8fb5046b03eea6888964bdf63a1cbf99503e9254c29a0f4365244ff9958bd93564bb04c5cd3b05c2fd47cbf52cee5580d31f79977b751822e3ddd507ac3193d79c6063762817c997c08053de7da4caea373cb4164b2781358c40d17719719026028940aa53ace41563cfa15892bbf962859a85a40f191104575628db88b95dde57e0c52054e6568af10b98d1e6a0080eaf95dac5f15ea2cbe5835dc0a9c8f68cda3b0c37fc3e1189314ab65f96af3207f681ef7599c8bf4f5c565c706934bb35419f3721d6e22137866da7b2794c0c0341c9cf6d6c0e7a6e9452ebaf2cc0f97e75e01a8687709378599e573d1149b8835139abfc24280e5a971d5334035074f953d03de8f1d723a26ddb5c2f9855a220c628f73615ed5c58dc930123ea7610d7c36f73ad3a1f050847531f2ce088ce9c90aa50cb0c198e85af5ee70373671857c89439232df082672a6e57535a8c9843bae3223b6e8af89a03ae8361d3c6ad4582b638f8c9102116d365921b296ed6e8666f317de8ad4bbd2d002dcc6517b6f41509ebfd2391180ba883ea9b3d2b5ac6701a48e488e1ebb6034fc03c594ceb84067b41e191269e998571defa0553ff6280933b31881005a246f98f9950f6a4847e36142c0b5bb8232cd084f7c2d50f13093359529e318c017dfffb482cb220a93d347cdc124f65201531e17682ad6c7a01b90a9e1a26cea526b3608780b2577c5ddb781c7f4a123f5402b0f021558b7bcb2b3ead9591f9500cc8b54a083cfe040182f903003e4fa2c07a1a27e4dd240a74f928865d82dd72a1090413cfb2b4902f7ef6b32b8e7adc19752c21e73bb61e5b66507c37ced8acc3123372eaa8b09eacb1e9370408316939625d9dd33b88445ee45ff088906bf1eda45204ecca47dd9ee50023b6e95e3001581cf9c907d69ab91ab2210d065f291c2152c656a3f6e2ef082a1afeb9c057a9466e604e914512bb79b68d64e01f93315a12be99a309b8b6214760809bbc5c2dc0dc150d8da884dcb152618827a9cd761fb2d92b857e5293e9ff64477dc4810287730261ca920847021e80da7ce9754d188782c86e2fa882e19796beb7c77caf3938c4ef07399c5489f04b4b2e2c32dd1b47fc521ae31cc6afccf51fba4268ef6badaa46aceb770aa6a2bd27cf088fe86363e63dad885bd33ddede44c89b720e81ee009097fad116fea8f92ee51fe3c3313adf2eadc2e7f945df844625145a84c6595c7129896990a4839af306a2a3a99d866fe2f60ef2f93ec1fba9c4c1cf02232aa24d34e4ed1d0a9a83ff198b27a6f569402bd4815c866650169e312b2b1821a0a07e59f7b49e334bf7fb5890545093c8ee7665420324eccae8c6fd9e814eb562f8203c958b494adad5f34923bd13e24942ee2e3d3d772c59dce14c3c8632924a0ceda5c13442bb213ede27839e6a17a98ad33749d7760b0979cedfbfb551046c4c522030b27d23d234cdadbfc36489d1db7f298194c0f8b908f5293a6e64686d9f8ae575193b9228535f1732fa2b8f8a5b2f3a759cbb54342ea4853d14c43cf4506aac4b5cf4d3d5231964997a098bc7dfc4fafe848d07b1ad500ec25d2b5a27157004ee504e2c4cb9e2d0144db4177904095bf49fe708f6ba53c4e3614510463d57034b9df713c0100d78510aaf03e4d0e083512e481d77a5de643f4ff1adfffdae0eb885654659db1044b324567a74eb78aa5a889b93f6632c3cd34e64019d4e450a85530a4ce145116915f71562389b4005b0e06dc4a4b7a1c84c8abfcbf9a003351c03b0208a9edd7c48aece37c706a568ae9b2a25513dd33bd7fb7545726d66851f0b6b5e4a940558645f54ecee56e9f1fedf1309e3c5b58cd97521ebeca3147019b78a883f70449e8b9683f47fe88bc163267a6c99d1da1e97aa5609a7660158c11c5020cf5e81c415943aba53174f954b414ac92cc9db24fecaf51af5c77be74e0a1a936ed34929969effb0ff8bdca0ddd3f23fa1c117719abc73c3a39b30ea5bd78dcce89e70072dc5b443be21725621ef8b182be4f322e415f22c11740f0d4f849a29a432b10248ebdd2dc02d4b49c243047028d88547c86c7fdd79f22cdd1eb35e7e1729f319deb3bdeb4d963e1af18501bb4ac7f92153a2053b6f29b80d5edc534bc11db3773d6ec66157d88aded24b7730e2f9e37df396b586b4aabb96ac1f675be5e13d2a5de27a35d9ae2be04ea3bd177cf9dbc260b2bc4e1c65ee9ff6528fe842008a91c86991db18f0b02fdd7d1221e762e070ad1e1d5f8499acce0999594fac2e1c1d39d43789e64430a593037b8599c0a03f6fdd4cc021dba3e88fd9387568cfee5b33f41e507136340c189f1e3370485f1e5336dde057b6d39cb0b03ac33483dafa4a2c7413edffeb4ad51f8fe4af2a11ae556254ac49010444fc0bcb6b9bfaf475f8884861b5083e94a6eb4fad8e7ea29e881cd1c8da464dffdf9d19a5a3db67978cd38edb7aafd0a2c44879ca2d77b19508076da166832329adb5dbf0171c5e143c1b7a707d81d267421cb2fc136e1e4e9bb3ed5606673fb486521f65effaab64b2b985fbc2dcb24225c2147c87c65ede43f1725c2b05a3091c049ecbbc63fe30474246536d589cf2480148f9d7df357be39428903c1200a7b23d73e5afe85c3f25d71d5b0fc4f503a761683a146facbdc2411f0956871765de54f0f95ba66208c50db79a4c0aa7a02c4696256d4288819e35f6271cf107dcb9a6288ec9ee66aa46c1f1883c29e9abb03f60dbef2fd93feadd0cac5bd3e13d8db16bb8da7a3826baab75e4783c091bb163dc7e5c2c57c443fa3addf3dbfce24686d1f0b06be36f68deadfde3b2153e38b4d10a9251f540fa130eab13e21646605859dd42601b488b432641f0da7d31ef05af031f8295f4945dc3d0aa32c8991a827fafc28efaccba0bc06c78e634dc4c6e4ccda0952831c7b6472658d916a3d72ac9612c507b90ab75b209205360bcb085a9576b0ad2f630b448d506bb417539c3260bbdc808be2f4c39c28cc3bea7c090262c4d513d38cb415522523adbbed11518df0438365b32d3cfae9a3ca6a0de7067870d9c943704e69879a049ecb9448952616740c274637ba56823428edc0957ad8ba7ff6e3d1af3fba10f8387e184a2bdd30657280e5ee8ecc6639202af6f0f51c4a2e98e16b6ffd3d5e58c1e5758e6612d072b375ee35c03d2878b9ca72042c36537d16e31f3b7f810c143a3dba6de4e9937554a188590dc0c88114ee8c52a3378705518f995e4264c720f1c8ea91ed602830f3e7370103150018248c136ff0825c4ae8e39f67308590525388fdd051d420823f938c0d9781b6d31142be8fa4c6971010c052d75d829c5a0c58c3ce0c16c9051844b644736b8b018e9419ed05977d42f9334ae851625500b4a8da2bc382209432f895a32d7e5df23afb248f6c1fe02585dde3bbe3a638b2d66488db05d3220d785f2f01552d00b082b04f08095deb4ee202097db9d100439bd144cbc6f2d72567cc3e02ca9958aa11694d7b71c2f7cc25088e9ceb391fb93feb9e13f5e1755d0550960e56adb184be90069b67f0ce6fdf02a0fa04f0ccd2b5cb578137299637c72b234b4b5f6697e194ecb5cf9343f14ee9e5badf224b5af1885815622735652705e8115743a41135055902768025ba77a638200c3979882f1b95bc75f67a57d6ea2e9aae5ba04c8aba422da274ac016325a41b674e9cd998371f1fb9cf7ff4ef9e3167f9e68d1be7a322e9af554092ca248fa306d9b706a2e82486e6f94f520c7f20aa66a2e7cf4d5cc6fedad3a185ec6544423fa5d7b623e02729201a7c741c27e1d2e46add9cf60684d13a603bc40856c36795b64f21811c429e0a9e3c6e43263e7a7bfd727bdeea4055dd116394d14c1d2427dc06e2c7d1b75074c7ae0b0dec8c4a2c84846e4dad4ca1a9143dc465609a5bba77703f3a1bc77176a74db79582ec407b99021792a4e2fa641226ac45737458761887ba5322184f17abe4b4a578e5e25550d138c1d695aa102692b943d49cc025cf97a41a955842379d3ff45df4ccdc432af29c709ade6be223110271009886c48258523fbdb5e01f8772eb5d594b909046a7576dacceaad5485ffddf428e9739feb390046ddbdcb514760781dab8b78ff5a4f8cac1859da6dedd31d027968625ce1ef1ba7c07586644e6c8204926995cb1bcc52b10d9c59810389841154dd34bb863b29eeac807eb16862c25243cbc3758d88dde9e410bed185a7d5bef18a00897c1c9f01bd6db035d59fd670c7b513a801b11ed517aebd41fcc28e98830d8f02173597ca914660f786f4b6de33308b9944ffa5bdd4e5f11ae9b87acc47c7cae1266a503fd6f1884d5d06ca1a9c61dcd66687f3f42fa5ee8440a6de93694f61fa0b209b42be9f0aa87533409919c1c2278852c042a447364466e5ba4db398e0d4c5331052df374668c9b137ea2403054318e731709ad82afabfd46c1523c29e98af8b7e7d4f38243e4c1c224fd91330f5b3ec53186cdd0c8bfb942628e92489c57de634fe60fe6901153ac67d90a00fa8b2a17ab9af49f0dfc76426bfe1fbee71faa9ea524a59132098fea2c56fe7cb024df0905b8dc66aebd4f3b069423f8a97c33c6ba6d88e622db47c0d842b16f4d05947d6fc8d76800a55e59b0303105f4f50d1b370da919ed707b5d043867e850bfc21fe77b785a3873ddaad19c5ccc2324ed9124b8608606c624760ae3e90e57fab4804a674ca05a9ac843d5d2e64a410abf241a6745691ebf646045aff89dc877c102ae0bab61977cc7203d4ebf8b1c0bdfb13294782ec80f90a1152bfb57a7151d5d0921962ca05e41145240a10931f41e5190ffd433043436155e14d6660e3d711150dae6491f64efd87f5e7b2a54e5922fa870a090459c2445aee983f00f811f585b870066263945a63f6ab1d105f284dfed882474df28879c370a002f33c50c25e1b2d6d0c06baa6419b87ce07e9c2e0220bcb3581402a55a7eac4212169e55575f14ce7ba772c260534135d94ada861c9a42a084c2adfb451d8d7cb8e09c68aa2156a4d98546eae27d2b03ba653449ca7ec57eb6db5af229702bea413e2399a53d5a023439c22a373540fad50bba5851f80185c037652393d8ec2d782df10a2baccddd6a4750b9e4f1dd304fa668ae22180fa029ced49773ccfbbeafc309e4987cedef451126c65e1002643a831d309c25de25c0c30545dc90320666fd887e6297f276c7f3c11c9c00fba6d12540029122237cba14706a5a62e66a0e112bd7fe071e59c06f71ce19e8286c67b81fcd3256173c7b7ae18d806aa4e9e15330b39138fe3d6780de73d333cbc74898395de9758ae641cd8d3ada2a7ef7cc8694237cce641a384451be090cb9d1a07c2ad02fb370fefd4092a6d29011a57e15920e0ae605154e2e9d161489a74dcdd3c788c20900f2c60b2d0cac09a1367d4aa112d8355cfff40e62c5df24a235f39eebae969f4a2c41cd2fa1ffcdf50d0ac154fb67ce50f3ad6631b74d01a46e68b5e3e5b6b30be43de35943ee30999e959e220b7118431629ace5467ef5e0b140f02800dd2cafbd5b95ffd0cc0456d41c915b500b92966405e2b02502f7e8b265cf644ed472ebce8e5338abe03192654c85cd27725aefa93654e215d05bed1e352a8c19521e922846d4dda80eba53e0dcb31a2a9b60f547ddbe054717b0e4175a77709802d41f183e29c3be5226b371426a93e11552d1130ad83bb0ba0fc54052c27bea731a788c67c3e70220eda6b51642e891435add0d8e6c1d941c1cb4e6ead47bc935cffd12a51312bd3259d44834aaa65af741c3bce950cca73a87a599975374ab63196521279cfe9dbff112fe243364819b317ca030a5b9e6a3797479b3c8e6e228542714bc51bd62b0596df5e8423f08aa0b14c8f5b0dc52fb0b4065f809ef9f9aae67c9cd88cfec89eaae43061b7c21091099d85d2e8b96510f19ccacf39c42a04bd64dc61f3252a5b4188db361057402b1c6cce9e1e8e22218b42058dd937dd954e8da856d17de5d64be883a20acb0d6cb6a4021d8006aedc032436c7cacf1bb22b013b161c7fe3c867f36013e317ef49f15371c30c08392d0f5a54c089cc80d00225fcff5d23d202cacd9f355747878852cc3aea686bf213f740f3196751b9d57aa929328f4335b85afa3d6303edf836b341c82f87e1975790a7da185680afe28cfe755ceab7fce044bd950977022d497c6f9ffee6a6bb054fcc3c496796e8a03afdfb23c5e7a8bbbfd359d40e08021fc764e5f1919c7f889f1c93a7dd57278d154565ccfc4289ae15aab00fc63d0cc5167addfb36325bb9cbe92695cbd87c433792acca07ca1da1cc45cf67c6b6fc18ca2cf2a68f3cbaefe7583f32954627bfdc82b35c01744949535355c1d873d9dece4a3795474502e2a0a4ac3222efbbb2eb5f319899be1fd400ab0853c3f385b3a554019ccb70e5fc286bf3d754380b9228778e2f940afe17e4e41e42a008ccbc75d04050146f5f00d7a7364ec877db3258c96f58d6bf9723b17ded0bdd7d5ed6f910d5b754c244ee5787e58f47ff034493ebb71c0fb1ff83c4bf37b98b4266ee9737745412ff1dcf2d52409348ee8647a6537d2c6ec0e7dde2504dd44aeceb1722b437096d2d047c95fda795e2ee18d5d6698d6433c9662050b0d7b25fd9f682e24be99340d8716cfb079147f895c719fe8e9fa9989cabdc03acc2dfbd4248738533d59a34a3f56d0130547f332b800d0c72fa343c24715d219cea330bfec53132c1f3ffb1cb3bc6427d503d1044624995ef7dafed1be5f9843a5841f7727683a87631e0caa17c39feee6fe867c6e50772273fb2f06b80b0591cef477a20252e90d631b32f9c80e6a6a4b12651861fb75a6a576468583c4cdaf67dc93f3d75c3ece2741dcc68297e1e3a6c6ed8c6b15d200853325dbb50d5ea0a02ce7ad2fc7dbf79787f7cc2f01c136801c5e2f82c0f449c443725a3f5e477d55e1c25fb15d46dc36ec2c8e9e44f2da7492e40d89f1796e853d1fe32a413bb987cc5af8682173bef0d90c5360d5fbf9c1020def9fab3b8586cd4a72538c4605d7b633db62ff6c9332329d36fda1002000119c8352810a640b229a8d99850fe6f729744e07a411bff33b6fa16514cd3eb34812cfb36db704081a0b5b40e94ebcb25f11b1c4b36afc4ab394247e32277570b51eb8df94ad74f891e1eef9c9f08f0c0c2d40addfee33608605321dd7985338c6d16d6b48486b32d364bed87cd3c594625d5351fb7d85d28bf73cb340788c740ef2e8d3030b43f1f9e12b3d01f39de893c74e8ac9c909830532f4c3a8e46b15597d0076381b983bcdd31c46ebf6c840a2a562918b928583875c3b0d60e69ef8783aa5458ef4228f5f892aee01d79f7b00d0b886bcd6bd804c08fb5f010b53dfe21007cad06c2526d757707f0348020fe251b74326136276596a78ca1c00d81c5b24de7700d1b7717374459f126d321f12357aacc068ae884157d819631214fe6c2d962f42f068daf2d5750ee1ab818d7cc5abbc7f0b0eb3090201bce04d5dff43b482b1a321489ba8fb4446a93f0801a0881d9e1a10aebefa6b7b1514fbeedf091882382e8069e4eeb37827b1ed64fe4d9c5a4affcd9a984dccb3870fd2bf0f5be16ea2f7205f8e963e051bdf0164c8354220e327d305121042abfb58f7ded59be899ef08e05b910f0601b1fbacda2f125dcff3181d0b3251ffdb7be32723bf65544988081724f4e004c5de380a63efdcf9cf7b7459bb4a104a3882f7e64555b28329bad2b2ab0a33e56a67c981180a227ee9d2a9882f2c8fc701f80a70d851f6cb38811a03178aeab6d89e15ba9bcb0d5a0861616c1e7db7c4cd482b02c9bcb4e73a90d52d0adc2b131511fa1f3c19b08887168ca85981546d3dc00d9c947e5939eb68479811405ea71a605d5e5984dbd7322bc62e22922e98dab086a31d7320fcaf070e66e9ec0ea987796064f1b946d570bc81191e09a81887b8795c8ca3a3446665eb4b17b7a2c64a22ed785a8f6ef071d0b0937e59e862b583ff50c74cc8007bccc2cf41a6a9134bb397ff751f03298feabb24223e01f2a838803b0f667582b2392d05055ab88452808f2b99a310aca55436f50360203b964905d8e4f8902cfa56b76dba4d4c2c29fc361ceaefd339071af087db89c737294ec5afcb6436fe137010cc463ec416aca1556582416e98d1acf105033c43a99063720eb64230b0370c2d13fc7b9524fd984588d12b2ddddec7c46b2b2094d85c6020c299ec19130498c75a2988e663533fb4c085a632af9dbc51560298cc6e4ca606dcd8d5d10add4b107d56c235ea3167b025b9668f0baedd3f7fe80be54e5ed8549462d29e5507b4b18a0ca6e443af3c0bd38b5eb29e5d1f5952f17262176d343c15a2caad402783f9493ed86adb252d29eb8366091ee0d07dfd5ccb7552bba4521aae7bac78e273e9f900d6babcdddf7f3f4c29045eeb0300424a18520812a08fd342acd7c1685fb68ecdcf5171aecd5a22aa0519b1faeaced63cd58d9480df052b4a1d14197143cf54130aa5c84deb3410539a905a11fa4e3a8eda71f8ea6b70e3f9eab0fda0fa981295ed6f408d038df8286f8bc4267bc9e5c4592151d3c432388ab48bef380c48b1bed0dc3b96131c403a24708278ead7a88d7e425abc53e00463fad0792fd57f084b758066113b10831049ed93b80e669e6d5044e2bf04cf8874d620adbc9eea5ba7fa8e7d59fe2463e5f94e5d819f0210b5e7388bc4e78e299765c9bb801530227bd781b845271831fa36967db08b825b41aea4d6ee2468b0dcc07c67700966b5972a5b5aa726e07da48193d26ab4e03e3060956d8147231251036ee1879bf1fde46116ffbcee6ea37a01ed3dea0208dcc6da4abb793c79be67ef7f0a73ef996889f497b6c6200d18ed60301f419e9c4bc8305bdf06e535cddc077c07ea31462dac14681165aa713ad0c2cdce4853afaa02cb9db37d78ed02c7ff166395884d5baafa88f0dde7644f57a8bfd358b17f6608f68f4a6d255bb805860ec6ddeb3acb9b78d21d715aa61f6168fecdc2ef6794cfd989eab2f44a526e447266a3295e8fb6f7c24b7ca15cecabb36c70f76505e8e50caacc9f0c5b2e2943442292a47974412b9a1ea4192c80c5ae93627062a63412d96d18d79dc25f75cdb1bd4b8510a7930ece299579e6df47c2c44f52fa42ea12f79761ef74e4806bc23043436b02cc53fdcd25b1b455969ff039a26ecc11da08385121001c405f9e1a45c6e88767094ce68ccf3f2405f4cafe1f9ee3ad09afd62e7e58ac9c8d89b19c23ec302fc169888e4dc64940776535412d1812d68166f04df5eaeeb9b0b91bf618a22f0108217af3391c047728e52363734de5254a49aeda410ffdd4e19120edba16536a2e2f841072b00f625787158952d6ef026054d8df430676c7e8337a81cc5a623e82952342ad511c586887f2aca50e653e0d08de0f9866075f03b0c579e792cc7f1453a6c3ac920467de49571f5432cfeb84546e138be630caccb62c22825090fb2260318168a53685609313930215de9eb093603497fcc5166b8121a881bb0ef702823d8b195644240fe1e2c145ac9661c7622aa2286332f9bc24c10c31cb235814a4fcd3a9b770ac40ce66bae61307ae301efaf473a785f1329b41abceb65f2c8c56152cc650c84b1df90ebaac816a4b179ad319fa9133fd76d550ba3c0aa40564abf53d2617e28d53a1e4ac058c6d3d410c4df38f3b8576a010674c6a90565f4ced0554a73127135d967d7540ac68deb1affa736855bc0f0a65f9426ef10d0abb1841b0803d5530530557771dee049580799beaf8dd2873523f3b9bb90419b4f2167932c920f314a48e088b64478a5cd5ded168ea13cd138f02687909b9d5ee18c27c71a63607e8390dd84501cb9bcf1c2f148148c29f6f5c12246173f19b98df66a148056e152263d2b8a8661331f242b9185dd930d5b434b2dcbb2fcb01dbfbb02254a1342e384489f3f3e785744a002454bd349bb4a8ef45fc3c95e62d07ef0f8b511a71a87d095ce5ed447765bc04e5ca06b70eaab656cbf80d9cb71be49c2e24805b37a16784537180f4a3da738854995a88e10ea40b3e19b8b6e93005fe69f90ad1c6846e32b5d59821fb206c4ef0384d501226a2d0546411282c69fe56b02289f2f11378598bd70e3237d3166a9278ea49f89ccc289662f802ee4048ad5b23914e24129e595de90a17db434212f7c5f4e14bb913fd34f59a9a56857fdafd2a7cd7fc024a20cd998d55579c81f408e1714217e949cae349563dd4161868b36c57aa1ad78f6a9fd718da2f3fa1de4a17c3d8bed2810e7cbcf7b01d690e1628f04f8e75d8c30785440bb5507e69f145aef67066fd6d3c7982699b6934762e89f48f4f8a7fbab870a15d4dcb3532080cc4d7212f13b9c59a20532fb27a52571987386a463c12277a5c6dcab2cdaf0b3553ad99203bf996ef8d9d9dad0aafc639f9f47ff7de53ff3f2a368a4afcc513f47a496cddfdaa038b89993ea3f1b64aef322468b100b7b02b8ef3df7b8f79b5ab08d4750e49e54c9cbde36a296a05c5785653109ba826f0dc537386ef84ee586f26da2492f7c23292af8694df5a7fa3ebbc2811eef2bdc8d2f14bd3e80c53de7a2915ab254c438049de574e37bffa0584b8a6cd748619f9f1e073df5dd9d4552880ca2fd16fb5dded0426171d7ed32404271f8ee8730bc8b6ebd5827a216c88c7fa9496cc948aa656ce734fa48409d90f74466d87a09151ee674eecd4b1836c298b1b6cf90c90975390e8dbee7b1626e69344eeaedc56a1419ff7b78324f1f08fe76094eb0ddf711f275f0bc406af5da119f4c7c7cc98ce84a0a41b57f5ed17babe40a0fe502151636bbc085a5fca903cfbd2aa500e459f847e1d0a03be7a7a9382a59f11e062284683aa600be84a844c5a01adc4722d20e72f61f123a4a841cee6cfb5227573f1842b7650913181eee4e45a7e0c7e974162deaf8c2313ca4ef40d8759251b4dd345431487d915162ea2e1b1eba6e2f41edc005a72d8962fa924603166245bbd5a223a8c343777322e31b0f11eb40ae2674990b0533c839cf45c4bf19166cd14b54665e4f0ebfcd12b045290e0c0ca38bd8ab45d1dec655bf60ec5cb70d2448bf08a7c5963006371163d6c0f31740fd52e52a08fe089b7278adcaa50f959789f02308423cbcf4d5f8669f67e71b79b0336371b26bd41321a71a147a1d4fc25e9367c18887b73ba2cc1243a830d4497396f6631e4814f7333a9c2cea727a97c7bac4e769202ed6793f12f5c80d6b0d661622ee6791d389eacb423d12b16ccf16107dd1061810c8cad850559c170e6a39e41ca93cd5d528fa989339d3807c30f953efd90f554c548fdb6fd7dd3cd54a89874b79551d9c564bdf5dff9ba065f6459afefd2980d69e70d4e0d3703f6beb33a8ec60823c122a970d688987cb54912c4513dccec98288ecd6d9a92fcbba8754bece3b506e90e86404dc0112e33c25d9eb88cf2cd8cbdf24e66831389cf45617b0ee61de4f0d48069ae1b2a591803a16a654e19794d7848f976da91b9f66af16e0e989f01c58b36e43129c7e22e6674b4bee06285cd4564610ca1584b3cca3b79e6e29c1fb5911814086679c18736881316dd2c1205ea3400cdd20bfb5be75e942fc74f7adb53e96d87b6e99d8cdb6ff6cb711e33a3fe53d63509b677fbbb4d0406fe917b9ca843540cb6a2cddc778789a0c3c372779dc43abf36c5f07a26a0e5b80b43e7b083c1aae1502efa91f83a754e49927dc8a07ad5890f14a87e3f381ab7b351f60cad23452fb2e25a5c4d00cfe4c5770b52764e32b94420d3132a86aafb9c984dbb025ade25f78f93b2abe9be00e715435ede8673b42d0fd9a21093d9f1145d1a10672b72ffd11397cb7ce6c707ee97da44ce361d7ffd4cd11715174e4620962d432fc63bf21ebfbd9e570b5cb9c9d133501eda5a1a6f1b0828a564816ac688a52b88d404b0b84da38e25bd51c0f0b63def89a46bc8930e9c003f2e16d22bca0e0bc8457fd1122936d94df94d71454ca9f54edb5c14a65b2aa0dd4b7d0653e1ed2318cb2458f9b68bcd8e970da9f1399d4e41f3f35dd3c1cdf02485f11d24305590d43784743daac5e7f062350b3dc395250d04c94656d6933a0784d5fa417f270f10ce99c9d135b6a2531b6e392e8c46c4a13b8f60828f230ca6f6e0bcd9fcc9fd2ecd7b177cfed2f07a5f9a8402d7ce2fab3eed80360501fdf36f39006138e480b2bf713bdafa6ce494de4b5b680961e913c5467a0f75d7f04721c7ddc196b00903ecd6e5b76e4df2a76cf1fabc9436789f00793a322276a7847e6b9a3d043e53d3241c00b9fef1cd83a59ccfb720529260f273c980836898a54f9e652ac13d9c4925ad40eb53b9ac3c3d465e31c689387a52e9f4b0d59c12f0e555f982448d1a2f2b182080164366d0aa07279a1d228f5a6c720fd4c1797261c851000f9bc59a4ca354a353842edc938d4128f1e1d2a2f81401eaa8660f66a5fbe97aacfae264b52d4fef3b436412c9fd1c1d232f167a70349b4a261c9ff36f741da06465c71bd8a33f023ceda6338f78f84f37ddf7db2af5a136f6eb9f3c2358e3fcdf829e26c42f1fd38358c15007eecae099c0db4d230679178cd7eb3691f2e7eb6d4cab2c603c520efd6f858e413e18261b70b67e129b036e3a8957f8e35a76d652ececf620384583fef71868776542f334bad4b86cc368e6e98e7e6cc30ced91aa0153b0360a1335324cc697147c3015dd61e26386e0e7436feea1ea8c693aadf4789483bddb22145a2dff4381b54a7e5ac70b90c6de6a3473b24f53c7e38535b74acf4269da8096f89c3bbdaef8f1d06fa8c2206d6d7eb1aa8007d341a8ddabb2f232a401d1870d87f3e5dae36a13ce549531b8128e51b659ff8cf9c1bcdc32fc15b37065ff8aff176afa1a1c11bcc4e16bc5d96f99325b8d42bb49e4ab8342b15022d02cb9fd1691602eff62d49d4d8aa4215ab51499b7151daab68aa2bf1b251d41021d7a981022680450475217e4d013080b64a4862257e74434bf4ca32ee59c3480a563dcc1d888196ba7de16bd31613d8bbb434903632da23b6cdf6088be7b8255bb1dba6bb4569fcbb1f5f79f3b7c6b70930d017c365e02e8d40e04dacdb3fbfc80a3d541100ce95765ce96961e1d3a2c9518d2f84371c22953033a0ade48132907cee237abbfa4c86d01f9fc87817f099be4d207a096906e19d679cf7cc63deb3276dab55cf92ceb7d2f614330d502068d3c5890ef61ff451e4528b982dbf5f71811378d651348d9a3511f54ca3437a2cf5ebc0ed048273f9b0310d37b1447de4b5a17c9055d808857f1c35f2187b7f1b08aa1e29b99b7ae684ebff7a38dc7aa8bed4326efdd010c0a83eb62d0373f9f8b97ad0b2a92f92a56c208eadfad970fb0f64c9b15c755314169277d14703cb4c236e7d4c553fca8fb6055475575529ddf61be181f94cf6f6f76991f67545ee4a573d29b2ea5cdd437f291b8e5abb57efa127cb0f735e396a9b714a2fdec0259f846249624030985bdfde70e2f1d951e6fda811df6e5374e159c1f8291950db02ffb5383cd15aac8ae87d6d645d80e3c17fd8d3f0afd0ca41856cfde6a9d8dc7678b68442701371cb04a51d1738d16d75c9b22afef6cd925a508e76e4c57590b27d7d275b9a06aae5844fdfa6e029e668f544bd6c1b111312667a47c79fd14578f8e7e82812dc13b3d1206287d33068ccd5f3459f951cc11defb032c70611567918785cbd5e460e18c3ee8bd1876974154a29da1b1a7372689849768d2ae8e20bb695aae233441cde73e8d5e46ea4d58e8c72f8694786690cf0eaaf5bcb29e5803c397e8cb28f631df0d9de33d0d465efc7428ad53fbd51081875a05df54a336b5b2720b03653ff32eee573f79a895890f1f7a9b17c30d34ab8442dd6bd4dc65f0e1654490086b6d5cfa9a39b20a7ccc3ce883971f64b86c05914ea8654ddac2916642013f4118605adad82f0d7b7ab2d6253353498f2a8ad8baa67817d4b4461559bb6800cc0bcfe9b4403a3d17fa09c5fa5a5a4a4fc3e499640d221477c3edbf702d94d95c2eaa7d3d992c54ff5d76b7a8351c9677f3ea42a881094844a516651c3a242db464d3a4336ae203015d637db467d9b2ba2d301746770af3b804dc265d187ab3ced36c688d60baddc32e213cb5208d36dc1030c2df3e641fe549f5e37154197ac4fd46888d8960de08b1c0434bddfc798eb86549080e25183698454178dcf6eb63f65142ba3d7cd548a01cd429ddecc462f936f36c822484664a4a5c884fd82a9a249fa5c5a5ff526024000d55bf8aadbf4c513d9c39d15a8cf0617b5c49dc87d6b6f36ea233f9ebcf11c4f990ebc83d08c2265babd91ca9103b266213f1a70b433f618e77041d369f83ba7e6f4e3a2746a2b0b8b02000336e8150e103bb3a8a4f966c428e41a2bf08caf94a95fd28c821e00ffa573a4edcd1afd80c711062de0fc0918a9fdf61089415d7c43ff95f8830400550843c1ed196548aa50eb8b8bb4e3c19baea89a4a1db186bcfb7434338c94edbdc11906e1a745dff5c6ddd4f84dfda9d9c56e1fd3620a88294c37d1aea378a66fa0f96577200a55805c189b72be8a61afee220cb8e3660027c1ccef20a1818e2f097e7d0c659ce537c663f1526f479edb52661f5279998578842da932c3973a36c331f406849e766181c143430a5924e034d8b815092c7387fb68fa5477a2b13b215279fcb91ba20d001be6a6d01770faa732c86caf5372b44aceb1d384a16d369f8c40d019f6050a20a608a3bc237b872f797a2d8654b5691f8b40a50f6b14bcf6a10ec8872960fce1418fdc221ce1a5af433431722f74b9405d60977db264a77a16068d6b33712ffad10f851ebce351813625d95a7cf92b4aa4bd8956b3d7233d2febae25deb0fe70099fe74f22b0efc5ec9f4dbb695dd6abd49f5cf01b63b6cc3ff18b12300b68391c530d1b26fbb2ef6eb006fb8ad02fa09d20307bcefe5439c433d011dccaed256aaf6addb4fd8cc248eef6b4e67b9422d5d394e60d5ee33ccdb3de00ffa0d78e90bb4aecff3f473db93eb1fcddcf2b8143bd718a74cef87c735b6b271c2953a22e5b33bfb61b1a5d05de95c7cc16a441a5900fa4d3ade3f13a7c9677babe59e1a12a58296a54e8c416964effd372ee0fba067aeae3225c78d0cad302a0fbf026dc84a11b7173b23348c2dde6276ad7259ca39d0adc05883da3cbb63bb029f821dfd6be7e57f148b5263ce86b1e73256da47a718d14c905ad463c894569b05e5578f2bf9c17cf4acacba183a17d424dd490b124f72091318f2893e361b379cc8a2d5e8dd9f86b9bf5050d5c1d96424977d785d2cfd6b1ee85bc97015aca06348b8b20ff6636da994569cde643d371f911bb772205da04f8325b18255ace6eae126f666db133c35bdaa4b2800f2cc3abd701d17c74bd7463b5ddca92b79ef8bbb290f95f5986cf0e5f9d2758266bc40f933d5b270e1e22de73b118c7fcc00b4113e36b529b57a63d39f8d7b61f8eec05b6b89ef5ed6a44fff2b59c538fa51e1969147d2281aa2ae5a2f48fe3d86b681fb8cabfdd8cb1210ca8cc7ad857f6d4e4fadc05a6be12b5c0d0ff69a14377b5c4ead75f3a408047a3de8d0a540d6b089fcc5be9e3a806c5c4faef85184c2832e6316812146d7530f8dfff0e227cb4b27f9b442837e951535b6e749e84812153b6810854d97674fbbd8211596ee8c27444cada114263886855dec8ae656924a1ac900e15996be1b42d955ca64d64b7fcaac0dee2ee4082122f15727561ec413a05f8560458d3ab84605f0998422bd6bfb31fdbd2c32daa893cf342d5b30aff1e2961122e1aa1626d98cb1fbfc03f54e222280f1c50ace928e0b7eacb1529f041314f4818ea18dc222957174612963f766a869c1a9d92b6e3ee2b8f7d58cfadacf3cd7a1655d33bb1d5a35ffa2e50db512217b1e6e5ea6558d5c6e50e775ef903bffff3e1fae107122c1a66bd76bc5233e995b289173685ba9e2164c261e9106660a308c41390471e68495a6c0b7d9d4a99c8f846e4aad01c772c98c4f90564d73f1c6540f2b9fd8099d0babe6b8b17ff77e752f62351da6a84d1fd4eb3a940c6e513e21a498699acf72919c57fd8580734710724c6bd6b61b1f823e1035fb0e94ccfc2a7fd3e76f591a997e47a1223ee1c0a911cdb9a3980681ed90c2c48701821723fad5c0354b3007281e9d9369bab293f989a39494138c1429e50988c55ced01e78ba908c00fd5a24bb3a4c87e62cd6fd9b8214814ca4c20be439e51ba5fdc7f5b3bab3fb849e007f65183d73238e122a4de8cba39b90b7d6562c27c2c09a260d606727fe5847812b5aaa0c63bc32f75f33389382444f77f1b71e7c6cfb363512248dd31575a78ace42bf061a15da78ea5cc73f92af05f062c37182f9621e2742378a097d52a1589fc23568c2a0632b821be3a9255f30e0131a2129b6616f1a3ee78c55ecc04ba9c997ca3a2ac4361df21137722560907cf844dda067385943328c2f32fa0915ce8bd1fa8635b8a5bf0aa14b9413ee8bd49791cd3ff31767b1039b882ef22983c807646903b8b6d757a25c1efb542448888a6f52a5f3d64cd07a7748d5f474489ee6ac5548b31c22de45d86c026a3c305e7a91ebe444fd6e1ab87039af04cb77fa2033c4c218f31c88faa6b6dba02cc2ec5f359133a3e14562a44502120edb58377e5c6f9082e197febb5ecb8e087fabe36d8ab92e3fae195a1e71f433c42ecf175f9a977c527cccf2a9f6accb95782e378d02778313b71a69cd0b64708db569e24048fc68c9d2ac6d0f604a34031b96d0bbf24c09273aec76b1a344bb06767fd428de9ad11083a0bc07caf1c0ea8ce5e13499fe4b7804896bf29d02919222129cb6b976133c577332e30cc8fc587981919bce8c2cec964360e663ca6ae24f1e5a089493ac8b57d1d4c10749d13a7c9f4aeef8a09a92f411d538d4825246e7f6081303103f8a142014729d7dd5481d7d9909ba72d1dd71604a33d4a5e3a29bc485206d86a0d8ace035c2274638046d4507e87f96622fe2468fa72b01419e43c31f9f1115c282b45dba8c0f026a5cdf61c0d45df9363743d27f2ecd1d280e221ad369f5785398cff2e54fa97f8875107a1aadb3941d5e9cfe597d4b580dc6cca92fc2faaf996c7c50bb574ade95a0c98423c94c07b101da9619094936a12c117b818cc34d9aa45878cf76f35ec6f7017cc518f12c3b8323be93f219d11f549109e87f7a88a5fd5d0267fc7338562c84500c3299f69a557ecf7f64a9498daf699de2c81b1cd80fd47ed0f8e794269014bd54e43a5049128fbc47bca067850e421bbf2fa2b78816c4fd64d4c84b9a5c0e6a478c9b3a455a9d61e51d1bcb8e24226ce058b3e9a5652d529e59959fce9386ef1b671abde8ccd7f638057ff85d11c7291b6709ec11256360230543234a6c42c7e0b09ab0e3b9cf32b297e506dfd991b584efb6ec078b0282b07658ad532f4af566cb5e4730cdbe48cf2c9535fb58cecf337d3f87f76e4bbbd097f7ec1cf26170d2a91cf191e815b5d6bf6e5c15539d2c671f4dc2fa91a486f67534ea7bddc33353cde01d9bdeeac8d25fe494a4a0d98b9f1b102fb335078a9136c0b968f076d0e57a403cb23693c919b513d208f0ff0e42a10ab70aac4a8f4cd07f72775340ad13c6c9d18148c0627c03a1a023bc59d4835e7f433401772264519fb88acea7869b62c9883b3ebb91a97cca820fb0b20af6b17839df090384a643e67c48e516eb0e1b079fac6619780ed90104d724d1beec412db14911126d754134cdf070afb16bf69543f0c37a00dce0ac1a75e4c98894f4d0dcde2255aa2e42b91f88f50417f53f5d8f18960a433f334a84ce584d78f4d71914b3d9d3d6a0a42553aeaed60fd724977eeb4d2912f8bd046dafe7e767089e419836067d267bfc4c3d3278b987e455ee64a6692dc6da31f155aa9257a270bbf8a3d6b0ef8a1c3d8f7da2d6f9ef99d1ce909c0c170c22af387e19de726f0e0bb80d716263e035dcc81cdbcb15a5441e1bf8849e64459dda4ebc01c34ed2de7d958c9acc6e20b6013c2e38c84d5cac1774cff9dcab906962a2d2d2244959af859519c84550a77edc74564d49bc11d9cba473af9a73cfb05365a60a1823c3929a50861d4bd9329e1c3f42188cdb47632c7636ffc1ae4ccec4d71ee8b431e4e830273190cefa47db8fc12f8527b23d11e87293f6e897cbc523bee992f7bacde76c11f4f88984442afb52a80dd47050afb051a6936c951985c87fc57e16058daa9093bad1525cf2d16bb1a5b2373a4fd553b4c59678c2e09a0555f56485aedd0be21aa30bd1b97cca418e0191d613a703f24858995c19b6c960e9a2095aba8d94645a8004fcf71e610ac23e25c4ca9a495eb3860cd993d93675205a31e5086c2954e796b94984e2b624af3ca0e180b3a0f5cb4acdc59ecc3475fea51f18cda2094f87de401459f070186ad6835cf6c335cb84a3d463b64c7526450b7208ba95cbc1108ed62687f33361de7ba99b4816f1f32ec8dc170b9f5bcef44f440595d61778c126fdfb649f12e5cc21036decc96c0e5b2c08600ac909bda8a06b0fec8f8d99d7869018010af6317a6034e400106750fd47bac98a624856cab132a45e45412a2b3aeb55c32900032f119ded5ba7ee7e8decf0fde794cac32ff10150d65819d280487a03698fbb09d03e6b677b55a4591976f40163a42156889708561800f9099ee09953a7c5a457466c8e8395e681b2e11311da83371b346e5c25d24e0fa68e3820f6a842e77ee9b3b78af1557d833ff9b9a66973e58759928ad88474ce743319da6705d05e199e9fb4213ec069c709b13884740ce82410bf32ec1384a1fc844db988f5a6eed7e1de2a9775ffed8f915e98ed235eb8695f4d4b4abc932bdde1e000f4950b25bade5231b8de67483c7804fbc0af0a4fe354c4104f7d28a3ac635a152684860c7c3ddf856298dd635da4d0961bcd7b4e8ca9e2d435e1511a0a199ade0d0898c2e94ca3158edeb1d5a9bd9255a74d323c264561c00477064aff66a0d0ebcd0e6c6005ee4945731155106858351d00b4ec6714ade0533e7d1542fc4111e692b2c86a4b47f63186ffb9f99db689dd52b26e29b7ffd28da4dd2d7a80ae2adf325cf125e1f1c457aba3aab2acf64b60d6af60d663994e193836eb2642f6de29a31387104c1044b4522718563f459c7e50040dcc3b8d2b18210762cc008c167851d28e949802d4a3c31020b69e61860e1b58322b551040100da521833068400303729c78009108fc00075f7471821174600a1d9f001c506606e0fb84255ce1810dc25841088628c0009800b1846868872234ccd0020e2db218a2031c288010301962b09586981ff8c0c9d894c615a200052641b480a385832e588082138c40041e60c00210001bc00f4a888682be90010b625002278cec40075f74b1821398408a28903080114bb882031b9cc0045a7c204ad38741402d982b4418c20f5ab0822cac5c5185120af810360026412809020ae2b269c17c2183165040024a44f970003c0415010ad24418c2173270010bb2b0728507aa586201519af0103424880b488f1d36355aa74e830843f0810b5ac082156461c503552ca1c40214102508b0264c74d0f155810a477a9089e9410c5392406289921c281480c48dc90a9634bc2b74564051a19bc24a03a70c74557453703add0e2f87fb5c703c1c3cc7414317030783ea05cf052ec7a9050e078b8d1a353cd649e6258605f3c28b0b2e31b4b45854ab94aa4ba550288feb54949600bca049c5a26239c5ac7ea8583c195e908818a259d5a45a563ba71719eef492829d6c1e8cd73a896144049a52319d8ae5740323c30e079a5a92bc84a79b1822ba1e30a0909cb8949014340d39f2d332a23bb59c8ed844a1a90845dc0006111ccad5a2810811dde9050f87e466785038d8a02995a2a1280a0b323d06f07620e2004d2eb02879b9f172e3491116c8156e81429390ccb2436c09968ac58341299d10900411ab534c4a064e860711468082e5861b4459a1f18098ce0545a4a5cae1d4c30751a5081ba89a96222d02483139dda0caa108123cb143111960000e564e1418f04802b8687229671230024647864b12831744e5c20f225a5439a45a56311e90a01d3c195a8a40a1a945150473b432020350911616232f47a1101234b570baf9d19272d98049b5b800d10c408aa696959119644834a13c168a4bf9906a410549ddc0d3e352b2d8b032926a51b900f3c352c36988a5851b3108e0051c37ac70e8c1480044b4ac3e150f181e40828a542f27d50b2897f783e5e564831351b1a85a4e3a503d9c7688702818bc19148e1c9615e8e5001424c7aa05070b10227c865c7aac6a4e359c6a4865a0e98698d30f0a07d40c2c359c6290d9e1c95044d3a783f3661ecec943118066000d3081ad1de000185b54e94006a248c010423061a5d983b1013001624912244745477830e2dae15123800000c04f2c58411a679461041d780240f3820b2a2a3180c11452f800a4834b06165e5c525c6861c50a2aa688e2024f50a100921a1b747c128800d2511a5570820c8833cc3801ccb69660009df104695151a1c414202c3910a30a2a5c39fc68e1864bcb4a15030c231001930f898678082a02e4eab1c3a6462b06e654810520e00035c6f051820e70200343284902e4478e1ba71980d184243c437eb0a8521e38c2ca07a0704003902080052a500106100df104b1e185a38237850e8dd31537a323e364840e08a831381d7438e86ec062839730ba19745f745a741ef03ad0299d92b81a381a5632a0628071a16ba16381bbd1b281aad1b538d629a67341b5742cab55a752a1ba13e7715caabb5bfa473f69964b12a26ce64a2fa9e3430bd25ade74732f2e2f37e3161e60eaa966b558d1ddab66b560a0bb05d0ac9621582db9633eb36ee335ee1f52cfd483dceebcb306faa49e6fb2292d3eac004cd1dd31cd6af1d131a755fa359bdbd40c11e295d25ed6e4fbbe206ab44ee550d3a822dd9dbb058131fae475cde1d0ac150556522acdf843af81798e9e6d75fc36749b9a076f69f12a6985d461fd3c1daf7a84f559ab4e75c56b99565ff499f507a988fddad99d19fbd3eabc2c5fb3f8386de0e6c7e29c7167e4b0c379fcde12bcc15dddb4bbc966a95818cbdaa4e5a6a5a6460817a2e5a68500ee047077f7ee8e4877a74377c733241586bba870a2ddc54a95a9017437ab59a9a16e77b5b82bcf5e746f89e51a8d5ef73c7b3186e79021a91a566ad5ed98e652e68ee9d7b2bb70584b2bf399f55c5aefee84b4b83c4f0f5f09a47592282add5f8a73c9635fed50cca757eb319b1a725e5b2d5dae6a692689621ebe284e30085777bfd02c149416653397236ab6bbc297f92d9c7fc5994ba16bef05b2d97b6d0f4a48f7f7a99a858aa1f5832dda8508f11d358eef17da51471e677f2dc8d2ddb8bb9734ebf46a191577e0e0cfb77cad6ce674339d6ae8ce6172cad1dd4c6ed458c262794ee8ae591e19dd34b2ee2e4897437707759f5a272f005a743bdd1d90eeee4777e7a3bbebd1ddf1e8ee74babb1ddd5d0e47b64b3717a5bb816896f7f2a1053fccf97c7c39383b3eb04cc76c474e8e8f1d5326d3d10981ec98fdc0b1f4c39fe705bfdbcd98d2feeab0b43b41229aeed3aabb07d02c1962e8b4e84c45127b2ccf188e66753dbabb46b3ba29dde25cb2e3dfd614acee6ea159dd00bafb46b33a1eba7b08d38795dec7953aa6355e5f7421fe320fc5d2d6b0db74b74e37577677edd60f78d0dde9e8f6ee2eeceeb1591c13799c7134e86eaebbafafbdf7bd4e0fbfde32ffcdf5c717c9917aa6f366a7559af31caf9df96c0e8aeeb6cdea0974374cb338ef6e169ac5b97477f8229d33c79f6f32f799f56a699e7ebb76fc11dfaf51dd9dabbb9d34ab737437be1ff84b30db04ad284e1db73baf8c8a3ac08b75c8a828a3a28eb2d27098ca4a459c6ab355a996383d7ec07eec30e1e47c40807c3b74e04a670d14adcd3ac832e3f2eab81f8ab494e9f8d1d674747738dddd4d778743779fbafba5bbbb4135c61497dea2a9e9d59e4a080970716969a184f213cd09a8079776e2a1c4559422887875de9dbcd3c90b814b8b041cc7cd2871ae72e2bd584ea71350e72957b19c54de27cf572be7bc24efc4717ef2bc53bb74509238f75e4e50963a5f65cf57bef2565054ab2ea5524ab1d028a54e3e44d210afa4ce39a59377e79d12e7eda82a2ead11705c52e7de4cd2cabd97ca5d5cba834e379f3cb5d479ca51a71927395e4a29ef1747d3cd38c9c1e21c8c11ee75f2a4158d13282f158d12cabda4138d937ea520070bd5ba82757217827a99e97a8ae8b81eafc97b79e95eba7e49d1c05044e5292515cd14b7ce533453dc3cd701554494933779ce79d7b1780753c4e2a7992842b838c7f232445393cbcc113af478de3213450ad7e3f9113af49cdc7b29c273ce6166a2c0f86a264a93e71c4d94223c6ff123bcc785a6c9f3169a2852bce7a5c9f3ce5f668a80f1c173cfbba2ce89742d335238295c0f8bbbcc443942879e1697c2f5b8f8e9e58546089728aba3ee79a111c20a2417e75c88961e9719d64c7b362c29e77a5a1e6039e9345e291aa5296e9d4f713bf9a9a83b79e7489e73be82293a79c31479ee5e9732c265e5018102a5009d7b5e00ce4f0ec50a2495b738942852bc07859472941780c557de0ee508ef41d14029000b8d14efa12940ca573452bcc773154d01529ca3688c90f1bcbd0029aef6703333524e51a41cb1f28074ded3cd1c6185131db899234e51a458e144879792e7fde2fc88138d154e747879de5b28716965d1450aa4f030440c9ac078b5735bbcda51535eedaa2a2f947331a022e3d2ed5a82010504038aa67da6872cc409a1689286802145d343d210a8a621d23907a3042b9f5e2a2195f7cc0dcaf329459334440b7142279aa4215e298f06061a1838ef1c060ee5298ee6e6d57ef38221e23cc5a114e0826a998181f318ef1e97191999178fa11122c65f58de3d42b8388c276971168d1032dee2302d2e44cb5dbc7bbac76506068e2626c687e881f2e2323430703430f8e0e2328ee422d3e230345064bcc5a1b4dc8585c659390c9cbb67e3f9103d2f33ac550e1867d14081c27a19a2a73503c50aa496cbd040b122690a194fc29911021734f50851009a261997a1298010449ce52d9a1ccfc673efc557342c160dabf3b1f21897f1a41c10c8d0147936ad10b0bac7e341129868ea81f1175fe27af05e9cbbbccc704d2f0e4303054a8c86c9b3f1fc7aeec4a87b62dca87b60b8a697be02e3711c156e0a1527a87431fe3223c3e2a7198e668993f1181a2850623c8686abe2d9782e4363d43d51b818194fc6bb27c673229ecc4cd7d3f332c3f5340c4773a371569e0a869373ded3823ac538305655d838916183b381721b9c0d1b9e8d931352366cd8f05319366cd83891712ac3860d171b2f302f2d5e0d964ccc8b8dae46d7ea589d4c17439354f3da39997132e364460d4e4583540ba9540b9ef25319a9540ba953195570422a954a9dc838957172422a956ac1934e5752a9540b3b3b383ce5eeb16043d552c9a86054aa93ea458699f6629869c1619869c15f9869c15d98c931d39e4d0b34493868c49d170b5d8b2689a5cad1a9bc5ba956669ccc3899911a0247c732011c1e1373220347153a349c1013131383c21173ba72bae23132aec28103879fcac0518557524c0b078e1319dd8f1867f9a90cd6c909afa418cfdd0b474be532323858aaa4d395578cb823eeac5839b8140e9a249913e72cd024ad6ed024b1689272d4a049f21a8e2629e775324366e66406a723e664c6c98c55143230305c950e0bcef302e5c9745ca4bc0e8a4c8b4c4b8c8c0c0c4c8bbfbcb8c8bcc0bcb4a858fed2f21799176fcdb4c79a79b922e625e6e4c9c0b84b4c4cd759e9ac74563c55125d5c3146b7ab5443407149a9dc45e5d2c140e592c47ab9a8fcc4858b4b950e8b8e0b17179794abdcc5259f5cdc25e549f9f4828bc7a854aea249baf14305c3ea60dc467b406c783630312c57b1582dbf310333d35dcd0b8df8f26271171a1b35665a68f2e9c58272afb37283d5ad44a0aa41a38241e705172c168b85eab860755b745b74563a2bac1ade6151a383418d1a5c1519efb090e9b89071199aa46e8b174ac65335689238191996abb82bb82b3caeb3d259e9ac74564e329dca072e4935c8b0f4a94505f7b25a7535ad2a584939fde266faa54a82a5c4e2a85752ce2ba7fbb16a81f931f232d3302f5c8b6ac5b1d074565435b8ccd4dcb8dc34152cee9594d32f946a8a1a6e926071afa49c97e72c2deeb910223f9d154ec70b4d4bcb0e0c727a08e9ac703a50de55ba1ad48c152e88eaf46aa141a13a2bdc162c2d5e38978e45012e5dc389252927e687cceaa5a501550b8675a3b50156528fc1522dc152927154cb65605835bcc5712d8771186f98968ac5c1a864684e66702a1aa4254c909630e97ea45a032f94ea64462b03ac94731d0613d5122cee95d461f703c665dc73b1fbc172cfc9ccd4fd88f193199c0e168d8c4c525721167619273364684e65703a5030312732ba1a94195c10154dd2103baf2494e3215e294fdac9f1429394e3429354a362a149ca9163075583c7e258ae90e30203e4e2e2f202d34ac0620acdd28dc37ac0090b1790e101cf89ce89ce8b34babbd1280247450c5c3cafc5b8c2a59be338ca3a55c149c085e33aaf552bd58a0a1a701cc7ad58a60083e5c5f33c8fa5450a19a050a816170cc040a552b9bc44e1021616169617980b78e1e2e2021303050b62382fe685f34e4f64c1c54c165b748c10a8bc925e325637e195b47ab59525ac24c0f39858358e4c0ccc8b4b0bcb4a95429dbcee859ba12c9857d20b4bbb7a0b249ef094e0d2ce751eea84ea3348c0711c2a75b280ea039ee779299537830da85e5028144ab5f2a29085142a95cae341d75d64418114cb085e3aaeab4017589cc1719dd74c30427b42a0c0124e1378259d64ac93045eddabbb18c10a46b005d7dd7d8a401727a8b204178e09ac1619308a90ba8e8bd2af554ed2ca739cc8385de9f68e68086ea6c8090f085267d37917258765d5798a73e28677cea55cc5e2e21e8d0d191a989a97c7d1b07865703a54273292f08621a2e1a438d1f98a268995038626c9bde6e56406c7834ba5382e9534c4ab850156527f91d4601071ed8590292cce5134274f120254a36b59810bf7d2ed554179c300f1681c2f47e752e401910112e31e0c8c67d3d1acbc852689d3e2d5e2e23133ddd9b8d0247157bc5a54de7155683a2c381d1d4dacabf15c45534493d46210a149ed7456381e9d7bde030acdca8ad7b5a46025f1d8e287ca79cc5881d5b97b5c5f498971bac262d5a8e1cd24ed2475ee711eeb745a01b9ecd0af7ed568f96985c36db80158f01b9e8281c1071c6ec39170d020b140d39ecd0d5fb1f86be535645a35dca5c6ea85aaa17aa16aa45ea81aa817aac6e985aae1bd5035ba17aa460de75ea894b75a3b7435645aac1918d68c8c8b3b2f189a93199c0ece89782f334550af95bbcc14f15e2b6f9929c2bd562b1a56e378ae9af13c6563e694d47a795e80d310321d4a0a4e4020d50429619ce00c2a0ce18b22f49c9c8042037e70050d2041c5078696100532a45842120978c2093318d0c4194ae8c20a4d31c08215c6ce155fecb0b870f10c38018a2928f0012b5e40c6cf04b01803094aa8a00351600001de03649e7004171081822018b144030ed0c5042650440ea8587123078bc5f2d389e5d55d5c40060c68e2010f58a952a893d7790e78f52d022a08114ee044142588b20029ab0d38408681287e30832f2e6004287a52537cc08c2b2a90032c9ec0041cafeee2021c60a20926aaa47820011c30c1040f40c0075c29a802892f1c60842a0680a106677400056094b104289898010e46c04415c2984204a21081a3549df29ec8c1ce15ac309ef8e20a16172e3b57705a3cb1c5134af019a2cc800a1834e108474c7139a008498082023ea002057a76ae78c2074f88e095c45a1dc06b51b1ac2c3081138bb73aa5542e342c2f07d7e4290f6581255aba1ba7d32985429d4ea7d309e5a1bc23a0b8d3ca6bc089880ee4800b2b16a083055c810839c84006ba3002093da71b2c142b868a133638c2069a58420735b0fc7472afe105890fa4524948715a2c9142830a2ba0c008495461014c0818c000317ad045026a9014188778d6eaf4a15667f8a33dea41003c884173fda5fbb9ac73f4e9d78234cfd1e672d6e9355a696f2dfbcb309d3eb33c5ca0bb919ac50351101add5fb564395f66f3cdcd1dad13a020167477926605916e6dd6dee9e1acbd827c6005adfac325266dc6aec48817dd1dcebf7e0b7f893ef846469ae8af4e9f591fe9147de82cc2ff452a929bd1cc473e887416f141aaaf34911e1bdd9edec2f9d8a822c9f58f5e456cd0dd9deb2fe5fa4b40dd0da45945a6f4173e8dc51ca9c84eff786d9e34d3904eb274f217a9c8aabf59b5140806dde05fff1a121008ba5b49b38098d83cb37e9b36b7d5a7637abf3ecd6ff0b42101e5f0a2fbfe6c56ca1e9c24f6997525708a3e1d93b376bfe8abd46d6895e6d2deef3f5ae35fe25ab6fea3c58ea70de987ca4fd16723e4b3c467f652fc21f54b32bdbf2cd38ff67dcdcfaabbbfb0967636f3fc5a7eb17caa7cd5866eb3d730b5f9ed6d4471d678b55921cdf2a9d11ba166f9b0ae9dd98cf3b7878cef96c9f1737dec2feb71a2745cf34cfdc14a310ccdea21419c6a2b0fcdeac9d1d8e21c69d66b8b5b9d7eed0cd39957ff1ad24bcae75809b462ae21bd6a94402bba28d28cff7e2dfbe372822ff3f01f044b6c6be943b3887881ff6736f49bee9ea15944a8747f9808119fcd68c82292a33f1dc4b8d539bab5483a50e94ac7fbf9435b41c7361869960e455ff8f92fe92f1365b1af21e950f38d657d8fc5fc6b48e1873c23b884c7a646c8082ec9f84358b5a3cdb8047930cf9337a4fb33f296f1ff6cfc4c61ff3358cef8431e1e519c3e3c8ea723091132824b6e775290cebebe8c470893ede10983986c4f48619f6568d6102a43c81ccd1a52f435890dc909ebe321dd42c4b8a15942a8b084905f93988e6609d9e9af494cc88a15048caf492c08155f93d88e6605a975778f66050940779358512c08ff3faa3f614fde328c56292e61239d22080b1f36824cb01c569f66e580c5f7a2789ff45ce7745ce9ccd5fadcaf369b6b69c77979fcc666476747e937e187b5b43d18c44c53e83e9d05dd1f4b5cad4f782df846478c72697fa4f931cfdfa777fc259ac109c3f47e582d89ffe6c963b353facd4e597383bdec36c75b38df88566958bfe876bff4e1bbb6e6e294597107ff6cc7bfe12b8156f4bf13d36a59c4bf5b9d3ea37ef3b499b1631b460733bd965ed2a7e3e9e1e31a486b36bf093f93e3e73cc3fad8a7e779df633a3cca98d7e937e1e70952912c7ffcb3d95f898a367f9b7f33ebe3d7b2873f5e3babd4dfe6b83ef8d733b6a3e3e937f86975d6c05b5ab7d9b1ff9d79b47756c3f75f9a35517cf9e7d87169e99d4b6eb355c9df868f8414570b625bb339ae5fcb7e330bf2cf3175219f256eb3fff867238a33539f51dfe1199749252e6b3c7c929c37635acbee33fba53893f877e924dd2686631efe92dfd81a3c6bfec3878eebbcd21465b7efc13f4cce9b3d3fc6d36995e2a7d57eb7fba51391cea5e9197f9e229038417b04e38ac40849fe0b56eb93edd063243528aca52d92ed9012688f541afdfb4bf628dba1175602ed119b3d92af255f7ca45c1229815ff3095f462f8865e5911d3a12ce9ed95383707e8c5fb73a85ac45bab606d6f9463eb74c8e402fca68bebf5483b21dfa1165b322116991bfa5486791b0fe11927f42f1588e94698e36bb384b27ff84e2bf8ea9734a681aba9b34eb26a69b467bac45b243a258168159d8e7127ca6bf393b705e7c8c732df8609d25c614967199144e587e8c7fe93efe5b4b519cbf44c50923ff9560b007af9dd5f2fc1066b3a23861f767998a34973058025adddc00ba9b36cbc60a439aa5230d6cef3f715aa537b15a0fe78b6eb3e34c654e67b3127bf879466b383fbe31d99beb63d9eb07f63b603099eeb6820e16726814d32c96a30e0f1c1c5aa522adcef076e7482f095bb29724272cfc4b49a6271f04e7b5b3fc38dfc7252c0c272d9dc84a2c2bebdf309c38149f861406ce9fc1f26398f8609d202d2c9360197fe9e4ef9d2f82585662587e0ccb8fef8485e1dc9169ae1f529c79cb19c60ddd1c0dba69ad207081549f24b2433ebe9c6f076704995cae116482d95033a40bea6e6e078ea7bbc366d9e474871fd2251b7e68c1fa7e13679ea13b520e39331e697eda2d497c7b25587eac836535e885ef37e269f3a183f3e09ce1e09018df4fb6a383438e33e31f697e35ab6608ddfdd7565a5098c14ffa9beb8f0fd6d2d63aff96e42d49d8e7f917c44f1f168613df4f7663b297c409613791246709fb5cce5c7fe9614c74f6971445aaa4047e0d84e5d2d632b5c1f263fcb449c2c8f935587eac74e7f817df4f26000de0d25fe6e3e7a0d1e63a6b453098bb3eb43570feada5877f3fd77757a5e087d6a7bb6dba392bba9bd62c01d434be5f0edf8f8f070ece8b13c438b74cef24bb0004e088f62142dc5db198673c497fb0cea5b04e1e9e9d5208f849429128ac2f9c9f762752ae7f6fe973c3f7e98c663bf4e11ffdd3663ea251a16a29be9fa4bbc95bc31678da5c1427f8d3ac1ac8ee1d9a5583cf9a4faf74fc4cfd455aa5d85f2c0090d1dd1fcea58c05800dd81a02404a772369160078747fa2f8363cfda6fe12a539add28c2f9df9ccba7f37512c670e863474fc3eb38e5fe117193f078d9f83f0b5f702d53255f222395a9ff03fd7a01a98674fae4fc1fada91043f9e2fbe11d38735a8bb6d68168dadbb879a4563d3fd65fc345a893dd76874f4276f797e2ddf7c2dd71f4bda9dfeb5fcd90ef9177ecdf1ac3976db0f554b31fe23db0ffdf0a1f37f6b484a1304bf871f3e7466ede8870f1d6b437aa529f6e8f0b04da31d3c6cd32887876d1ae5a0639b463b3ab6690444c7368d7ee8d8a6910f1ddb34eaa1639b463c746cd34847c7368d72746cd328871db669b4b3c3368d80ecb04da31f3b6cd3c8c70edb34eab1c3368d78ecb04d239d1db669b463876d1ae5609b463bb66904c4368d7ed8a6910fdb34ea619b463c6cd348c7368d76d8a6518e6d1afd4f1088a9d07f91eeaee99ecdf230badb362f8f1d5f0e4eb5d92babe1598ba1596e4577dbac38bbbf64ddbd86a7115aa5371fb95c3012677092a3f571b9c00f2d686735e8c379692412a38ce7119a690d7a42c5596911a09b48922f1e3c4510769f649a23d31c7998e608525ce9cd4c0f7b3c65f78bb0121e1d1ea5108ca7e8f373bf08bb5c30ee8a0cfebd16f46cabff48732dafcfa8879fc12799de3175ff1a920789c1ae85855fc3b4d299f774770cd8ac1992f097b9cd1e7ec69ffdef749cc572ce3ef4176514d73fc2f7c3998e395f0e3a383846ba9beb6e870ec5a73fe41a8dbeedfe125126cb7bad4f9170f6fcdf2220a6a3cb85eb2bd9ec7261972b5f4b922586fd38ef0c9779e6a307eb1467cfff0c866f93bc5d9b6758a79038ef9344e21caf1dc2b759e4127fe94598cb0ee1ffa102852fca26a63f4076f49839ececf8219b407466b21c9007109d1d70f2e891c3cbc09c1d1f3c76f0983aff618f1c1df0757efcd4f901fe0873087bf0d899813d7cec00c294a3f3e97c3f70706ef3de59c3d348a5b3c6c323ce5ced137a6d8d4708f84966d6dea22397ebe9cd3012cf3cc35cff7ead521a1e7ff284e5fab80685f36b434aa0157baacd86b0f0317ed05e92e743eb93c4e512f2a105612115e712ccf6951caf1121e027e141f2232cbcd3469676568344d1fa84417f2d08c3bf44331de9ad94462fd17f9eb4bf34da0b96f11433a64c0fc3e2ac348ab14867fe9fa35c12fd58e2bfa4bd6128da1afe5bcbb0b03e894b3cf3fca1d159b53e5f7ee94377df2669958a327af43c36e1d3427a65af1a21e027c1308cffd22abd650a4e72c2befcd209ac06e649621a86f36b30d0c908733286479f673ea2554a9b18bf50a595cef16fb6354cce8a619f67c6b0db14ffba5ce3677cc33012965f142709c3a5588e25c8e33761d0bcb348083985fe2f520fad524bcba58591e3adc1c8b1ccb5b4208c86471839963071669b3fcf9044e2438ed7484bd1ddb7594c8ebadba85939b0e89ec1f3ce22afffb6fc327f3cff8295fa4d142748abcdb6dad16d761cfe5725d08a3227fac2cf998ea305391e94c029b3d75fe675829e672d8313d779b3d727addba1940dcdca91adbdfeb4796dc6dd4cb35ae0e2be6c2c2be9b729be11d7dd2e34ab8529dd6d43c56f430fe7d73cd7bfb3a8bb71ba3ba7bb93e8560c4c5f7e4c331567bd9f99dec56a2f5daa404ac0800d1ed84007288e4084165091032141b0901a621582965608be50c2b378d2d5268820060308018b00c818e0080466a6c0e83441812baec061420e07e490810daaf829000d901230c407a93e2316d627c919f35aa636bf4fc53bdfc3afff32c736dc6eaedf0d81ee26a25bfe13be130f92ebe3bfa4bfcc332e4717bfd659039d1c6fcdc3bf53043fcc74a4627757a4bb0382d2ddfd7477916e9504ba7b886ef5208cee1e7d7aba57779fba214a280da0fb4a53ac55a3aa4f7d1ac2b58a0a17a25a9caa6538140e2e865be99c80b4c7c4690655b75aa14e1ec7750bddd75d733e9c74e05a1504d53229ae398e43a17a742e5d731ce77546384ec5751ce7a59e745cc7a93a1c461c97e254dd71309fd7a552352dce9dbaee34853b715cd7c23da1e3581ac59d3aef392ea9e3b86e85a483a1e3bad4a9e392d0715caae37ce05ae038af5ba900e5a962381c1cc7715d0e1d0b2b8fa300d771a98ee33a0fc675a716961edd0bc7b3e2503578433855d79d76782d5dc7d9c8fce00870dae152c42beafad41d06b893577342759cd7a826b82070dd358bc56aaeb913d7716670abee068eeb505de7711c0f4e07b7e25ebaaeeb523e9c0d5d77eab81cef73716125000ea6c60bdd033854e70277e23caebba2ce5bb8537734d51ee314e0f58c0ab826c282cee352dc49c5c1709e135db77279dc8ec775ddc9bb17961a0ec571aa9cd30e1a72b8ae25b5ea541ce7e2ba6e075e8a63e94ede1247d3951ce7e1702c2e1db752711d916e866e864e06afbde664b854d77130279677ea5ce8ba8e4b71a719c75203e782ea3814170304862e48e5c2d271b2d58baae37ce0561ce775dc8933c2c9d0e5d0c5d0b974aa0ec5795cc7759c8b93a173e95427ce43791c0784f3b81a8e857be1382e083743d7e2a9b8d589eb38cec571291cdd0deed471a8139743e7c279dd0c9ce775dda93b7139741df742d7c2b170ab53c7719c8b93a16b5179dc6975e2380e8873396e5809f17040711ec7c29d72702c2c2e972060988103c089ebba54a77a8ec5428e8b118eebb88ee3389c5635d9400cc15df9c18cf61f9e20038c1f668650869219040e2001c2188d34a3833e7a62067f34bf68a327b4a080d18c25f2e189a42b45b30791234fccd0042333869c1c9ec8a1238719a301204080a901c84c0bf703089c157ec4d2a8c00fbf427f312acc8013a3a2bb19430a7be33937e040e5e60c1a62fe4283b750a3a9d868d2319412ed2723babdee6e0074f7acc64f37014a26f87e4f4e107f37932eea6e219ad58a62e619c260643c183c13349d14d0743a92bac139d513886049d18442bda804a003224e4fec38b5f01285065209683a1d61c1d112430e239a587e3801e1cde092532fab22ab9d548b1724470bea054d2b2c9a6e3021820588470126bcfca009954613eae5851b34bd641a1334b1e488e95441503a504c4861c1c5850714714aa249664666c6c369e958e568a551040a87d58e4a8827e3095945d1e409edd0916a496da0c97349bd70ba71d9e171a797d34d4b11140eaa1f522fa45a52492f375e6eb0e460c1a1fac1b34211a917bc2a45a0bc680a40d2697458006438b95e6452ad13e7e1783ea7a29716529d4a890a06d5108a85182ee5e2a14e2f9ee7759eca5b792c2d319c3c1512550d99a296962aa5e23cd5a9c749c7895bb9e0c140040b0d280d34c56c207ff39b570bc6b0b5404a4f5b0b8cbabbddf6331e9e0c837981c5d724e6c5946e2f625ee8e04c6bf9d9dcd4cc2c0ede23e6dfb5b389eb93d6668f588ba484690a21a1557b95d8a15b83ee8797e8e9b5b62f622d921d0a1f49a804dd7d2d8f905ca9257fa448f56b369e17d314c295ce910b928b1cac8231babf582c53cfe483e0544195bf2aa829592b8675aa602705504841153ac79b02292920826b3c5ffb4a410c2f149c8102276c70a637953a9e35eefe4241ccd66cb1170a6ae8246dde028cee2fac334ff2b545d3dfd96b8b22253cb7a0e9efce7b93f9cfad28fcbf45e11f85af6497de48561ef9e43f3a419b600c1338d1fe855f03e75f13901fad9ac048f7575f696613d47409c02841951234559ba57e5482a2ee2ffc12e4e86cab1663fc8f35242db470e227488b25f8b5d8e90fcb4accd2c2bf48166864414577b5151f6521a5bb6f7988950599454df757a7e35b826016accf0a18a19529df9718d3fba41511b7b85c3c8ea7cb4accc334471e1eda5f1e242133cf1f1e9b99e78fdfd4c84a4c821a2caedcb0c0020b297ded0c8b255f931816352340a34720c6d724f63f822a23685a32829cfe9ac446b012c118fd358989608baf494c044e888014011111e408c1951078d15f935808a88480a96b01532c2b71770784dfff10e75627ce374c7436fbc29fd86995de7cb4effd6666fd9629d3d0c834851c334da127716425fee8cd5ee7fd09c236807306ca4afcf9769f04299e3d5f7b46beaf540ce787e493656e1273b982b8f978c1fc7ee337379be39b48c3c748729d36bfd159ae16bce5fad58a959c2316f2efd2af655c665bc9397a6c4634692c26fae3fb4bb9ce6b6b361ffde5b1985bb05a9aede82205abdfc457a2628d38433c9d46657eb3433733faf2afca4aecd886cc748333bdd1c84a4ce3bf44b3789f2cb137d11404ef81086709911224fffc76e76803bdc945fc9b55c734c881b21db243d8c80e21c976e8e7da225f6d44d90ed9a1f07f89ee705302693efa2f92ed10969547dc0d8e4b77e3d27eb5f702953ed8ec91cff36746944ba2d0da1daacdd61e5e944d3a8bfe8bf060bfb97656a99dd5a05bc63c304da16a69fe9f85e2d32261909dd520a31713139dcdca23fcb4e8c6833fdf7a848cf6fedf99ed2b8685a2b5b98aa2af0a1aa800a3bb3f8cade8b9b45e6995deb8cd8a2ff35cca6c544c692a8a3e9b908a9ca782f5e529b4907df8a35953e0299cbce5b086d5828fa5b8327a21c594eeefef4c0a22fdd94891c3da8b5dcdc20018dd6d738d871868ba9fa7486b3cf66180c817051a9fcdc574f46b67517821eba15951901dfe056f62b12876baef05aed01d3e786d91f06db386147ef84a61a5207ea3a0f08d8e7ac2cf950a855fc3533cba79926f14666c8f645cfe846fb36105ba408e1a8dd6a020832ae980628b9e5984a209fb92bf5850ec7c4f6734b4234fb39eb8d2fdc57842d11a411232234a128ab6f60416dd5fec0929dd5f2cc6f48e9f20d2fd84382f1531babf2febdbac48a58a1e1e21e027f9bf3398edeb4fae3f665c2685af4b43970b6966f1432a355f939805d0680b78c1b2c0140bc4da023b165855a0074115784163a629f4557196215da261a54c53a8324da18f66fc3ebb097de6abcdf4967669cedcfeb8eb2b157db439db1effecfd2794fa2d2d5d9ab597e5a7dde6884b7b0bf2efc8feb84f274baf4f5a9712a6f796f6e679bac56ec3fb4b6fb3463c163eec6f093eae34f65e277863ef3fa17ec34d14e7df1bbcb4379f05f90c911110103ef43282e44640482f20a31d1ca8c7918e9008f9579fb4958e5e19330e058a87ef43781c0a14b7a9c1f4fbbf33ffb0f5f0c739e49fd2df998737b223d16ff5e55f198bf974fcb8c436fbedce9beb8714d3aa15a7c7628e1fdfe0d9cc7e386f1e7b3c76142bed0f1e8bc55c08771e1e2133cf1fbfb9457ec33313ff48c8486b47e4147ada1ce2ee4e00777f9192a3056d8dc562400e00b75924c7c9f4a1cf8cf38771a6b5747b1f8899c5ff093fcfff09c2ffe4ff16c1a1688dccff79b10cbf061ed12acd5836c3fa241310500dc2f466fc46b74c435a3aa1b42446cc3c7f8c5e619012688f607c95407ba4fe137b67ff7716d2a6588436c5197ef2965daeae87a60931ba7bfab52f3411450d4f0b3411fe4cd144cd572dc50013643c8089dcbf447198d8e9fe423cc4448efe78986c0f9ee204a968ea6e40ac013bdd0d602da184fe9ac46a99da264c1427ec97689e4bf47e08c313f6e1f06b609ea2387d7a02391b98b212dfaa5882d53f41434a90d1464a54c134b4434a4cf966d65ed2495ac32c2588747f73a48e6dc8d42df69b5fa2e2f7a0c48d99b53db85c4853c6e82956bedb2be1e0b130e87b88dd5e69c6aa8d39ce4ff31ce45f0dbcf3b1dfeeac54467d4ed05e8b3d93aff44b2148f1ed95b00d8fb12b0969ed5a908eb65af09d56e94dbc1fd6d2bf96fdc37608dfbe073b74fb1ec23028fc3c2968317ed9a16ea64391d67ccaf02b92f02b8d1e656b8d6cd3a88a7374c1604344414746404960403bbc8c88908e603057cfb0924802dfef3e297e0d06c3f961497fe13bf14fe95a9bdbec496eb35f1bcd4a22a7dd25b3a2cc87888e789801400d0b09276eaf04132768bb94a235d00b58220164f4f8767c3b703e497787a4bb43eaee8eba3ba3eece87eeaee85a98cb55ed385a1066c3a9245af2952c79cbb6667bd8df92bc360108b8d2dfcd4d4400182f0424f1b7cce56cbe1090040134747f619db3a451d938310d6fb25b92fe320ac35718fafc2d8bc297420595b204db30a5e4dc98a6cfc4c71efa4859e1d701c6c8b6fa01a8dc446bf3cd8cfa4d770335eb0045ddfde1a7bd4897e8251d673a41fca2387d8ea8427737bed6c34762b23df7ab6d92b886a711519c3e3f76943c3c4842664464a964ed11970b89e98f2072841b000d6a0030a8b401980c50f4358919c0a3a011258ce69af8d11e3986d168d25f0f92e33c1e24fc1a2e49cfb8e461e747ac86a79198dfc4625ee767f3630779cb351ef3e9b5596f53fc10e7479a8b98a6d037f3aca92f7e36359fe3e03a3c62ae34b3c7aecde02c7283cb1a927f387f499fb198cf6cc6b51449d7e11186e1f4fb249e3ddfed9562363533fb4f281667184eaf985e3bbb81337b7ba51a0fe7388a5ff39bbfd3317eca642f3913ffc80e8515c98bb25991643bd4d550e3d29cacbb6bb30ae085ce978383c387c1603a6ea418daf136334cfcf0c91b52b5b3ffb931d95b54c3b35613e7dfd7974e682d5dae0f5d2e243bab41428cd1ddbd452ce6c44b08a67e0951d4dd5dad5722216aba1b4f5b7d09d1f2854f4e5b7d851fbed18b22edc1f643e1e71962fc20581e4191f24131d23d095006ed9697b4f79fe0540238314e02d8210218e96e59f92409419af5a44a777f31ebb1bfd64714274881ba5b87663d09f1ac85ff21056979f484c8edca67fbfae093b72efa088867fc4c796edfc3ed956edf03bebd92acc41f5af056d47dabe9af498c098daf49cc0b262a4c4c2c2622cdc4b29161dbc21681a21d1f4747f7b3d21cdde64a6513cf37f20f7c12fb2ddf27ed259d66c707c634e014c9bfbee3e38846f187d886dfc1653fdf2bd9a54abd4e70e619d6f034127e2d2fe9197f28da1a27ff9546173aa2e4c35fe22973171680fbe7b11fed51ccbfd8ffade56cabcfa8dbd4f8637116f10f538fc52cf6b0bc4819cf99f5d88fb3c6627f6d3ef22f632be2b29669347ab365fa6ac1198dd97c466336373c4842ae2d5213abe19fd99fcdec88699d35f04770defcf466c7bff42215419c5ca351d1314833a6a2f812823f83bfe4f36f8dfba4554a9253c8bf8ca9e8311e2421311fc3f9b7dac713f44a67162797d62dcdb3ad4cb6c7bf7f42314ea5feb43b459f496c11a6b6a0bf76367ea62e2024a221ffb05b2c4ebff9f1cfbf58fe23ff9c56e9cb6cb00d75ac71ec1fc6e414bab95fcb4fb3d973498ad3c62bc516c9bf9fa03bc512a4f94ed245b19ce1a74d929c5f735524e1d32aad653b248ad3e747eb53c17933139045b24838fc1ffa710e814f1e7932a48ed0ddb16609a00ab57162bf6568873eb4a0eb46da9bebc3e6cd95ba6a781a71b9906a78d642eb83414adafc78d68a1ecf1a896faea5f599bd11b6b3fbf79fc0aaade09398298f0f563be472213d586db582ef17d65702a70cf6f4e61f3cbe1c9cafb406ce110787c4e1db8aef87efd37ba74ce73ed775449c9784b14fd05f3bfadfd954d8e1052ba92340bdc02f920e02169d40778bf371778026d12277795331d37d811917e7e34a67b7ee4e6a16132174774fb36a4874b70eb1190bde0faf755ab5d7e67e839f4ea3f205eb586855e8ee2f7471d25c1fcf173d4f7fd9add672d7c20d4b342ebabfee6ea8bb579dd0b595c22a1def97d726cd1196ebb485952ac1c4c9639b37cc3469049784749215099e547c8194b420252d52fea30fad10fe2f92ffe845d97c24d78a13df5fa215c9b5a238419cb11d6179c298e6782dbd9f6f7e259066cc44cbf52949c1bf1509137de53fba2f86751af9235c8ae42d8fc25acedee856f6d02a0d456be4331390517d10ffcf9d2ffad02ac556f4c9e483e0ab3e4964fb2172bc463efc4cb125ffc7366f58cb54094f7933eec1638947c8082e71b974964670092c047a5156da1f4abe94107d949c7e5fe95a1b6c36b3df7d253cb3e3cc66d6654c8d9f7e3158b531afd4f3e320b0260f66c2a743e88e74f7a9bb21f8697e314d21970bc92b7e313f769fb79c308ecacc2196ad7814f36c453cb37e2da64b34f419fa4fb104c509bacddedd5d4337876f36d0dd199cf561617d0cb361981fe39030188c1c4126b23d0c2455eaf8366de21ce79d24101e3c76507cc32e17fef263b719977e13bb4f9b750ac5fc2613ed50734098a1558a311d7d479212743ddc006f3081def14577cb9a75430e584d7c98c11457ea398fe72d674e667a3bab34e39d2f0707c78a185686e1ccf573a5b05f9a2fe2090bab95c16e609e210deb0461a26cdeaf62b9545d99e961230cdfbe878f92d3bfdb2b390e6e9b978ab00fa4a2ac24818ebc7c8e3cfc3cebe709560b1af9873db633cb65cc432abe6cd2250f1fdb6b73cef871b6b757f2cf3b78f89fadbdb05c92353c8dd4f0acc1327e1a0d6b781aa9f1dc0fe71b5102ad2873b940da53c3d3c8cc339cf98598906e998a335f2bf460ae3fde66d1d3eeacf9dc0feb1fd9fb40543ba4043ef8e411a6f8ebef90a3a3c3c336c3a089f1df307cd12c964299c9655299cc98c898306142c3a4bb8974af667874afbe944b77c39aa584a9f1fdee631efa34250249c8e8b163c797f3edc0a91627c13ebc8fef05522202324ac2829f4d4cabf436492297eb470be6d28ee0921a9eb51a9e464670494861f87f268a1364fab0f288b3cce0ccd882b0eede6916120c206162f3f55a598d678aed575f4860204db17d450a02297554a5bf5c5a0faff59bd027cdd46fee2f7dbdcd97f96dcea32536b1115c12d63f8af9e799ada9f76d8eff8b1c05c0088c5aa6b669442500cd329219bdf880457f311bbf0983627fcbec4bb3e6b59c95619098284e9f984fb7b9522f593ec4fac361fdaf593ed4747f455128a2d29f284ed0564cfd6f0cf64a33c768952acd5b38736856d111281045219638fcfcb4b0acb396fdd21c53a22792d162483c6ad6900b5c7ce187ff55662fe9987abdbf646942febdcc4591da6ea28c626c49ff5ac6a5bd4fab33b4c9a5bdd9ece1fc4babd46b1cd31ad277137169e9d25ff226abd4c307a7480a2511eacef3c818fde5faf8c8114772c252042bc516749ca98775d2d797a9877f6db5351b9eb51ea0d003953596301cc09209d160095550c10822123e4d1091aac107379e0061070eb0e00204201001ef1f3e748cb49488604c39f95ad9ab88a786271eabcd86a2b5208c698ef749d85856a6397e68eb8bb0db85d532f9218c698eb44ac17ac3d3e5fab184c77967510f586ff8956483131274aeb820081c42b22b9205019850031686c45e70831e3c91c010233c81c8164c5480084216b081db42c60928b0820cacb8386308a1171d9c618226f018e1293c18729d48220aa06f7143b6c008201f3e64e87c31661c9660e4871fd50af0162827371ea8f2041780c830849341045620c50494e8501350441a476222802263c2141448c58e1636208001265460925c3c34c02260c40f29a0200c1a703087a06406536840006e62c81bac9c2388c0832fbc21fc092a58faf101118610a5b100316c5ea02300426060e289272f01c0a007469e06be12e4b83889810b9536a25bb32b8def5761f733858df6ce60e0935807f84b4088d2dd61d087d6c7e5aabf94eb2ffd52486d1297eb4918acc5e5ba413c3742ae15a78fcbd5e272c130ac7e18d21a8c921346621c840e8d738c80f00205ac26422d20ac005105100f0022014010a0bb53dd02a2ec115c9299ecac061d7939f8018dd60f528eb4bb7e60b5bb96f0c05d51b86b89e8ae253dbaddb5e4d4ee520246b7bb9438e12e254cbadd856faf045352e3ae5692329260e1ae244dee4a72a3bb918ce1ae16928c4488bb82e81692182d242added2e24b1db5d2da4d55118edae23b15ba8e5c38e91133e7c3fff38abcb6d0e670fe8627ad8bce51c41263b7b1dcd5bbe3213d0bce58b1cc12523b864049720b9b605dd9d173a74601d3ababb2eba3b1674772be0a2bb53410a50d0dd6d7182ae9c0c0f38ba9b6b110d81288ca61b9cb1030e48605b0115babb93d121760942680012badbfb8134d2800d6ea4d184ee3e510145154536b2f082d361892088a62080025a2091041a6c2e4a8806babb3b02a4031190b001892874b7c70203c030e3014e684183ee4e45a00934b8305c5720d2dddd109ea004942a3c400840bafb2481980a02b51724fda0bbb98771c185428c12e0a0bbb930643a2b60a200273d681c978ba788245f16c9e5aac1f11442047a782d8869282b6b99d2eee74c6df96973a43c4d72743cc84e198490fbb44a673092468a748ecf446f9ea3ec6db729929886b01749fbe4ede29b75dcc87ea29f90c5b85b109bee6ed2ad21961d5f0e4eb6f6ce3732ef2c0222c76bc427881caf111f237186f38d6e3757a070be9150b6d6480b136851022db2e8ac74952ea4dd21c156049d297f497327ad55c2d2f2f92dc2d2f2e1d90f4d6c48620c2ff4747713b81b9fe6a8c0a57ad0ed0231a6d80cd4dd91e0e462030af49376c2832e9e04814358a4918612234b3d9676983ee695fa7457bb995262004b523974465daca99a8f56edb5f9876525ae8175de9ed41435bc194e4eb0a981613ad38da0bb13c14a55f4a1edee42d0dd5d0182eeee03162892a352b1d2249c15a02d3e26afee07d079731071da5cadcbc6f282355c92309b2b851561058bf54eff252b0bfad00ef5fc3cbd481ed6e972c9c6f2fa4421d2398be5728cfd920d6f6bf98c81ef776d9ef733bd0206373a3054d0ad1e30fa56e7eddaf1c7329c5694f9045b3d13e8eeee3cd0dd55b971cb7986b6ba5c1fdaa1ae03dd1d07b80b1479311da015841ccd3db784e62f7993715074312d22531a664577b7814e03dd5d06babb2aba3b2a3a29ba3b0c74efd0eaa20adddd5d14dddd05bafbd441d1dc900ed498d0841ea31b08dd3d806ee990c3a737eb7c3938b210e7e9cd0d0ac562b13c61eea595d9ec4d62381684dfc4bebfd6e7cbf3662c2b8f28393df6d7fa7c41fe75774f50e9f05a1bc6b3e895ed502dcfd267c7073e0a67cf8e8fc7b3279c3d2d2135ddad297a84acda5b41caf09b582b880aaee86e6ceb2d8330d1b1d504504c58d9d0a245e92e6a1f51ba158690eef0c59967911f6c8121af0ac07c2d170e43847848c78e021c0d26d0dd49a0bb8b0004ba9b922f519c3e5f2ec94afd471bfb2f122373f93ffb623fbb71a7e4ab9669f5c5ff19cc6618ec7f76bb62662a9de81e40854d8d928561fad960876203f31b5c2300287e53737b25d84d06837d27230c19e2b7044f49cc30ef24513760b07e6dda50415a3f7ebadb5654cbc7147a2c2bccc918f2d4f034d2f211fbc297b57cd4b47a90f1f59032bdd5c388cdad1e31ed473faf222d1edea4ce95ee6e3bd4d2c1a2a5536be9e4e86eed10a3fb0b6f22b543ad1d2468eda87db5bc6e33b561ea3b6a94b7c433cf1f2c729a3a07e96b129b79861d4b2b67d53f9dcdab7ba5ce76459f17ed37333b14e496f6c5fcff28e633eb327ffd7c2d635b29ed6db356da8a84909048eae7dfbd13741cfed2c41ed6194e2b3a9e365bcbf3fa28fe1ded748b637f83345f9cfee5d9f4fcb8466b20bd3f7e8d7c5aa574f4d924160bc2c33a31c5f5a543b54afc7b7ab30db9496c665f56ed049358d0f6b509d00f918fcb0513c5b7b95c2e1789836812847fedc6712ccdf12f515ab5163b7ef917564b718873a5137c12fff599754cfe2b7d4d624ad61ac191d95f0aafb5790df25c6798edd02bdba25b4ff899ca68cdde223c03cc63bbaf04ce8bd4133e4652cb21b58575ca60e1e392c7c8bc93e409e7d75e7607319c5f9b304b838530b0bea2108b750ee8ee9ae8ee98e8ee1ad0dd2dd1dd29d1dd4de9ee18d0dd2da0bb5340779744778744779780ee0e01dd9d94eeee00dddd11dd9d01babb28dd9d11dd5d11dd1d11dd5d53773744775780ee4e88ee0e4a774780eeee497777ebee98ba3b5b77b7d4dd95dd5deeee7077773fd0dd8513b2fb059daddd475e4843444004191119f19810922118d00eafa3232021d88fd14b491112d8929750cc6360f7920c37fa9ba1babb86efd78a01cf0fadd087766c2e490508103ecb7ba54ec9d783f5fb1ad237b34ed47ac10b1cde696b23bc10a59568245a2ff0408f5ec8d1722105fddd6437ff33af81f426e6ffb3d7873149a9488e33160bc9b194f9b447fec5489a2d1671e9416c70f0207e83e3e0353ec4499a61f9c5203624cd35a03841d810bfe51775e8a037199737168bf947d22cf31b1b92e61ac7b989778a74ace5c5c9d5de99c7c4395e5c2dadd49234fb9c59667f068bc5627ea9b53424cd972ed1f8e7921c2d188bbdfc7f0613e7ffec7f067b91a49987e7bf48d0cf60ff45ba4b2396d3b6af61b532a639b66e5c69ddf0c289eed68d5a7f4d6237765a37c6682bb351a565234a7f4d62b0b05a998d1cddb2b1fa5ead1a6374b76a60617b6a4cc1b61faa61e4266bd5407537926eb5aaf4971f13395e9a35fcb5dc6a4db149deaa753752cb47f74752a5232461b53db61fb2fd50187e18be6c3fd462d59025085a7f91d66c8e467fd4866ec978d1df4f90b764a6fc1199584b86d58ac1a2bbbb1513ebc636284d1a53d3dd2d9831accc6f600b060b1829dd8259d282c98169bd88f14285d7e9b98cddbdea84ba3ffc68f8e348fd16736cc1f0996811ff9ac4624184d4bf1b9e47fc9b37199d5e29a64b4c5f8e311cc331ffb0db847f73cbb496e368c19a9779f83714c441d5f68cf61631c2f488450aca7628db214b45a01b564eb456b1eed62ae76b126badba5baa19f4d72406838d20530dcf5a4b45437fd86791909111afaf5cff085cd24a8dd14a4d699c69b5add4777f21d314fa3c4f723689c58290d10be20f67338bf36190db54b23939393b6a6ccdc7bf0769b6353f4da47376cbd94d9c592c478afd26f3ff998736cfb090cf12a7555a94413ace7a0b419ce9b489d6cafc6f99e2cc205fade7e9f8ce7cf0f0e1e387ad6eb397e6782c95f8178b794c892836eb1467e9c4dab2b5e0cb7c665f14e788fd1fe7fe92bd73ac81f56548b169c5db24e793b618398562f76bd9e222219f255e696814ce1e99210499607b3f74b7d82c18112e17f84b2e5798318cc47f2d9806912b5ce90fcb4a1cb37d8df91536d0b21287f50ab52bf05818ecbb76e6b1984f1fa7e46bdef2356f9927a65971fa4dbeb686b3adb3da0d0d8d5f5ad2fe4e190e0e2a7add44315bd2c76b674145af6ac9125627f8cdc4c7993ec5f36dee3796a70f19e231ec250ea95d9a20a559f16556c459a4a50c07cfb1c478fa4d487b917e48fc9b496c51285a9ba536ec6fcb99debfb3fed2fd23c7b7fbb4280a8d79b0a05046f708851484000a54741856dbe38489eef6d12c282ce9ee9910090a3b50c8419b4fb8c01390e86e7c69385fe9ccff5a21ffbe743249ebb79cff925f437a02901392e004279cd04313a4d0041c74f787a7bfbfac5a70fecd3e08dd70135fb4f8869b28fe889b50a5fb7bda249b80cbd16dd648f8b88435814877771358dd1dfbe14307c6842ab16b63e59d20a6e194eefe981063c210a3a7cd22205aa54ba8d2dd6d2fe9af2530752fe1c815285c8141ffcdf897c4c7e3d7f24df89febbcb3a479beb3069647573e702514ade359bb5758dd1ffeb2d2faf90c2fbe4a27ed0c26fa7b7a060f33d0e8fe6895de6ec6f925d1ce718299da4a9a1103da2c7ada249fd023970bc90cd20c9e56f2ddc41876b970acb4b79bf894f6220eebbb4d4df8a5dffe469c20ad79a5b50c5622ffea044b5066837d66b138336e129b11d5679a42b1202a9d39a6362bfa4d14e778edecd27f42b1b5347f3915c9910679dab47992205dba34db74b7b965727c9c6a6b4d5831fdf9258a6f89cb5924ca447ae7b5e4f848a11d7ada2cb2432fca2639df28dba12023b8a6e680f8ace8eea5bf6466fa5a29ed653c3c42866e6965351afd0abb85f32fd38735e869b328accfc3f34fe891df08d1e181c4e61ae4373b2539bf96f114ff093d22e71bf927f4e869b3880c23748741d5fa7c5f7ee9e47e9e854fa34da4ef562715adbd4ffacb702c9671a593361de3aff7976e8943af77be682de9a1ade577a61cceb7f6fe138a614b968431cd11061b329231c5f78b789084e4c7b0ff9b652e57fea319d17db23cbab68892b53d78463423ba7d0f99e987c29f79fecc88b0ac3cba5f6d44b7ef0193f8fe675bfd66562ff2af0c3d7c7cedbd6fc5fae368c1bf3758a473e6d77a068372497e886f757ab53889f67d2d16cb41f869ae33e6406002021220d4d0dd84c90d0b082d63eca0bb09130fa907c1e4ebc4319c88ef3b1c77cba0bb959a953484a6e46bdef2f5cd5bce6b317ef0ab0715bdfcc34f61d98a384feb373771def2157ab6a277774a3cbe0689781e3912ba7d0fa1f5c97f14528c4770090e9f56c3d348586dcf0d9c6f047422e464fcf923a2f8b2b31a94ad78749f8ae417c94c3f34f3fca996fee027c76b043f2547704999b13532f3fc09e71bf1994b2fbe91ed87747820093fa4f7fe121139824bc2a070be9107e9d2fd23a53bc7fb792a21c76b0449487ff0cffddbfd250b62faf35fe4767f898aff63b343b7293efe25a05c7fa4fd512dc22f92f42259a430637aa48174493be86003dd9dad88290e1f48074d3530cf11d3d195033460ef7656a9cfa6104a33a6eeae354b0c2764a6a7dd5d8dd6ddcdbabbefee42b0bb9375779315ebee6054babb0134f7447797cdc2419506eb63fcb0e6fedad90d0b0b0b4b4b9d3db77c69e87f89bcce4cafcd5f366e10e5c3b54c6df7c7035988e0022d16e4e85c49b0d80a5e20460fba2648685afdbfa1486b60cc52b3c260023fedfe9265427ec64a4e5a24aec8173a25a7c794402bf6c01c7f36fbedce25fc655bfd5ac7efa50892e4cbeb8f56c8e542b2d94a8318be26b1fc58358330eccb3896198c8d7984dc64451fae36d379cbd74d111765145f6bc325ae5f1fdb1ae8b7b43ff887cb3cef24c9e9a1bda4df70c39db6e9dfe31f0e2dbd4f5a5bf3d8cf60d5d6c019d60f6d8d7d7973cc6d5e52e2df83f54b278f7d767741e8f8ccce6e5a3793eeb6e996d22c19f4c0f7fb1a384125d08a38555841ab9456690cb6e82f065fed8f16c7a0e8035f31a8a1bf5ad2c2177d6c3f04832dfabbd67560d0d41f0c725e16e40563c83cdb50ddf6822adfccf305313bf4821a1780d18de94dac442ea0d29fdbfcb5638ddfbebaa0d62e705b3d07a86aa8d4d0cad5a19c05195368664400080000b311002040281a8ec7e351c1704a7b641e14800471b0668e58194ac42488610831630c0042040006400000301b0601b0b474da5bf7ace97a393b2257e592880058f14be396fc924ac108c3402f8bfe42a25a2df0377d4e1bd5f69e7e924116dfad3419d1cc872a9f513a5e11024092988af1f3f3487e019352ce2467eab06b3b952846512ca5d33e54988214ab128680d695c310406ebac91bd34d3506d736280600d7784744f89a7b6a2e1c0a0c3fe008b8bf4ac9353467b4efb447385f269f9231fb0bfb1b26aa17d62df28308bd187bd9fe8096d38eec77ccb4d53c1abaa8ff996de9e4696885852aa66db3abc2c8ccb43e4f91bd4ff864b69def21e174e07ac2fd7c807e130c1ef6dacd7187d4f75622498bfcb678dc1a641fa038a2dd7dc240e25ca43f130c6eb612fb94082cc098271f6f5611c355d0997b56fbc1e5513b1215184dc912e6d39729d09af9f013ce08ef26d9163f9e218d422c70bd2c8b39ecdb9c99f54e3a5402002ff7a9749f6590c81ccd8f2cc0b879f08765c6a23386e830108e6d226afa09122685a2f5ffc9c0894aaa53816915b57332441b76b51134e0d75be6362d3f40b2031b017336392969df5e3172acd1377f2a19fc4a186aa38253ab80538a36dcbeac1370cafd64538a3755bf4786a0b32ff488127236050f2331a70ed90127e26c179d80e2cd5e72dc883cf5343894059c05b8e903eae4ef0e5b19fd88986d512580b8d777d0146874755102d609536bc7bba793bb029052001332db72bf7f91f2682ec4e099e86c7d03fa50c48f8bd6af61b26f8847fabfa76c4e78a04d436ab261d7b409246df0b82dc9f5d8122cc8b7def50136935490215340fb43640f8a7f7ad1551d9113326ac2a126795f2405989f7df834bf51b12a487f92f9a01bb65ab37d2dbcce2342fd66f5dd5e75b4efd28c5b353abe9c85041202703101ad1d6f516100703737dfd702c6caaed3d58028cdbe9a8701e50ec0bafc2ce5730845ff53f83e0bbd327769b941fa61f9c5eaacc0a68ac04cd30001e3a3869c5b21d225e4056bf261fbda4e31f36cd831ba6e663bfa12836a118ea81f0ddc19dbe5fb66d668877441b3021a54489713cfc1a49a0116e8656237254251de88a650f8647ee82b95597e799f84df54226dc1c4f6b3bac61071bb19d555d87400197733cea657664e846fba2e0c0b7011339543e2c7fc262b831f404935f7fabefd547692afd3cc59c74fbae2a50d9b1661bc0707e73995b9664baf2ce64ae66420d19c2cd840f21d708d69dc685beb357d1a543e050675a6c9f64ffc5aac5ca4dc16270d7544af004fb3f13f3ac4274f5414e8917c30a544bce8385632ffd2cbc5120455745a70c2e7ba63faf2716d00e9acd47cf83ab83bd48babf5a85269147d10629f756c97357363a9fec24ba5c5e8fd0efd0848564a779267ae2c1a15edda38093ffd82a5617f9257307ffef070181962c620c9997becac0e6274449196fbceb6fb5e368cdfbf3bea8d9a530de468be9e19625d08d005b2a07bb2e93c41ce335d8eb617e87aa1cf1ebc0c7cdd35ccbb2867c546a17f836e8448d149c46119921ebed2cf43fff538d3cfe3faac25cdc66f3a60932c2b274852ff1b65fc7f00c807781d74d2f8a3e99dafec8e81ab38524abd29c12532bc1512b18f5d7f5cf1311d4f4f712bef1df10530bf3af720198a36e40759ebf2a31e99802ba0a72d73dec97c36a20fcf9e20ca6753cb31ee1d30ec1032f61721e657acc658895cb022df6b966b5d1bae1db0b12879fbbe26afaad88361710e435816488ce8824c168afa11dc14480bc70dad8d75440e5aafb80136249a14d21cbd5ab3329ed4a91172a817599272ac00447592e5e43d297a3e73b8205c41c622c12b1ce988bf7f35cba16b396574eecb35a455d65fca2f1fa6f3780a8a60dbc177e7f45488905ceeac2d37094cb032b473b2486cf185548ee05bcf8b43cf2a54dd47ca3c55439eaf73c3301983e1bb9e8d11e7e96920e3862c64045adb2da6f85f9d64ca5e5d36cd4fb76b3f9c51ecc8fac836949d93d6c7335f79850635642edc9acbe5dccd3d064cda86f7ca6e7c79263b62de6874c917493b20eb62c92ecb3a3d4a33bc2ec683beff45028e86910c4f4a64c965bcfd20d7070a77c547d6e82e99391bc94f21e91e62f6f7c0a9dfab332eb248250bf5f7270df41c71fbbe8bd76010331a9e8bcc6e2c67ee67407fec804ca6aa9d27e7fb1b4b66fb25b944d87fba009429b6e50e608169a01879aaa981540221b666ba3f38afdf9cc4ab158ead4cdf01273382dcdc6f552d0e3d83f225feb8159bf26350ceb90978b9821a4d3afc1c5e4c10acff4807b87f43e79f6434fdaad73ecf5106b16583f21c1895b479ff5a642228ed4dac476e9cff1a9d3ba994ff65b0366be6a0e5b531e0e5c8d83193a9c106bdcf0c895d877bfbcce376dd8ef0bb5cc556400b625903d497bd947ebf621621e8e80310d4605118e9b8fccbc8fd3e31809135ebf8f9c6797d69e1fbeac9efc1c0197bb5efdbaec73e6ef4db51e6f3112286fbf6443f583e3b8a1b0aca771c932533003c2d91f09a8e465e68467c6d98ae497714eac504fdca063b1b385a3b3ad26f8cd3c19b0bc38260e0969adc0e7daf3b48ad1f6bb68dfaf30ddc48f0ffe5e2a90ad6a78e89ca55aba0cb53cb6eeaebb559515a8433bfc2eb3fe5b95b154e4067607596557274ca818c33e1fa9bb2c74c125818adf3e98b3cb8bfec1942a7920925a6815e94ba188fa5693799a4af8d11c84cc3883e084dca00aa68b235d10fab43af83c957b5e56fc6da51c4d928cbf868ae8c31bc0322654253f21cc064f4e144e4d9692ae55fc773e39fb3cbf76c29416039da94212b37f7de08e2552b309139a21644650fe1f3aca69afeeb34159f2f32f2234ca55469f33602845b2a270d31459f64b352656b8360753e2f358732b729b32b2d58fb6e410ec8216f67213a4c274dfc2c480cb7253e6d474c1d3564686a3aa10838cf0b2301e9e960ae57c415e6e9d815905446a2a12b06660f037a3d53de1095f2a62742e4a9fb037a900fa769f0b089cd16211a413b8c0689e2aa9d1c0e406bb9161c640f611c672866825b6f0fa533d07919564cf23f1f0a31c3719fb8bd0b2cbca7386e4f0878cb51b82eaa4e088353b1f59b2afe7a9a717c452a83b798e3191ea5e3c2f618cf1082bf66575a7d40147f2754a1a182b01a0670c3aca407765661867a9d21bfe42075075df028d916210e80bb68da32a1ba3b58ace97fc6802d4ec5966c51838d1a0c383b21b1474330675a72872eb24ff21c082cc6398f24136ebae22cda1f495b762b947f2dc35a3b66e25119333753cf71c91a13e9b170c522d519d64872dfc29b8dd1ed1d9e8e5b8f47d872e221332bbfbb47b3f4c15e30efd94ad5ca68a42506c8bf9de382d494dc40be794d17ec3d3d7938a3a0e4af7421de26bdacdda2fb41456e3d69cfaa3f3a6ad849ae049c2186b333a1f162c0a254a97e5d11a7d5674a6326a85484f11e4be1df7a6aae18a5fef57a6da1f5a423f93ae0f277e8ac2cef7d2d934a45fd8a1214e44da9d9e281799eeae1fc546550bc42e6a8961ce1ce93d3939236bafc5ab15ff22e64758800b5e5420df201945c724937f01867fe12b8752e734acefb4f47b6c30661e67141b556bf7f9914243ed07f25311f9e6f57f13db3b60182c266a83a9842453bd7a3e912b5d182138cf8ca00641e46f11699d01b5daf76df5899ac2b937bd1e9511c368b1a2e242336b5e988f3c737f3d60507079d28ee011cc57b5d4c034d2fda06ead06c7b51e1f9e20f28dd48b43f096d5f64573128a3861998469f27ab70c681ff0febc9921eed0ddd1a91ac26670f3838666ea720519dd6e37580f5ca5fc6a8dd5e9e3672f6457e074b661717eb5c4d6f57126b87a01a315d81a0d07570ed72ce8885bd609df22e11e41093d69af34518d8952bfb0a9a8abfda1d112d134cddc1467967a8f63e31685f92ebc6dd07a1cfeb91f82c16cb57e9decadf0f242050cb42f7362846b9b5d24d36c20efec1c339da776c237aef9712eaef7b40a65134a67e3d3c69c1ce380f59fc2abccc75f9aa4255d059ef80504fa36d7a58f3cbbba0066be2a461cb80a9a2d9ac20f771d5e909a87ec2bfe542e7737b0295aa2fb00370f2d20d8b3668292804ef670c03cabf8fa06dcdb518919ff89796b8f7fe66c38e37fb0bf4752af707041e0f53edd7084800526f5f8c92d6d33181f783c34e4384f16bbaeb69ea6b358349c617a965a730d346ed1dcad5b49c0ed54109928a3419d8c36863e6ec52d553d00320154bf297ef742cb1551e81ae6b6815f177796c3b297e8931355e78e2ad8488882941fa2629f69dc344822594e8d2dcb443468eb4723a668e22e31380fa02a620694e5d49655a121944a18c8ff8ee5f6f82f310e304e1156746aaf6566e978c10466889ea6c0c5c9f9f5332463138d75ae0cc56e462ae7e010c92d86d4bb5e947b9fda992b36b6b229e9fdc1478207366262121c709ffe41652f5c24b4e7562715e47bde0972a77822a511c633afe34d7996e66586831adae7f734cf7cea00dc3d62441b10e519460db14df28dd515bf0173aeb2d53b67bc8295135aca149bc53db6d44d46cd771941264d895511c43790d854f525723494107a35135d7a6e438dafcdab54888967652ada411f362c2b10fcc9dd55c28dca03defda839cc565bfc7c23fb56743cfb5b939f2f289d1438f357965b11134b5160b403996bb6c6fe0dcd26788568025b471bf27742646e887a916c3b5c77352b3b9f8c1426d54458e9908ef26f32773e16ab5ff6832ce9cdb8abb0130ba8260c0a7bca25e1a8d12bf1be9c61cd7f6131c91dde4d229c1df080f8333863ecd4fd453f3be0a34919405488ae74d51d20ee301a15883704eb819fdc8c955570506c1525bb2bedf3944e523e241c174823f284d35346aec73081586ee503b16f0e7c925cb4e5ed1e302a0dfff76d9b9331f63f4ba77016471a0568246f72200810d5b0bc231eede8e6b989b52b2748c1b4749055b98926b05d180b3ac977f163fdcda0220e1af1c336dfa986155ce873321e06f885d9bc8806d6add82ce3e796e1305e6ef0cb3ccb64d09dabf64c5710ba67298067a912ba77ab83dc6a626d5376c06ae338eea61a8d8925ceaa97c2ecef9810bcd2722563d0e64d181f9565904ad39e233201ca3c8b4ad6837a1256c1e0569552ce99cda050615dcb80ccf7fe7ef0f8968c2bfc29340f26ecf058d9e7ee76345073509b1d7cb3e431fcebafd38f642011508290eff34494cac23a4b650fce45edc62bb50bb0f36014bf52c29001dca8407bbf397c4133d377b3e4b9e48f0bd3149451a1c7d98f16533f97b05ff71fd5a5f319ce651a458afc9679d1ed4829f50380e9f3e8e5000d17ccfe83426fa32c0b29c1c4297612ea8ebd835d80ca384d82e5e81b17c8b8f9c9b98cd07621cce6b240b28e3f05db6612b80c44548f4727b805d808b0b9da2925000aec4afb01197fdbb71fd09b29f26ff16cb24f04633a2abda5404392f79880003065e7ba27ca3c559c403dbfeacf90775475b856d31618dfb85821100700691fdd8f10631c50face8a4939010297b86c34cd2ec7370bb682314c22a7ea34797d2f12a2bd59a2986a207c0ae3c048b63d95bea90b85290d8be02e18bf8e2b5b64e52ecdaf5730a1e3c0fff09bf2da35c5460dad3f3b53f82836959f3839aec3550e2110e3bc31d1a0d22524af882c2362093b32098c560eba48e97cb5a61ba120d4d685a7fe5186c8e7c8cd7012d52c7bda79b658f472d252b07fc380872b1f990c151944bfc284710eaf948563a9a06f8a89cc78cbe3b0e81bb785d294c98a4cc7746dfa801024ce503c939bfe2eaeed2be1afcf2e571ffed1a7f41f099738eada1dbd56857cad7dfa0a8c733442edbf2d6aed4df0bf71781d0a6c18fc604e591732a03771f14ec7a81d0efc98565d7c204e7f3bb9b20cd32e85dddbe4eabb3c9cd5c8ac36182cfef3817bf13b1135ef2547b71c037e7c1b3f876e8ef7cdbac1f05cc0f5f5857b56d40d65ed6fcc48083f028d6518478ee170efb487a810404edbd7175bd28927547f446d0b79c3159f1ccf4d048c01c94ee617972d0a101ba43f2bc4cedc057a45de685995db63e46825904dc047179202efab92f5c5f239a2942be58855c78979749946f3439d1645f95a721e155ae4b01dc89fd268ff9ea1b0656d75210e64a6abe825572bebcea84e25e6caff95cb25304f039bcc64e452faa8437de3f24f6a4a05228180c41b786898dd021707eb611304c4aff8927ed82e26827e1115c83356cc8b6472596078a8b66f3b54d09a4efe779f09024979da996fbaf83d658b6f696ae16c091d9573831e3a9ada9b0dde701e6666d336c04c0adbb2f518ea43b5ef73606b86179da8b7fc8dcbc2a31349ce4d3a78001aaf4fad227ac4578e315048b85feab60b48660a22cab548d65cbae13bd8d389a0ca73bee445460f09dcfba43eca9dbc69293e19062b84c13604487e9e04b8b6c1205daeba0d7297c8b275b44cf7644e4abec031e02faf5de4dc51abf504f803f5daf7389ffdab2c848b47805feb87f3bf019fe9ede8054068dea2f3763371feaf559ca912b96814ecd592a7b65621ee3b663712cf8545176366a4de49ba4dcbb3759dfce5b726db1ba3ba185b074889b8cb0ce85352cce1b5c23720d8c85f347e433b3e6385260cc67df48b65860574dd77a9ee14ef5c6d2d4fb7ab3223c542cc3f686a649b5134eb172a88ae2a819c6727fb3669eebfc8e7584918d77204aba2cd977a8ba3d0b12225d4eed3b6221545b59e783b07dd83c302bdcfa028eebc96f7d19acb1b726086df71d8e89c5dec68131e6ce856b64f1b17f787f99bc10a45c0e0011b0ee6570c7eb02a5e5d12425d4bcf06faee368e2c1829fddd145cef546b0c60ec420439dc76cf9fb0bdf12cf2c4f9629d3a341c7d4bef34c5086973845fa3db7592b37b2d385194104a424a2375e7e005ba9a7652303dd1feeb875bb2dfb08fe98329c8de93c6a62711520f6e512aa90379834fea8164fc23b85900c55a765fe4785ef7e921efecfe94b9b50ed2aa7a9805fc77b3206ae510a9a095459957a638fe133433b3bf5d01c9a25a308879e19da0b92b3f724a85e4936e3c6f303191396b534395364f74568c9a998647c2121ffc705403317b31564fc88d1f973f45427d47180202c461a21f11f15b6c22c3708acddad725ace747bf7692500b7931e09652a2273eb954f5a0bbda41a0a237f977d008907a6f68a8471782b9349d846237a9b9fe710ceed1e560e1089588a88ee975d7f485146eae4a0246996f486ea849e8049b5179817d3cebac5de00c4fc53b32cbb67cee5ae8b287031f20019bdda8cdd2540673a0e39e6417d506517f4eb2b3d3e1c5e1076a4477d1753d5c035394b639e4dc5f412082cf233ad53cdaef2cf2c14dfb2b361942896272fbeaaa77424a1f91531496ed57911c26d68816f59c5f6cc00d38b6d1f93c38067ad209ef5de26d3d728d04fda580d6c2c5511e7b80c28eb4b0d96d9458c69c17781d03e6db27c3a74879a8ca8a24253221b7b6d716dd59506618dc025d93e3a4d5c780623203fa78671b9893fad2f59d583e531a61e43bd5e73817ee30e7254e8b87b78633aaf039b348bfcaea272b9e85a848ce22fd1333ded9b30952eec941c70176c5700947c4938a1bb2203f582724f9077333ab3cbb8078cc24acc016cf636fc508ce4eef7df19d56a8fb37b278bd67b28c635187066c21cf06eef3b9c2c0770ba2758221e81ec62d41327fb7f0c2f93f5e1136b1f7d8a461130ba2e43b109f3b6aae6dcd932103df9051a76f59fad7d11bf3e4ef3e50ff97301bf32788019993d1ec6c7d8dd450c6e8d7679fe5117ae72129820796e1ff77af02ab48436f4daa4cc59b1fd21422231398a196b22e8e1d46c91bd121844b0ad895c5742ca0f5c0caf4760f54495229c17b4c2e694de5fef70247caf7e6090bd7a48bab17887f4202d7ea98fda088cda64d61c21b999a101e7754c1427d246f2c447fbd7427630487516cd3d3a0e651ece865ae9551b580a1017d0f8ade080988bf974d2b5418098dcadf2b7b5e8bc77405b91a91ee12662432ead852e4ceb2b1418aa303762755c95b21884c039ecb4967074ff29c8043bc19dfc559afa93b0be6b3bb902d50a5f6dd4b8b5c96f0aa27f8d58d94e1aaeeb779c8823eed198b638d35c88ca3bd5f46267a601e540975514b4adce7bd96329193294b837904d903586becbcd953042a78ff2a5d8cdae4256c8e34eb64f6d2a217ac353215e6baccd45d161d396ba6ff2fec882421bcd75c2f45bfc1a66e678c183b74592d4e59ecb874f28957df2ba9931a0417106c94c8041355a6c76b83a1bbb41425584d66eb52a344a35fd28d40baf27eecc8d2a16eff159001e018321eb78539c300d051ce6f66d8c415a1027320457d3297789303ca5e949b007f6a2b576e2f8633343ad18351ebda2fff43b3922c3dbdd850a42f01b1f000764e3feb3b93f16cf1f7b86afb977fac925aa793993dbbb417513767853e2edf7346f9bdec5d78c7223e85b36e9ac5eaeff48ff9c7b30fe57a19ae04f8a779861223ebad761a00cfd60cb036fb8cb98e973c1ccd48af440d1b7bb1016cefa64459257406af8fc61b605390760aa3fba99018352e3a31ec3d8b071819e21cbe49e83af8ea9ce6ddc6ea480fe2ca7ac6b2bdf86376b7f84f849ab2bfb1f1129c544bccd2d6938dcad6139ea82626b4cc619c5f734022071ab04f4e25ff8d8a98fb7791662f455b58b4170ab371bad05aeaf98cb32df810e8ec757f92b864727b32fbdacece3b476ec944300630241cd20b6f2cd675be490967cf034338e7c1da88881c3b43979213f068c06c3c41f9069f202486f3b4f195efe8fdf9a4255314dc517ed5840908647feb42063ba82b995cc83f8a43ddb8fabd6c602ed931f42a956681673f979532c81be29ece049730e723f5af636740740be89f16160efa1b378ea5ca1dc0667b9e29c1513c58dc356f833bbf73d2f3396f37bb876c2db31be5767287dca4d857d0d356065a4224fd8f60a35a4cc2d9b7ff947b14080ed1660b716806cdf0a3019666623b1e1661b3ff5a767e6e0620ab013f8ae6910c29c983137c0f832d7f8173e88b12c48187e445063742ca8db5b458e0fd3eb09035025615a55b5d319e441a646423ceac4633988adc63362ced60a93d3e96c3b43016b5090fd661cbd2792932b317fcf18e4175889972fd4ac219d2630c7b6b2ed036c24369e7af49de3863f32c39afe1a10f66745ea6014d2f3d2f64c4be50636213105b48fc68951c66de8b076137d33a9bb30c7c8540cbc05ede8b8f1c6100db7f92162eece3e39c45277672393062225aece4c1e49e310575b5d8206201024520258f89d2eb993710cf423e701a07828b5c94ee10d89f2f46133dddb32a160bf67858827c8a4b5bb6e95c5d4c1fdac0af279035152dc4f6d4350cf9857786ed4634313a5231b4991d542998c9052232390de75227cab49702f920b4a89e7236957cca786e3b2f9bb0adce7c42b373b1357dfab35e49d319add6e0675c958c3d0eec2fc0d311d75d27bcc12fa0401dd6f17718da1e48d2a9c9e73b161411bb17a538fed43e6c2bae01343c35553010ead4db63877627b2f2cea9cc2d434de55b661ba02557b4d5b8b3ccf550bb5cd413b087ecae011531e35ed670998e118b55fdccee6f64c0ca8cb6ef12c65d788ff70210ca8db7c1be036b4296bf0c6afb36d623e9b88a79631be8356207ee0a286ea50eff52b9a1688cd95ad698e58f023665494324b05e6588be44a521b0509215d0545e0d72ff62209b7c6ad78937137549917e66394dcc8a062fd213f0957e39c6b14bd5337b30a661f6696c0fbacb200c4450a56be60958ffcf97b173dfb46b8577150e313f2ed39cab4d4c4e55e9635b7f9ab9f6ed7d9351110709a462fa669236c50d36e5a992904aa03d85bfb490a8cb3a29a3af9b29f4eabc5eaa68e44dc2930e5f7a0c923ddd9bae5a11ca683089271e947f2f1e7bca0ac44b8efbac0d70eb771abe7eec94cda0499331424d7feeb2adfb89aef798ed3de66c5f6599537fc5c20df81a75e39f04c2b745811e3a7aa97b81212ce563d99ae362b46d079de13ba6a73bd7c03eab841473236215a991f219495c4b6ad804c9662240ae9f0f288f4ce9c25c2cd30c01ee665d47f6b0f83e35d3988c15455aaa59dd0b91863345d5c1432da1385ffda484df55fde3f9ce2bc4686af89058b4200e3ed4ad38bcfe7c340d2138d1925226b591fed1b3468a236d4464281c4f51265d0fe880bf06d7cad6179977b63e67119e8fc3086a0370de05e74501f2de1f8b9a79789290d662e75dc4e09fb8e337c599a11560f9aec0b138f902b7ee8bae04a55fd2f4ac7e78054dbe12eb44a174d4b250e67e77237604721983f9b2c7ce04406b74f86044d57fa1104ae03f18b8ac7972169b23ed20c7b6efa81f891bc132febebb8be5a16d690b68671c276b2ce9a62b2b6c6cc8b06af74936a47a137d477a650ba28fa8a00d59f7e46988239c80f0d6296842bd44a2a796c8e55b1a51152a2aee08555ba345f4f0c7aaa3e18130a37b624173253d8b83fb6b570e08c28f3b0f1e3803d23151b0e7611495ca7a77d45697e6ef1257c7f3576ab4a013e04a43bcf44ccb07b9c6660d9ad2c2dfb4e3de415b0548a871e35f3b317b85a77f08a44feae1a5354a5396a0e077f85013f258d6e02abe78e74af5d8253b4101c7c19d20df71a262b44ff33c43a5b44f195d0aece6d28c5cf3c2dc8f58ddb60a600417c0aed112b0cd3eac04df47068f9f65f4868e619e9331c07335c323d4e93a6f3a3187174089fac67227866da441e7cca1380dc3ac4be6cce8896b588c97a36e078f88eabada0915f44b7b546a0579cb627c8065609b1c0390358997668ba8ddded2d6ce83703b2ed993aa24b26368a9f66974f124d68cf334d63258d1a3c923617e36b719fcc46537cc87b1158d2172f44c9ac30667cfc84ed09df0db19e26c81d94af621601794449445680edebf78ddb62b965c6eedc74f1463043aa0403bbc0c12a820ac2130d7b54b114873b53ae7daee38d0d56d404acd83fe496498473ce68f56d27f7a55f04a69e3a68a43bbe00a8e304a71c750a7196b0a8c24b9ce9ca3c513b4dc37e1166b5114a15369db348d9aa8c39feac981608b27086d26e266992ae08e1de470e770b541b3f8a9f2c0486830dcf3941faf7f20ac2f254b2f1e824dab39ae433c676e4758001c991a668c0daab4e24959cb62a5afff00ea8d207ce13e30248c14f3af508640d5ff3604145b80612b3aa4348defb3e292710d4ccb0d07f0b647bfb1190fa4d0689ecdcda1e0ccb03ce90a497b2b5724907eb05e1cafa82988756492d0c6f04102548f16b403fd4e2e68552be9ed084017cd1c463bcce601144803147b97ec05af169331e0016dc1cb62b813c735ac2c8224b9410deb3a5bf5ccf00a71ee235a9da81c7023fde982556f3bac1334c34341bed019f443ee97098bd6b9cf1b8c10434f96a677bb25f38df84b59e3aac6b3dd18cbae7ad784682bb3e91364e0f0e647d65c2857a603ddc97beb5b52243a37e3a663e1141ef4653ecac157b9bfa917431d80e28ba0696138ca2c7cf62d00130c3c88dc8ad38497d0ddd139c18689385dbbac34bfb52de6abd07d29ad7cee09fe5acdfbdc5b4e26cf29bc065c5d300d0165a3b0fb98686871767dd4756214e35f17ddc1ef7933f8dc4259e1a61d875fc04aafc0f9c675e61334ef825063f3c64da870e2df46dac79d56862cdda3dfb2c32285e6f8d8dd36fdc67cc6e6d244060d622a60717693d32a00dc4149e2a11401616eca3f762017e3e80dde172af5e1ac0fefc1d38f2b273adf27322a5e36e539240f2a57053fc29d6ad5bd5055dc44a2afc879eac501ce09a4da5be1d3735033b0c3e21235f10f63dacc2f2bdc872ef18b5539fdf9fa832d364d36d4eb2c294ca90139b8a07fa8f2964c84211ef376df592b9ffacf73321c87c3103d47ba36b81be6628e5670a90b081ba79c5b50eed57bb98fb08cc5404f9851dc039e72985cf35e8d7eafc06cb625540f5b833b14309a8b5b4158f3b8b7e213a3510e4c2ad81b881f3264e339eb18f46a1a31aade0b68fec08697c56823b08741f01b5631dee42e9e71db88e230fbee3b6c4b6016d792168a7c383b433bd1b7aa39dec63831b26f314ca0e3ad79371ebf5d12291b5f9ad6efebc49ffada7cdfe36329187e35d05e1d7296e736729d540f5813a7617165804eac2d010f2f49fe0044688f4d4400ee4df23e27bcfe919921ba78bcbb1f1b89c5e02aca45ea4c12746ffb7e3d1165f72091261f28c3e93bdd9dc8abcea8ef7a9781fd829f53634c4d0bfe7e1ae860fe69b4ecf7d2a2e65bb923cc7fda2ef7a378ee58e72c0c8ad3e4d95dcbd2facb12094e73f1b782f84092dc2e45aab58ddff2f9eb01ba0bd8e4d96f7c9d664d1566a8ac65161d03d19ba9aaa282636fb3a8aa19ed37145fffb11484bd54faa7721291182f7988005829ac2330cc4b0d2ceb2f410f9cf89f156094dd559c72be7ad1d27e2c375902b87e4143a787c52f2eee340be94441afe95fc2a6c9fcdc6ede989fa58859441bec60ee5aa5925b3451a400d8760b660736a6db5a8c847fbdfee763f3cf6ae729b4a978bd45ce2f9b541fd2d1a9efad3456e35dd017b86f3d6918b2359704e5a9999a88f7ea3209f20e8d0f13042d61d068da49f836985b17055b59b59c75b11ca59468b9524c73207eb3a1158b2db4fe339b85faabafe70936bffb4963667bfad77c89221ba1b56c2f3520791c22728a54d75023748dc62d1cf744e2378f373ea2516b8999fa52bc9fe63951ae8f2a6237d878b64c09d254a643e2910a0c0eda761f0683d6d1ebf18c300cdf2c60bfcbac5300c30b877f0001a971c32cf79c3e81308cf57f0dfbb665c7e1bf3a3f62030b4d03b355c369ce0f5a287771d4e888b83d4a3edb476bdc4d84f78b6a5bb54d8a6476d8c83d5487f725e5e1559577ba1e20dec15eec601222c8024b564f42fd86401565cdfe303c84f5d0625a51bd9ffc7563ec9ef2cc1ed5d66ab338049cec93433b83c2d5c70463ae5b54fb51ec8d83135c2d11234daf64721335da751407079ed7107c87bbbeb5e739d6e79bf3b5432a52a3a7ec51b01346c81aff041dd7d1dc72d3f891ab841b7e5079f7f9af236b66c9ddf2794694635a21cacb474420f72e3a8d1ecbedd1fe3e9ed7d46e8fae50748d3dc2dfbbf3fc0dd93c5007936a6450e54fbe5658bb479c7011fbf615bf9453550f565411406af59b7d3d98b199c2c210741f238056b85d900551cbe1fce736b0338492c5f12d9e271572ac89aca311f235fe5c32c1a845f94a8cd93976970cd59f9a3575b99072cc4ea45b0ac893d963a9aed964389807a7ca2e13e212c84686e46fb0e99b9ad4b69d9d0b895af80860b5cdbc27ca15a94010858e9ea0d13c928d1dd91c4b1a735054d5f4bb62e939d68d6322eb8a18b7f739c1caafc8d5bbd22997faa0ab635e21764c24f6375648ce45bbfa3a7e9fb95b745b535b9d5534e7d674188d8d13c223852345f633aef9fa318dd508386a8cc50c9a05a34935c17ee6bb34ddd82bc4b147202b593cf2f2e1e08a5b02e5145cc3af554427cef5736774afcd9e5e2eec714c34c9e1abe5f337a8a0638d4407191507cc340628d6d8b920814f1fdc4413667c4bdb6cd100318b545f7ebde24457277bc97f647b473089b57764bb52d9de6e254e5cee906dcea1bd40b17fea6234e374be0a793f3cc98095db502fbee33cc42f3437a4fb440ba9717e4a5b76f4097a4b02263bf382a33d9a7f976ef40a3169f8e09b1c58c9dd537f0fcc13e312bb6a14555c41b741e07fd90d666d0e0c7e23b2b816c30ecd328c84d0762ad37a01b2c42761566c1e927518a361c50788c1b5945c7d8fb44c71c189df912ff244edbbe3be3e644b3f3b3aa4150db1581414afa829105bf3a5e0406ab08685f38529613d6525f2b0dfa38601c4909fc2e13479b2419f5bb885892da98720b5008d379612c836837ab8b51ce795ed7328de2dda6c71e0c3a33bbc2219748676fbb427e427c32bd2e947d4cf7d9b7a07ee8175dad73e83a76166fe9c9a94b521594347d9bb3e8239bff0d829a0fc6e27365a842fcfa5d38cd78fdf698b9dc8041d0d96eea51d92368c9fffc5d0d541d663d93a70e3fafe1c24c20ea538bdcbf9a51ea8973d18a87920bde4a8c9a66029907419972e4b8a0e1bd7636d7df45fc45bdf3ff59e5903fa4bcadd97cfb81cd68d4221e714ad422c52ca4edc0964ee1cd64ece352889702ecb7008327602c8a626b8ae1305128b541d040884cc71b40343453b0bc931d0c0e1e469fd19ff76f22377b6ea7b0e969c5fb94fa7b1826faeee78c65f40481ca2ca4e040adf85073b447d53be248d88049c4250c32cde643c81a962fc7052246fab5d192014ee4974e5639748fab8e976bb1d9502cd624878066f170af51fe31e4468aaf863f72777cea83db381f78fa6678dc888751b793ca24071118784c23da53ba6785b9f803b3ad238b59e0b0967e9dbfee0c6e3eb62017490415efa6afe0c621ba483c5f6398053d09b9691a1bf4d50e2f9f12cb8aa0addb01206263b3c042849170a3adec867b70072c4c4025897e9f67d9d39c91da5a1863df2a022d55df6bf26a20353d012d63ab8edc4a5d8ab4c1a22b4e0e97e022601f9641d4c5d858b0f3cdd14b72f6a5ef57d2fd3d03d45fc87a4f4a932ac6b2724f1835032313d5422185062dca52ea64d2cab1301f6d1050c6e88de1ed8fe22f163966156eaa7075c69750cda0102caf1f5b1570838fb4fba8e08737e22b7cc82f161e6c289fdf1c5b0f42122b09989b6a960d50e68102c14f4e207295fb4161ec60073e386f8475c3e8ccc87a5765585291cd1d3934bdad266c1a2792a9bfa52925f99916c4e040b6f123485b3b43f8d411188b0f09d885b48d1ed45fcb4d09f94f4d47b30032ce8c7500bfcc70b929725cedc15f1ac3f7a1825be0e9dd5877d0293ece63dca4517729708a8190163b4901db85bf9464192fd7947aabca00fc10930b658b5f1865b4486c69cdcca042eb20a54f5d1644a73e84e258072212fe36ab0dc9ef6bbda8cb590fc6c13a86c47f2cfedbf4b4ef9593be54df02d20f34b31eb381c19c3334b9a9e95d3ac0e195b3e4416028f4dfb04ccf90affcdf0a4b9934ff9d7f6280f5da8651655671cbc823db869ea79b07e1295899cad3818d8157ff5d53a62c517c3ed927a4be8b1135c5a7987fa2cf6e57b283ef010edbc98346e17f98c45c95642e3c5133f6fdff3f81d01bc9bd76366ee2026917aeaa3436c575dc0d08838a1d9315f84d1b8e3cd249f84dd79e2d41bedec0d3ba0c3013929ba9f17e099d88cfa6e421910cb811fba1c4d4642e8761233a34f72dc7502f428fed96b9ec6920820cdfb3b7e9c7760882f2afa515453c1e23f165bea2db0f5c67ebf63e25042b4e8a09d4ea3884403c8704bad6c601224b2628f773b9c6f5377854452acc24ad60a44e5cf7480b37fb9690675b7d7aafaf5c0adaad4e02da72e856aa988af70e088a1190af65382c43dab77f3e14ab3575b9bf7867697952b64093083005a3a1c7deb3846d8057a4786ab4ca831f274fe1a290537e24d70cbe43fc3ab27f84b5fa20338d016e7a9580535751b1a5454dd3dd3934680f9c5148af792315262de77cd0a7806d57f6c49773b81fc7a0dc6841143e04f46608d56e932469211c393e426abaabc58c253a702dbad4262f6d59a87d9dfa189b85e6a65ddeed0e4d3de5e277a6abe2752242e357d952d6a2f6f478d4cb372c48a9cda7a2139d8057a065bca95162213cec18df04cfbd4f8034f3ce5880b85f8d01961a25ac0361f405ee335fad3b32476e00331549bd8be6ec5c0e19d7f537e4e6867e8e2b30b3c969ccf414d22325c299daef6f79fcfef50196aee810a674543fee9ce67b48892dd5fc104c96452143f9d04960e208f7a96a748dd5410137de4cde164e531bc2c0b514ce45e2dd9ae91a2d56ad0a0c5ef6d465f5a1f870714ff0b12ac8aea811385f82b8dfef39d38d1544457c7008091de3c1017972d6a79e25f8ce9132450b89d61345cc5d790a4ac9318244bd4c5851bb9f5e2f04921212120b9c25bf8287c6e8944544864fb25726a60b3a4efeaa542f2af25c599e90c6f07823c01b874d8aeb1c47101f3c468301de80cc76fae9ed5344b2bdf49bf6cd1233a92fed7560eb897b68812c680b86265bbcfb5b0a12ed7079ea25dcd9eb4fb48905733ce07af1dbbb80666586a31889acfd160425ad6822ba955edaa727c203fb63ab3ad17a7a6e903a94080a8d0cc73fdceee51373298ebc33bf78b288adf1b760e67a6f8f91e8340692b8dd6552e2b406989eaa7e33673a58bb57a8df46bfbd1fa53724397b2e11625235b461ff8f667670ef42b68753c565903d2f780b2892cf5f620b0c4f92f4ac425c9248abb219eeed5be2dec7356ef76e2ca7bb41fc68a514bfc618af02fdfce46ed9bc9951c4d3b21a6e58df62cb239639b488bf1bc75e3e92f5745078dbfd76c261eec4a09912b76d5324dbafe1cd265f1acc74b51bf4cfc3c30609ab869718c84b307554338a7472f9274edf08de5f71aa28575a37e7239d40f08269a89d6ea1812048b80e0de069b20e43750a2d337959b8b58861a266ad964a519b2073415342e72e5279d84f3d2b82e415c017ae2be418e3161f38429b037ed863fa8f1419f681beb3b9e201fa03a648e6510a07c30de7a669fe432a2db5ad482335fd9974a3d0ddb62dc978ca7c50fa0ebded751d2391da9760192b8540c981363fc42f3cc98b56f541c61b1ba0dbcf90d1d1440e58e90a1ccd650bb63f2e382b6babba7b056cc3a0749fc101c7a9b6d681a8407b60369bcd3560f5a7087dd1247bb842b104c105fecd0c5a53ff72d8728664f31ac2611d7830c89b15a3c6103331338e33890401a7fb580d62f465159a8f97a6d1c0af54b4f1cfd9a9d0ddf4f9b929d8427cc38c39fcbe5730ca35aa3dca7fad8668da3efbc898595cd917197272935cdde4550fc4b4c0261b08e8a583a152cf459b3ee9e1840f7b518af21ea2b00da0b949ea4d9bd2b22726aac636ba51da8fec25c0e4e3a94d26f977372c5d5792780a4d05c9e8d60156a9ee21a26cf48f2b1029a9f3e3883af3feef8f9c8a5732165873d5071f8bbf505641e547fe7edb007b26bd72fde75796f8fce215fb63358a75bd364d0bb77fafe26de0a492f3aaab08070966703bb3bf1ba8d0c9df6094c6cb1af0b176784f1997559052697bac7eac18a87e2b7ca617bdb491ee97ea71427a5923a1515b32b17d691262f8cdb6b6eb640d4d6bde5b689e1ced58205e615f535d32658ca9260bc83c9026980ee43e85044f68cf84ca1190a18f9189dd2ea2834cfcb2e4e872f5af36cdb70439327de0feabb5d966eeb8b83c6b72e1b28a445881fcd9c49d356c90756492cdfc149a47bafdbaadb5ee800d9309635f2c26bdb4eab2d8ee39446f7b6beef79bfca1e8dd4254c45d668654ac840972f129c6e12cb9f6994cf1740f0f1214df820bc9f8c072b70cde59b6cc2d48a3aee1094ad0473827ad42f64310b8b55e03063307218ca349db2fe208dc4b50f0085f90af8d6bd3cf464ae5b45ec44dd6512af3574fff304972723cfba29d3bc2700b11078209c11b8f546326faa44cadf9579bb5d5677c429b07b54015e81e3cbae8f0bfac301a21926287436100fd07708434fbf7356b0420851733c76b4442f45bc6b3549eeeacf6f0489eea07b78f79abc5bd56f7610d8432da1151b49cacf96cca9922182c0e9d07ac37a63ea9f972eaade825734284d1cb41dddfc8d6477ee3ecb6ce2834ad213612cfa35d88ba27f5c94d9a8a2e2ca2ddd43b801bb1a68289c16f486a50cd7a9da987a61a7b0770a43124351bbbe6715856ce70c80077aa9419a09420b65ee53c64590c73dfe84e6ab15e4a30276e66a6aec0f466805f4ec42635b839de94cb0c999325f2eae6268a216e4b1af68298d1ae9584b643ec8abc573fe1186be9f865f0336a3c0e0cdf7770e030c2ec12d55c24c9a345edbbcfc44fe9cabddcd3919688c6c0af96223174272107201d3dc81f516324d0b7aa10c5f40197096adc341d8f08e088077478d87e624e9daeb1d2d01e343c174fc02dbadd1499cff53db1c5bbd252e520e3d6c023e96e90425ffac5ce8e046982c141a836e5526e64304099565268fc049edee73e4fd8962e2556ef207fb531599a0d7a394206b19853b21140ed145bde994f6833dd3c060d3d0ac19e90d06f6e44ac8b55a5084d5c3a9eab90852e07ed3f3beca55a4be648dcb43ce1e1a4a50ae7ec735b3e78e25c71d11e661d32720a8ef10e82edfa8984e239aa855a02cccec27d68b718b003baf03d56dbbd414957394412ed943c92fd59b13cfcc6ce86790e4e386f9d2fdbd086f91dea141cec8c79f3bc2edce824c5f4908dda99c70bc34a0f6ed1ff0d59bf2d99ab490fc5970a33130e84a0d55bf369768f0f6b1ea920db53b2a48d46abb6a8d687cbd2ad1d76462ba55ff310ff2d196df5d3a5317942d7d4867a5d9076a7e35a811242671b1d454f8b8843a0d60d90f94e6f5f4208644eedb8b318c0e6a218feae622dfd440d1c3fa0863a443c39760d41c4996eeab7f589e9b1ff69bbc2f7e498fcc856dc8607a1b74365763cb1ec43d6055295a3b4e93e13cadc5fe7327875ba87fcd29d11c287bbf8ea0daf33458fa06335f6b00f87f863fb097df643678286bf2e5280d1444ff685b313801bcd742c28737fa8cb40ee0c330b3b51896d4b144ad36751f01346c452d4dc27e5c13a423c0b0369c464cb9ab55fb18699991c25ca1485338dda3c09f3c3ca9302e23731249cf21d6c795101d412722514c317bbf7a41059058cb407779b53b5abd24d7471add955d77ec941b8010946c2d5895bb19b63998fbaca077bd24a6c7fa45c3e374998647c25d2b6e2a79a3066487f8253e83e5552054a346d43a742287843cf0eb33ee260aff0449c6f34c1a6a0e587c356bb326cbe0532e41f4cc12231a37f394fa9dfb3dd22515c0e8766fd874d63ad09cc1389192990d538dff1a71e79475a000a5ebe65641db9ed4ab2dd72a3dbeca82e2caafc5bae7a466e09518ee48a9ade18824a0450cbcf1cf4bd34e96d26d6fb9e38bd23ef6643e4b57687c7993f3240040ec08381a30bb17d3fa81d1aa096d3d0b83ecf0a7c3d323f15287e15373e92a24bb1c84d42e3ed608c34cd0d2e441fe500b94b4796d9f9fb343f1c41ac6f1ce50027dba4bfd060ef9fd4d3dbdc87e2784357aae859cd3f92b939fa20698223ce46ac87104e8feb50efe2790b06d710461d27ac6975817b285d9ca5709fb4347ffcbd7384d85df68527f7a0aaacef6b1ab19c012a67800f98a4099b3cb7673fb3f55a8542d83d2529107b820575c3c1af32e20fa7722b68127d6a90e2d0a71a1af3292f1d360f7ab6932840c7c0f4ada91366eb2cc13c26d3cf38ab845c0b2d2616c1a54c2eb83c4dab929e58de0da31aff80aa6ea199fc83bd43b7e594f9393394e054e50f028e85be9be327636b9aa072d763cb56f1ca2113e96457385957d1925b52b8c6d40582821de8df69055ea6b656a289467f4850a9243f6e4d1a4b4ac95775b25dd0684ed38682cc43338f23a147ba542689678fd76015cc37a70a58ca4aeb49dd564cbb5ab4d87b1539585dcceba0dc436522e77899e821e46de83c87b7862e739e119cac9746c23b74ccf16c04b2f999362ea0694e6ed0bdb75ae2f23875454d83cbd20981aea2b0cd440a2644f720dd43e463e4127f2e3534e675d9376e659f4effb642e71a3707ac136cc0d40392cb45e5fe7aeebb422368c0dc0ee44d8653d054894257401aab9a9c3692b13d6b2a5907b595ff3289cf491157ea42a7caa9add4a0af10e2a9c049811f2b28b5aa0e780f7a6b31257f5987958a2fea881cd822c72879f3e777b7a41485b407588f0a07dafdac32976f77485f17cba4f64a6cd3cc6496e41500726b9edb00d6971fb132122e689be5736cda91f85e8623e630c4784405df4ceaa81083d07f8a0de10044cbbc01174aa96913ed7d2cb3fe391aa04fac609ded5bf8a4972cbc87564946c159c8d2ad7e59eb1627c16dec6bc64832f7c9ac30d7ef2e57c7e564591364e4a8374d43fc44c0e773a43190937d0710c02f954df10508920b1fca016af825d78174651420980a323261441d100f5da07bec07b4f1f08a2a96460635f49c86fd7466808871469aff3df10b966d8e9c79d431fc39242a04c83392249b6b8f4e3950e1d52aa8f52fe1ab449926f7d73a2a1152905a1bd5e5dfa2e258f48d85fc731199439c0bd6af16dee7db747e861f41534fe50cc0f18476cabe28aed7b9a2e508a55c87178220427ebe06e542677bc2ac9c230b42cd763d6c4079292b6a6beb009badbb7ad602477a1e1585fb8b6bc0c566713503ee989a0760fa4cdda5b546852c65be2a555fb12306fbddb6d2cb96438e1321b3bd4ab7e731df62dfe06c954d92be61407272bc21fb0fb39a0b55627915c0cdf80f8795efd0fde8c709981d5488990738b892ab47823ba997746ae34994c6516e9a5cac1968e9843de67e42b597a4cc304e256b8a16257015c4e352e075c64a58f60860dd16fbff636afa8c230f12ce8fb466618503101fdaaec55b176f50087a8b41dc460e0c6841356a90daacd874842373923cff5dba61fa42d219130956dac86d6e195db223268675ac86963b4c81428e2a2e29a94c15a12c49bf92972260b945d71690f5a84de0b45a7c7b3cbeafe550737ee732ad56dd9f941708298cd93326bc098f97aa08b370d2d7f41939387ce3dd16b59e9ad856d45954fe6ae26582f109666504fd2b346d0993df5e7613d1ab91333e44dd45305b2ffceb88b1e2e2be1e19914db85d777b84d4a344df990c0f6c2046f622b20adf95b942fad0d75638db9130da017841fcf702bf4b9d2710976854b7e60b3c3cfd02213e5e185b2305676c28e589ace20dabb6492dd27f706ed2fbb33f07b97b5341f3590db6bf8145f100404257a3387219a9b94ac052cf9c203f393519db8746f8aa93f6847a9a598ba19cd87c9238fd819697c98e274da1f85ba1d04d9ad9e05e7bc467e6c5d2ccdc3d9c5f68ea2220b3dd1e3cab9063e695d43c4c1ec73edc65c99e8c1c77009da0af27780610850ec3334a52169d5443b014cd94d92d341d136800ceb5bbe7965549da07b460eb3a606c9399c6d59230ab9f2282b65145dfabfeb06602fe5f201983ac94a7ec246a70b6accda752a7d46730df3f3ba3ac54367fe30da87bd198e48fa2385b541469d2ca158c11913ef582242479c4e7e5907d1f0b1922bfbcabe501c81da5b4af10734bf6c3308430678cdbfb133226d5db9e67a1db5d8a4b14f377679639ed6e1acc4e8321f953fbc79e7258537106c7aa6b74ae5035eff43c0fe9700f556ffb0b4a704592a43ffd42db0a241c085f4c82112b348b81548defeecbaeda1d11f89f4cbf61c729f5f8a7eb97c4a687e12915d1e010033fc2898907c7fbaf497cc5ec1c1c1d030427086828b4cd267b2b1f26f258e855599416e29558e5d4cae1b0c85ff42c5a9cdffba655027f5e2a7368b84e03444c2b29d8cd1eb7d20b2ca72546d3a038ff10c4245e5bfde5c7d0358489d513adb8d80106401d339ebe6ccb7bc72bf8d3015ea06a64248c4c83a394cfe7f94a78da087cb5421cdc46e36b5fc33a3742980ae766c81918105cf4cabcf704238376b75b31322e4461bdd79c2ed9ee81647e897f536994971a55f540084687b0c09b151b194ccdd87389d6426d2c95982445db9b65846da12a0424094ad2844ec7ca1b0dcf868c30e52a6b31ee239e6706afe4d1b1bdb60bde12053d8b298678ad481351f22833d1a08b25b0a1b58f97da9f0b83e3c1d18e45d58bdd123794606390cd4c7e5759025f4ced69bf1b113f5c3b1bed7f3c09a763aef8b56de15365b4d8e84fa30d32f7557b30cdb4cc2f5e59822168bcf126cfd70c0c041602f4c9f9c9e87f5a3d3fa8013d97269dfb4e7af54af3f1a4da2aa11d9c3e7cbf456290240243f57138a2aa32f756d2607d30e89f8077b57ab9c1b3f40e31e73c6670e2f3a91eb5b847e597b2b6b72b413566c76795518c950e772b1ef1efc5880b2d12d576fac783586f1dc9c7df040a1753dc7da32be62c508f9d5d5812719ebcba7fd8f49009dbdf655c4e80158c06535e1d1c6bbd9cb09549f9506ea7eaa6375e40fd7c04a3eff563eb06021751f0d7906fac1c2e6d6b24b9feb5e8bf2fc2553f97b3fb3b41b6cb1ee769c9178f504715b05352bd14ce3b4be7225cee0515d3d29bef202c9e5fc85597ef24544422b29cd7e0e029f6a1a031fd7e98a3a3b356717da1953b6cf493a3c399a472a4ab0b4edec74ad28451a42c94ed1d1a7e471fbd95827ec8692b20aa56ce28f235eb3b2285d38c469b0b0d6b2e400081dccbffb28cfa3da3429c96c4d2931483521521a75c39ee573c1122ad51579991a8ef9918fdbba3b81a7386ef22b0212b7df10f6d8d1cbd82cbeb3ab9aea9ec0d8a1e6f1e1528d479363d8d9ad330f7b5ab7330af41439825b0c51552a89022eae1a3635964d4045a968dc4db3957957aff6e623a6ef3f09498af8a848d58f34ff962d05e9764848f591c69b36f861f06c32d8791b42d74ea1a692052925d917b84d341e42c6c2ed2e6f4d41d9952f65e0f7594ebf88ae6271bcc131fb45e66f88cd6605b050a08173c9e5528bca22f8130605bc7802efa5e8db985ec4145083c690cbec3969d102e1af7d48ee9ee03db9d9b9341bec3300f4d35658c5f4272e687806ad05f16f0a961dc2a45e2c8323f852f3f361b8f55359735e8efd2024d5f11b124a97693cf8831f3ac94fac3c807b0784c95aa038aa492de23acbf655f3c6a06f636bfb4bb719de1b052887982b66f0980ca952e57ffc8958bca66ff5202a984f9a99df8e09c33ab820397293580a916e8d66cc020ee581402046ef784f60631b7d5fc080dec1f14aad9f832af56142a8c1ea628caf2ccb46bf13c0d5c3c7359476151bb414ea72bb8e9ba4c81c0bc554e6c8b51b373c32cc943fdadfc575982cf79eef7636cb3d80bdfd32c2999c5a9c0a27e99d40c81940a8f2ed044cd4996f22b8417362f7d83e1424da9cfc5b4885b23af9eec43cc234f1350f6c190eafd693885bf16512a891cecd3e7ffa773682753efa68771802522e8e73d3069e535a0d5992503cff8d438a7473f7146bb4ca65e6255664251c5a46cdcf166bbe28f15aa9d512c1a21d8cd89feba7f1cbaf5ac6630b6177e0eada7dcddaf540051095abc5ea8c0f4e724d9a6a4f084018f869b995a1874eadd52147dcd1e03bc94610e58b9e80190bbc9f53b19c4ad8cb41938a2e54251967f02065f54af09312824d82834bf92363d1e0bf8d288699bb877f8c130f77513fb71b93c9c96c773d9de36212a876a035337e8b9831a75fe11e6a837070e0c62625b22ff1be70906d146ebd837e29a4b0b81202d3811dd5163e10a63a15593f22bdf204ee68aefae06954c5b6e8f637910c87ba3712e321b63d3bee8374940fccf4304c7235ae9b5732100c2a38af4450e9c01c0ac6f78970adb0c962a0935e4e3cca037a9c28cdfbd090f862f81a5cb62cfa21d7361cd04fb9b1a8670864f5795494b03e6b2bb0c26e0011d5a63126b72a36d1c01d50ef34c230c45ded2be6d2848be2f0032d904e51d93fa562a4f198fd333c217551b9fec23dfea84ff8f948b2433dfaa457cbd6cbe6ee94f29ab6a7592185a20fa65efd19bb74c400ae5cc1874a816241d493fcebc38c999f1fc208e16ffe4fc225c126a795daf9e89e7c041d2ed440c3909fd30ebd37daada1e97ba5ba84a3c6f061c45c41ce652cf478df0596937663e69071eb3dc4778f86fdee47daab7adce092035a1d5c0f9cf14d828cad7fa9d01ec7856ebdc14bb06a0a8d7131d1e9a537023383b1d0da717defa7e76a978859f3287b16ebea3236496b10b1856d240018d33eeb319caaa394b888566f328eacc1ea6a4433670745a68bf2357d065bf33d8959ac1bea082a36d40ba91b511b22efb06a1d1aa5d8dd0e19418ad6b7b69f94d0be29f2b863ffd77897de35c76affc58d337e0c1ae58537b530ae883d8150d62bcf129407a726b55c51f1ab142f0bcc0c485847975682b25f1430ad668bf05b501670216f11e8e940d63db2d6bf02e127106239d27a34b1f2787937e9c882c977fe3c24ffd2c0584863095332bc4b92c958e66f80063a5f55a9da78c07369c2c91a0a45ae0af0829d33f20d39c12fc3a0317e06729f9d724aadde53d4473d6241c9d24b4bf90d79446f091045f9102f206e17b2841513e1fe6b3134d64c3e2d41c4f81332606960556cce83d3a65b230454812b362a6f7a836077aadde1a6fd99528c3c52fbf2e10714da507dbf2d82939e78d3f1abd33b0a1b8ff26b22dd4c00307be15de4bd2d35185f085f33667706f2020cd217b66a8655d5194d7efb738498eb62bd23ec84addd4aae229edc32d2306d132c868994421495382ba5e9e2b7865ed8e76682946f0a4e5f76ac08d3561940503f19acbb1ec1775a36f8d14c9ebb89c28298934ea6c0c6a6e5cb5e84e176c832d4f88dead066717693c1b57d322960516066c4374570dcc8d7d17ad449ce09a8535de73089cd08322a5965b2b09011cc4ef82abe837164680966453e8e0bb60d72a9682362ae6bea196ac1c72831427a20c388ca0f98741546ed80cbda622e0fb04e385fc09c415636e844401c8ff219594932b13f73447179dc574c80ec9dfd8f95efc403e168cb70bbf2956fa6ef8fd19fced43bd5a02a7afd8c4eb172ec861350868b0320a33b787193f64eff9593786126825677a2942ab88ccb9d23b119a003727e5d4ac41c8989e507da4bcc7638cd906278dfac562bc41bc86535ef4f8d2e3045a27dc4bf4c38ea6a2c0811b108591d93ec199f7104da1600c27c0d173900a14110bf3bc65330abe9a9050bbdd93a6d6413ce7e0e06f5ef8c448ecf9d6f5a60fbb6411292dec488c63440cf00c1b154684fb1bcc6684ccf4db298914768088bbb296ac1dc51aaaf3c344bf160792c7c89544cd59e12f2c3dd644bb197e73cf432ce362df75d5e2be10625f9b0043f3f6064e4604070ba224aeb7d16eeb61e3ea3fdf85e0796934a9cca8587abe85a46bf151b0806b0eaa8904f6415e85eeba61ebfbb94b39990c1fbb570c1a79c3b45ecaa4e552adb11807cf3029833c904c0c03754116d0dc7492808e4fe66e9faccd768c382c7ed1d4b84ff1730688e9f1d8512562fe862b0efeee3698aebfac54a33774beee49fab5e7969dd8704f7426592811a97fcfde510d7fe14e890f45180bc58af336a615a3b6476767b0fb01ea2909804e4ba89d6b60221818035ad3b94a52e7ef03d9c2daf2d48bd5b66f1868bf006f38d5a41984f73652b9f17ddeb162167ecfcc1e3e50b7c55903c21bc979b09bf194a9ae44dc71d03f48f1ab173963dd55a4943a4481fe1f4a89a248c11049435136f4098b0513641e64f6157871d47206466558a153642ef71cab12e404b2392d23d7076bd2d3698fc769c6d09b3ce390f3807f10f5b75fd6109e56393dfe76076e72b479349803b8cebd892f2c857f428459c366da19f017bebb4ae18d8e0b12a849f8c403f218fa192615b956b92c58fb6970114755b3ea8d78b14d262b9a33451755a95a6bfa4d38dbde9a6b64f67b8817567d777052b98fdcd2399f80119410530c26c9c2ee48b82b6d436802d3652c9801ae9ee5cf5ab4abad366fb60e9b0212974f4ffc49c0ff12a81c1f6fe48798c8cc3d09c0dd9dfdbec7b78b261bc0b837cf5a4fe9be2ca9113e4809c741c60486bfe3a041d5918c279d61dff1c6006a447bcf14eb6aa2ad1548b0e8c8ed54ab7669bcff67f6f3494eb944e047ddf5f047003e106fc8326beb7cac86328c47e51e18107ebfb87139ec1150df818aa2f288e6493ee4a00f448d53c5a9ed91e934f3aaf9c9e4f74b2a7e5722777d95730d7d4de6c5ba4c56d33f45966d2dc6197ae60ed35ec88fb657b8fe508ec111057c09339a5b979619bdf0658e4d2af4021b686bacd87550495aa7b36dbc9cff55ac151051bde20d4919425d8427afd0eeb18b18941330481a76c267cee151f0392f4d54960d9ba7b14bfbe673dfd4c7939a746589b1fcbe806d873e59cbb53bf0c681ba66fc7f71436eac35e9d94f4967992bd2e02123cd2de59212ca151e40ed78bdc6090144891b13c44bc6ed1a3bc9ccc4941a1a8fd7e7af67388cc5d3729d2431711d9d3818bb4ded2e22c326689df1423f93c660f92ea632214900da830726b03d806ea3f89f139915d402843b1635a6e699cb0263ec5f38e610726b5f888cac5237d6d098711c4fa7bf90c0aa86d0385382a46422d1fb99c5c9460403ef11b369375375511e7a154f43ee8c0d7260c9cdab81d3b5550cfdec413787ac37d5796778e92913e534bd211c652d97c5bca01d87f04dd8762daa25015901a20f0c2e04a8207df8adc5f34ff7193b809e2c12ea3904922e8a8d4f631443c33b5bf4ff72b65b96ac44bc190a4d6aa5c9427ae9e5a528ed1f463ae753361bd06da523a35971cf1b76e84b9b6be1d15ede47ffec79871a6013cdfb7212351e493fb0fafd50cfef949c58058e6e1b8e3f0292ed1e82d2a2b57d0db4e9ccd86c14631f8d15aa0bcd3cf0cc46570e8ac631e04479f09a43d4160d4695690df09160bd32175bbb05344bc53ab3cdc63201f87b464371eb5c1fad84067dc511d28881bdc93bb499eb34129911d7b8c0045047a7207ded57b6e1501ada01a21bb363c630194e60ed097421b0bbfb4cfcb014e60fdaf7bb2b36603528064558dd38220a506c9c60a29a2874c92a716c64a0647a0df923d9bee9956487f1086ff1667ced8ab44734f58a6768c6dc07355b95180238cb2373e1560029959355cb7669efc88d9ef3d595699502e6b234e81c69be60e8cd9b0383eed0acb2b14cf96dd178698edb9d6d47935159c898496fc46738937f773a0a20e0102662157324f4d94bc528152da7d41309f343ef532978fff2fd1e71ddd134f13a606c33edc02ace3b975327b9de97d7231d59108a731d0a09f6df0fc20a65ab2d00bf17e53ec019310eaeea1f45b90502b4bf6139118f52ea4cb690d9c688562733941e78a0dec85ec07174646d790926ceeb0d76899aef4d27b1f754b304b1accb45603af4fe61622dbd53e2331a62a3e6397b7bd97a0ed4ea875c3cbaed1f6a15820dff6b48402c26fa094afbd867c8be8a39e4f71472d557f90b514fc2c49fc0e974bf60071f45dbd6b6f17199ac2ef73b6189b699da16b6097bc8501f6231e34d2745ef8c7e1a78508e59bde348e9cd9c86bf333cc39c2b16e94fd6b3361a3c859b9126242522a5b02534dc497efa96c1f6dd9f296f83714792258cd79cb4e8782b7c709519420b60c01fbbbd3c6fa9f48c355a5faf2f8e72150cdd5d0b7d197e13bd341ddd0ecde67fa4f39067378c5c4372eda7b44d6e7945b22beac583c247c4f7e9d49e4171bd5dfb2bd2c32f1f939f8cab72803cab2194aedb62788b59a8bb246709adfa9eb452aa5ace2dd50b75c31668b0a47d2f609903f4aaa1364b1ac72110d4d6623a4a0faeb6997533359462c35c61509f9ac56289beddad88606714afad42fff9c3cfd6048109fdfd71963dca474623a441c41bb73be309b4f5089652b752293279170072e6beba772ebc3b41b60bbeeac9e319cfbbff97d9477f2f383e6321d5c8c8478e5d28c3406361bac51b89d26d5133af279f6bf3aa90035318b0b95540deec718d532e68a32604155af194493bb856b5cbf24088cc75b0046435b3709808455df44f1e284dd90b9dc9d5fee137ff5962e1de2cbf34af6389ecb052f43498adb307b6e1e8504d41a7e1751ed374cc244269928076f8a0407ef9177b9caf466b54844e45f50b47156e588a5ba6e65c8ef5fa235ea75be6466271834c97429b1b35acf72f45985e3342f97fad77e922ba0720e3fac2eb4f81d6f904480444eb57e9ec0cd6afb5c597f286758385d01b30cbc2d61f17e9c28a806174215f72ed5307006fe6e23ff8dfcbfeb5b995877f09f1a53b3c63087b45a92a5583b4f323ad5dd9a1d950cd43219a843306e6620cbb8e90a17f580df86b25f913acffad1bb0f761b0e1ef14f8dfd8602f9c346ddf5e708e31623cf9b9671bdce0863ea543f3d970a8b1e01f9ba6dabf2bcfac538b6d6ee50d7c4a460106ba19d7dbcf6b1f73231afab1674d0fe11e42c16a35690ace08812bec7f34f19f9844afd0563ef64efc3e11d63fdfec0842cf5bd2f4496af9005dd512466f1bba30c300a2a37b54fb3003dc1afb6ffe63d77ebd41a2518e5d62f73ed9764e3996967c5765fec54b6feeb99483ba1639b65043e2106a243f5e25084bb383df619c79c3f1a7119c48603ff25167c81d3f900da8bb726dd5c3f09363d31b7022f0bf7333920dcf40726dfdd6ddcfd1ab2cd4eb7e53f3e5f0aef9337cf7ee1d62f9fa27b64a68a1f0eb00a3a6d976866d66400d3deddbc8f7661ad093b29dd7bf81f3e0cb5c6eaaf3193ccd9226fb0e8d82ed891b61af4118d6a32d8f4b68f892a25b8ce2a2cd7de5547ae1104a6051babf0bbaddd4794d47e6da6b7b0eb6f3dfc49ede99106f92bfac04636d9e7b57f9f384341aa188679e1b10c7caeccc4154f1a8c027c5e96452128f892fe73eae5d0cbcd4f9667bc46bb15e07defa27cded318d62f6913ac89f7f30357f1a405e6e228082b3e660daab1ad277a76d338a842ac2143f67b85ca0a37ae7b2e3bc091e9ee7d3340fd9d3138b9eec3b9ecef3f89d3afc92716cc164aa9b119d016a451de282870e6a091db60a60b5cfb52092d312120c0630a54f50a4af66aa4b8fc998a2c6d45330fb9b304f228e73702dc2d62ce1066c9be9380bc7e3ac6bd2c60492a9e712969352328514220f3e2ce1c12decf3a12631c4409f0aa3446081c0553eeca6a148ab06b6bd00208396427c568e2c1eee6216cb07c8e6702cf0a40e3432626dccc7179541971e1148e2b54ec52b649e50c7e6ae53a887ae8eb1eed26e0f65222512f89d8770b4a27f7f6c152b51684368bd504d2e67a32ee62ee41e8c7b9343db5f12c3e2d4f12067b71d57898b66ae8499a106c5c75a3017e4d6cb0239b15abfd6fc23ac224950cec96a99825cdf9d508b6da84fcd41c6ad390afb432c9ba837ea6aa7a9c1098ba294f34e46e7e2c78b676e0ccd17a5a2bdd7f56c110e5df8a2f92da42a5ca4106f2a17b45a86672b2bbff4bb310146942089ea42c328d8d971623bed97e7dde09ce63e6e0e24822316db2a6c17f855e9adbb1f7c9711d2e232372b56d2479c5fbbcd351cb2d2e401a7634d4b116205422cef53321bf8a5757e79bb5af0188ac5ba6f49c5a2a6402098395f92a0bd09e106eb81aed01d70bcb4af379949410e034c7679e1a7179b242d242ad0814120f1d448e39b449c9d32113c383e1c3de6fa65af4a0dddae42dc40461b2d6122a1993d51d2e6f6dd45cdfa0ab0331a695db940aa7474b390ba2faf8f79bc0c28ba38bc7fb4d621569158535878fcb315212aebdc7a39a0b8bb6e5c2cf7f79098e8f7291335edb9954ec903d26cfbfb7bc0b189feab2eb11bef82f31c47d97e308f86ded86259d9a058f4d7ce88254a3b378910ae787c8695cc4cc54bc2f9d9d2d6067d34dec6bb83629c47353809c3630442d09bdf6ea9360160061bf216d0e67525353f9559291794df671d435d06f04861846e20b478d064506e73aee0dea5675385a1036e765e55d0dcd942d011b16c19b71f6747fdecc3c98371601b0593cd6107ee193f11d125a1e6059725cf8d61c015b423fbe5e34a5ae8a259f9c2e4acfa68fb5364c361d051d85bba3cde576b23ab98394cb5c43cd2e8f3ff8c8f85f7dc82e4224a670be6abb578aad09f5c69a6301a97c6c7526df3e721a54034f532483400c0db0b79b795b12f20c54897002d527b3166079ce94daf5d4cbd5d8451d85e8ec6a33b2ad9783aaf6c8ce092685291fe1769a1a37bb82089225a8127b4cd35e47be9cd60f4e38489162d767d14b8b3a28fbf3bc320b9741c3229acad0c8354d0a1eec67684b940deee8fa1c783c15203f51463021cbeedabf7266673deb2306ddbd7014f2e861959c73819365411017defcfb4ca4f4b153d8e81bebaeaa31c163b441609a67168d5a58a56561276c612029da94aa74ad7ad4f9bc074d8515a380cb47a6d83147d15800772474490bc1bf95fa12a995c69682dbe8e3f86775a477e993f512547d6f5466ece70a627602912bde9a0098e346874381cc50a868bfe74e8100ac6efa3941261c4d996ccd2a0d73e7ef68bd34fa4738bca01891d1c0a6bd6e01aa4de052215b7269457c3894b8c1031b4052019b1ef895645a0fd22fd042308d8414f6074a7ad2bad28468817ffa897550879366bdc45bfbd2f68cda81cd528dd458d9cf642b9abdbc5ae95e5a511cd9253f26218cca2ab787ce17d42e6e85a1f77e61b89b2799ce72687aedb48e5349ba3336b12f1343c30b6ca8596b356109448f774859464059b58c31c412a826526dc097c3df9bb02fa3e3cc913af1aff640b2df16419c284b206b07f8004ee96cf918255499a9c35cb914713000bb439c3a3136b251bdd16797633612c9a958184a08d248cee04322e55d20832430dab6f1c430f5329db894dfc87f7a589ece67d3099ace6085617a2e2987841af8e915615a9c8825ddd0f40295470460a22669850e54834c946928836f4661238dbcb5295022274b55cb32853119e2625c45ba560c092beed48c5c8e84cced0d77370144c41e853846ef30489c490abda2ccf14c06a24d632f03b278a50a9f8a29c75b0bb399e8945f58e0d3eb6fe96479b389181781f46978e2625db315a0a0b8b22b4c0df987adcd10fcadb26f40594ccc065e2318cfa9d70868c96f4c503d74a52f9920cf23e69e3e8a65adba788dc11456c16a5d623348f676541a3830252c349cc400210615243f1a98afa447b6e2de33b01e9683f92c060b40e0b7c408668e2871831b5e2a54df1c0c3ef52cff5080f8300be0fba464dd479911a886bae8607f725181a8f3c15cdd116b38ee75649a2b95a3b3c225d4182aea400b932c01c1456b6037754ea4a5fcf1da2962850dcd0b8b86a020084029981ed228886bab009b8da48dbbe9b9724a53e9856e1a54763d29b13d944e89744ee4dc72753526623f3de6517b0f207969ce44ddf251a660bd0e93bfad2d5d68200d256471dcbc25b27d4715bb64a07f73b44c99e05674a9ee5fbec24d0ec462c12fdc2f58fc247d53e45ba35c8157cd33a220d2ac60a1b53371714d9720a46b4f6b0d290267430873f9c24f4a3f85137b9a45c0a83efe375ee9be929e4ba9ad93427d3ede54c17a5d6f455f638964b9f8cd0c6e634f9e9ab1c13198a4c2c5569ca8d0b29422d9a4c0b79d6f6b39ea01e7283cc0828fef0f5e4c6e83767d5267a637bb30120370e47725028c5f8b8711c18612b39af7483299aa81ca58da38e19d65739f89084d6d48906518bff769e620ab3dcf30fca6bc048a9f893c6828b539c87f378c2746d8d4651e6720e62fed215cb8dd1b340a321191b835b22ad8c91fb27367ee4d91b62066091dc382ebe03c54655c2cf5b20bc310edee61752dd8ce548d04829401fd5281ad1c0911baf3976b7940a230a1dcc1d3776bf3f690242fb9137a3e45897a76021565e6843c91660e7eb1542ddcbb8316ac62f0a46e326e14e6b39b40aa462e747213449e2c605ab3ea4ce56aa73a92f31e71f9ea270549047dc183d0f4d1f9754eba54b726e9639b2976ff665a4399b1166d1bd2a59d95d2c71633496c4ca2baec95b579ce812d9b7b7132b9b26b63b9a236533ae39a87f01f0b77249968ccb8d0be54c51b70b04a0d5de958b5e2d4e8716e92430a2439cc7b9e826af43cca3d0cabe65e791af091bbff3c628d4ff58b1c8f1e6be242b22a3ea31ade736ecb46c5bc690d906dd9d370e6c037f4410aeca8c1ccdf7686e26d7cc4509621080e42572e5420b37f3cb4bae5cd6650b75e56029037b0dc5aa3f9bac9e92e6cc6aa0a8c3c355b2523bf61c1adfb6339f0128452cd6faac21b86a5599451b76adda0e122258557ed32457f62c01491ee3199015672ae1f1c66b4b02ca70e38dc3ecc2c8955c39eac68de5227240a311dce662b50dfb74d75cc285a473d1f4ab19ce7c7b6cd57befd1ef12eb443500179fe0bc7154d7bcf1320e01bbc98ceae22deeedaa337c1e8f2b6f6cece326955ac08fba7254e33ff36395073558b0a89bf8d5bc25616d4d60713d0d4653a70ab2efac94321dee9d849280314e1e12c0b984c1c3b56352b868eccc01ab01b142d36c95ee80739126ffa7ee03e1e1b08ec099123dce1c48af120968f0158c6024ac69552b13b8210da4d79def74a22ed8e1412d0d84a232666a20de98c15e67ed1c17800e2f1b6a98a8399391949995f14f7b82c1d1756603010344fb9466a2767d408b3a00655f7e7fe6bca9376727459844831b29e12c9a990fe30e22d70466fef4416bf3425876e704edb50b71b76a584daab2cc15c9580df60833dc149470638dd9e41e9dc3fa850b1748d916ddc4d34d2d510735bb430967474cede4ab04d0e005dbaba9602994e63a9475904f898b979be382efabd0c40bf667c9d597e26e1f2a5abe48d9ac1ace0b30b956fcc1889e4ed4e2f282e4e2873873ba62f6fb6c95b97c2a9b5d34dfaa46a96dcae0c83745e1949c86749b30ca4703e46cbe95d410bd26ec16120b45b74f6b8d8f6bfa8a592795fb9eaf4b95e3a3ca585862041df0a6c7510e9b2ed2168f1995839754e78fcb237ca24d9511595cb1dd51152dbc5cbf73e72718252649a165470f7a154eb33a622401bf63f9295e04eb979a199d696b9345dafd9d83ca5c913ad09c7a3af6e50bdb7a56f8a2aa2408d99e2a1c05b089cbd7a3234034a635c0578a88c555e6aaecd87da3911133227deb7e0cce5717a809573079b6cb0ff97ebd00012a6be4e5da17ca05e111776cf1318154e96676e4ad4ca35f7eacb9ca2ae3cb0c8451cd65b9205a965576c0d21611f23ace53852e43c34e2e75cf15153e516413f484ac7ee0d94ccb910b9cf4cf78bd59a2f32d3c781efecc106f1f1c407ff2776a6bd7b2ca76b4b70817ed13b333f2c8027adb0eb010a5fb0a0b180e2ef06e46f9f8a788f2418ca14d4de88de4c679656e28cd3cf2dce3f9db2af525d742be27d1445ee5ab641bbe28b8f2a3c41d7e1146c8839a09e2855d920f7cea8cc71106bed64f2c228f8490ee6a7ad5e428b952594de9c39869138e2e457f10d522f05540d1f6980ba1bfaa9dd44514c2ddce966486520c392ac82d750049ba65f78ffc93f80f141c9922287497caa92d9ad17a20922cc74cfd07ff1df901dd66caa07474354d054fbdec1fd1218e975a0697025919b0be9f691287772d079786acc220c60adbc127f488f4992d4f4a03562b97c3aedd39a06a2c9f63b9502aba9a06a7ef5ef28b6888c66b2d8b4b87ac809eb46f570fa88de1672c034a8b5a6108ac24fe81ee9505f12c199288785fb419370f22edf9c20bf869b1949bd388d74cd19f8382b7d66f24873a57944fa7555e4173d109fd2bf93806785c6e5f0adf4327e8c785f59c9a61551688032def42ce4be340348ac6b4516e441a8b46da286e2c8d4663db28372e34aa9f74e12c29828b742ea84a05c1b3dd467524fce905a84ea5019447ba4103ed3ec56e26e08c7c416ad9711d47dcfbc7f81348498fbf33148c44bec042d06fb1328bf0cc89473e287a9ec74195a494f22083881516999f5303498d0f5dc9b774298f39960061dffc90e832d043d4631a1b36d328aff0d80856c155aefc0c5d51653c1c0c7cde94a5f908154c46afaf135407798bb2a28e64ad2f97d35e587f05c770a07936250986dbfe349a6e9f9b465bf2fd66f138d4adef1ff346554789f9ed8ffdd79a61d9e214e08eb542fa93b0a61dc8325370b8a9cab98be7ac7dad7bcb16e82e92e69516c081679c6f365ef7d7a75ad8d7b28354f4528af219406d1b62c4c00f9687f29d151ecc3bafc6e67a7c0caae85aea0a7aa47a8c1e721535c088d1a70e17504b909e40354bd7a4a43676c1a358beb35b55b1f71c612eb1ac626435fb5200ba79c23c22be9064ee54fe4a5580341633fbcda44855ceb1aefeb460385176622a243b4988f21a27ece4955c394ff5f969f28e47e3e361a548cab4be22e3ebc83aaa7a4af42c4909b1d31bdd3701ba12314cd43c8aa89e2341280005ef44ffc82d291d9cf172de664c383c9d102a9712f6379bdd763c1b05ef5a76db94ab3fa3922ef8fdfa1c338a5d58798f3deb889c110aac73630da0b8f8640358576a2192d0205ab470c2e4355f12a909ea93a21be5052f418d9486bffddc3570448a529bb0dc55d8978b436998dcb1c1cba2d8885c23fd2da2f4a7ef27865ded2d9b6803c6e18e4076bcf51a80c7e50a3d11f8885500555962abc55f0388327c8382841da5f554326635a024375c8efc0120223e761db7526c1ad8b80b5265c4c77c344b2bd897f920cc36e5580a28d4b12c50c27f9502b825588e071a84ab55903230af0fb74baa55ab943e18baf5e1deb570f0d053806e717d7ca4bb664b6b63e3518dc8a046bd65648f376cccad12e906c1a43f97e371f72f9cf91f0c636d24451a7d1b6659a252192220dbbc7b69912c278552dba97b86331be6127b252450a1f59cbbcc2b9827cc30b77b4852ae813c12f89da854311388e3a3aa87506e2bd3a038faa7c3d8c2c9131dffe2ca065f16feadec1665b121129175cae941d36f16ffc56ffc425d990ba8c0fcdc8a7ce90a571bf5ed944ee54c93a26da95a660feea2ec31201e602d20234709e62ab31c89c2c17147507cb865ee37b819bbdcd68590d3a89d4dd4c2c292445ffc55b7e6ba32eff9e6d2bdbc204e31b69bf7f70bd045ec22dd294e466d1ebba99ae6e022f5c6c1d1cfdba54b5a1e0beba4a06b666b66c7c50977a3c352ac8ae9167a1a91dd4f148ee882777634d739d2db45cd473b789dc56a119ded0d8fecf9e53cc9b2089cef754aa918511bc57169ed61a699937475a219956490ad956c8ad9a3544550ecd52df0cab2f468bc4b6f3116007121022605d71982683573bbdd915c8356cb2414e3f5b1d142152f2669cf4887e0856b5d4ecbca5d6248dbab229a5f69d589cd0e3464a2ba48750429e2e8508f3c661645d86ec1cb23cc05eb6c4fc748edc6e4ad617fa8891cfd5c1e0e8944990ac68c089ee45c35fcb4cd6ed3c5ef121694efb836e82e4b8b48c38272a13c8e8499656cc90f463e702418102b41d23402b6afb5ff1c1a16240d6f1a8d6330bb6ee2c67dcf443334784d8308735f962cea1850684b6b93730f3c791153e300568d7f18436c7c1d7a9f0dc672bc60be7d75e736ea5c51e5f47aed4826eb45bf874f9b2bb4c6bb9daa43ce2acea761cf4715b24b5128c23df20ed2cbbd14e912ad6e236347e4145ef21c04ba00f178b96d2371636406d518e47c6a841f1d11049534596d32777d627e20eccbfbdf72a0b9f796fb3e687d0d6c45006cded2297ad7a493d1063658e14a71f0a0c2642d496f383896977d5f583de6d89f2fc5635ea7778347fa1d57ce8f4cf04ac781f766ab739176666981c845651c6972418ece4b65bcf64dea41660b95d2a5b7ab6fd20a8e24df3200c412783f1046a1d00c15415d0270c0ccd0a26100290fe393307ecb9806f3124c5d96f4833a056500e4f52cd4127a71d3eb2cfd5e7a7fe8cd6b6f2f7bf3d2dbc35eb2af7e0025512cf4fd1f2740063a7cc7a22b5f0f0bd5229f68e404cf9f0d38327cb0ca3bd994847ec0cf4e71d6d3559bb1457fa4456c3673ddd920303cef7cd1ca5d4f45752813841e70f671c1ba6f1c129f8d44056ea538111e8caf4ce8b7a4855f1e9cf39e44d7ffe8e15eaa1352bafce158d99a3ed416471138d9fcb24013cacb7feb9b00c948b08a40d3ed568b5b34332202c935f6d3538d351108a2acb36561d8dba6103080358e1371810c96d7c11030cbdc67239f44d5f55e1310ab248f1d34ea9551b500a563de3826a0247c444a562ac311dbc87b7b2c65fc5f53b361f3e06420b24c9cccffc450e83fc57bd63da04d3589efc693ba11bdacf5c0f847fa7adbe0ddad5b6bd43d0cae092b8f066a577dca9f360a9921a42cd42d9ca0d96703eaf2d49a022f4776e2de797447e2e30e4077142985c098eb82a7ba88bda7f4f1dc068f765d2306b2ddad594485e5a33c8680cd2879dbbf691c2937b6aae11bf889da62d4b892cb64a75854ba497bd8492e513021b8926427382328cf0dcb95d538d3241b39512d3a1bf9034870afe488cec918ea3bac166abefbc001d38383a9e7be97745840a04424975cfd85b6f8eac367be0b6bf9db16fe7421199d43166feb8b3c3c77667b74056601909a62e655ab7c34acc829270b20a956a196efcea415170258d7fe2a00764a5ec28f0ce965c8e5c3f972b8a3b402704282af1051be8a4e1769b9e753cf4f9ae06d15fd95123c56c80882d3387799593ed21768336c9e1510cf79c29ef013f542aae60ce283799f51cafefc57be886a69d63c70cb267256309c07b452055e1448521c3d104879720a0850ada2fef62fcedd48b387becaef40701747056afc8d20d1884694e0a6a4342d215ee94d5859666666e6c4ec9bc18a678b611e6b6b76079a23911f05173a2c48434345991c8012f01ae11320406482d8d07069949f4aaad64c7a8182963081900ca24192f518d2c00b2f2654684903c42218aa24a9d2c1abad39821e6dfaa2a1018735c4480f23675eddf9c268eb138caf027ec543001d405cd89185d10521a80a542272a8204793142d27a8bc989fb87af852e38214115fc00039d9051204c7450613c4303143873e62a7023541e400923170f8032bba8450e506196ad8f0711513b86077c87ef1f006040290b8a087868e137604b211a7558c446246750d49734982b2e44285008618ad0082cea92d19e0185078c047203f5db07c30ee2995a241ae1ac8aab0c4d454213443c69658a26e66e0206007b0000f271c865eb15053498410562851234ea93f856a50e4e815980b997c8043a28729de0d6bae18b2e0fa19344ca83206cce6dd10c803396504b0e1d1c2c557215d9582a38a0d0e635e1e7801081445d078f110e9069e0130b0b9c3000b5e93666c7281ac8c87025517287e2a504154290f5a0452db340667ac060a5f50c64420a29108c5a2569f6e097b484b902f2db49b1239342ca01296f0094a0e24ec906d31724198085c80299cc4425f76d081d025159e3520364881c77aab1a41b2e2c68d950296d83829af1cb6d50d9c062070c0810332344d6132c3c5a72853840079350ad30639826873c2183a290a812162478b44e30119295167698279c1a9800b086950b8384c400630d26445c80b324ec0517a5630c1c80228bacc1d10c840c5f4009f32b5e787e823e404566fd620f162f5e49643189a269868e0306080441e11306acc8835ea73c1d099dfc311c1ec00516168541d34df0758ec294765ab84a8b0f485054d984b5f04621e2962e1cb8dac3f01c090e442ab4295441068ae92e82083a5e1cb0a1e6339e05cc9d4dbe8c86445c52342aebe24d9450a8801c3444f9b2f505f2ebdc91283b7c6460988552164f087c92546865864ad68f44201ba201ab14292034f80f006a02c30eb050d153a5a586070732580110688a245460d293c6ce89001cf81882b3f27582924589001b245700021183b6c60ab41b178ea01b6274a9b0d9cf0b0c24a086dc8e08c511265c02005a484e806551420029190896ba55874f2c465c44dd5096ab72d7962510182060a16a372e051e8800fcba854a56235b043c90c371cb4c082aa0b063b32252941c98724815aa43db026aa842a3530a2414f1a073a4648412181b535b1008417b146919df0001b344f348c4059514aca9809eae44469c163a062b908e1070c096094fa04daa189130aee1cba204517141d5964c844c3042b3c35212b5a05f2e21a22b6c4813f4a2e387203871d90021d5ce0410b016a83a5304006352f1f740b984951464a3ef4a237032a508f04a8c04d90ea1502d2814590a3503998baa3e9031f5fab173e3e199923ea6c0352407ed8c1836d472c05ac252168681285d40296e6bcc1e105a8335e94d23025e18119214897213b29460edd179e5e9c027352e504dc211e4ddaf45113450519238a82c8d080a5b03840f0f4dc8006f635f1cc59e1c80e4d4b804cbac18400366a30d0d41aa13c50d246d00a263c18b3c158aa155b574c8910e6a3479b4d244880358a051dbeee2079f288149dce018a1e7228a12a81420c1d63242410401b4c1aa4d191c8130d615858c1e68e9c1d09706062149622a9500bae009808316353827860d7c4158a10ac02c1f83138f12e2b3a32386308851148d41044410f162a606007c4c668b5caca22c2541b0f22d81723aea20c69c7074ba4d020c81466808c367d58b990c4e4c683031c80ea12a58e26167a6e7894028f02647a5021c6a103c0348002ccd422333f2e2a8537112b5a39812469861941769cf0022750da0525746883a8835e052d6a017b7cd8e960c0a700aa64ca71268e1a8a2ba750e9b071022a523910be165d01109801c4171823412a200e44256132870023435a48e204094fc54180084d7a28e0e7013c18850ba072991b8a98a4502288588aec14bad120c18c874f480a4a720dd8be0fae66c072b10788f3d92d1cb4996302a21fb28cba20c512433c8a25950d3dbe5082b44bcd40e1f5e306ab4684dae030c995ae855237b438e1e2d5891c3230e509d40c8d949c2901689592142af00c608103195383eca4e132a96ac481571e5623a0100b9f9ce000151cc09c60478417774aa032020f1f4e2c55e048c59bcf15012a90c42290e4bc9241d307381a48d01f1ef81261c00698bc28ad20324018213d7080b00303888f4a67c8be16f9c8b26403970b0a28505109960fbbc9447c658744d8a5146a42bed228790450fc90800e083d5e00f1c2b2028c527f5c00334305070a1895a3874aa48210b3c2490e33646991270854321651e0238d052a7cc9b06a452122a55ea91145c70389ffc010a382196c46e8c2db11048d11cfcc0e80d4ac98a145ce150f570ab0a4c3ef21eb8d2a34b023810a90e3c80154240e40f3680512abd8c81022484f041bd886d0b0270f8f50449c7c61816b73482b29606bd4024b241d6a41060ac0128dc012294dc61d44bd1f3c10307144888c1ed4f8a6425cce14125edda0418c902d163e603115e80a592714915e296ae12b0b2874b0c0418a1812a24eb820f99a0d8e629821c88da01d36203c2e163095019c19cee0b468c301231b6404142ad24bc482cf11553b147a6cf8246c8a01e70ccb06940680556f68703931e2069548493ecd314b21a2c408a25cd4d8a12512a44794f912c198e620928c1430de9860d321120f4b39ce6c2411b228af1524284d41e16c47006b54211002812c22b828c1d31f14ec9aa84e1f941992e98f255529e8b8885271443a8524d587c10820718017981abe1c413953a413abe4830c4c7ad07861254b842e2861521893a7080f14b4c83255a8c0c007ae211c5f6026049620815ca0e045838a0a6e06306e816a170b2d8b04d51741e4b0802a201888d50004b93631ec1013a6824e01321cb083cc9c94a7e83eeda042992f1011a8348c2e6085062990014be0880861e86174098658566a1cf15143265063789a56c0a8d4e7ab8e8a430078437f4cfd1b6b5f2064bac1448a2f2c1b9c71540209a722901343491b14474838c42fc08429129c4e7b12ade0408fda0b72268011484ded8cc7029124b018665a751aeb7344ca043816d9f00449c7f8c1cccd1c4dc2033730becc3131333562614b94a953a41e106472e0e6a74b231007d646d21f511bf40dbe5eb98072c00a19e02003508f088f0b36f036c86105a58498490db05874a30549615cc888c00f964e1cd0798183bd52644203510409a65484c6c458f37268067f140a8e0fbbaf05c4989a14c9c6a21c5a30d9b24101573c70ea4307875cc6c13342b1338b20dc7104ddb0c6c6840a7490f169c850db9376e705a13057bee20d8680c8d442140332560d525145d2913e55a2b4da41030a1b44896ab46a88113c3c6e300252e026041a33e4c9718d8016e46380082711a7c288e042cc121d32c822450b1db3410a175249a22085ff5145d412b01158c11ae567ac00b4205e4d24a8263e3ca8a055ac1903b0b080587de1c2862d2e82007203235816dc19634ae390a28608d4a49864890d9d602b28dd00849897a1b3b34eb91f226cf02003a85325e9d48b444552cc1113053051468188422f64f052b13179e9f4ea8400ba740a82078e1110807cc13091c2185f270f0f84b296288046e583c1c018112af080631681193b822881b2f1a91825f1e491b44b8469851505e84c857d5f680e2864088f15491e7440031a2a1094f96284d8734319852400a73c3e04ab0ebe6f051744aac6ae68d0a501434dba2668f27d5f3940a2c28298241204110708570fc8f7c50821530f2d248109a5a3501d3c89588179f4094f964326dc28524812961ff00b17a45a512ad357f0f41b3a38bad201a33f24b0da0f44c0c31d2432c21a40e030b4820b3856e42134e301ae26ce0c16238c493183e1b72e712ad302cc150b6b61a04430e38112b27791963c804004704c5db2736a93035b60369102f2b5e013aa06914977b2044af37d28463874a82bb7a290095cdf4743821cd4881824e664129eef73f1838ac6e3c606195e28f3a5909f7e20a5690007fc7c9fd701a576d0003313d57c9f8b18ba88828526ab14902f45201e10cdad4ac2f779b5c191c386561c39dff702ccd85a0c19180afb3e153ab422d580a487329f972a16422c818182ef83f1425426503934f93e1520c80073c80d90ef6b8aa82c13f8f83e1828a0692193f47d2baa94349bf07cdf97a335fca9cc17830b2b03eaf7ad28e1d18c38df0716ef8c02f2c9782147cff7b130e2c5d4f781e1b9857d322cfdef63a109cdf7a100bbf47d33d09469b105851a1a403e175f8aeffbbeeffbbeeffbc0feac70e3e80c10a311535c25a9682ec8c302ca0c3b7828a229152510b006597b4c504106024f12d0818aa55363ec74a579e084cd01b004527479d91416029cb050bc2e47c49858312986102fbcb1e169da10a3c9123b332c10c3012646d6102ab4221607dd6f2d17fe9725421244397122d50dd28c1925e4794463451019aafe50e0820dad10ede1c345057b008c16fe59a62f6a44a9ed81e315a284465dbeb8271f2280436f2645b0b685cbba8a4085223a3e009080efd0800d521ea519fb620a060e31258ea42902e145a84087f8c88102caeb8737070422a5b6246d052513a8897148900a2d09d5c90286c75296a743a70808e5e245046364c41a81c5914f88140e3c20193c79c9118489910b2624c073c30ba419378ce09282044e11e822619222e80b5ff8f42101c985a9056e242101d222244026cd89d3648511bce4248185b218970c27e655986986a6f041063776838031505a1938b089d100655c28f124e4c9aab3149cce0c99c1442a1b3cd1c0c302cc94aa222fbec456a000f3d38114148f4c7069c1821c6948449080122a3f7c10b538041622052010b9c1e2e50f52739af819a0a2a8f912668faeb7c8c71b3c3c3a1083628917154800f5f91ef440644d4c8ccf0a2dc25cc02003292d2880826e6281a6e3d203336e88303324500a6f367d2bc830b236440f580c7b9aa870839db5225f194c4b92a8408a451c131dbcead348ca0527e409f14983451bc8e88191f9f80a018731aa2619b900125a08305c9b3452089c784117458ca59b035c622cb4042da171c885496d72c80082c84a978e188ea87cd2c281114538b4128b334a4202f3f5438b1c402009a0d64be485131c05629058014603dca4551c4c2dd89062026a229489182b5248a100ab0600049dca213298ecb4f0f526013b3888995821582dbe74a1f274153aa8f040d79723b44faf34504169863525c0c8f9a80141947a848a8f2e3b3f5c0084c09718295b01ab4f81344122c00c004392d85191a3d1c887555362588208d03ea28201332f26f5298428ee3891a7003a6b76aa8850c3cb0411979c8c9161f608d11840592d08c1900287365c5a6474f0c88e62404a160334207961038714ca8c1280d51803876e404184399dbca8c8b19306c706094860c842aec064f849a173d54849083b94ba93075658ab287b54b868e3c3f4e409843c675410f381cd41568546aa1e14a0a3c9ce1a518b64a078e0cb568582159552269042e1da7a9839249b0c6e8b1d066d4178ba9c4954c804443e70187286c68e2b615e189140d40759047d0170733a4021a64ea526685304d930c3592c1b1b4b042db07c0a7835823875f044cd8f1dd60c999ad103c2c4871f4e132cc16d2103a1458d1a2844782021602309834b5b48171d3a155158a880c987291d615040b35681006054e0f447c622082cf11c439751745a5dcaf46a82286016f48060e91194da31e6075010301026138b1e5f4d7a25987d02820112ec1cd0838b363248a8e860025468a8f0b8b82c1d566d900acc001c2090814e448f785616ce63ac560cf2c0d404b162fd4361cc044913a26c8718575ca8210299580ad48861800948153965fb4ab4c52a8413b122508b6408881d37ec8065850d34ab665410cbec89d6a3813065e30146087c7690cab1c63c101180a430a07810fa62d2a7530ea1366073a42bc42225963c082a389800062e334470260311236778be459c6094f08204920b1f180163c12902491f0e0b78959a94aa8421472c91203325a7d327e7898a014ad8c205ca15206435f4244a0184042d2fb6209026048e424df69f24b83a4d4aa1e0f580154a00a741603e489c18e086294e0c29f4e810eb8616aeaca8b404930d8822d9132e28092263aaab500c32bb48070590a0e5c48bc692133a6cc1d181853b9520d1a9204f2fc501614f7018c24b357626960f3ec0ac69c14534853335278e0d2ff8583d28c90408a421a6c6991a8958891d19a3c0aa4f25a4444121c84ec0ca500c3750aa523e9c012082052dea34ea8157e3041a2a5bf2f410c1880e129871023574e254055f9702929e8d4a02204191c39aacd9e10e8d2f03999a3a64d490b50861c303d28d1da080931a381879dac267001082184d6d50e870c2003f87749a86fc00f68885377c44b8c1cb07607010faa4dac460e1656bd7c4f791f32493c5c2288b8e50329ea0211325a685351ca5468776647d05ac6c12225b410faa1ac85021e4e30c019c56d8a000163d0f24e11383a728c34da81b2ec5e0008e255183863871a20421a62a8629ae2f52da8c01ac28bda872b1d05901f6b5b5e216a986b4423e3ea972c44310325830670c462b1262a8f449002a3978d8a10798033ce47c8579c146580911524a70c1e2b791a0830c54c4b066da381100da1f1a587ea4ea22c023184c508d0901ccd20815a5ea1b3f022c50bfbe56edd891e48402020d2a13030e234e50501145f703103306ed701123cf891e272d5d5e0022e18a0452577878ea939e38f9ca5ae2f527020752ec70d501250db0bc8002099e4b293299597191800f02c04ac3ea480b1947b85e94d822e4894d0f5f630ed8d96140cc0ee855e40126088810830aa936f5c9f322530d255250e1a07ae8208e0f3f6f5a58b3ddd42173a15364c7d012434b54cc34a848c881911e1a94fc3c90670f90a50a9903420fb880c00685272413743083a119321c30786e8c2d11a1852619d7040a502888148a2289ca19408c4609516726b880d3052db2e4080364ed061a0a9c094c3c62a9d9e0440f189570494810d54208180493186d81e402891a8c1e60c0032c339cd0b1e1c00e104c049650e9780f4e7a60ab34585b92411b2e659f0a1590410cabd6b01804018b3c5ca988e068e12987ae26695c64dce993c11a22373419da80c529481db88100cc8ca9466a9438197029546e87120cd0f4028b1a7c158a1f9706a5898104042e510249314e0101c226136866e0d3b158018320c4030cacd3925223508c2805eb0515128b52a5b0828e9c3c592849a9b45fe1c9812cd0162f317cac4d1a01960e4661c48c40a0c69414507cf1399b81428319e8007a534022565f1ac8b1c20b80022e80a0824574088170230418a8b4822147442a581e6440af3478c1030d3683d4be7aa49973bb41c0d98c072e6daa4004414754b4e1f38308abce8a1840401a13237440458617a9e290e00715999203a0d0496829cd89170c2f7834a4ca41670e2546abca0009a98a00b657a60f102d6ae00708aab2342173c20b25aea094282b00102713566e00e33718e495060386030cd17123c2882b1ea51fa15648e1a6860a5df22cd20560055f32c1c49d462e4040408c890072a8506987ae47385030b68397000dd86c40b202eb041663765234b0e54b0aaf185c85d06a07586932529889010350850b155e60681ccac184126254f434f93255a151a5cc820338e012088e8eb400446591d001c505bd4e9b2011a064cd8130c40a65fa7c693186021564ad00d1a0230319350f84b5503643838b819e43740e1083e9b645cf075d1fa0a8012a6c0fa131600471d0809e3d1f70c086052a0c3c6041060d2b3829a9d286498a126732489979a2350aca9d389ebad86ac4702202b0415e2ed4c00214339cdaf0290186481f1c62714585084e6338402d608b734642cba92183be48e2e5022b0c4685a9119800c0150e300554e54ea1592bc3c2599617708f8048b482851bd8ec29804e0d5b45d6463cd0038f0f629c2915882cf72a86212ea424095568d2932f4c699516e862a08f0a7032c1c935c1f2c28a2225627d22222cb08856a24744a91d81b1e992023f2ee8a4729461042406160aec7c6979e0800868fcd0c970e98b9aaf440de451810227842b658204a64773b6acb8f1620d0ca9088ba3b016de44524bf4c84ea18d80572c152feaf0f080ab1e1fc849544393188a54fce0b48174e100511b175cd950a703024ebd7813c7559c3725f6e424f9e03f017288f2aaf3c2ce0f532295fa3eecfc2823a2c789148cb6101f52b9aae187045a26c2024882c2450eba02443846a0f2260a99c083129d3479d9334138095308fb40c30d3b234404d02785105140687191a5ab950a4359949008d0c4c5130d7800f13402003d1906d0fa11234e07343c4823a905167c4638f9b24188250e0c594231e949060f088a94820b49e4a4132058e06ba1c80334a1aaac21322203568fd867149019a728e01343b628e045016228f568818638289cd8e9d3820620b08852721b84d842e0458b03844c00294495198240434224d2195635cc90282e8e40073909a8b9b369cdafa2024603a02c50867a08628fe50024f1d4a2050b0ba46859e155d10a0f245a3323130d3264347043a31d78a070aa11016608846ee6ec0143e3b9d2e449982444194051188b4e11b01071c987253e4a91d1f2c7cf0d53325eb02106a5ae9b45827d0b62811c43bc0024047cc10a15248829576450032b86aa4552c8a2ac187307ac815c0f8c8b8f0e72dc1068005431668cb17881e48b45080104c8076cda127e516043aab41c12415d928db116a5849451d1aa832d25d674a21244a2f9c4d30028c260a84980060ea0b2410d9832c154261ba498faba016617032543a99674f9b200040b64d241052f139c383ff4dcf8640986024a915212e8c5a54ab44786c410952c24baedc9d326af4664f0d818946a10223c2ba4c9000154a552aca2a16676c27165d41aad03b8bc90aae1c58e525b1490d3e361062a2183529083a78e1716557ab49430a945054f46086ac001515952a89d51cafa030403231c50e9c58b2b32c0b8a020d2ab462b7eb8a1641486679558261aadd65ecd3b23388a6582cdd4a41da948a0f801d00f05f2ac0a432653a705c42ce221520b575296b0c0268d0a8d4a72f674d2d1c5150d1c688031b4123a2d8c4860a10ccc0a5f503c50a9aa2076400a7834bd30801c4a660268d1c9040922904434428049375cc1da4b663870036b60d318314a0b24d00323c6151e140228e2228116b24cb1c052b04189ac042e162de0209286420d372668f2b28355834b978c147a9b4ae8c065472a09ca4e2cfad30509cc8e19002256807ac5aa45d99a4c6c42dd612164cc880a31ec2cda31600648898e3b676480bdf022080e1a015aa1072e1637bdc50118028fe274224505501695466fec9cd143648508870ea9b8a9629135884e219ecda618bed7a882e886188d6228000bd3ab406fbe4c58c40a4c08ab2670b5409f586334b8595b6143db65f234c8cb173e5fb15264da41074622112cb8a173478e0a38168ce1444291035f65a0194434a03083046b269c3052048a4dc5075140159069f764d0261d15bca082630d060a401880a0c484a90c4ce4569f725063e17543924f81e0ac5980db0885c10d733ed8a1e20006366d5ac5654fa24231ccf4518422cc8b2e17ce894804ce8d5b283d5f1f6ca2e205412317666372b85893211598248003720a0f761b38ea8488c626273664caa012a1102e30c129620806b1522b68e94009a840a7225e04d471d34217f6aae18304c29f22a794a4c841465517113430b800e283150b5c88f2e4026f7043880b0c08e036c1dd358087011634d244504ac48f1d6e5aa9a139f1428d5a06280af5547d033a8df0e283dd9ab439471e6881c7498e3169730c18e0090b08544a6427d40c4921220d4a24d27de041a31e18d9204406143e80cc46917848a3c288354e588749935a9488a3006f4d873e3dda6c6a9242aa1e09cc386188499329b92f128256f0adcc2821019b7489100578880a7d960089f5420f0d132c1c18d2a9871454bc5a206c821f3520e183498695282a7a5eac38b00777e84d9d0c9a400046458525dc24573a4aed2e6b615a4eca56e4600548a320beac6d6d49134e8b940d31fe4caf558ae64821414d902542b6f070f0752a16920ba0f888e2022b1b978e081912aef88c64fcd8e206909a1d785c562880a10c8c5836516fba7668fab3e3440abb2f6c3c7d911143b6c9910f522abc3293410b1b112aa9f07445cf1b1e04c822a684474e82a0793230a4504a9390d7081920c02a6c41d2220dbe5694612096203f3c9ec05a9631195ecea8b812e685110650bc78a820658427a25e107b51c8861c5d995365471cc0810f8e861139bc40707525854114f402a54aa1268b4d0a25a490a155a15631107dc56056c74f160e5f107801c60a0f0fa1446562f2e84bf100ee05565e49624053c784ae4b074e654ab46026cd8b140cb0308a91930022e51608f3eaaa815416175ece78da6180046b4746e1520050e5e6038d17c432fda02a6abac34023172362ab1e5088a213e24aa61910a0a04833d96302063fb4e85442241e48f0b1b1c3010007706c4146a0a10201573a988013c21b436bdcec5c613200055a020edc0f5cb05027c2d02ad20c044c6961848d95214fb28c911143428d041772d8665401b4830a5c2ebb5d217b62a3482b0de60320164b360155519d41ab5ce5f8010d0b1134c90823e12ceb541919b115185d808c0edc88c2958aa4f5c3c4c4d828457260106c3281429c193699ba628520506ed8c3c2c61bb02eac50ac79ca8a61a6853f5a5688b103213a267653a64441a1eb21b222080a602c04c13203e00bbe9906908b251b5cacc8000313b68e40e9da8aa422132414fa2d0698858606861f224346904109982e25e0af3f61a2761320e1726ad59a13948aa8d0b342850d32e0d80c428c1ac4e589092d642001c34ef7abb6b88c6c1003021b8136f8b2f41564060d1635800ad4bbb810c3d9192e612a26f87c3a71b232a50432232c44ea0034f5821523af394d76b0a1da326c91208114ee15039d2d589cd0c1f244860d504f7c88a2818a13af86f0d0c747ed238af7c2540f67e08b274158205b2861a6854e706ae0a00210c5ab27a693a71a7d5a2000c71a0e213e3416a49820032851502d900217562d7045caec51e442042e3f80f8187021edc0c00354b2b080c3ebabd1a93fa53481ea21a581af2f33986920c50aba274a0d96385142a302030c2ee489c1058c13de00c220c802638c0c4a92c4081b2634f8a010a49cd0c29e4e9c666060c60b40a150642048e765d31900fc78302911a64b804cb448f38244d91b0e26cd7112c48d08d068fa9ac127cb9b1b212851f4431f45d486b044261407043185d3091d2b073c80e1ebe2495208163a00a1f3aa20c90e32b81000903752120120235518242f8c3023070a2255ba4408070fd6801d2a917bb40a051445257cd2d2d535515870266cbcecd884000e402db64864fdf92383472834148a56b0aca4ccd8b2d468c51cb0212b88e58092a50612a2ec1a65a943366345a6ac40780b092f0e007462e703a33c7b62b479a0451a504b16427450301121073626be3449264f9264b9938375f685098a0847562879c5818d19d9111b1300584104150132c0f8e483c40e0540e2010d4d8d0c9bf6dc80e9ebcc8003be48b933e591575ba3458ba12d1591761082a2e34c8e95180a50a110240f178c0c44067ec0884212c20cadf810a26004f8b5958110366dde0802418517926c408094540c4153810edbae8a9512f284e19188c58f1773f620f2218c09553bfc99b469122e0301bc3288800220941c8942e70f030788a981db48f1c8862f89685801e4c3024b080b954421b8e88100183ce833e92801c2910c43836edcbc74a6bf064746833832a8ec1027950b19521849020b55a30d20a8628374f6061e272eaa30008b4fa1225a50d031431bad9e082d3406f56042932c2e82105a7b12c8d157006550ac80c1dda1c789492650bda0a4ce293e715a3402f2481025148a9cf099743be137a93376b8c48a93984d7e0e68d200a241633a0882424aa33a1ebce9b3650a054b9cacc0c4800f5ae82804042c840586a412e1531f33a0543d99a1c3bc583030ca021cfe8216b8154038b050860230618789184e633c3dd0692d090a2ceee42941811002b02c30834e97a349034232ce4c6222022640754fe8a347180120c002b6c3d202a6b13f784add4881958cf07e6061821511222f58b06600ec49930255e2b88a8129043a9bd6948080591a4d964e488bc1b640d0a0541415760658c5e7d38d31288cad406307823c08d8c93a9516e7024a43970a6214d00877c48b9946bf842113806412c0872f3a75cce838f5e582cc01aa7a309546922215afc8d4b0e6e7dc68d00187aaa70f8f53301cf01483a645891065128433436981111d7cd948983220939c1048e9c85a8006181f0054acbd0115dd684f1b8c10644fa889899a179a76c0a004108c4889808f1313274840c0162f48adf01cc241826b28d2aa2379caad91c287436a42e154a1d9ae54c1802037f6e7c505852ac6588e3d61c09cd5083cad44833d6e7943de738d7ed7cf8f6490df8babbfd276cda90e2395f7cafebdd02318fc9b462ae79c57631d7568b3e94b56e5c62f88c3ef6ff6da724da7bc578a052bbf61e6fe66a97158e2786a69b79d2ebc5da9a482dbf29c39f617efca29ad382c771bd7a3bc51d0566c698fdadbeb63ac1f87e5aec7bbe9df33db49b1d96cb66cc9aadcb04c30d24aef9f365b8fa7d6518b1affbc4d2d59959b1309fa19f1adda7f8db7dcdce2b0bc5179670427b5fee7283fbeb6d6887158da1e5a480dd8014a39a78db56f9abbbf1fe3b0bc4d797b6821bdb61d4f6d77bbbdd001dee8fbae5f563d7f8ef2e2b0fca2db69b9c99903ac76d788fdcfb1c7f96dc56179f3b9adf37262b1b2226241c4c6c4cac4ca9488f51fe5cb76a2a920005629f3ec17fbd863fd75fb9cd9979c9a2e77cb92070ef05f7ce3c7f1e61cefb49e8a9515119b546da70b6db61e5a68138b534dec2c0dcd4cac4c89d86dda3434338aa696a33db490f21b683addedccef6eb71136c0fe43cf658cb3f2bb2de7382c7b68e14d4bce8c8bfe3b5daf64556ef10070e6af799456eb3fc33f310ecb1b96fd7bb97dd93b6cc9aadcb201f2a63bd3a23b73514098580d02e82dd63860001b613668e49871800c1c31228c1b2f0e70c173d1e2050b2e7df3b3331d8e157effdd0b15607e2e85bc7d2d2e50485e0c301b5f33ad86178c13328689020498fef7c07c1c25e4ede36290087b6a371901749e195a8d115384bc1100c044d3f5dbdfdd6e92cbb533ad7fde0d8798d195a70ce3aaf70646f7a52763eba6256706e68769c9dbdf8531b2e40dedb6d3f576ef81f933be2f13be16adc9fa683bc7f5b5885115125f245072827c5aa1be4f0bd4f769d5f07d5a9fbe4fcbd3f769d1f07d5a9dbe4f6b86efd392e1fbb4387d9f560cdfa7b5e9fbb4347d9f56a6efd382e1fbb45ef83e2d17be4f0bd3f769b5a0c5c2f769adf07d5a96b4a468a121f145fa1427c81782c6f705f9be4cf8f37d99b0e5fb32e106111a067c2cf4970960dfd7a24adfd7a209beaf45bbef6b9191ef6b518def6bd1d6f755c20ddf5709297c5f25b8f9be4a3813d1e4fbbe265f8f427d5f8f327d5f8f207d5f8f147d5f8f0e7d5f8f3ef8be1e65f07d3d9ae0fb7a94e6fb7aa4264089af4091beaf4a84beaf402688f0dab1c2e7b543d2e7b5c351578a016e7c5f039cf8bc6698ef2b0c88ef2bccd4d7881fbeaf11a7beaf1199beaf1190beaf1181beaf1178beaf1167beaf11b8ef6b8493cfeb4d89ef6bc4d8f735227e5f23627c5f23bcbeaf11dff725c286ef4bc4262f2f0160b028f1e5f5e67e5e6fe2e7f58680effb4c7c7dbbefebe3dfd757f6799d9af3799d62f3799dda7d5ea7b27c5ea7aa7c5ea7907c5ea7827c5ea712f8bc4e45125e21209df8bc5208e2f34a21d5e79542a8cf2b05195290f479a550e8f34a21cfe795429ccf2b05329f570a699f570a59beef3b01768244091264de7c5e64ce7c5f97b67c5e64c27c5e64749f17192d64a6647d9db0e8fb3a81cff775c29beffb4e00fbbe1895fabe1811fabe18b1f9be18a57d5f8c9a7c5f8cf0f7c5e8fbbe4cf0f47d99a002020784e14fc514af4a5607f8bc2a009f1755f57951549f17f5f47d5d92f279d14a9f173de1f3a2227c5e14cfe745e17c5ed4cce745bd7c5ef4ecf3a2b7cf8b3af9bce890cf8b2af079d1033e2faae2f3a2027c5e54ebf39aad4ebce82af14542802e3012747a9f179dfd79d179f279d129f27955053e2f3a3d3e2f3a057c5e745a7c5e74427c5e16acfabc2ca0e1fbbe11264eb0005371262bd4f76555f07d5963dff7ad7ab2c525624b6b0b00ad10008420116280af01e4f7c9053ee90508c7e70528ecf30284e2f302c4f579fd59f579fd09f579fdd1f479fd71f479fd11e1f3fa83e7f3fa73e6f3fad3c0e7f547edf3faa3e5f3fa13e5f3fa73e4f3fae3e3f3faa3e3f3fa43e3f3fae3f579fd09f179f909e2f3f2b3c3e7e5e7d4e745e6f679f9d974c22bc50a11df674280cfeb44009f083c254aa0789113f379e5ce3eaf5c96cf2bb7c0e795fbf179e506f8bc72007c5e683e7cdf37054fce1ad4d505e4fbb6e2f77d4322283286cca766030dbeef4e0446be34467a3bb32542be6fe7ccc21298610584e5fe59ee9f5951a67cf4c0c317e803417e5f9d381f9c285f130542957024949133cecd440c1131440d2d55160e9c166595c0dbd5f91196b6fbedcbcfad10221598ef73419cd4d0824a9bd4d1bf97b3b38d36c2d96e07e6b4989ded1fc68cd753d3ad6d258300e0bb1d98252c17c00cb6dc1aefcbd309babe0bf27d3ab4b39fb65676bbc5f9a26104dda8effb4488fab4e4cc6e679bc60fbc9d2d6da3e52978ca9d62a7d42974ca9c22a7fcdd3732e995b9aeeddd2e88ff39b3f0fb1c949c59ef9f9da909f93bdd58ce4cd77b6642bcd90d4d0d94a2ebbaae73e273bfc7fb5236dae6a925d97dce65a723b2b62684d7cbfddd4eebed76da4eedacc9da598ec9ee6dbff693ac7d2e71aefd7ac17c9fcb4d4a96dbb8b2bfd32dd1a5e9764d7abcfd95f482a0e972dfa3e9723b22bcdde7687fc9ef66ba286b3b35defebbb29c199a0ff279b91ffe2167dbac9b793524673c332d5f09aeff3270f7b998e5744b7a663928fe885ae8cd3e9aeec9cfe9c8f4482d1654b2feee122426801c397cfcf01176038c37b3d10bbf121e3c7a382d664e764c7ae157121616161640036160bcd9ed6bf1ffa624460818214a74f2f123fc6733f8e8814058ee9fdd6efe4cb7a52a072e1000d8d1e3f9301f3ec2fa8ec763d88f2e04be36717ddff7bd2e1756080419a6c34718cef6b5f8ff95f9be3489f17654ca8e8c056912642cac4718186f9695f695e9ecdb91b6d10ef8be2f921d030c088b613e0608eb7d5e18eaba7e74e930c080301f3fc27cee7f5c8db80c71bde142c27584cb0857025f2fdcb0d3f176fc6e76f6c2a58f2788b7b3fdded662e665e776ec08c10515783bacb79b501e0f1e957ae1c16356ca83c7f432a3541e3ca8177fa446a151fce7a9f1e051b1647c6da5f30716199680951e7d1784078f7ae4c711de8fdc57f2bd8eafed2539b55dd9931fb9afe4a36d32307bc94e973343dbe9b66cb48fb673ba3077844bdfbd27ff8cef2139284d74645cba4e49ef2fe9e9c878ff1339db7f888e0c0ce8cfd474523eda26fbbcb34d043c3b5323e2ffd95910de0f0a66a3f9236bfefb9f83c283c78f1b3926e59d9da991ade582a0f529bbcf537b4296334bc24b43db09f1b81c94b4bd2bfb5ecc78b99f0606d4e9ca78ff13d1923323fb6aba5d0e4a6fa74b1bf2c3983de181fe4c67e49ff12d4557e6b790b3339edaae97839283c2c49f9949f9444226676741cece82f83333293f7a3d08962b3396fafb11ae3b13d2dbed266b5e27c41f59f33a213f7e4cda6352283d5e4e3796a754cb6af5aa6199d41fe1b2d37de97db249d5b6f0e031bdf0e081e4fbbeadef8b120294c2be0fad8331a3029def091993236563645090dca60459d2bf971b97fdbffc78d2bf97322efb4bf93db3dd17bfff2ed4e976b7f0efa6171e3cd2fa8fc2334b0bc2334bdb5a726769686669bc2fba1ebcef75b91b2fcb0749694bf6dff578457e785d2e521e371e65cc34e000a40ebe6ff7789f06bc9d6d4400399dcfedb09fd305f93ead1144e44f2dcdf77dbaefebd1a99b907fe6cf7446723f8c6e47e4f7f6df8d7dd19d7d216b67392650723a33f06caf6d253a32273d3334332543988c918137274c9c38016fa0122843982cb94d09b284078fcdf31d7c02ea74fcf7b6969da6dba529f1f2b5e474673fb4ecb226479eeca0e8c8767e0bf15b088f07f67666a14eb76be2b790bf53eba9f5cc82e43e175d198fa7235bf2a347ff51785a74673d9dce499adaff3c27bbbfb6cfc2ce762ec84ead77dd17dd59980bc2dbe9c8fe999ad7a1856d21696a5c743cb38d96d3a971de0fcdfcc6f5726a617fb789f0726a5acc78fef7362f01335b58186f7fbecfc2785b6de3c0fcdece8cf7dc0ecbf11b36c2765a98ae17963b82e36d237bf7f70eb4d65a6b6dadb5d65a6bad94524a29a594ce39e79c73ce29a594524a29659c71c619679c71c619679c716aadb5d65a6b9d73ce39e79c33c618638c31c6f7de7befbdf75a6badb5d65a5b6badb5d65a2ba594524a29a573ce39e79c734a29a59452c618638c31c628b5d65a6badb5ce39e79c73ce19638c31c618e37befbdf7de7badb5d65a6badadb5d65a6bad95524a29a594d239e79c73ce39a594524a2965943ae36b2b9d7209da918fca5721b1dddfd1cd8efc9c99961c78b6ff93bf6b82f67b47d6f8f745e8d2f7656142e3ed2f613a2395783bdb1abff1783bed76b67b3b5cdb5c74bcb01c3dd278519278335d1426f57a2c6095234f6e43c02a47940439e2047c72039d40290b4256e4c893cdf3fddb6cb64f6bcad7203b83eadcb0d96c36c240274db27df224cc1a982f5ed47abc5d97345d0e8dcb16339c962a54a6488902a5ec8993059a902d51920489912244c021634282ecb0e9c8112b56acac50d74b5bdbf59daeeb48e355f07d68ba1d91dc3fbbe97ab734b55b0e7b50cece36da139dae4c880fad0c1a919055a9854b5f827a0ce9e9ce9ef07aba335e4f77f6e49696b679f0d0d2dab9e3f1e0b1776afbc7aec7e381c6db5f7ae876bfca9a909cce8c67e6c56c88cf41c953421181e70bd009dff7f1e0714be38585ed7461a01b665ecc3c6f67bbf90fc62cac534737eb7d345ccf6cb775a46d79900544cb4696a62fab054b599238f8e0136f67f3fbefc03e38dbe9fa0e9dd977456d17aae57a5c2dfcbef3ad33beb6d229a3d6092d125a5a5f161059adfa78f09d9da9e5befa94f9be2f4b96b05ece4cd727cbf7d5a77edf97b6d6fbea1302161f1fbeefbb11c623470e1b5f7c60e053292c87a676a6eb61613f6796d3ed421d6fa3a1e9c07c9c16dd6ea7c6fb39ddd98d3067a6630702613b5d18d9260bebe9b4d808fb3db39c5918d6dbbab390f77b3ab52e6139b3cf65ed73b94144c6a87645478c31aa5db1111696a586182c39b2f0c8d2ff16ae0bcbeddd4e23c204245343a555695049c243065003347a00ea51325e248d5281803837c808e1b140ee811812911100070c515c70e28cd154162ac6a51da7317afc304102c40aa831689d92f8f92ad81a8345f550f3a9dd19b315e395aed36a909815e448ba72c38d1231177c093168001f0188e9147039e1059d04c4ec6802288ca3830f0eb81220ca083c1e2239f028803f901ce1c80ec411b1860b0b653f3840a58f10222d22e8c101b1342b681026c4ad01555c481002222b6920d1104f67109080480369b64869adf181a981262ca0b23ce8c8d0c00b52e000ada8301066541a2e18398a900943085f070838fb611a68c3264b0ea40b436444026574487113e60b4f10211b40696b33d448017c09b3648d4f9c0d12a040928fb59d004a76788047aef50085824c8f3eb006000c2195aef49005069303360d09035ac0640046cb0860260e9206f06ae4ea0bac23406a290dae7c91c4a38ea31bc60cfa52014f7167d134e0cb6dab4c071067d2bed860c14b9b1d77aa78591503027adc8851e185110a9eb684d98abcacd1322a9524b21d5eca9ecc9882e7871b2f6142c60452022b93daa9ad57a052a8a0839a211660917d1171825a193e9f0405685ad49070f082a72620905053c1a413191ea31ebd1a4a109a8d62f5de9f22664eb57081063d354c2b40e98569d10ba2d6a5530f9252f448e410c302297c20e0659a12eacf9a132e5e9e4f22d488d4bbc43bc36011d7aecc0cef828a97ac78b1c4d3229380e7c08dc4ced29f1d9ddca435727858b3e38c00c833d6c30b3b1db0767636d0e1499756b01aad7021c10c5d1ccd4a43184da1babc1121d1ab09a870e93285821d32488a285d08f0a00014be4e5f6939f07476aa1c1bd248b861800a477ecad2d084a11a7247cd585a9334178e4a2823e90a199da83b1658425b514937c8872e0c177128c419393a10060f1c5cee78d1e5c8c9c03580981fb6a7dc9e3ba5e80061864cae4b2e013f33a88e1d9c5c8801083562d3a8045a0b696877ca5628a2201429b4f0833f9384304185360788c2c30e8f80b3575a04c4f161047c1609d219057112619023b57086e5ec0047632e091f96cb2a2d4a0ce83c0e2e266ca1e11599107eb8a88142464e2e8ab83cf972010f36a2442e340a4001023eaa946c31852a2ba79120802d8572a83a700722b690e16d3982c6850b61b8c0d962f6a9ac0d0ecf904c667ec23c096089870e66bd522d3469e255cc808cf00910203210cc0240414b98404808e160d0920688453054c1e5a1a1018735c4088ecb5701bfe22100cea212914305399a70596a5c9022e20b0a2d954cccd0a18f182a2d167409a1ca0d32d668d93cbc018100242f68c99148cca8ae2110843d0041e7d4960c72d8887b4aa56890ab50822db144ddccc009a584355cc8e4031c123e7e2a1a2654190366ff115c7c15d295a97fa6081a2f1e22ddf0c936b94056c64bf15b0452db340667cc875ad4ead32d713d081650094bf814c5af81f143f0586f552348de2b876d7503b7418fe15394294280c0ea1d140243c48e96d9d33a0f324ec0517a58e85dfc12b7536346ac51df0bfc73b98190e442ab42b5c486b427d857786b6c9480e0611bd0e88502744138cab24396455922c8e2248b0c18a4809410e1702bd5c9139711371d6e85588cca8147a1036e63dc70d0020baaddcd88951b0a09acad89052030e0c9089415a5a49061e083107ec090005689815e17141d5964c8c40010ae21624b1cf8c3c0083c6821406d302c2fa861c11302d28145d0232c5b7c7c323247141a960a6b49081a9a48c1f2514ac39484b77645054f2f4e8139b172658e0357f6c433678523f10a02686a8d501e2cb1d2831514ee2079f288141d2b6e748c919040006eac44b152438498b129413c50e5064ebccb8a0e0daa20aaf2c01723aea28c5965499b3eac5c486252850a28538bccfcb8a8444550901d27bcc00944050c953114a89800e20b8c912076ca26499c20e1a938a670e002a85ce686a2293a12cc78f884a430457399c2b5c4108f62c941caa51f37583522e4464a9d572772c8c0d427295e059e012c7028232546f9e14e095446e0e1234a0a48621148726045994084011b60f2a214c50a101f95ce90814529008a0e69943c02281480a2080a044e7298214b0b3d50169061d58a42444c4129235516c2914005c87124a64c4c599132b04423b0444a9bf1a4530f6a7c53a1fea48f0f584c05bac2e4094f070b1ca48829f1e48720378276d8819e8868c301231b64624e5cd063c32761930c271b3831735261bc31c1a6432427df0293c22c20878e8b281587a405b280a9e1cb1114b4057034d084950a0c7ce01ac29b9cd084cdad09143a05c870c00e324d060011814ac3a80e13544c448051a9cf579d154ccc3051c2840c1419a01fccdcccd125c8bed81265ea14c90799903692fe88dac09309b044d3123d4b724b32932d1b1470c56ac9d6ce2c82704fa08405196a7bd2eec050728192ae64471257491ea14812e78324558224115b01892a248990a441b20006488e8ce21d2174e5880347881c5162648635237cb6915d29233ef61801a008a6221a14c1852a4289c022228948052c88dc88dc3805f2009e00aed102cb2c1836c19053430e0d293324c990b11ac6fe8c79190b3256424826217a84a009c142b48258b2f483d0d18426480f62435306880f5b3e208ed47c40e0000142e50322f62900a7ab7723f7cf6e5f7ecec6da6edf761bd76f3c335b78f6795a5a214c8430c1dbd972bbdfebedb41dbb1e2f00fa7d5fdaf755270b6f675b3b531b42896c938539331d61ce2c2cc70595b2881875c192ef7baca52ddaa48eef77bf67d6cdced2c07c2f616ab99fb6d1c2e85cfac2e818eaf5bddbb87ec1f77d59c2765fcbefe5ccbee890c91296dbff4ca7e36b7bb7db7b0901bb3874b876552c2883ebedb41d6b3d6a93d23675e8c29c990e15784ec270bd9d1676761684070fae04fe74214af17d5d88beefeb7d5f753e7dd116b5ce1aebabadae9aeaa9a58e5ae79c71bed9e69a699e59e69835ce18e38b2dae98e289258e58df7cf1bdd7de7ae99d57de78b5cd16db6badad96da69a58d56d75c71bdd5d65a699d55d65835cd14d34b2dad94d249258d54cf3cf1bcd3ce3ae99c53ce38b5cc12cb2badac92ca29a58c52c71c71bcd1c61a699c51c6185b180a80ec8631079c80a941e6b27470c60b85a3047651ee74351d657898b2a4098e130d0d5238b32852971a232b3c39a181429c7a7091a4852bcfb8d00020e1855a70a3011f52f4e8c38004aab6d89c8d40e00a980176fce015d38cfa41e54eae84176a0ccaf2c28d2417a57ae479754587981f70e05a12c6a901488a115e91f9238b607129b703270298f9bc2a78b5a9090f581f06181fcef4346110be8080af2a34011d1108f07002a63237387ca8c84c6e5ce98171210a162d26fc8c50e4bd5c6dc221549c2c1f7c8972b21b200f1701c60d2b2b72a92c1367429c6a6259e092a2221108437e70a2e5070b59118f01052ea02f5ec02549416e980a6499c34a542c0654c1b8d4c30c10b3351b627d39e4f002254a2f5600895ac24491527d0ca8b8f1d3434f035f9556a5412569031d4ed550838fb2576493623440a307a01e8df1672b0b08453651bd159246a940401c1ba14ad0d212c41c46327080f15820f7400c89984cb20341f7130b891a19386088e28213878c073e68eaa2e10f11804559a818977631c44a94051017a153773481f961820488951aea6c52aab6505023664d46a7247ebe0ab4e06c9170b1c11d01e6bc6121aa879a4fcdce9e3b226a50e280263f9b50c478a5ebb40201d120005e7040072c071433e448ba72c38d122a2e3a68752686aa058d165f420c1ac0c7884f35344941950c359f5ca0a080cb092fe824f0620927bc0a890ba4c2d06802288ca3830f3856dc583583061a9a70b81020ca083c1e20a9f9526463d418329eca5204f00792231cf98c531061882e08958c798958c385853257aa40882f72aca14abb2efa0821d222821e968c72e128cc953fa416a548b38206614230d001a2222ccc5991032a15bcb8902004444e2282ab100af801c32807185e0cf174060109401ddea4fd4e12c4225543c51629ad353e5a78434282194834c54245e6c5022acb830ea74d237c108261adce1a122f488103b4a2c280016a3b1ec8c1062b0fc054a4e18291a3c8983438dce0183d694582075ff83a40c0d9c7507c84d539e16a3f81d1864d961c2867422a49d5860b385a34568c48a08c0e296d28eda01d3d29b2c78e922f3c41846c00e93259d96627ced038e023468d14c097304ad820c08209322900d0615b116783042890e42381280afca8e4d5b5c804300194ecf0004f0c6248ac9f56a2057f410c5028c8f4a8990af25ca047490d4c00a8c20286904a577ac812522a101907a5766746c01cb0694818d0822341ca2e060936a2e09151819a427ee29e9e1546317e4081931865f1018f1b65ab10c539f20749b293c206476038481ac0ab912b203c109d80c7012f455a338e00a9a534b052a7951b2d5a72949a2083163cea38ba610c08826e1ca4b981801b7a6350f01477164d030a70c1448328670888e3696c95e900e24c5a025642b040550b98cae469c18297363bee5099b4c2069813fac880c10b143120a0c78d981478688020d207c111232a68a0e0694b989d0883571d74c1204d0d480d175a46a592446603e5cfbc5161c0234a96e2c98c29787eb431d5c4ecc71727174e172f216302298195e9092f829f23480a0abc79b1f50a540a1554a549b32717e88af88352b0008bec8b8813b6b4b040015218409b6180179f4f8202b45011a73e0b801152250ad50b0e5ef0d404840020e1d843868649a91700a960d2890c8f51022d2842b4dbe2d1e814e5ab04a1d9285637b123051e5880a38410188c22664eb5708106625cf448342a8414646754605a014a2f4c0b9f22ce41f3c6cb9efba5d6a5530f92509c19abf2753731706a021839c4b0400a9f341a60ba71484c02efe781155342fd5973c245c644048f64f8385543ebeb93083522f52efd3dda6c10ac325359313058c4b52b2ba3270f2bb552afcaf898ad00152f59f16289ac54ab0920f0632394819149c073e016c01e086e7d3410e14e055e64206900d50fd28f9eb43a25a4988e1116b1c84d5a23870735665605e2a0ca1929906081310220cf580f2ed8b921e510282d401b4819b0767636d0c1c90432305a6396c1275822b080d568850b0964e8032a569e0192bcf80ca0989586309a40dd70a8ce12433d54c81835438444af26a0c2250594462a70c891ca82045a50b043064901e5031a2a0d52a414302408141e1480c2d7e9ab8c90a3516080645c9a4483a7b353e5988ae0011744c8f8b4c3901717370c50e1c8cf930deccc10628c921d7a7894220cd5903b6a84905a7144034a698d6e5b5e2fa05c12a359980186c7289d0438255b2e1c955046d29531740c78a447890a1ea01652dcb1c012da0a4a80686c1d1ae1a791aa3e5e62c02e62603dd6846086250f14dc0910bce0220e853823e7c419192669d5085203500183070e2e77bcec5808054035556fe4f1022527550962108053e2d0065820883300190cae01c4fcb03d2529a20656100194b14754dc294507083364746768174cd2f3e1c8f385c489a720b4d42940959440391814ca12187e66501dbb371cbc2800d4911466a40ab56200428dd834227148109a43005c1ad5c6d497a137368115748fda648065034e0bf44814a36c85220a429102009434a7521c333f385af1c19f494298a0d25c78be64e29435c70c6c80283cecf06ac8d92a54019891ac216532b40888e3c308f889a6b1800831d8c103018b6a031048ae52984147087d5208038a1426b0388930c8915a7040072b246c9174288d9a0c43581cbd29f1c07e2087151a04c82181542c1c8db9247cd8172bac09d582440193daa0d0a2c480cee36860538e0911dd02b91133b6d0f08a4c083fb713068dd1d4e281231eb48042464e2e8ac858a2120b2c4cd60b10a0f872010f36a2eca8d32545251392b2bc60a251000a10f051a5c486a1542890c4604787262d5065e534128c488463ca095d0a07501000450e5507ee000049037c2a31a553c4208dc6a830235442ec6260a1d2a737364338c85ca071e142182e7052f0f151a68b093da8f991c24c901049514a78a181f5558985009ee955d606876748265e06177c462ad520f5e6459827012cf15035421006849c3e614d4852946aa14913af12b3ea1ce2b0fca23be3ed825cd9736bbcfa636b0e486358e396597f4f73dcd666b3d96aae72403ab1bed9ca3f6f9ebf724a2b00bbee58c6e8a5a7b54e9df36c5100468be7d514fbe9b1f79dc6d99a00acfde38a6be4f8875947dbe3fdde5662662b0ec8690d6978f1afb5739d2f68b3add98203d6ed69eeb47f3d33cf33e39b14b3f506c411c759fbe6fbf6df799700a47edf184379e7bc546f7fe7961b507b1dda1e31bd917e5cf3561b307a2affbce19d396b1b6dac6eb6d880f15ecc7378f3f5d177afd5ec96ad3520d521bd914bcdf3fdf6d72d3560a67cf38afb951c63ce7304e0e59c66bc31dd38fbee3f0460186a99ed9f9ac7dafd0fd38057ce9cc32f6938435f774403526ff5bdb5ff1e79c5d99f01bfafd4eb9837cf9cd21f1f00a5d4bbfb3fabd5d47baacd80d473ee73cefc76cca9c65b65c059fdd7619c94fad053ab6381114f1f73fc5df77eafecb0c0f0471dbbdfdccaaf39afafc05a77b6de5fab33d53f0601c66833a621bda1afb36309045873ac7e7ecca3e695cbfe03b8bbbc596a2ce9d6917bec0ad491d730e4ffdac9f3e7d207f052eb3f0f23d775f75d712b3063aab1fcbfe3bc6f8fb60790467935973a947deb3d4356e08d91877c4a7cf7e7344a1ec02ae3a721c5fcf66c3da5abc019ffa4bdd24b6d965dca1dc0e8b5f5776eabf3ae6168750077dc34e4984aaafbc7ddab0263a419df1d6e1d39ddb7e600722927e7526769ffcf39a7027f28afaf92d37aadc7019ca1c7e1a579fbcda7f4378091eb7086fcfb4bab95a14405ca1b46ef75f8abb575fe790a9c75febdfdc5e19ff56f6f03c831fde18c557aa969f7d914f871e4f5fe2c73d4bac748c629c5a5c0587395f576dc6d582f0f49819386d4f3def7b73ffb2b4781f9736b69aff7637bb1f4382caf5859919d962850ef3ce7965a761af24cab0e05761d4a7de9e63dbc3d0c4350a09d3ec434dbdc73cd33773b81560de09c99d63c29df21bd3f6e9bcd66cb3769ed2790d2ae7def58877e67ce330e4bdd43cb13a86fc6fd662a7596d2527e76b68948f965efa826ab7203b5680031fdb9ea2b33bd9bff5e3359959b9a562730eadf79ecfae788bd8d7906d0fb6fc3886b48b3c4db4e365a3280fbdf69ff0c431d669d25e66d5c137c936b5a9c401ffe8d33de745e2aebff31809feb69f9a7f8e21c3bbe761358ebf63e86a18cb9d72aa52690fe9b75d619879302ad4ce0ee3f76df7dcef8625f6100c3ec75a6d8f37fa595bee79bd60b60f436e25fafbe37bc3f47b22a379c960b20adff4779fba454cb3b3181d17bbef3aedb564eb9ee382c6d369bcd96d36a01f45cea50cbd0fe6d7ffff11258c3f97b97b1d6397fe4de6693f22633095a2c809bdb10c7ab69a4944f1fda6c9d678666b3759e195abd3790d60a60bf748635d4becb6f7bf4369bcda6631b2d4b20deb3465ee7e55a521d6d9ea35509cc36dfed65adb3f2bd7d88c3b29733c3dd7e18331e25b05a7ac3dfb9e731ceb8376f9f8d690bb45400abf6f8773ffd8c96c67b796bbb89cd76939340feafcd975e2c2be7f6cefa434b122839efe10f69eeb37a5ec5ca8a88a5e976436cb634ddcedb6c3cbfdb6a45767f6d2b39db91c0ebe7a495c78c2da6f65a219aacca2d8c1624b0f7386ff8adcf9edf1f770a60e679de9cf38f76eb49350ecb23bb1d91fed39ed86cfa11e8a9af9e7b9939d6b4cfba7115c7db467abbe77463f582d17d29b3d970bc8db3d9b22370731f62ebe7b7f786ff2667a65a8d40deb7fd93f2bff1ff39d625365bbe490cb45000f3ac54cfceb7ee7d4eb94f00b58f369c5dff2ca59d35a3ed7444d076ba70ca0eb41881f187dd4ebdf79c7dda69b369bbeba5512c5a2680f55f7df5957fda4dabd553c8aadcaa682d027dcd96c6df370f2dfd796a9500ea3ac3d0873b4abc6d0ff725ab72f35a8ac05b678e34df4ba3e7d14b1c9668ba5d58fd97552b11b8f7ece1af77fb9fabfd5a8b0430ee1e75d53a87ff5f4aa5d6086096974a8c3fd5584e9e6feea62567b6e6a3dcfdde115d2f77c4ceb48d46ad6821027de4b2c74a39ef38d27a4bdb68d8889608e0af34f6dc6318464e33f7382c7fda5a8fcab55dce43b40e81dedfdfef8e14d3d9e3ac382cd3e84ed744d7cb1db1d9f01a2d43e0f5bdd6fbbdbe5f7e69b355e9c566d3bb5e1a15a35508fc3f7fdfbfff5d775979c5118fa01502b8c379bddff7cacc6b94578b1018250db78cdade1cede7b986a035080c29aefd46bab3fd3f87140410ef29f197b2c77f69cd5c10a8f9fc9f735975973f8c52ac4c8958965a8140eef3b7dd86b6561beaa8b50081377bed23cedd623eb7ef7fc0a963c515cfe9a3f5f44a9b2ddf2495b8022d3f609d3e57bab3b4de662f2d99945290d60720ad3f571af19e575beea3cd864bd0f2000cb7cf5f86724a9da394be0fe863e7beea68b5b53453798b68f1017bddf687d9729c69973aee01bf943e638ea5e661e82b8df226ab1fad0e40ee7fbf3dcf7ab9c5de76af1b8b72911607a09c72f23dc3dbb3a5dd66445a7a407cbf0de5f63cff2d71d631a7d1ca03fe1c3bf65a865277fb75d5c203caa979886dde32cb5be5d7da00bcb2ea9fb3e7d6c7bc6dd799e94c474b03d08691464e35a59b671b6a9b8dce0c406bc36c2dddfa66adf9c4bbb787d86c1968dd0143bc7fe8ab9d37ac5c87fb4a2d3b20d7594f6efda6f27e7ea93dd3c200ec3cb479e2f9bbfd35e7af5507f4bc7efbf9b4dd87d2d7f96d367d9376b42e00e58d91f650cbff3ffd7aeb9b9c70b4e880b1c65fa5fd1ad7305ef9e7b400dce1d5bbd6505b5f278f73c0dc6bb51267deb996786abd81961c305f2f630d2bafd3feaaa95605a0a4f4e68ee9c7d6ca8a2f05e0b6f96e1e31fe35cabfa9d604604867f531df186568433925d08a03766f3de69b5b9c6bd43ec301fdd561e837e71c7f4ef99ff30d483dcee1c4995b7f6ff6df4f9e64404b029057fb7b28779db4d31eb91b90ee18f59ff9d64df19e77ce3620b69def9b7d0d2bc754ebac81161b70ffb9a38ef2eaee69ee3572a0b5068c7b8615dbec43ac7df4540db8799ed9661d568b71bc92f2d18a008c35739a6db7fe675d6706a40501e879b8b7fffb6a8ca9af346ba501f5efb75fad678cf7ffabf568a101f3debdfe78f7b6d7fe4db5ce809fdeb8fbfcf87eeced9c3346a0f50048ad9c368621b753fb4ca7961990622baf0ebdb7946bec311ead32a09e5dc62c2ddefaf65a732cf062ae6bcf3ab459ff50760a0bcc745ad9fddf5bd7fbb3b693f50af4b44bbfbdcf73cefdb5cffa266b1060d6b84baeedb69ecf107720c0fd6b0f3be71a57dbff9d1364fd00ee19abb6defa4cafbdd215486be457daabffdef16bef0328e7d7dee61ace1cfa39652b5072bf2ba776ca6f37ad3d9355b9f5b27a006dcef5e21ee38c12dfbb7158ce6b598161482bdf37fc36521ec050664b35d5756b3c27adb736c95a05fa1beb9eb5ee1843fc73c46199ed95ac1d405dc31843ae75b6526e6ba90ea0bed65e3f7dffda72aa7d5505deecadd41c4f9d43fc25af3980f47fac6fe87bbd7af21dda6cf4e654e0ad3aea5072af310e5b8c03f83de7ddcf68779d366e7a03c837e7bbd6cbaff4d8ee8f0ac47fdeab6397b5cf3ee33d05f65047dee5fd9f6aadc36d0328b5d5dbe7987d98fdf5d814d86d9d14e75af1def2f60d28ab1458398d72f69f431a33c72129f0676b69b421bdd8cf99e528b0ceec43d9fba7547b3a290e4b318fd5c4fe4e8da73beb621cab89ddf23c214b14783fbe5946eb7bd69edf8ec3321458e5f55edb4ffb0cb39cf24f1628f07e1bfa8c439bedb6f9661c9634ef7a6935803d6f4e77bf93f7cefba59fc0ad6fce35728d3bd75c63ed09ec5b87d17aeaa9ded8cfad69006b9ff4f690e71d35e598d6da098c366f1ae2fda5f65c87d766ebd9aabec9dee7f1b6ad1764cd00521b6b8e3df21f6e2bf1b6d9a2bcc9cc41960ca08dd6fa7b75ee546e9fa5bec99c278b1378f5ecbff79d33cf387b4c690ca0a777865dcfcc31f621f637a9e926307f2c35c619f7f97b78a3cd46e5646902add6fa66f9a3e59aff9b6db64c56e5e6252b13b87da8e3dc3e869fd73939a53080a1f4517f4971bc1a84ac17c0d9299d565f1fe658431979365b9437490565b900ee5f431f4e5db9e7587a2b5656448c89c664556eb92c4c208f9fda2e31f7da52796d0be0ec78d73f6dd73ebc73629b2dca9b8c727e907509d421ef9ccb5ec3e92996210e8b355182d6a7d86cf3ee7a69344b160ba0967fd7c9338edc6e4df90a20f795621efa3e7ba873f5382c713db32f154b4da525705eaeb3b6b48719cbe9ff59ff5e6e5ada2cc9aadc8864550271edf5534f29d794c09ba9a69e471bfeeec3986b5501c4b462cd23be21f6185f4c6f924e02fb8f14638c7bbfbe57fdcfceb6589912319b6d7ab1d9a4bcc9e965ca3d599240bd270e710e37ef3494ba9e8e047eebf9bf35fead79d421c561a9257743eb60e24cb393accacd481624d0e7dc75fc33865de71e670a60583faf21def65789778e8f403b25e7d7461fd2a8a7b6369bcd966f32eda27530794e9623704ebb2ff53a879dd77bb7cd76bdd86cfa26af977927ab11c837aff1df89e54501dc5186bcff4c7f9fd65a5f667199ac13403c3faf33621ce61a7fb8f14d8ec96204d21fe6905f7da5945277dd29cb04b047cd33cf36e6d87ff8afcd56e54d9eca5a04e2792f96f6ff1f739c7e36712226446c4c2c88581325552dab0490f63c3f9753ce1e6ff75211f83dc578e22879d5b1d698080cf58c7b5bf96fdcdbe3ef8fd86c369bbe45c9d393acca2d6b50160920fef54bea77c41aff58250e4b9e5996bc33b39e9a8fac11405ce9cddc6a3f77bc5ff728b334c842f469ed3ff47d474e239697b244002dedf87bdb7bf6d87b3fabe59da5a199d943e0f63c779ba9beb8d638a921d0eb70f71c3bb631737cfbf27357e27abb49c5f5765a5deb4d215985408f6fa677c75b67d4f8731c96ba30a7c5ca8a88a5ad95d96c3739e54de617b2420043bab795bdee7f75aef9da6c379b2d4a37598440cd630ebfec7fef7c35d6544cd620905f7d6f97ded71bf6782f0860d6fac7faedd5767bbdb52030f49fc769b7e431cb2bc34020ef78c659abbf3863aeb3cc640102ffa776df8eebafd9729b6798ac3f6038edcdd2cfaf73d73b679e1f30cb3dbb953e6b7d3b0eeb0720efe1be955e2ce5cf33bc1e80b3661ef25af5e5f35afb7158cab5ac3ee0ef566f193996dd8732731c96b4812c3e20b63d5e6a4369679869ff382c230593b5070c6d8cb9cbf0dfcc7dd41887a59cbaac0ec01946abb3ad974e6a2d0720f5dedbf9f7a5da5f6b270e4b3b79597ac04eabee7b87b3eb1cb79f382c7b3a5d1e5066bd2fff75e25df7cd1587653ecbc203ca3f779ff1d2ac63d77ce2b0d468591b80f5f39a739474f3f87fae5a34006597bcc6ce43da738ef9f3ee96ac0cc05effe575ef9afb8d39e3bfe3e9705856592597ac3b20bdbfdbfa27adfc86e1cc76402e63b63e6e9dada797460cc05b39b793ff8e6dfdf88775c0ed71d75ae73e25f6315b5bc9aadc90645d00c6cb43ac2dcddbead0df5c248b0ed87faef1ef7e2ffe3f87d702b0caccbbf755d61af7967b0ed8398d1f6bdd6bb4ba6a8dc39266c901750ca39c3487de86b4f61087653621ab02507a1af1cd35dc3886fa4e6b49c8a200dcfaf63fc32923e7fce78cc3bbff717d8fd96c6311d75d2f6dcb55d60420dd31dc61d86bad5b661bb3e280e1a4f7e36f6d28659e75c2b173c6aeedaf5bd7ac3760b777df6d370ffd8cda4f09c048770c69f7b26e8ff58d5156c97203ca18ca4f71965a7fed71c76179ed3462b3899529b1d924def5d2b2da80734fdf7778a9d55fffaa71589e9ded5e7344a6cc620376c979c65647dfe90e2dcde9d0d0749dca6e76f6e49f716e4666b3d96cb74a7977596b4039c33933ed9a6b6d73fbacc9f73ab2cc3d26ab72a3596ac01dc63bc3cb71957bfa9971585eb1b22262365bffde66b3dd6e324290150138afcc3bfb2fe3f699f7be166a04c7db4670bc8d0345c88200f4da637d73975b6eb9b7c561898dd86cdcc9989811b131b12762654ac47cee73e95bc837db95d9d06ebfb7a724ab72cbd2939506acb2e7f863ff9ffbbb79c56169b3f5ef65ed27c1f1b6913131214396d86cdcdfc4ca9488dd7266b734ddcee32b77bd349aa542169aae33917506acf2ff8da7a59c6689678d334e49c9aadc70590f80b6fbcfb5e79a4a4c33ce382c6f3a9fb164990143ab338fe1977873cfefc56179659855069cd4676cab0d6ba5f8ea89c3f26bf17ff7d1ecd49101abec91f34f7b687bb6939feddfe3ddb89ca9712bc5ca8ae8c6b4e4ccf4fc5e97ab7f0cb827ae93de6db7ed3cf28ec3d20b975bb8ffd9ad4ab1b222519284fb2b1913eba92db1d9769fcb6ea385dfc9f73a3223363bad945a96c48072c72f43aabbcfd46235dead536973bab3319b2d8ad8985812b1322562365bda46b3d96cb6abc9aadcb2de38005eeb7f94dd5a2f732831c56179ebed74bc9b9dbd9d8e5785340076ef23e5df661a52ebf9350b03de1ff628b9c59a8795569c9fa0e976446c369bedef74174d2d67b6064659b3fe9a5e3a759e5e83f94676ff8b4e090360c069238f7bf64ce5fd9ecf7abf80da8716e31d7a8a73e4d4e3b0fcf27374f79fec7a4fa4c4bb1e8f6a2f60acd547dca5a49e7e2ff92df7cfb05c4bd3752be6ad9a589918b76a627a7e3530ebfc39beda779ce5ec9f1ae981d3fa5abfef94cb3aa9be1b478407ea18b1b69447bb778d3f04e38f88952911fb5a72db89cdf6b5e4f6ce66e3a5e92426ab72f33b10675c7fb8e3e578d3ff6f5aee7a3cdb05ac3986e1df7c731f6edebdd5380dec9cf7aee30ef3c69beb50ee7a3caa03c398fbde386f5ce30f7b60fe4d8b1afffe76a5585911b1ddc64d1ede6d5caf4f72601871c8bd949f6ea9fdc63d1e8806fedd7518390ea5d53f94f54ca7e395accacdc81988b19ed4738e379e5a668cc3b25eb5dbe7ed765a95950ba8f5c758633effceb46a9ca74453cbd1db1670cbfcadd5d163ebf1b43d9e99126d06da9e3ded3fc6ebb5ce37feb334b5b298000eac13eb4ff18fd176abafd502d27ab99efaf7f9edac928620d6daca30fb9aa7cdd2d20f5aeca5d4b55ecc79ae3434f36088abe661e7d44f297fc6bf97b67d10bf9bd86cf99255b969e9608865fe1b6f59398ddd3e9192b7fbb98716f6e0e0dd917add7dc573f21d5a1c9639eca9695eafe75d8f47e9067bd43fc63d79fd71f7bd7158de220d92059435668a6de7ffe249c38ac3f236e7d9d9ef55df40aa6795feeb1bc6196acb2f5995db1506c03e7b28399d5ae718edfe36dbd9d9eff19255b951c102ee18fe5f6fc51ff7fee59f40ae80f67e7b3ffde1bfd3765ee3152b72da40eca3ee7bc63ba7e633d4bb0a983f0e69f8a3f454e27d6f18339e9a589912319b4db7fb6172ba9ccd86a696c398acca6d0b15f06a8dadaed6cb3086796a5e103d650a9825d674767ea99737d659ab14f06f3fb9f73d6b9ee78f928813b12251c08ebba5527a3b7b0ff7af3a012860dc596ade7bf7f86e8c2b0e4bbfd3a8ad0cf49dc6308637c4f14b4eb9cffd2ae40928c35087d8efa837d73b8c382c271127a0fd1fe76a35ffd5d2f06cefb4fc9d36e5eef788e81e5a48f302a0ad7a76cefbedded6293f0ecb7ad56e3db4103701b7b51af34ee9c43c4b4d71583201bdec36ff3c3de696774e7158e6fed9ed4e6b8790813ebc7aca5de3bcde73bc71587ab3b55c109b6d2db7cb2e25ab720397dcbe94803ddc11dfeabdfed1e6687158fe9ed3e9df734c72446ee6a5e96812f0e32e75e5397bbffd9e53462420c5f3f73d338f35fe9b379d47c07b2f0dc36e33a53e7eebbb596ff778534a23208e9586774f5aa3acda863a1701a3b43647aa431d869e5b8cc3d2eb7810017dc7754fbc69d67663fbbd0e0467d83df55a867c6b9b6b947108e8ab9eb6632b7118770e330e4b3ac7403ef9ceded73a75d83db5534a2160f82de69ac61ae7cc315e1c96364710b0df9e6dd86bc69bc6905f1c9669ba9d8f1a089867b8a3f7b1d31cf61f3f0ecbb33434b39bffbb8de365891500719d389495feb8adce71ea7a7326f0039c12d76cf38f9ef750da8cc3b2b7d3f14d800f70fab0734aefbc9ddab8258e87e5ed0156bd43bb31f6f1d66be7c661f973bab37ecb7d2fffa643d3edd2e4b464556e3c1200436c67f69efaaf436e7dc56199ff4e37b6db51f8acf29255b9611ee0ed337b9ee7e7fbea4b6b18ea6e3db3b3b47b42d0017be49ef68ca38fd76e5ae905212c0065ec97db1cb5ccb45f1dabb420c41cd0d6d06bcd77bf3a7bde6d083960f87996f2733aa5fd32f6101580d3c65d7bfcbc575a299514806197d7ebdebdeeb5df9bf104600c3da53d8619dfcce5c721e280327a9e379d9afbaa779e70c0c8b38ed2f39eabd4364b2aa79c106fc088fdbd7c8756f26c77a4212400398f5852ddc35babf5219a1a8fabf1b095bc2521dc803bfb70cf6cfbb679d22ba36c03ce6e37d697c71b62dd2ba541846003ca8d69a5fde3ffad8e91af01799d79e249f1e53bac3e875003e6c863973bf37df38f38cc858800cc39e72969d41b4300661fcea9c3ca634f036a5d39af38ff79edcf94864003ca4b7d8c61b8a5c5da5aaf25c419d06acb69ae1573bff395943609f100a8270ffbb53e8cb7cf2b3b3503d2db431f6bc5d16f1b5e39439401eda574d61dea70ceeacfd4d06ef589cd66b3a1e98a7577e454562db795b040faad0cefefb76f8f3baeaf404eb7bf78721ef23f2fa75d4180f46a4ff796d8e2197f8c4080be7a2bb1d5fbeb9d79f63f80f877abb9949fde6ce7b4bdafe5f67e114a5dae408e37eedcfb4bfff67efef01665970f608f52fb3bc330631cce1de1f1ba5a81fb471c711875bc95c630c46159a54d4bce4c6c6cb7446c4c4cac4c49daf6fbf6aaab07107349fd0d6fa621bd7f7b1c965f6e3c33b4dbffe1ff44c4c6c4785eccf6ff44b4e4ccfe0ff1a52e5660d7d7ee8f7bcd57fb3933c575f100529e6bf69367cfb7ad7dfa9c9a6e775be3b74a7b663c4f79e35559a56b15586ff775e2edeff7da4eb9037833c576e78f7f58b3febb76e900fe6c6f0eedbd32da7de9c46199b677526c3609ba54813c4fff63a843e975e7b5de1cc0b8390e2faef863efb997351528f5ec185f59a9a61e5faf9ba10b07f0d2ab7b9661ff37ce783d0ecb49b3da581325624d94d4d97503e8e3c518672bebde52e38fc372d7e3e5cce8a454ebba5081325b4ebfcd7ee2194ab94f8154c659378e137f1ca9969cd999cf6d23bcff89d86c5fba6c006f28b595316fbeafb71b779902ef8d1f4f4df5cdf167cacb42ba4a81fd631e86d6c62ee9f4b99ff67769536652e09758d7cdfbbc92cb7da348ba4681dcdf3fbf9eb5d330dac8bb4481334a3ae9cebf723975de79ba42811d77d927bf59736ef1e5edb3080ad4735bba37a6918e89edcc76131eaff7793cdb5503183de6dc6fdfe34cebfa04c62bafb7ff7eff7b98e3f667666a9c4e5e972730f65f31f59cdb1e2d0f3526ab72e3d24503a8f1d7bf5aabe5ccdceadabb3a81fdffc83f8f5ce61863e5382c7197ae19409943d92bffe1a657ea9d2ebc51c943eb5370d825034823eff5fb886948f974710277e613eb9ff5c799ff6d7974c600f6ff3df57e775b6fbeb8cf4d60f6a1dfbb56dca797d46ea909a49ffe7a75de36da69a9cc7437b691ceccb1bc5d3080bb4e3eefd421f59263fd0238ebf5164b3c39bf9853ee023873cff6faeebdafbce3df8509dcfd723f7bfd78f3cd43cb40570b20ceb4865bc61f7e1c759e75ba2e8151478abfcd56867b461f65075d2c8031478c378f7fe6d0db1e5700a7ded5667ef9ef5bee79df74590233e7d6cf6cf1973b7fb999dce9aa044acea30eb30f23a51dc7c9a68b12b8c37e6fd4547fde3dc7714cac4b05f0f3febb8c156faaf58fe1241053fd79d86f8e7fff185649e0cfb94a8a67a8af8d32f248e0be7c764ce7c573cb3e272430fed0fb18e9a6f1e36a3b13b13225623d9dcec9c5a02b05505b5a7d945bca89b3f73d3a111b138b0b883551227665d723708632ce18b1ad78877b524760df5aeaedeba7f2eeee7f2330f2f0d770761f3df67a5f1440fd7388e5ec72cedd239d27803bc45887b1636bbbaf76ec16a7589912319b4d6c8c5e485d8cc0cd7518eae9efce36fc56e3b0a4f288964f0625c7c49653bbe574361b9ad998d8eef77465365ba664556e5b1f7499005ed97d0fa9a7bc6e1dc65af1742d027bffd2728a7fb7f37b4a71589600e6ab2dfe35ff6cbfd7d72b0239cf3e625bbdbfbe8717270273eff6f22c6dfe56fbd092006e69e9d691feb06e7a3f1e01e4586afff9b672eb1087181178c33f6db8f7b713c7a8250e4bafe59e2e11409ae3e4f3efad39ff12cb43e0ceda86b9d3f9a70db1c486c0d076e9fd9cf256fb3dc65d85401be6b9afd7f98696863d86006edfefdd52d27a23f63734dbfd2864556e665d844099abf561fff7475d33cf83c03def94da468d3508e0bc357f5f750d27ed7a7e41a09c34dbadc35de3de360c0381b9c7bf7ff731736de74daa750102a5deb8d66af1fd33fcb2e2b0fc5c76af52d0f507ec9e873d72c97db65fea8ac35d7ec0ee73b792535a65ef51e30fc0297fdfd4cbdd77fc3587382cfd9444ba3c006d987597358751febaabed03ea5afde5397a9c438ca7e703f2ffe9cd9256eaadf53dee01f10e6bf65387f986374fde0188639772dfdb3fa5a1b69e03904ba9a9bd52869aceeeaf163da0ad1163cdb59d3de21e2d95ae3c60b521bd55deda3fd7114f3ca0f5b4634c63ef36ebfa2f0ecbbf534b9b726ec0a9ec51cf3bfbbd1a809efb9fb9b5bcd7abbfd40a746500867d5eafb9cf51ca3d69bd03de18cedf75b775f7ccad1d1087a1cc547a2fbdbf5a875d188039ac1e7b1fe7c554f62e715886ba1b8eb78dd488bbea8096ceffff0f73bd3dec3e775d00e6e8b78f35c4ded6ddb7eda2036a8f2d9d196b5ac3f92dd6f9aca5cb02d0f25f437af3cc78734d7dd71cb0ebb0d6fdeb8db34b0ee8fb8d55fbdbe9a7b2d33a93888d89c93d5d15803fc432871a675929951d5300525c67ce5afa1f43bbfbeedfd2361aee9a00945ef7b0eb7ca7e4d9fb108775571cf0cfcdb9f4b6cb90fb1bf5955ebae0807e773f7be5f65b4eb5e4382cab1dd3f506a4f25fd9ed9f54863d873a8b50970420967ae6d0fff8e3be3ffe0a45d7cb1d21ab726bd2e506c47b86fbee906b4e7f9d1a87cfbada8095cb3879c436e790d3b131319bcd66dbfdf07b9bedef2eab2e3620b59bf2ee6bfc335fab23075d6b40fd79d6d5c6d0ea2e3560e414d71ef196745acde9ec8a00d4d2671efe8c73b5be5eaea40b0230cb306b9de9be7e726d2d98df5343cbf2d69506e4d3d7ae31b5b4eb2df1e64dd08506d461f6f27e9efbec7c769d01adffbae28f759c5d0f803ce2bab5ae51c6ecf1b4d96cbbdf33b3d97e373be389e93203da6b77dc72f7fd65d737a42174950169957bcb70eb1d23a5d71ee18a054a1b678ef9dab0c6c83bc66169f3172e5860cf7bfebfeb969c7e3f3bd72b305b7cb59e3a7f6d43196a1c96776c89d898149f53d309d185b923330890479df5a737b43b7fdac17c2b2d1060d84329c35b79c6ded35fb97e006558a70ebdd5547b3a3dcfba02adccfc4a6dfdb721ee36fb00d21d622bfddf1773e16a056e9cf3f5f36f1fde29f7cde76e3e6716563a86ab07708679e75b6d78ab8e916a5660886f951df7db2bedfa4a2a7900e3979a7bef7daeab406beb9575fa6f3b0e4bb40e2663ae1d40cd69b8bbae57da3c733867d401d412ff48a3e69deed96b9e697bc995691b2d4aaa0aa4fb87b66fcba5ed9edb9a03c8a7ddd45bcaffb7b8e74f538199fb5de9a7716ec9edac1307b0ff1de5ecdd57cbb59f5493e1ba01e458c69c31a65ed7aaebc561f9773bedefd2b444eb537eac5e26132e5460d4d58772635b63c736aca74019ff9cfcde9837fdb8471bc069abcebf664ef7f5b55b5320c5325a9db9b47bf3eba917ae5260b6b27ffba90d6d8de1d7379dcfa4404ec3edafe45ae398ffefc3350adc3b4e8bebfe91622e29c66189458135f788b3dff2cb3937effff0d6a516ae5060be54e39d6dfc3bb45b6e1c96bb9fcb7db52e663928b89e99149bcd66a3800b14e82f9f3af36eff0c77d5bc0690733f6db65fc6f9c3de3f0ee34b56e5c6b93e8176f210f36827df576f2b69f504f6daf58dbf5adbe3cf7b7aa101e451da18fb9cfcd2f0d32c88ab1358718ebae66f270ea35ddbf5d6766533805deba8c3aaeb8e3bc62ebf0b78b6cd7a6968199355b96de19201d494565d7b9491faee3de704e24d39b6d9f39e65b43fc600fef863e756eea97fa421de044ebe437d7fe6dfd24b2ffe5a348121ded4dbaaa595fae650670269d6f8d2f97518d27d430c03286728e9b63ffcd4e7fe290ecb5bb52f80b4ff383dbd99fbffeff52070b900521deb9f7577ac37e6d5e2b08c920b13287fe633efda238fbf52df02a871bc31fc31ef2c6fc7512ded12f837aed5efaa6bde948695059086fceadca30e2bdefccf15c0d9bd0d279661b82def35e3b0bc80cb12d835f755ceaa63ff73cf5b09acd1ee8ca9e65872510263ddde4b1ca3e49eeeab82a5767aad2fe6fecb49e0bc59f258b5de5cda904a0239fe33c4f286df62196716ae48e0ccba6b1e6adcfbe73d6a1c96bc9f19e08204e67fafbefb87f2ca8dfd4d018c6118659e3dfbfe08bc618cd35ffd7ff521b7d3117823bd37f43ef454869cee46a0e731a4d2fa89436ef70e690a5c28803f943d7a1f6a2f3ddf1be3b004a77cc2750258af8ed7e71eb5b7dcdf908b1118eeca75b4586b6ae7dc12e3e13201e458676fedb57c7beae55c04debe370ee3e5bafb3827beaded7a519600763fefcffe768a378f619d87b81481d8da8f3da691e6d05ab48bd3361a4d045acdb7b5947eeca70fd5f4d83fe3dbcbeef3e45ceb5a187091007eaf69f8fdb6725fa9b19e806b04b0efccf3fefbf24bbff6566a44a0a7a1ef93e2183b2ea79613e01201dcbfd61e2b8eb46f1c379a9c693bcab48d466f5c87c03094747bba7fd75ad63f71589e71b3aee6ffaed77f9acd36a9d49ac36508a47787fd861dc71feebe290ecbfc7bbba7b6e4e23043e12a04fa1be64b31f67cde505bcb1502a87db8c38f63f831b77df31c215086e10df3f43c4a1c961ad7e11a0466ad635839af9c7e9fa50401ccd4eb5d43ddefedd8dfaca53dc32508ec1d87f5631b5a8c75b63ff6b8028192e6bb63cf386359f34de76f182e4060a67d622f3fb579ea697d4fce3fa0debb63bcedff7e62ec3d0ecb28b1ceec96c6b364556e92cb0f78e3d4d3febbe39fbefb8dc392cacaf50158e5bcf66e29b90e3bc63f8b9515e9fd275c1e80b77f2cafec7de3acc3b0e3b0bce576ef03fa7875b8759e3d5f395c7cc01ccae9a7fda1bce1d631eed478b92fe5e4da03e63bf18cf852c9f9ace18f8bb83a00a5a73ce2f865c5764f4d75242e0e401ecab06bbf73dd7ac0886fee928621e634721fe6016bd6f3d71ebbff318638e2012bdd39ceb0d258a7e6b2ca465c1b803edcfa639bbbccd547293b7169005a4b7f28f1b7219fffeb9801883be5f25becfbd6d5464e51e0ba03de5bbfbf5756eb23be38d65989cb0e9871fc5a4ffc7788e3c53343e2c200d4347e2f73e53f679a6bb5d211571d30cfcab5bd38d689af0d2dc5c47501c8e7b4d8f63affb7d487616ecd5f4a07fc3d671df670f6d8abaf9fcb0290fe9a71be78e3ca3507dc21af55fa3eafa45a5ecf2507f4f3fad0e6ffbfce3b6ecd5501a82bb5218f38df6d73fc128765de715100fe29b7a6a1af79566dbbc76169a5055c1380b17a1ba7b4be67ee25f559b8e28078f6693bf65cc61c7948d1b8e08093db5c7196347e89a3bcb10dd71b506f4b7dd778e2b9fb0e773de392008c38dcbdee49bbb47a66303a21369bff6074fce21c971b7066cd37cd7f572fe3ff1c87fd919a65e06a03c68bebdd568713ffd077cdc506fc7a66b9e9cf7c77cdb75fe3b73973506c36af876b0d18c3a939fd7d56eaa30e310e4b6c854b0d88a3ad9ce328ebd55c622cff70450066ec678c12476c67b7d7e2b0cc99accaad012e08c04c75e87de4395f8eedbc5c6940fba58c595e7dedb5fa865c684069a7e6347389fda5f6c738b9ce80787feae7fe7846ad01d703a0f6fbf7acb3a6f4f33c7dad6fb8cc80b2c76ab1bce19d91e7b0522f18709501770fad951cdf5be9fef5521a0bb45e7e2d6fec1b537a2da5141658738c21afb67aa92bce7acead57208edfcec87938ebf4328300b9d43f7bfb7fac5d5e7e810067a5faea7cbbc5b97ea97f00f1dcffd67f71ed97d26a5d81da761f71dfb85fd9e9c43e80d7f2f9f1af31624c2ffd5badc0fff1f5d86a5f79b438c45b3d80da6adb37e6fb5b2f71dd94b20263cf21c7fa62ce6fb695f20062fbf3df5f7acee3c7f66ead023fddd5eb1a7a4ee9fc916bb0b503986bced44bfd6b6823b65a0770caac7d96596a8da9df7a4b15286f9fdcd2bea5f63fbc340730de7aa5ec59723ef3d63d15d8a3d53be75b71f8ffa694e200fa28e50db5bf7fcab9f1b7d96eb2ca382d6ddd00cebb3f8e52dac9afa77e6fa102710ee58e35f63df9e73d3c05d67df90d69ae3f7e297d9f6fb66c0079bd33ec998698873d46bec1962930bc955aaaefce3dca5b6929505e7cf9ac786eafc3106752a08c73536bb9f4726a2ff12870fe3879dcf1567eb5efdf6613057e8d79cd92eaf0ee7d750e054a8cff8f18c7f83fb67d0b14f8b1bf5dda1ce9dd7ffe70ab0650f69a318eb4ea1fb3ad590bd9fa04eadce996d257dd71e8a5c5b3e509e4155b7a7b9434ca90eebc450318b5a678d3fdb90d650efd934ea0f59cdf1abdf53bd0d60c20bd3fe4b5e2ab67fe3f6719c09bbdfc1d772c69a7dcef425b9cc0fa31be9d577d3bf661cd60becf8d5179935342da8a01ac98f2ca6dbc61edb1ff58d6fb4fda6c6d02fbaddfd6905a6e7da86b68a7a22d4de0a7fd875b5f9cf7dd714bd9c1562690475f2fcedcebfba7ef130610535de5c4dcef3ba5fe98cead17c05ff7d431777963bd164b17c0d8e7ccf252ca63e7e13cd361023ffe59ea8dffec3af21b5b0027ae5752fdbbfdddf7eb2f81587bce29bf92879f46eac1160b60cf98cf19766b759edc731c96f583ad15c0e875a45a6fdb71b6b9dadbecb365099c3646af656869bd3ec480b62a813bfcb7ce1effcdbcfa7eff6c5102b1dc3ea4db4e5af50f6ff68b1633de945b2a80b45abfe9ccd4526b433db726817dc72aeb0f7fa86f48c3b92509fcdad3bd339d1ecf4aebc461a91b6d4502e3b77d73fe6db53ceb1fe2b0bc92d11624f0d71a86b64b1ba7f456ce475b2980384b9f7795f9ef90e28b71586629565684f7055714b61e81f45f99e5d73be456fb786fbdaf05cbde2f22c1962330fb1a650c71e43e6aee7523b072eef9e4b7f22a5656444ccb1fb65000adfe725f8d31b7515b3e4f00f79c3ab4f74b1ce2f0162310cfabb9e43bd6fa6f9e7bcb047077eea50ff79d537e19caad4520bfdaf66fb1c671ab0450cb105f2c7bc696fa7b2dcedebea508e43ff67dedce75f76835c7e1bceba581d94a04ea1f63d4e1c514532faf4e5b2b5b0353c11609e0df736b9929f7a194b54f9bcd66b3d9a4c47ba7b631085b23809b6a9df997f97abcc3d86d73b6108177662fadf672778be7b422807577da77ad3ed7e9b70f0f81fa725a2dd6976f7ead5660cb10d8e9bc925f99f1f7564a9e36b25508c4755fea43dc7dfefefa8fa558599121b7ddb7356c8500dafff9bd58ff3d3ded7ce3b0bcf5ae142b5322f6bdf44aa71c138ba0581325629fb60881b3f6d0fbb873cd36fe2c8bd89d4e0f02759d39cc17ef304e4eff9d720b04104badc3da2de65976cda720b0523fedf651c61a330eb70281976e3dfffdbbce59a95443cb3db5253922760b1028bbdc31a4da531f8618cd0cc7b3798975eb0f88e7f43a721e72bf35bd1a87e5df4d69b6776570b6fc80d977bae7ae5d723fffd51f8074e24bbdcdf76ed9ff0ed77a369bcd76e9dcb3e50118f5fc21b5decffa3fd5b677e36a3c3cc5ca8a1ce903625fe5ccf747eec3cab1c46139256f8b0f48c39ef1ccfbcf6ff38d5b7bc030deacbdf4b65719ee98d5d23a00f1df7fe690ce5e359677e3f00dcf2d0e40eba5a77c77ee750c37f5552d2d7784b7531be3fdde9a104d56e5b6b6a507a4985a497bf77fe6cf79b6d9764cd6f69916b330a7eb37b40ec666cbe978574adaca035e3e65b6a1ddbc66faabdfc203c6beeddee10ce5ae5ce3106f0086da531eda1dd62eadd637a6d9d200c477d228ebfdf5f7c9b7d651ce560660def6d3adabccdd66deb7ee807ff23971f4b35babc39fb7ec809e66d9b3bcd1c61eefdfbadc1606a096d7ce195ebbe9ff31d6ad3a20df5f62cc7bc636a43d8c126c5d00e2bdbd9575d6ffb797986fd10135a531df4967f552eb1cb72c00abc5fffa958fa8a44f8a15692487510cc4400c025088f34a034002f312003028241a0e07e401a14cd9a60d140005526a668c382e138a23c1483492c3308a8220066218846120c420639473cc2a3dffe16c02a38512936881111b37b7fcb4f4dd213a88209f7390eef4ce1c19b7f3775e1c179d1d4e7f93d902bfa9a1d6b083ce98bdb95d5091a06d05503e067ab6269a3ee85cbdcc6cbafd9291d3c99ec99c45ee3175937e24bfb0ed6d27560c36233cd54484d38c551fd95e429196ad8474871e59397afe01493801d12514dff6fd96164cdefd8cc491b003526b3571ed877185d860322156fe295b1ea2fa7d1c11ac2caa0a3bd5e0785db3165fa78f413108b4676aaa6147792289a8d81e81d7fe866fc0fa887a8c876bd090066b5e68739169b7620dd933da5ce0efeaa5308599da000cc5f4a7cae00c00e303e7ae6cf1611379c1d38a08e7e9cf8f61de53f4b4f13b2b43fa32666577a816a7f3f091a40aecfc200e44811579a6fe241bd8f1d4a74156757ac87a176b506b1d173e3740935fa54873c4eb7d3c5e606722cd126e70311efd94bd1dcbd9ea1b094962023321a297865242d63c164d4df183cf8326f74cc277330cc301cc43a9671f17c3b4fe882cf5563fe85762be246ea26233186fd2c530191dd5a89bcb88d8894cd37f0c9776a8f5c3ca21ff5f674b0950ec13e41abfe86befc4857bb24d9cabd47a8c527ef7afcb39abb1abc7464f54f0437e72894d3779429ef8813cbb750eedb39d8c026717b28b15d5bb844a87001e3887c0f5a63e77b4bdbe8dcf343084661894aebed3be9e181491841136d5b878b846907201451880f2f84587ac84f5f3c960b3bce8c7263b2fc314a85cb60166ffe8ac6a2bb4e91ec43edfb00dc9056648f5fbb8fe44f44a0b1c7305cebb1c38da0e8418c0f18708599b3e807da807b208d1b3ac4ecf28a4df05de22a05a6bb840ede1ba7426624cc755f4093510a60124a5b1b9588ba32c11026d79c484db9304f41a8d36214b84e442ffb71a82b139f8722e0485639916a743efa89e3ef5511834f7d7bcadb01c61681e7866cad8d89ceb08449979793d1ae8e83aaff2a8f75308a94eb1335699f4de438131d4b71ad9701519d6c260ad63eb7be19fc7e570f81b8c00782cb4769487bbd6c8c8be5603fe6862f908c81c0c81f2588df58f98c59bf7425f52e0e9ac8619a929a70962ec7cc6a367eedf8cdd5dd023809ec2cd051d32d1e95d7036dd04a9edd1003da1437400e6426a985e0da96f12fc51d9e0d0540e5e74871839273d6285846b85be77091dae77a07db17c48db5245bd1e4817ef19f83250a111abdcd25e9938ea0d3ab8a1f0424c88da551916ca902a3195e2bf1eaf22f6da64dd66687002612fbf55a9c4564e73eeacb1c2309f499481d98bf05c3875f18ec10bd8376db736bddf39aaa4c99941495c53b53fea46039ee49a2068f85473dfc63001b5a20bfb9d7654ce8b7d0d42a00b0595819b107454f12ddcce4c3ed5875e880ba68473e9fa50eb8b845c0b5fe8c9c08112a5fc2c1f00698d0c7c92dac89bb7b781adda8c74320b7f0540994f6b1052cb0baf015c758d82951dba7787b87cb39aa5f3a27ba107bb258df7af9b20c8f3e3dc926387fc1fe5765b3668fd043409e6589b0a12217cb8a004336da411f9ae4cc4462ea4b992229e81e148e310b64835f75851ecbdb7ebe28dc79b2d5af63ff75681ec0ec8e14f702479558e4c68e245bee263aab638adbe9c863e77f0bdb60ad1cbc3a763e84fa1cd45a10988809b0c8c66ba251732021b0a044c3ea69164b3b8086fedfa36f2cd05b66e7cab32df983e81492164e36574731c1d4f65a54f1e61bbe7524fd6745a8af245a877abb50f5f946a68f7bc901899b986d9e029820f0f1000c212376908b0da2041d13faa928df0e56a350000f6c80b1f44ed89c1737c92b10086323541fa5bf32c3add154637e929761fe2147ba807912ac7a46d090e4356e8911aea3da0cb5150db2308e04b82f1507486388c21cc63eb2c2383b41ce70ac801b2940972066d045bac82e943e6ad460f9733ad8a0f7f935e04d06f358a6d5211865002e14543602f82871304ac14b0775e081802dc2e039ae980aaaa5b897c1640f987c058ddea6ae0a1418d20ad2906c1dfd17d87f85ddd8a6ca08451d30263ff42b1250363647e6122219da2b428f6251ef598efbfa06fc1532efa184b2b6076f708989e0da05da5828cf6d04558f0c46b36d3145031255ba7c18e5e2d5ecfa508f3d65ad6afc6d4c9957df15ed1d1c92d400bd9d082f684de8025be148ec2cd686effa489ea9ed60265a9cbd71a526441b20e7cd4226006ea05f53219a26c83d3d7d6a460f7852d29d14c948058cda96cd67a10dc63faa6bd05babda1bb7de5c1cdb6168886d96d1588f0d8d1c0a9394842a4e3dffa0dfa8d733f08a7c985a024fa10652a0d64726bb9092142a58b2ce41b80be898ca9391acd5f520e2a018fa7264342ed6b23ed23c41a83aa887766fcac8fcfc40371b4728c3595cb7609d66c310f86e31146437366ddd81738c4c61faf4531a455aa7701fcab1cc25ac1e518759ca6487f6abfd0fc24379a87bf9be5d8613b382a823fe583a06777dd59f28e8d6077b627330881ceaeadbc0e56554e9c0be77ae18cb3f888e0c38526f237c623ef3f68efd22ffe4f58b0134b49969acee5ed3160a22f251357e47886b2e5fdd70d0836d9262c7b6a145575066d314bf4807562e0385043f5bae9e5a4a94b3bb3025ba682dd1916759a6bfff6c09dda3231b39a3c4a00016e650620aba2f667aa150902408cf2b77114e2591e89c755a4f4b15aca0edc2fb034ae011258ce0fd229ae8b5bff3ca5cdd240de9fb72d8c94fc4612b142882d8da827785a2aa63e386a364339fca8af3e9fd4b2978ac84218cf2ac6189ce81d734799e12c44d10c8633204c5cc7bb25af48323ab4b03bdc57cf27251a8a1c402581f7b4cdc852da25321a2dd23754cb348ead11bee35bd0b20b92669744c24a4880868a1d685a0b6ee55b826991fae5d2dcb44f647e3ba293ce198d88d9e8380519e9953b4a5dc44d30b60480466c4f151dcef1a1dd4649c43db26a0c28ca0b07aced17f153fa42634e3ddf58ce9229531b4beff5af26118818003469f5d92b0e27b2b9fb14d3cf70adf9db8a7a9d272be30e64dd9d82bc68c877a9920185bd00ea8c5b2dceaecd90e4d8f2c13567e1b09fcf61056db70553d8da10ee9b789bbcf88edec1dac22b34571e49223f74929670819382be785c2dd8db1f2706f92a1239d0d8a934bb08c4b580544248583ad8222fd81c3cf55e5e6bed008d5a58901ae854f637039479dfef914b3f780ee3e3c9c59a03d6fa186247b017b9c44d6f52cb8dbe6a22b82b166673aadb562ebb647b2a6dbbcf4c47b400ccd6f1a4f29aeb7cf5e5ff5a43253613d9748b5882dce2c1cae146dbd5b995f418af0428d61d73b71a0747a5c818222d2d20cc959c23bb0d99cee78f71b1a5a0a5e294fec3ea9c245ec675d5fa8dc33fe842c462990f435f94ed1b650cf053d3c84bc1ee80a2665e038dfb4996e9983207b9c8cb910ad7916e0815b76c6b57954eb30b3aeca26bf5a8d07450c0abee0bb7f880a7b1db86734664c7951086be0d7705dad946eb445b97567e71f05ff825d9ca1089d492395a5fb6d2a5671004798b65b90111f0c0987aa6a785f301321df7e260e269aefe4addc6bb9baee778f5f2a03750f9cd1e74e96e7cfd074e10c9b925740d9166f3af521df56471e5b7975df248e80a7c5fd78630eb8e007b9fb140f04735c348564c73c566c10160c49d1652bd351e23c95b1aa43c40615f6c7a8b6eb840004985a8665ee498c4aa46005fb0ab200845c1869a66cc514cf1eb18462ef7683ffe1382b37873cec9388792f2089f7a472436184a2ce9fb8666c4638963955c7846e54e10af89526c526766743fb39597ccef2a7c8b06083bb6656f690bee466ef3f6862178ba5bc51990b442f820c405cadb1b7839db3c047a23ba9578cc9ed09bbfc84618a6cddc7234fc0d8b04a0c10e1ec36d31b907f5f2e1dd1f7089b3a46e4ebe8f4a0aef2ffa5e0419071eb6e3bbda0c28ba853ed26ad3aa3152059cf364776877a7afd3f63ead878861ed2c9b2d69cb209e691593f709a00230a48f0bf84a85e80537e45f58e8ba0b1461939110c06cdf4a5f0a1d6215720edb944ec2ce8eac6a0720ef7a49ed894ce89c17e05fa07dd0fd455ee5c236df04ed6178ba5d50afaa689ce8bb913eec006500b7eef5ccbd4c6dc65d5b3b28d643bb0d91865c19b50573cec1d9c63c6c23f364104f3467c57fa1c204d18859f4e4e8859dff78d6035b99c99f05bfe6e17d48e85304929c242657321a9c51103e71918e8b0d04bd61fc0421bda41024cf3c8904303a209cddb9f27cf2b7ac6fd7f576abfcdd9fb53f532a020c0b2ca846e1245564e3d3e10cb2a7a31c3f3b1c8b16d1cacf64400c93f2817797c167ff49e1be8cee3ab6492f23aedc0929f7d5c1887f6e1447b5ba7831818534b560beb429014fa765860f8a06bc9163f555f45e85f45fcd90d74c0b123ec807ea040d3f72ee540b401c298c60f738b41bcfbd2be507891b77282c67bd2f4b9b7e8b0645b6e99f194634c065c6e328deeceb5ea8f3c94e3c565d6dfacec5c392c221d9e1ecb84bed747aa35b0a30d7257a9c198934c3246bc5c1053b41ef6b59a2e6be6e8d61b891c8d70d553db2e3330801b8598475f2e2f35eee3e3a43b8576438b2417103973c6193e66242714874e59ba20d642aa76860cf29a4e6d32e7f06a4fe0281cd73993e0e64c5bcd4511309838c49979930ba0272410060d9d245ffffeca101276a940e7896829134c4fbb6659cace75877cf4e2055b6e5a7aca6e0cba536f403e4cc9818ccb8a7e2f1fddbe3a39da0a5176592ea581170041841b6e54f4f2785df9e553c0332ca25161d93de014621a7181d19898047d20d56899264922236a976e40b853c17ea9034da186311de0555e4c63869406c021565da68abfbbe68a93b09ed29984f4441b238a529cc859b523a41773ecc770a513a79b4c0845e0077f8f427d15c91ddee935bf5cd93316e014028caf6b625c6c3b33787b26e3e71ed57685a32e241208812b21859e643af149677f66c1846f00e9a112da1f3b1008981dafaecefd73bed40b95703022813ddfcf8faf325aa0d8950a14efe0a3083baeb2eea15a97beee548ecb8811d8383608a1bee9eb52f746574ac7e5939e2db87574ef2f8cee35459ed2ba4394efe979cf5710eb42e4ec5a79c6003231464ece0a102702e9da079a6a64874454ee64d1b2d5a644982d9109eec2e23bbb42861ba641fa80af82cc3f4f6e29d7f908a1f589b01a1dd17987ec25f88c814963e6a8599ad31f251789d8daad0da7978a83e7e195d95d54db67933ad375099ee503fe95a822e3c6ac5a512ae9566bd546caa38fdc3ff80d3df761df2a41bc39765212b361dbff2f9642aae57c10dcc5f90b472aaaacb86003c35577a5ce8e10eacc2b89795993fa80e7f3bbd922ead505772d1b0fb0e8d603f7079353280d4cc0864793782c18c6d2ab6482c2151f8985e54c034e718f8ceed1637ad0f3a216957dc710702ec86e163fcd04242b12b5b2bea484f810ab03d85964e814ffdc303961d017e318b6677d756de03a92fa808bc95c73bd6f94d29fd084b8b6e80074dc6d49d6107efedcf51e6c2392486d7baca615ad79485bbc78862d2b0371a7ffbe6fdb85eb8a1ef422fd602a6950f23161a37b7ed4a6637ff2a022da9dee355cbe5100d88324eafd13e1305c3c16609a4bc9390ae1026ba8f2e78ce4871ce5306deca2d21c58f9d9b3c199696e873b62c8479880304dc682bb07eebc23ff6707a7b32283c663495a224d6178d9e79dae81e807105bac7fcd3d24080d23cc229da73e0406c9e38c9198e77a2a6a3c7e1f6d9e105ca05787e617134e33a279ba1cf19088b2f76b619fae04bb8601c5892f4211bae01f393ed6f84d208d036b5518636ee14c6e4c34c1361a60344b46e1db54b49dd3d282f75484b730fb31cba78bc2b0e1c1b6e7d3f7aa9a87904b86903003a96ab88edd5423b574092cabb196ba42952e66dd6675549334b188bff621b0b69bde11eda9dae03ee9101fa12764af2e0ed64340403f8d899f0cb327f4209c666e238d4598c64b055665808aacb6dc1685e78e7c190f5a60b7a65c4c6c3f191eebdfeb97bfcd46d6fd6e356c36cd4b9f1f8acb75b10a5fbc63c722b7767707ff419f2651704f71a2e35a05ece6c5b99bad615596045e692e3767983ca47c65cceca5b179b414fa8e91505c75b659648dbb8f84ac6db3371721ee9c7491d9d666fe265f6697c31bd89bdff5f4552abf2fcaef787e1258d1aa0b29931268f1048d58ebd416f984115bdee7d166c78034d8fedc71456bc4ab54877ef2b848b8921e8974980a9319821710f18333c61fbf75bc8eb1d7a4cd38a073aadcdfcb467e1562f0bc246acd9bcf8d38d77ce4b90214f0d175aee17c77911626c611061f675aa82f9d7615f35cb5c79f150aacf3e0d39b40ffb90f5a9cb9d7e537676f388c0dc7a7769a71563d49e3b4beb962ecbcdcdc57d13a9525e9138cf5e90d47f3ca40637ded34b770b3cd02600e8ddc12d265b5be7e88022707288769cc82638b4463cb272eb696d1c494349502deddbaac4b41defdf312c3f3e1241f98976c0c4799b9a1049ffe8415b90ec81c89ff8e79f4a0fa94e31b5b23c729b02d33718c880088d82c3882e5028eeb06e4251b987c241f15ffb7b031871455061c35028702982112308899bf6e5be7f01249a93b507564e156bfcca36b4a779596cc9e993556f47894e892d642b064a7257ec93fee3a7cf66461b381b9ae93fb17b91bc6bf4966c90b7ec58da6f07b9326973011003f61a36e69991d81e1f872dcef41dd3b99400e6018d92817727e6d304bbc055022e5b691f5aa5671bf04b838903e30501f1128415609cba134e1f39de92284a83348e30e6718c8ec27cb2fab661967a15d222fc43bd792c58e8ec2c8b2a108f811355f4efb89b902a7f26556ef7fdf6a37bee1d0b0955051b851ba0e60c1a3c73840c303a1d121bb49c4be716ffa753b93d0767d1edcd72e64e4741d656691d310ac0104114046e4338b8fcfe269040e706a54a5256b503dee830524ca9c0679a5cd2949e84ffbd1592018c2712def4680a36323ba9c81184c5a5fe23f6f74cec0ebf373e59e770584ee8a847b66735489e2c9ffa7a3f9eaa6976fcc5f38fe02a60dfaa35849578c4c21390f0120d54fe3d6bb1acad93582935a083a8038fe01976de91d31c684ff6e7980922e151dec55f02b8d46185ac471e79abc8d7e0f80ee7946669e12ebe7dca7762486660e5df6ca7d66be3768662e781f80065fdc0bf96fc65da3ebb3496eb810cd1129ec4de265003432848889f35aaa724dcb4d01d86699ab2ec61f1f9c210a00f6f149a91247d0cbea705e13ac8c9962c1d91ab229010d6a61a5674eea1103d53bffce840cb53530192a7080918369702058975089ae11158d629200637023365415105220bf691f25e1b84e290a440c376242e62850d59a48a8101448cbbf3ae210c255daa2351d671acd347f0a3fd89e816e06881eae5a7730570fabf620d0a3d14ec3588e358566e9a5f02bf15e06287167d30da2d97b08b45575c24012bc61e9cf33b4deb06423a8de2869f2ee2a9a56334ad033f9c1771cc7812cf0d85a737a46c7ca8c8b26ac3689d82eb556469f0b9906286788828607e06f9c026e8e39522ecaa5d8c6d9d0a56f4f39c75722b37c85e5e908b108c821d5f80224d3793fd9a5f376f7990e5e4ca10289a5a8166c746d41b0475595ffec9b988c23c90603da86ebd89b2a3ab4d283b5390889bfc1646b2670c6457977f2c76f4d6da1bb3b62ca4b238c19ab1d6feea093c34986ec6774d2a238586df2d3f1b7884dc676113b0dd36fc20e69582e52e1408fd367a14d1270fbf0a600f265b66f9cd00d236c8003f98baf710e0e988b4c23c5462e05f03a9269c72d10dc1239b295c517d2c826027c45633761ba2c5b21800564574cc826605a11ef069fa91ffa810756307a17a70658baf31948c551276d9584bc62c0b635958655d280bab2cecb298b524cdb2319685551a436958e561978fb504ccf231968055228612b0cac42e036ba99159fe3f96a755228612b0cac4be0c8ca0c5a21e2de9b1e5a9efc26ada3835e0a493e804ea7d00ce380374d44146a545416c9d138fa92f979851a97328cf8332a4093ed96c0404aa63ccb39890f5bc161f74906474bc0f571d587d150f087bfe79076842a2ca3c10c6bb3e6ff16062dabc8cffa55f02ac8c706afa21c16f74a6f36260b6653a218d03f3038eca5308c61c4fd4e35d60bf1450fa873af13f61d491bf0236169a8306dfa2ff16ad199aead1d7cb905b4835a1259e2f3117c7a930004e848a8cce908bc284d3c935463cc7ddbdc216250f5ccc8cc10b4064244975c90814c1a51ba1688e72b02c9354b10172dad15f1af12c481aebd2f422dfa3ddff9f344f9b50e3232f1cb5731d99fc3d514b0ee5e3d1236802537ed265ca0c5094f31015768243ade16a2f498c687c5becc1a0105f3e240ed0d2f12103b40e95bea863c6bb6057b2bffe7e6131214c552ffb3290a45e0b8fc94539e1034dc00ceb7ba321f382d091818508cc585ab7b96a17af0179c70d05793607ba4c31e0966bdcb03f2a910f8f1bbdc5b0c748dae6753da78c1bf9a5918ab2d9a52b83574cdf6f532801b4d9ad65b980fe674e74395f931644c8ca46e8fe6a5096e42a3d059b5cd3c3c03bc35c9ea1233592fdccc9f691bb2ee384caf4b635acfa9d872c79dc1967130baf5fd281103f35aa8dfb51aedf1134e126ca0c5d8a17d445ed9e26a75d96f6eb5a39e83919395b9567323a1f7e76e9f6d8407ca8abdd159611d0a579601104969bb09695d94eb818349812261ec83dee22618b27dc2b24c577c7cc7bd296dca1bed0caaf0df309379f0cded6593c91a1c7de93f6dcd423bed1e6366406308b45241ace5352e17bdfcfb3874e28d56fdd778bb89e6c836a88fcb139869c474e4cc30e9d2e3f327446aa85207aec8568faadbc3d49e87c5af00a23d0cebe29797a3852d839ce6d8b36abfc19f2f3d29f0761483fee84f754913c9f19b926e5fe68bfbaa2bbd433578decca5d7e313882be153ef7e5d1207c62938f4f0e2d2435815bc0b529fea152f4ace4bfe69a872541ba7f8af01c829da975c84f8effa56de23401823396516c0bbf0a0a6240aca09f39d15951120a2b9538740bbf3fb3b513f472b8db612670a908de8d2a28313346c6462bf9c8b512d398ab892b766198c42d8b5b620043fea6be9f4c12163b36e1f6ce8953079671287ea1e1187b6b49ee2b8763670ea6f0e581e04e8807c6b8fec21ec815b36558f5969a7cbc5d6f0a23a126e71b6ffcbf7a629647403e60ed84be1a10c327c0f28bfa9b0104643f1e492c27019b39a871184a34949390c544089374fdacd85f8ab83e65874fdaa80eb0121ab4a0a8166eb8391b2e5f9285a7403c4601dd9a0d1d3bd96c0bc47e91429cfdc14cea869ee94fed721179ac5ad97b0b5c8aeef3aeb1b4b18e5cf7d508b41de7a3d27a28feeca5a5c7d3992fdfaaa7140a192e1abe991483e7e7294bf0bec6e5cf4c58223c084fa2797035e2fef4993cba50e85149ab20c8da0951a490b99441886b94be632bc692588583e11e33d22b1a7e97320b31e0e9c879f169909f1d6897ce88fa1701d685cf43e8eb02273e8126570713024fa8c8ce49e37a613f1a255284aa20c99fc21a2cc5a988f587f1c9788185b3156646cf64b1e3593168d844ddc61a4cfe12bfb3df50dfbe38df24726520f2088dc552439a8a1016230c0c92494406e765e8ab71a158c935a19fe7bc8292bcc93150f94c149986c5992c527ab72899a505cd1ffe2e273d14a27ebda1109ee7876bd1c416b816f8ce84da1cb42d4253c788e5edf29bcc877b639231180020890caf6df89649ee6eba07c0bd06911f5d3e822072fbe0a0c6535daf261c39472fc018ee93835456e561960d08092da4ff615a3735c73aec3161df5709317e4cf5ca88a9ef73b03a178008fa6f84df20459429f0319801650c1fd9f053d728b4f97a82230ac6ba40b1ba0998519d58aad5643f473ce5139872b678c0b3243630388aaba092a5d32dd46802e9112b4a4da7531b024f95410302e74a4447cfe57549786216ce728cbb0b5697375b61a17c62be51604a3057cae9e00d9eb2c1d82686af921a2e919ca29eae967dce0c26c13c3ffa870321d3ce88341d223c7a77ffaae98430f10d4d05cf40146aa3a3e8dd90d0cf987aacb8558b7849cd5438a1dc8819d681b457d4c73bf24ae4458e2d4b3c702cbc072d4b9a5a910e24c372dc72afc82eed6d0625cf327dc4e69a19af265faced334d0d331e6201bc59d57edb65b460058b7161d9e1f1d7c5e3901a9472911fb1ec878a1b10102e5a9419caf06dc92854274a6613ca89ba0c72653ab0cc7bc3c03764692f2aba2cd868ea7c1f275f99a7459b68cfd9e88cc084beea80238840e7f6747a592fbc1679ab17e9d36b8736b1fa0f63b71cb69511a7d13c5edf935f475dd7f40b45064646d21a5ca5b1975965c5ca15cd0dcaf8f33cbb8d6d543afd0d27316e511401b031c4e6a7ad01a2172dd6c5aea1a8d08f684b93991361b7d1280cb43e05a2d53f8d21538fe6e62f4acc525410941168d222bdb0bd0c7c31391bcb1d55d6a7717d6f4b24a3ec3bb06efb16a1aa12ba7597a4011b98cfbc1b91c00e014f5c03ecfaa121f32804018d3a013eb11679f61dd1f18444134c00cbee7bb48f6cfae46984988257653b2a06a03f447941fa94498abd53a867092c09bacd3521654b2b22cdbc0a41b0bea4aa8dd0005894c769a290cdb97c3a1d107e8c92e76a9e01d982786d7e47bc20e6b5153ba34ce007e972e5de2f767323fd6207ff86cf7374ab21c39611d5d0bb9c8e9ae360760b93e3f948248d283dab2cf88840e49f9f23fb803a02693a339e61626e6c941538ee5ba999976e49ec1ccb829e7d04746c4d0ded2805e90a3ceaa49653384fd515f1a9ce56cfa8f24e6720e91082c25370fb67caab845208b48a3aeda3532a583f1133a579c14c32092f3cca002fa8b2204feb39d604ecb6bb9f0f2b55f7f700e0717c675117ef563b2fc59e906bb24a5c2cd5d9d219f47e86fd173d1715296f442fdc82bd50dfc4b216e4484049d942166850dbda4b92b094ce614c8ecff0a27940467d58709946b45627c704a155a3c54098e4101849602a46099b46074226b3d74e29e53f3fe46e598da78f3accf9a094dab71248d13a3d2b40214dff8a818f898205a12dfc84cd086353dae5397f2209f964af9829dc211da506cf842ec03f8bdb98e2db8400fe58ac69d3034b9ce2eddaa4b46eef2f8453208661d4aeb6f75ddb6b6001323db9f2d5df86161794d432574f097d438bf8e8985306683c38aedfb4bca61305df2683b29694c81193ac5321295d1e4e2970d496253867a7ec8e162f1bc186c5305bd40605ba84ca55d2fd4681374739ec0dd2f11746b5067940fa0fe24e7791c622eb2c5e5751345ceb48e10e200776eefac39d20fa7608db664916b30ccc93b9dabe4c73436dae147aa3efd6d4a1b39acf81c8480ac3a5c96f09d733baa25a8f89d649b878346c102efc3337ba9b443088d9a7d2c15f5b4de35ec00e3fa21c7d5a1c0a1f5b4b331a2a49124903f483dce3053ee148f56c98f850186b1c563cf1b5398a4a2d9540fba19a972e228b6f193916a930f951cb5c2c7ab1cb622e08fe7e3c531f578c0f01314c360d1825734785ccd85a7ca9780153e724038f1449c3c412f8150a315ca626f15fc6d5ba822232afc91a3511d58031dbf73462e8a25568a3401b8ba26ada693e55eae3129d5b0ef3b64cf06c2087f77cb7054620997de2a1e8dc7d0e34c0b5104c5ae65099e4ae34340c731aeb3f880449b1b4361d3fd362aab6026b2b7b6aceb2bad6260ad117981e9b2cae3b45b712c260ea79038d5574ab97833bc8a63bf4725709cc11cd5be50b0771b23c567a57ad6109dff0ec7fc2e80b622935b107a9e6e1112bc1c135f9dd6e244390c74c184956f8ef553947597687c8d1114c217fbe902d3a4bddd90a3103be704fb22ba1d6893436056466e881cbe3aef27a1aa1f1633cfb272a995f2c19ea48cea75e9b7e4b2489764c63835c3d1ceaeb456ca80db9bdda1dc5711e7f13c5d81fed24eca8b753d0943990dc52a8fb8c3476847d9a57184846eebd7953ed55ea4f4247da120f6c1dd13bffef9db03238fb414cf5e95daa78850af815642aa690cb1a6f007cd35903209d6cbee03ff6e7d37bc5a08e29a48fe3f2286722dc733bc202dfff58c3a5c88bc255f482f17f2e4b20bb8211972afc5b9ffd6cb6439232269d1adeaa63c225b7271735913dcca223b3e22f95426ee3415ffddf5cccd7cc04edb023964818fd72f5c43ac1998e367cc9e130fbf3e9d6450926798f2b5c5a46eea032eac3725f8168182fccd348164b86ef8088a94c905cf2661b97204d8e3493052021837609a573947647635e5aa08383921cc86842061431087c780d23d33865e33a1e95635396c508c738ed88c43dc85c5d4dbd4716b3be4934370965a123d82a844a8c7571b9789f9d642006a90b057f9020e4f8a17971ef75571c7f6a0c48980b120a867cda949ec3683881c69f630f70b6a9e7b55ae856e6c9f5f5f7938391a2cb142051f134eb7e3265998ac5fb2ea1f9140b9987ca0346b984a4e6150f3538637475888e3fca21278224c52a539923cce79fde6d784309b7d3561b7e1d5ce806750b3d3f616a7ca8898966ac2f1068229fc217aea5dabe425a704d68b8e85dfff9a2ad635e8c719f4653ac21f7bae570d458256a25e269af6227b5f9ffe85a29926252402926aef3efbdac347fdcf417c754d2c370253a54d80c57506400d4b51e16fffcfd7f1063b728d7422bb920845069f8bfa5a7d98a3adc282c0e6bee5f758adc3c0530cf13b0ff3981fcec703718b25766d34c98f4e3957072b0bc116246e6a584e3a4f0cd1a930257c5bcb72fd947072a352eceeddeb32677f0b6e0264cadf9760d93eece14243e13a9e81bb4726349436bd8fb2acf97c994a9e660bc67cb51ef163ce8ab99dcc0342947775070f02045538e14fbe4eee8153497f6ddf05aa77a8ef0e6ac16e2cf14037fb24be42b8432f880a70d7e5bc7a15f960e71d801b0846339130b2aa8aab014130f0448e80f1d242e71ce402db03494d8f51d5b37117c372683733f92a394176d5548229935e3a4edbca23e182d3cfe5fd258d70c3cebc9b2f53fd27d8b823b4a9e312ba86cc62e922472c754626363dfc49d60dd85392d3147d2a9e74cdd770d884e95cb899b1354e48f7354d8d90576cb7cb94034d15052fed2eb5fa619a194a659b9bde384246d01144418158b6c9bf472609c998ea378c73322e0642217b7d6899c8967535a4a9c9e1ea73e89d0de076d9c743fc665bf44273284590553b80666ad03ba4b7f059aacd8687b7b7155844632e1a428d38cc549002ea921d95da331551530141707274db19147f982dad05ac850e6e8624e7eb8349c972d55d5054b8c863c0795485397e9ad275248caaf77326412e78d3515f83b51ac41f0045e855a29d46cda2bb4f3d106a51aa059d74e2f9c480e78ce8df2d57e6dab011de98123c06e6a6e0a74d2ab911efe1a18c5a32cdf54ad3476369843907c7ecf9eea07b92a5df4bd27fbb2cfffd8f24091fb0fe30d68271894572c5153e3fd171dae6f28cfd84c1d18bfff498b658e5927317d20ea512f33de744fbd8faf2c16034eb712b30ffadef6be25114cd3701c40fa10fc70222c074d63039c0eec34266d8be8eb6f21a2c719b6b1da692638b0f1b767ff8db1fccf4b81ad8f46a8efb0686debfbd48905a6db5d006dadf02d13e33521832088f01c39534ff5f942d64f000e87a9b614fd0831c36cc0423b67a5334a592cd63072f1bb7fd8e4267c447cdc2e32e5bc0877755ed4d690c8baeb9861c8693b3d2fb67b91f72580fe0da0b7cafe9e45eb5ee83e0883b93170d814ecf5215a60242a6295a42579e03864ffdbbf8649c34c90d1b641af4018225b211b4f6aeb4cbdd6f94e7b5d13945f567e6c162feedbb51836015fae42ee936f6086ce81b07f3f0da1b1ed5d9ae89faeb3c7633b147e975bfc26c93ea34d9d1e05a2a0f14aad9f3192d7c4685e697688a48e9667b699034bb75b84d5ecf978f8f9cc110aada8c3383fe1bceee66e9960c080c2939057ddf1abe3ff9fe7f2bc968dad3b3f30e89e8970d77d6817b675e3ec6233dc30cb3320cfe1f818a84f229546f821fce4df7b7ef36f395e6a0a93e4648ff7deb0e45c9f3ed21762ef619d345ef50bd5c3538cbe3a6863d84fdf2e7fb3c25c554feddac729ad41d37ae865c96bf38e53e8b2496b97da637cd9e4c16b7ebf6901f45a40398fad2ec0bae855ffbdab63e6cf7bb05383b4be2ce3fd15f33b7f4dac25ce57d5d7f743623f368ea06f1211bd70ff6857256b6f00cc584c7ae32bc3fbabfc73fa36f7383caf05fef353848ba6f68b6c0ba3a3e618e346461a3718ba1ffec8ce4358b57f6158493f6070cba20dbf9e47558f5c3cc174b6826b89415636f014505ce1d6e8eb23f2fcc31bb2d8fb8bb4bbe86d15c7df6b230cf1aa386463a881c8bcc6f6c574186f8731f681abb6c8020691a8bbbd19d503d953c7b3aa9b81db9b3387f1c24528ef7a7ac57ceb6c7a70890f98c16a5212aaf6eea33342cb6a338992cc895bdfec39b6c8e930f3e8a55a35edce7f0e06fb7dbb58fd98fbcd598cd6ac56107daf3a9b79f8f0863f78e1f536bf0d74d45ac6fe63d22e0f0ae014cab35fa686eebaec89f4f899db2d0cef9e195818c7ccbc8a261af4c54eb5131b0ec99d9a1a61ef95c8ec62410e6a7b62b460ad23ad7b88a762c6fec0dc780895120b6f8ba1a1ca6a7ae788e0372ac43346b0b0d4f029ed51da496c5997131fffdb797a2affe72b9f81579de8f103e87c842ce1f743f8a60293fe8450882a49468d43179ee743262b7f063e519dcab6476f462b6e21364f657c5dad9dd2b7763801ddeabfba2bde9ce49b5b4bb60b5a70fcace3f3c4070d35b67eec987f10ea840943eeafe730c1f37e7c88ac550612a254501d60b5ffb45b76d18f72eeebe531cc23a5559eecd81e72cbbb4a37f65c9aa08222097d15cd0e8217879e346cd854d886034eae890b380d1abb30ed2100d5da5747bf8ff1fcf19d5f14067afcf8f11d76d6e5c20b09986952a98185456f3d1d9dccf66f69a33bdf80bd2a1c2edeae4e1ff5e03b56588166a62959dd981f497f3f1c8199b33c75bc3328db17d13b1efd26905bb6ce4a4323387f058b7ecad4350c7d2a8b3b8715f6a3c4965846513e2b9b17602dd9ea6ea116d767f005290d573a22868347392a1b3dfc599346d95e60f675ef5572b4fde41d08fb4ede1f7975625d8174f4f23b7e02b376e18b581af050f3f5e78f06bbc1c275e9ce96756d4b03de903eb5bffdba1a92c6c7e403393bc26fc6f5b49fbb876030fe4bb6f93d1fcdc92e85e9bf4009661bee55566ebbd451fe0d95728cfac40f3a2ce435e1996fe7de6d240e8f14e141a7bbd39bd63e3038f023bc6e048431c32f99b75e24ac78d0735b7fb36df78b9c6b6d1d3f4e9cdf6cd31b87d0e7749c7024d72a6d3c9a442136302541dc7688a3a1a0e21c68c36d7eb2931433473bfbc475fdc07a1214069c5b2e0348195d8200e699332cc683e2b3fffafffcb1945361001cd19121737974da75f03ed6b58f5bfd5c8fd3787640f1998209543a0a6eee3cdf98bb85277f55dc5d2d1b90df6f15438cf7a8d08ff926f7f60f4393b14e5abe876d6f9ee93edce1e6aa22f77a2f7cc384978de66f99c607dd2a3f6aefa925257fe9d53c9614f30fc961d22da1837f533719a2b75fb9544f116f2a403890806920c305e406f09b055ffab9406972938e5412bff57aa737f4b7ec41f6b7aa0935ac7e235ebebde1e1f7229866bcd27dea68a9901db299807a2e3de2b560485d1c19b69325abd7c959a281d25546ec51a295d03a2fb15376312805e14e3e69b88d935d51319608c1ef3654ee89a682d6abebcfa7171a1a8078e41d04486265610a8534c5989895615d7c097765c064fe6653d5419a100e9894e8db5d91aca0c8686bb7752811128b64a58c83e740c543577e4e0477afcd23c17e3f1c387b543180f88f9802bd603800bf13901bf668568c223b375ed10b6448a344c573a5d9844f1f0e4ded76a321d342d423b6fcc4a7e5a1b907bc4e69be1a62e35039f93ac27a1aa3c12c9b4b37d9f9219e7512ef1a2c65423aecb4e8e36dc2634019ad321ea1d5a2536dfdeb2a634d5ec8c96e3d2054e51e345d4fab2246ef4aa9a08477f55de1e7d1c47dc6891bf1c03efcbe355c74178efc48aba69cccf63ef960092b3131305f8940a9480d71d0aa8433af1cab3501337f5ac21cc36b42c28209f31e51664b40401631039108c79b9e4ffc1bb3218b1547351ff34cf10a41bd0d876d6cd0647ab32d6555014dcc97133f68b9c09d6b5db163d3215de79b30c00f6dda52790ada4986d615c5d08ebad636751bb27a4fde5084928fa493f5113a920230eb564b6f1b5569d7e4d89dc1969f1ec0db384db4f0c2e22a311c47e6d8ccc47f23bed1fc72b6962c987bb929b6c7fc1f686e57eab1bbef819fc6baec03353e022311acb6fd7ad55309b263d6711533381f735bead01a408ae15ef7eeac8e92b3d2140b00e49017d3707d4c85685c880455fd82f3b7a68a7a88554a4ef606ed17806929b196b46a7aa68545fd75b659c8b5f1195c3d8d26d5ab603e7fae431d52f5065054e642552930e7a226c1c9e8babbb23281b08d6b09ffff66acd7a25847eaa8a7cde6dc84a6cb2a4f6d9a743abe83847d20b8d50d2c8dc9552f529866102b03707c8778e31725ed060e59d1c35d0e9864f73d617ebbda8392a7a1466958e42e1bd7e39fae67984785e3070ebb3b0627fe3d50176ab66de3df0bcb1b7fc2ef776717b9b43c8c275fa5bdd6c3ee70d5819401f041122d3802e5f517e0dc508d9867573c434c839379623945d99d8e98dd1ea2ed140e247d5a7107f6f5c068671d4ffff927bb3429bc66dcbfb09496c1c348dc2201af1825652b8f02f21bfbed02ff83e543c006731c01ab5c084188e3dcc39a8020147c691c4014f03caa52642890471e617e931dd9970eb220e518d54b960bc6bb68905c4437c517b8504714790e95994a825069efafb383257000ee7dee22c8384a41d2263448d48a3b53d12009954bfb82e23562f84997e5b86e1e37c782f1fc2c6184456cb32946e23b0b70049b9a66e4ad16d8954c928e552dbbf1e4718da101d3b09ec6cff5d0a7ba755af063faa54b1dc91d6b3d7c33c09d3db6082b507650342332fb834e0da62b2f4eeebf83c30cf4a9d70a0a98b143ed8ee284ac29fa374f522e85ee763acf234f457154459e6ec831777e245f51e543be8204d385fe68cec205adc4b7bde05f3eee395111d1f952dc2d14ca813125bdb075be08b5022d6c4357d7ad53c79c92fc89da194bdfb9b608e04f92b8a18882d6521411f2ac05df013625b0129fdd560582e292b2399b5b5716c66e3cbb91bd638a3f73554209d4d1913f43aa678461011ca4d68103a2343ad797686d344651c8d74ed54a218d4e149fe029ffc93e6b7cc9388434abcb9680e69c582260eba2f30efc0f91313d8e266e4d21e937cf4049bd1aaf38f45298bf7cd6719e72e9005002598059671d9462226ac0781a62e88555a74594d2bb20c870634e672735bd3ad3423c8d9794e143962ffbf9678800f83d22634f412080d5e242caa23fc172ffb6968daf1e2256311c2e1740f54f78c14480a052699e9a5eef3178e4e138fd0431ab3c4d610d8072ba9be2642fa7217c646a5fc9b4385a1442eef8e1108bd23b9d9acca7ce4356212ab4d364abd344f7361f1769188e90567e37c117bc86383e4e82492c6ac7de1d677325fda13aef95596d38109cdad5835f3436282da5ff8bbbb2cbc51f9c211d5bbf5a4f4b3b0c2979d52d43b20723e8d824c952812a745451cd1407d6f169aec6dd8596ddae27629c144aacf5f55a33351708bdef8d7df80a20355f153534b2808a16eb4ee4623832e3cd6cb275a8d5634dca946a3091bf1e46944d98898d5a3a4285d0a9b732099e7c60e56b392beb3aa0e2a56a0bc9188eae6325474e02acdc564133a51c56c4a4bf1e716637a1cb8b2d0fe1766edbc1da2ec97681ede86b5758bb5aed6ad486956394fa9bd5103fea5c9d049f7cccfab3cd6949f7836bfc556e86660c8facc75e924c3240f56d75e827550e2ee2a7be33fe58e4b2d3fde938ee022fb359e6835623aec8931a52fcb230ec4f35a723d103bfd9bfb213e5246923a321fe3dc9393d6ee6622e5f287350cf06158ed560677b26931247afa823743634961f4fa224b6d01281ab068e7097c9c456367894e52ec521e24afb44f9ca89fd39288b2063347de2677a9c1beb94cc6375f4cff40ad7cbb1d1a8da8641ebade8dc9465986ccc788e3743992802a8689d72ebe5ca71f6469075ebfaf77f10799f6fac8dd066f0149b5b2b98a0b4d468aa30feada3c29248256db25d1ed365e38f2265e55cab8f0d25771d716e556b4fbe0749406d7ea40e833ec43dfe2055da712010530d231fcd787dd1d36beec7d3cae54b852c148643dfc3026bfc471fb233f82ff758287c13f7b45528fc0e31a86e75a8a47039c8b08aff7b57e6dbf7efce8831be6b30e82f9b38a78c8d4bfb93072dd02c4c84f7b3ac09dd869500fbf22663b394478fbbcee3094717ced42a5cdb066dc13df782cb0099b31245ab7c40119c593dd0ff01963d0468a02e4af2c6f72c6230769c2eaa2752682cc7b90434727af3ac39f4d36a2c7fe036d1f220c3df0d7b3deca253140dd8ed87f9dcf8c3b409327ae0d2ac6559989c9ecd22473cf8d5325cedc8fa19b1a304204733ed3aa72f9ea313def3b60861ee133a82ce69aef7684058d94f5681072d8a88d2806230e399b05942801d59020b205f34349e88bbdf36e2dd423ceeb03a37a5e6784c3bd41a2d45760c343fa56da7e994bfd8bfcb2b2f338876e726983cfe369cb0e9ce742e56b59711b34ac88ffdee61a8b2b5d7d391961b4165a6d3aeb5f2ce752a6dad46e034bcd7ce9a2967708196fdf80c44c65352ecad80ee5e38be6393d70f6126ec6382900c58e71d3b3cebea8ad55135a15fe180bf4246115e70023f34cef9c52a121a4e1b967f730382b04529a292b48d029c31764537a2894de1ea25a658185a2e3145b71c2f2db72d0546e7157c2b189cefb8fdf9f80dbd844ab50313c6b816c049d264cf5e27ba0f85b751fbc4205712c453299c512a04f0daa6c1bb6d00264aafbfe8d1b261d8fde09e3e57e93378deb9896316f20ae3c8743bc0e4be4a06adde5433eafe4d4e8c4c5aa0475d965f60b881c694c7c90c4a4f6bc4d904b519f3cb4e3d45213ca6fb052902f8a749cb7ac2c49c34757bda84307592eec9d37002552c85b24691025aa5562b53ecadd2a9d66bc40adb7f9a25f7ca353ae2553efdb2049530f051b12d0a19c36e4a56f44ece50bdd234614fd80696d2d63e75333be40d6402b76f4a158edb4ad7d5a50ecfc44eb26a37a514bc9e9267a89a07d190bdcd091f7bcad789f421116a9fb8f56fa602d858010dd34a20306470e73ac810216c590991580ae5a885e3288635aaa165e410487ab8b920f255110b4b222269a2748be27c54b1a92c1a3a5d04a230eea23272a23496a88d68114731a9e3e8f258687d34904042ac90eb2a917cd1c8d68b24865452483239249daca0509a492981492af7d14ac611cbf26a898b5c4a885ece2198dd2aa6e59209ae9ab9b3687252358b2d9bc8e8a6ac8473e02a67ed5b9ab18a67fc7926c3b0e1a7a9c6ea859fc7bc58fb6fd9bf0aef99b26709a3b813a214f00c3fa7f59c3f3ed32dd81cd3a573ec0e19379531f1bcdc976568fc768aa5bf1bf47c590ee34c6995a6cc542d4a8455e2a722220fa5ca82b261205365e88ccd2d47128063c127c4b140ee90cb54ef23ef444adc2889b57ed056e6cd125b4b6998a10b99c7cbd650053a877140ee88029d2549b03305b48d7c1d99639a1b4138e0deeeb3d32c1aafb964b2e3aee194a75fe13f6a1ff2b469bcfb4d7dc7522148cf289181fd5c45fed823d2fdf0fa3851cc03970779fbf9a2ef1b5adcd27ed08be0a1a5d35be2d9fbe078f4b151c487aa287f2b82799064c97c257883cdb701173c22e06e144060330eac2dcefded5412b0f948b4fb5bca60281f8caaf2c32248e5317b393a711cbed86c82e5b025eba4fc41b4aabcb3218eca5910ddd48360a7a22256312b6eb00f9a20138c77ec2b9147e6d2e80139913a024702806225e5db440af57ba9f6c773196e1c3825dccfa414e38cfbf90324dc02de8104dc0b3540b026c3013c0c3c0c3c0c3c0c3c88bdc5b781b593524aa5727a330c236f1c92324999524a4c3f8403511300ff71d1885a53870c02ad0b9f0b9a0b77a7ac511d0e61cd0ca646085d41f64983086131534b9ecfd353371c8c9dbc76976326d8772c1f183b4177c73c54fce960fac5faf3e97a3be376e4e48bcdf3d62f8c30151eff5eece43cfe6b96a94356ce8b4d8e6a1a352787d098ed624d7a16554cf6e9cea78b3d4f93758c653ac94c34176b5a6dc299883ea1ffc2c53a276797dd4427c9dcdc62f5ff8a5134e5c7a431b65834f96356ce42c60b5e2dd66b62cef1622c0b56315aac22339bb059a559ac2664c526e8daf0e744167bfeacf899a895339b138b3d878a990aa1b7191658ac1a462bfe966a885f5fb15cd4d5265ec9a91c992b365542fd9e1cf514634a2b16694a6d2c593061f9c28ab5639afadc4969b41222ae625d4dcf51461334e1496955ecd153b2f3109b34769e8aedcbe2e2c52842c59a77fc3229932fff82758a752e69e28df6a98b1d35c5f644d94c529ab44174dc0e11344ab146adb99c9d22cdb65362a0418a65fbbcf377c9f4dda48c62799228d3b39f74c54c45b1f69de84c21e3565e5128b67872c6943cabf4e51c28d60ec273aed155ff315a65a0f1894dffcaee8811a29ca4a1e189bd4b9c3273c2937eed47038d4eac355f4fb0af7e62661439b108331594fecb218d4d6c3a13ce6448cd34b1aae81b1dbbf3b4b52266624f2a6a507ea2497ac6c2c456326377a53c1decf4e604342eb1050f213da853b2c49a53654596f40a9a54322bb18fa694425c9c1d1537741adb93394933d198c4fe254a66cce1cc49a64243127b38dda4b2ca9d2fe74323129bd78f13a3a7aae817d280c45eca63e99c197399a4d378c466bac9e1ea093e4afca2e1886d53fcee7e82783ebda1d18835664493423ff1721384683062bf112563f3aa970e3a1a8bd854144dae9229ff3ce913040d45ac9ac3a76edc141e43a8093412b1d586e87977758ce2d140c4666719fb942668a54ccc21b6dffa8a953613a3c9d1107b58beecd1612fc47e33c26e3513a445274d83108ba75c0e1a54a7d304d920d60b993339c7bc729c29884d66568e99fa9e244526109bbabc31052fd549afa60188c552fa2c196d82ba98d2f8c31a32a24768f213763fc60f8b5f8eeef4cfb94949131d7a64d0e8c3a6b3e44fc598aa1c3e1a7cd8c62b6c4c57c1be0923099440630fcb6f92b6bb22e2d7370d3d6cd2474de8a4c6e3c392872d55dc6ea957562687f1b038313d5493e3d6e53ddd618dcb759b2913b6c31e3a85580a3daac396e2be92503217d413a5c35e96ac3aaa2693d9f41cf614fc9bf05d224a3f4139aca1bfa496c7e82b953f3dd088c362973906557aa3ad8a7058e46c0cbd27af39313d79c3661b4b85bfdf0d8b0a5b6b7147d67f4725251034dab0a74c7aefbb47f59cc686f5faacd66213538793352c2a534d36319467c6e60f34d4b01333b4c91f74ec344a4cc34e26ae7d12671a346c7a3449695f92d5189d6119212343f6dca638511a665844063b21c3a893bbb90c6bc8e8badb580e38e065ec608c1e5e4619a9c70a689061ebb1745268257981c618b62f0ff1d59d3b8812698861cbabb2f31c4f4fbe9a4618f6aecef15213946e12752168806139d53be7dd293765fc8535e7133e3f557a0cd5d1f0c29a615494c80a6ac3976874610d72b4831272610b573933e44917738cd2d8c222ae4c93f3d9a565728e070d2d2cb699f04f72623dc9367dd820d82103d40a1a59d88499fc27860aa7a2c43132c608467c68801634b0b0494f2a68e25cd2bcd14b0c34aeb07ed0a942c6b4d48d69852df3770e22944cc1495b15763249082f4d15a9b0e614d43f66a6e908d1cc078d29ec41992635b9f25f6aa22885e5c9774ac6106a1a51d84474f4338b3d11d280c2f6dda4ace8739733d7131621839a2777a9306f52683861954fafcb18f304bd6c60648c116820078d26ec2747a6a0474ffc5830879af750671d64a04003c984cdecc3eff87f8c9a66033496b093e2e3c81db5789265d480b18718268c169494d050c2da3173fd959c4c52ab96909050814612f6db0b229b7cdb24d10469907e1c13d040c29a54274d9aa03776fe3ac26a16936793774e576b1a46d892f224b6c7647710368d222c664a4fee06916a4a1f6478490f1e5a8c06117682cc23623b34060b4f7af028512ba787ffd09138680c61919f9ebc1e4f3ef9096a1a42b06346c2634630965ffb54f9399cf4a3eda0c78f1dfb6347e2a4827365a41a2030d65253b9522e7ec5709598a51d626cc087b9c48c5fac75dba7bcf2ece6635fec04f3542ae534eac5967e169a942f36f93f2887da998f335e2c32ffcd9346c720edd4bbd8f249ff176ae509964c39d44a78fca83166e8628bb994d0983975bdf31998918b2d3e991c2d1364d00c5c2c1a4698c6243a84af9920d871831c28601de6166bd25b27c70e8d196acaa1e683c7efd0a1016466666666e8a829a6f030c3167ba55c6f9e257b05336ab1868d9d4b8858ae8a195a6c17966a3b934e964ab11c5a52cccd2cd614460527139f7c39946e862cf61457f22ca5cd3b32931c6a322899118bd5f632399c389ed4cf120fc0625f0b6245e731afa4b1b2305a50e28319afd8746572ccf67767069d1c7a34601e23a081fbf091c26841490e66b86227c5a4bb47f4555c4eb7620ff3a9492c590829a763c5269774bc33f53b8f7912121292b2556c41564acac99d2baad8342d2615c79e98ceae54ec99e0a7f6a7a51ecc40c516ea2bd6734d12a59a1c6a778acd5474cd49b918a94e66986293edae78322a87cdc49462132b9a33991c9310a2723934083348b1934c3e83525b29939aa41f3e0a1c668c620f619684caa1ab3a947ef8c81e6f98218a55840a75caba83885285621d4bd3bc64d1fc330614eb28cd236e930c2a55555430e3138b26a5d839d9586f8e9978623d7d72df5e063995d4199dd853d253358f5d4ff9cba1a69c584f884b294e12d799f31c6a3336b137c1e4133c7526c80b639a628626d64bf5b3b0944919844e83f4e3acefd232b18d500d7e49d493827a87fb484cec7d9ab04d8a39313a3d0e0f665c628d29359309239a70f942e786199658ce4229fd1e15641c4d1a5a25b6f50f1d630eda3994520e35db210609c90e1e6c984189fdc7621373e67b12db9de5f39927679c7d5c982189fd9405f929569943ed6860462416dd26edcde9aecb3bcaa14646aa41ead1011292623320b1a7adcb34cac6848a4c0eb5121f3e9c6130e3118b7e32b99b1c74dad2a43d5330c3118b8ac9abf2362687dae4063e4adacd4e30a3115b89b81ab9b9d8102514cc60c45a39d9f7dde954524e39d4d046c6f0c00abc033cc6707f121212121f3f76a445ac1a9398add169c7e2998ad8c929be7212de441376222662d1a3d4a268d7c5cadd841988583f7e1e8b223e3de3109bb05a2d15847caf6f3e708621b68b37a33275250f9692430fcd60462136a54176ae3027572ca11c6a3e4a7aa4b1600621f618cdc332dfc65927a9e506b1f8a827869e0ee92164d6811982d8497eba6e6da4e9e4971e3fca9811882dcc26bf287e9952ef8058e3fe4ef5c79119af8986d182129ff1874df9dfe514e63f97b4197e583e660c4fb4bcfd840ff5614d96c9319726771ed394197c584b9dfa91b3a03b3d46c28c3dac6741d47c75509a498ca887c584f2cc3927280f9b2eed946541f8d9cf9978d892fecf27592608a13293197758f67a66c332a78f2934c30edb09ab642ac3354167139c518745a3a535273e298e74061db6149c94a17a44079df71cd664a973266ccea9bff3298745a8cffb2427e72757fe66c461276fda154b33369a244b14c30c382c6b420827e89cd3a720f486ed09b7e1351bae2b99d00d7bde51c2f2ce47d37e0edbb0fea8d30db28916c4c5715c09463032830d3b2979e729551dae611faf950f39224d39c9f3c20c356c9a4fc6929c26a8bca0342c735657f1c48f1266a0015f512a8eefdfd881111c2320f0b1841967d894e59895e6532e13cd196658f3e68d934d0e2a75d095614bb2ec2f34c668be3ce530830c8b3ae133f35e765dcacf18c3729a64fae238296db29118f6ca18368cced298548a37230c3b29273d2ba6934f980186e573a83ae163f6eabbcc195fd8b346ef93ac134bb41fc30c2facbb673e7f99d85b4fca8c2e2c76e9634a2bdd0edf11186670618bb1ffa3c45d3cf93c5998b185cde27446c47833b4b06da8f993493fca28ad026ae62999b1899f62cac1627182123db63b97af9bbc624de9697ecd53c9ab8d2b168f418c524226dd496c5ab193c49755df58cc9e9815cb578ae66713e6899998552c1a7ae3988e1397bd56166aa862b924342c288b7adf64928a649c2b9576638f8a355df8d0a15a7a463b798ad5e2c3895a1e699f4f4cb16d502b6b554d4ea732650c354ab1874c4d4af1c46462fe3f2fd420c52a7f4e38bda5e76c3b5fa8318a6533d6e778c2a9ffa0944ea8218af5f2a720f5e474355642b158934a2fa69039a978aa27d400c54e8a31269d897f22aaf727d660624dceab58bf41e589bd3f7d339cb2955327d64b55312ae5d759984f5aa106275627752693ba4c89e7686d62d96c6287ac29d326c8d9504313fb933bfcc493c3ce3e3199d84244ebc9dde4ebdc5003139bafdd68f29863ea4be150e312ab1334f9d4d29ff20d13b950c3127baed227a9138fff41abc44ede3c3daa2e36f7384194d89edc39c7602a068d4e90e1f13b74dcd598c4eac42dcba91e362dd490c45673159393629336f12e79a81189352d7e769dce9d3fe520b1a8c69cd6b22e7aa8f188b5642cd9172c6a458d3152a8e188e5e2c7c868b6e3679d462c17aaf5e42f935e323d851a8cd893c851a79e337134715cc44e588b1e4f0a931f3ca688359a902ba615643579670d3512b17f363147767a5290238388c5924e9a1ce6d458e6d021d6f0e4a4f00f997fa3c6103b31c42851eaaf4ac92685d8abe47759080d4d99302116595e576b39a65f8e0d622768d8678a1bf6636f412cf6974929be2f25d6871a8158744c25ae494e4e274d04c496d6c2e493369349ba43121231d4f8c34e8a51313fa9c2a698fa9131463052c30f7b6792c92be6b49073eac3aa22e244cb71f2615927d836719fb019e33d8263e460216aec610d5f7d3298dc29959ee861b9f9cce9e9cbfa76c53182e3eca0461e16df942c77edf39e486be061f30b9ef752c7183f9bdc61b3b413539a944d2a1dedb09edcf92ea146a6bf531d36a189f1534e3fc13357627a881a74d8ca492a775653fe12fe1cb6aa123aa56f0e5b3efac1830c14909070e141868f63841a72d8bc4c35ef9626782669e2b06a32cf50762642c7740d38ac1b63e677522b0da1c91b96dd184dd20c9b6935ba61d1d3772bda29e5119d36aceaa44e93b3612c689a0d3b99981ed3a38979dc6b0dcbf826eb1426bb252f356ce1bac33f51b54b953e0d7b139c20eaa4e59d4d51346c32c32fdd13947e5e2676a8718665d4e213cfe3932b784f424242626a9861cf99e4b7bf199be64732d428c3beb1e12bb6d335c8b006b3defacfa731ec716f75ecc23ecccfb6851a62d853ec526a63da0e3e26186a8461cb24bbf0b80fa67e93c0b08d524ed80dcbda3cfa1a5f58b4c9a41c3fc9b8973a57c30b8bded061a2397fc6e65dd832e1e39b983fa7e9f81d276a70618fbd972bc49826a5316d61d310ea2c1347c6a049792dd1c2de954b9eeaeb6fe2655a623e8250230bdbaa67922ea5472c2c2a2e9972e2681374ca11438d2bece36482ac8cf13c4ab42bd4b0c2969a98c9339f820515ae2a6c3985f3efee8450830a9bd28e69f66482ec299d611d8a851a53d83265728a5916d44a7739d478fcf8c1761fa821852dac9b141a4613fd2b1e852d9349a6dfe41cce2fa5061436a9d67b31bb43efd24f58afe3733ee550ffe9490d27ec648250be9baf928a712f31e33d8a50a3098b565826286969831ad379078f30ba5083097b55e89883f49c46a6688d25ecf9fc3a858b23537c9f43ad878e1233dd1a4ad862f63e6352ffcff3276115359bfbbf644e4a5440a88184f5c48ec9f0a837a753358eb013e4aa3eef929898d208cb393995beb4b1d1c257a3089ba6a42773de6a10614f26846ab89cf96ec33586b0dea94f3a76fce98c293584b0c995c74cee2769a5de141b630423618ce018116304c7c8d6a0078f0709c6b6d6e31d9d14964f1c81b19f98b4b4a46250bf1fc82ff60f1f523e9906d1044dde4f40424242c23a488400e28b35c613ed4b2e8812fa8420bdd8b43279fd3365cac9d4284078b1e77e5279c5bc23949077b19e7d3641d95d3ccb1272024417cb5ce62693c2da65f8740eb5121dff2556460d40b0830df8f0914a40424252d2c380e462afcc1e0b6a0f4070b1e6265a26e8ff550c1dbac51e9bdc04f1f1c2da3851105bac4fcc39e8bb2677dcdae450d3e19200a9c5eae3c4124e8e27c9ee4a8bd5e663830765994c2c9559acd564f247ed0b214ebc64b128fdf989de29a50b3282c462513aceee4c25253b74a019800081c5b64df24c1e254e68c598821f898c0e9090ecf01f3f12199fafd82a4779cc07d3f94f8e2bd6b2a859669a9ca4a8510e352702482bd61b19a3ae93d420ac58738998caa48dffbc106415cb3839251d7ce4c924a115314054b18919cb94e34ace5d34153b997c990997365f299aa062d9d95419cbcb43c8934c05c829564f7a37ff678e2cf5839802d3f9cdb94e32a5586ee3e858a3d2c5b47152ac6b693d05cd63c9bcd6030a9051ecbd372ac85341f76a2f8a6d4fa6b09cbea9731a9050ecb9323963c6510f5e8362bf4de75f7ee1f33441904fac7b39c43c39833cb1850e71d7a4bc13cb5c6dfa8d0e1a4ed27362b9af4c8e974bed67528963040a209bd889f56199643a6a294bc23172785500d1c422a646fd9f7ee9e029904cac4146d30ba133c1c4329b294a5787766e52402eb1cc278d162bee58f2b1412cb1588ebb689b7a6ae6aac43afb245d27d483da314128b1133798b4984bebac0ac824f6d817e328b5f431971c44129ba6f5204ec9a082e7244824b6ca4b27da363987aa0e12cb88dda86e074dda4a7ac4f69920cb539c0f17220271c4722a86267c1addd4c102d2882ded939e207ab6acc4c90e19e8f061664018b168fe267562f89e276939346d115ba5b514f994812862cd27894b4d924bf6b76e002411cbcd13d4e556e79c322088586636285d6bd2432c5a4f50954f9ef527e8f4f01f371801075e8cd4038821d6cd5cf109ca6326a9be1462134d524b19422b540a42884de3d28709957efc9283583449b3d32bafbf8d0b628dbb9fb64dde1863f4ca28f9914a4afc078f1d368263c479a00305324825d04b208158b62b4bc5f26c7207930002882d6968e2a5d34ca64f500eb5121f3ad02940feb0491365e5abf9cac9ede06164b06387183cc6e0d1a3470a4314207ed83705a1e35d06994a8c207dd8e2cf52dcd164f29e86f9b0789c9372bca4416f5083ec61ff931e345f88207ad809c249312f4625b9d441f2b0f7686888cde4a72ec6c3964ef24a4aa520b34a78873d6f76cceb131f7e2509897102c40e5b1a7b8292f17240eab0867e0e15446807081dd61c94d09c3c6f56509acc61af3425c5ff3c83cc190af0d871608640e4b0afe7689b8926ab01240e3bb93cf5a8cfb91c6a06040e6b10423ce9cf045581bc61516531eee94caa894e0e881bf6df98e4c80b25e5c9a4a43b919094e12640dab06e4c6a9f682a64f3e9b0612fb1d9a183decfef6d0d8b86c739bf26c5a0426ad854934f9d0e4a733ce9679034243223d96e635c6e48dba44939ca1880a061f9cb63627744c9fc39c3a69b184e7e6259a913961956db4f1e4b5fb00ceb6d8ad7e61dcb295d40c8b0a98f1ad4967dd2b018c81856cd2842c7936490f9ee40c4b006953fddf66693a395206158e7baa3c7a04e8a399440c0b07fbc0bbff2e7bda202f9c2963e5684ac5142c50e8278614b157dd474bef2ffab328074619373f7c4f029c5474b775cd834b93bfc49f5992c66700babaf950c177b4534806861cfd5dd57d7214fe514310b9bc7d4747afd21d66c442cec51ab64a8ab27ddd6e50a5bd0cb55b1b2fa29132e2056d8bf092a5739885bf1384815360bdf04b1391b791702a1c22a6a9a761bab376509640a5bfcebaddc0f52bb9352d87379a598921cd1b14e19859d9c92faccba2b7db2630510286c41e58929558ef5219f3c612ffd5fdf4d95be7f272c6b3256a16b4fc4fa26ece1f449a9f2e44cd0a831611f2d354ac994dbb1f42137802c61158da57e9549999c3d2b61cb5941cf529b70e9c924095b65acde0a3e4ac7fc8320619b51b3314ee6dd8cf1115675729a533d9e9426ea204658bb4ca719256ca3af0652846d4e091935ba629f200321c2b2b7e92c013e9938f649f341031e3c3e1000478470628f29faa5a072d2dbf074137b8acfa47df286ad135b19fb85104dec6ba9cac4974a4f3a07a94789fb97146b42482616f59d5ff167c56b2f56771f8289fdd2aab39ce07937c4975833878f19f310a1225a23422cb16a7ea74ec1b7539825a412cb96b2f1f3bd28b188878f1aaaae492bd60e3118113289456f858da576cb4265330891c4629ae2e6faa0f549f49048ecdd9d9ff4697308392a48ac4fdcfc716175f2d47cc4da1763d927949e0a25329a0c1e2c831d3a68c083c7a4c4602b421cb1e71115fde1099bd3d981138cf821a411dbdac6f60899368fd52584113bc149361a34be2ecbcca1766410b288353e517caf4fd67768c083478e12325ac75d1b4214b1afa9c992f95673349543cd8797e4e92024116b26c9272995f36f640a22368d9998177bf6c470928758abbf94142997478466ce1062883d28191e9e683139d4500c1c397ee858810f32c8d0c0088e91111c233846b22ca4103bb1bcc9bb31aa3941e573a8851062d3295a65a5c7fc33f21c6a2183d8f22b73b86d62ce0962cf1727d6abefcaaf0bc44e121bec42e78d9dfb54c26841490a4200b166251dd2ef67532bcea1962108f9c31e2b3af7ad7c36e10986f8614d1e3a7aedc83fcf7c1ff6d43d4256e5860ffb8f996657d25b9e7442f6b03f493b939e34b21e561d399a4f4e2947e5350f7b96c7579c94b34f3a7858a36d523a9c242b7aec61981da41e3d52f11e3cb806217758ed77bf2ae54a695bd961151d33f94b274da7531dd6ee4b396fe8266a9525840ecbc5b193dedb37be66c81c36ab3093612da6fcff87c86175f267c8185398edb899305a50e2829038ec41a9cb7d9aa0e26e92e5d0aa2ab34784c061cd7b1bd3e8e8184eb042deb05513c73331d596be12ddb0977aae589d549b18e49036ac4167fb2e66f2fe5dd8b0c7308b4da254e934969035ac23a3796656c74bde8d8ce181d4c342d4b069a7ce23be62ee72e03bcc46c6f08085a4618f21949363dfc94c1e51081a16d1b09dabd2a80e1f0e39c3e6a5af497fa3aa15ad1033ac16457f8c41a86cc57c640c0f9090f8a0010f1e39a8105286b563f8b1b8f194be23c3164d63c8c9a44e4a691f21640c9b8f9598fa281b9a2016c3262b86f73a714676e8a0302cb246336562bc5879342160583de6ed947be65258f40b6b65ea8db173d8f14a7961cf93e51953904dd8afbab07f3c19563c47acc9cc8575c6d68395c652419c6c6175f2e75b531adcc14307c95989c521440b7bf6e90e4a3c3cb1734a481636ad4c0c6ad9373ac70787064a2c0d2158d8095ea2475c528b4d52b9c216b7f4e93c298758610b4f925d31e69364e74d4815f624ec9fd4e76b93e13a3ad020e8c187102aec29ccc8a6a0c4e49a3e640a6b89b5a457422885ad2b75567a5032775b14769225bb8a567dfa3a238440615116aad777ef9e4ccedc3d61279f54f364236b326fee8e9b5293548a87d38921a409ab99d2311dbb89c94b7467861026ac66355fa966c593267617b2844d344b5fe7123f97eff3428812b650b1d43c630c33592f24098b124289d80b1f3104096b051b719d3c26e4089b7a7888924967dc94821862849d5432cc3f29a698cb9268d00a214558af544ab9bb0997797575218408db56933a78e6998bb132630819c2222c7d9992c92b2ca520860861ed13dfafb1fe27790731187b66c8b03d3f30f618d7f7f6fc92fceb177b133d4d06bfb8f1c5a6957163eb95372f895eb0d18b45d36c52a1494d26eda720f262d50a9bc313ab2ee51977b15fc9b14f393e5ac650176b28cb4cba27d44ea573b197e9da2eefd8ff55c1c5221a42a7df342aeff699b7d847a4c7d19dd3d346c9165b756e26c57c6af3d4558bad332dfcc8c527dcdf88b4d874fa4ed9d2a13366328b3d5d7c4ef39fc962d11fd57c4b3b96d231b5118b7535f93649a5d891276a051bb0583f8f6fd814274aa5199360e3155b6e2e0f0d55eb7b1e57aca5e1c453d0fcb890a926d868c516224ca920762d65dc062b16758212276f8d7f90a1c3041babd89f5897fcd459585f136443155b9ae52a3fbda3794c6bb0918af534693659d8db2467848afd525476ac463629c7530a364eb15dac0d7ec2492263bc4cb193e7c6433579d513735a070f15945829d60a1aab9b3b3ce1f23fa45854e86e3cd5bf365f8e62335d1e9684ee0c1a2b68a2d8aaab9b5c1e339d3cc150acf317723fcd58591841b193d225eb20635262d77d625329c61021a32fae62ec0d363cb1ec55c75332a6d11d6c7462b3246635a7ba98e466d2634948520fd7618313cb8d75ccc4cd693a7736b17a12a23fa59c237ed21084c186261695cec2599ebdec90c9c4969ec26e0a1b353e6e30b1a7137b9f94d995c2fd9758af33a9732e07f5495d2cb1fea6d9ce38233a9895d83e99cc70419dfde68f129b13ec53e9be4c62ff4b53217a667139f9041b92582c49f90ad959c192e7041b91d82c3729aac7f86a268a90d8f3a69489414306d93f3f628d931b7f522a159b703a625352439a34156d4449265d369f9a45c10623d6266cdc202be8a620338b58747a087df9af494d4e15b137e19b9c1d3f13ad3a471c9c116c246291a37d3af3236b7747c46aeb41475a1079974f0eb19362f8988fa115743a0db1c5103bb3cf9b2af3492116253fffdc7fb88e4b126219d5e4a0994cd060fea741ec79a127f22aca3fc1b621884593d6f858dace13ae40ac6a33ca644c328058a4df09b1d91bd59adc1ff6b0995469d509237fa37ed894e7aa4f9d4e9858d1088e91111c2720848d3eacc1d2469d68271ff6bdcda4e84d109d56447bd89c1433c9ba103aba9ad8d0c3269498cd9c3406f1b9491e362bbd39c54784d2d2f0b09c6f596c8ed91db6203d08a9997fa2b3dbc1861db612a3d33fb1746784b80edb5fa9265efe289d4a890eab79ad654c193f5799cc61539bb55a253341546539acf76144a7ecad9cd31387b5cc93aa9299dc797538ec31f6e6ab2e283d4dec9458116cbc61ad91996066559e7230b960c30d5b6eff7952278c2c5151000cc1461bb6a819162f7c364109990d8b4ed7a53b7a13453cbd862dc6273f9ffd4f41687288b0a1863dce79f0ed267c8ce2a761534d3c25c64478a6d1d0b0c891a6fe534c731ed119f674e92eee6295c775d21a681098c1861936e5d9993f4e84b227a50c3be9e42aec3cc9b73687071b6458e3667ce9cb8bde978e61cbcaf09c572f3a793e45061b6258c43a13f46786e7c620e3c34618163b4d5e93cd527d42ce820d302c2afe244d4cfa2ed8f8c27af2979b63aed4396c2f2cdb4f32699b091bb3341b5d586d45345144c6558ae162830b5b1347a5a036a3e45ac7c616b69ce7b2e24a69c7b58960430b9bd23e95c46f98fe8ab2b0870d66179db0b196c2070b36b0b05c3ce1f74c54909e355e61f31da561357f12a52510786004c74807708c7000c7146c5861ddb51c4a54b4e0e41cb7518555edbb44834e3a997d7bb0418575c328f5fed84f1f6453d863dff5c8987ec2f37f051b52589d1c3ff36d3741c8ba8ce058848d28ece4f3b20a3ac7cef4260f36a0b093d4a62693a346d9d5f009ebed7c2ed1a9e44a869db0f7cf13837e62e534ea4913d630552999e99c49aac43a26ec04f558252d97bc27996c2c61edf1ed78a3e2cd7c9dc347fac0088e91306c2861ff0e5a9525f389fa1d1b49d84ac5a05b952f5cceab0d246cc2473c932c65242427041b47582ffe7e44556828f1a7111c384848b20e368cb0e9e4e9a4f82135cd2b2596031b45d8894e323be9a15347b04184fd2bcf9fcc133b9332c8d4c0c61036550b3a896932154d723b79891538d810c266a13349cd4815b1617382b1e8dff94ea59a3b4507189bd0b539e7d3f849b539d4f8c5767d49c369888bc94a5f2c42888db7212521a1438d5e6c6a3fcfa524fd937de7fe5083177b5713d62a3c5687d0d979078f1dc6871abb582f5365d3e5dc577141440d5d6ca364c8984f7592124341d4c8c5164daa9fc54c50425de78751440d5cacbfa937fe5e98c7f38fdd623dfda9e994c68b976f12121292f35198a8618badcf4f93ae82ea7c9352468d5a2cfe49a94cb3de0f13cd236ad0627182de5aee70999c9ab01a42a2c62c960f427dcc8f9f2c7672505aa9c377a8cfa463b10137871b94584f6eccca8fde056e4c620f97c9e4cea1d37ddc74470ec450326e486293b2e7241919b393f2dc88c4a2bb64e5fcf1afe4a518246e4062f95c42a428d51baf128c60240e371eb10975997063a1fa744810d570c3113b41898ea54e93644e153762139e41ae5f5471d2a9dc60c49e6b693178bee4c4987ac48d452c4fee3ff59fc264f88622f66ff23fa937c74c993925118ba9d81cbd831e51a249f710830a3710b1f68d3a39fe71fb74d2217652eadac5106a3fd5cfa156d28347490e528f628658c364e736670eea178f1b8558e3b79a9c93133627bd413fb841883dc54cdc2463ca5c39a79c2b1bc426d39363c990a2e309bb181ff01390dc10c4a242fda9545fe6ab23433702b193a467ac904b4d8cf159c20d402c1ed7179da44ca78bd91f36d9a498a99ca4643474ca70c30fdb099dd999aa313613eec322369ea0cc1b7c585783e69893cc743bd21b7bd83a7be4c57c9a89a92e3d2c7a2989ad5e75d546f3b0e8f029f5eb6efd74100fc6242b3e5ed7931b77d832395e69b43ce1861d1665bedff19da3981ad56113d2ae36ca88dac64987edc9dfe3e539c8768a73d8738c53f684cb17ba397fb82187653f935392574188f92671d83699f2f484bf18eb04e1b0e7e719d341869427ca6fd892ec537a74a9dc696d3714e3c8dc8bf5999440dc68c33697ce893fa2ce4e986cd8aa49ea6468626e3eafd6609db4185aa14952c3a2f649172ee94cf252a734ac3e9f2ea6e095666246834fcee4b49b5277864586894edf1cd48610cdb0685269c85cbf29c3f6a4f4537521d5c30d322ca2cfe309d9f1d2e47f630c3b398d34ddc43d9d15a71b62d8f7bbccc9212f3db811863da5a9a856ea3143c70200c60d306cb9e9845a4d191212921cc0126e7ce173c2e78ff66f7c8841428266851b5e58fe52dcad0e6ac1b4d2853d5c134c698a19d2fabec18545d599ec3f6566aaab123c1bdcd8c2a274133433f6bea185c5c96b4fd04f66612713545899cab44f1c991af80f109090a41e3d344042d281138c909090e10616d6cd37324634a99be420f54043c18d2b1cd38ea65362e3ee234170c30aebc9a492c7942fd606158e8ce1811ca413983b1fb85185edf35e0eca368e9dcc4722c35c05c98e0334831b5458e737c7f4153b1596f80e1e761a503b61b4a0240437a6b09f6ca9709b4f255df3d8516263dc90c2264e06fddab9c6e8800846708c7c000737a2b0878f1e0bbad9a493f70d286c4a5f5433f53138c1571e3f4a5670e3097b5e8c8fbf4f0afb4146034e3f50d0c35cd90b6e3861cff941ecf43b1219657c4008379ab07f9233a39c38323ecf1b4cd8be64cc4c0a31a1beb5186e2c614fba89199f259f9c447e43098b05dd3be19998c9a1393792b05fcd69c2cffe9fa9bf103790b06a25159c749ad63a539070e308ebaae74f69799e5c99bf61847d2cd7e3da7808b93887de2802016e10410137863072430812100946890083c7efd051f20b5f4440a4175b0a153b8fbe581e4fc60b0888ec629341e6c653e39d524ee962db14e37ce67052de28172536287180082e1820728b0688d862d9f097f6099fa2772795ecf8921af848392871c45a2c3f5fb3f2a749e99326a90cb4121d65f830115af8d881d3a0e40122b37880882cb65cb2d1ac9ee004714abe43c7a4063cf8ccc4a2440222b078c5fa4fac26498f9d893da3882b76d2d587ac8aa731d42ad28a354533aa7e8a150e105985024454b1250f4d38d17b92976784104945c902445091009153ac7b613f56b6a9828829f68a7f566a7490b57de6501329c57a32be15629e30d6c13c84082936253ae59464c53329338ab4001151ec41667f2e19534e4c354d0520e8a1a3240d07d8434749193e52241425051001c55699bac4d9887d121964a412bd32bc7520f20904887862115f9a528aee67f8f40f229d583429e3688226c7edce0c1e4438b1a58f4f4ca91aa346587a10d9840144342122928912088860e2002297284180882576f2c56a82c70dab4f994a6cbba3497732a746bdcd8ec43e28b188096b7238cf183fa526b1ade710955334c9f02992d874c5134ef6c7f2a44d22b167eccb5fa14c486c295f1364645e46ad8421f2882dd595956f3419694f1cb126199652ee94e2dd75237692f8a5747ffaa7a15356341061c42633c8929d9e63848816b185ea68aca7a5882d86b57e82d225624f624ecde505db3423624f67a77bbda9095ffe21f624463f9a120989d9c1293e7ca0882136155f32b2429a5cd97170bc39205288d5745af31493139f2242ecbb5a7a633488909f19c4b61b6c5313849079649c432d032282584b94853fbd497aef29103b41e43ea963cc83d02754810820b6be1cf1444be1c2cc78f7874537a827c6d0d14c873d521969de0fcb8ffdea05cbf46a92227dd8f64995fbc13744d308cd45f8b066fe26fe89ed8d5b53063b7890b187c5895e1d736c9b545fe550d381270944f4b095d49864e6d53df1b8063ad83b0f5bc9c9ea5c496692e674f8d081834201113cec21b7639ed299f804f972a8e11dd6942e95f8fd640e351aa41a94d961adeaa8f5a432a1332c86ef10630c913aecb1cb9ba4213c8ff747876d44cc6c652e3e69ca1cf6249f83ea24355a0c961c1695c9aefb491b54544b0eb5331b380ad0118943be3232c94c0cc361931b34c9a3673ce531f58665740c279e4c7a823cf3dcb0c9a8a52f37292f3c35394c1069c3621f9f9c968450fd311bd60d3a7deae8f459cde5503bbc4149b9410d463a7082119135ec299edc448d7e999452031e3f7cdc800d0c44d4b09c0cfda7837fce904e44d2b09332fce83cb2c9bd7241db2182863d8cb453cfa4b4d7dff9e8914a70b60191336c31d6f199b89b1c6a253bd8918c19f64cde2e9dd2e279fa67226558e553dee4ff049d1c226458fdd38f494f9b53df273286ed8999e06462eaf5e69e4a74a0e3cf2c20228645855395491e52538ca78f30ecab6993b0cad5a46c4b30ec24ffd552aa9b1d4a2787f60ed715f9c24e3efb8ccb448b49787a032f6c767ba262ae244a9c920c766011e9c296848a7de727e51364e4c29a9ebe53beac18bb996c61d11b46a99336fa548a1656b5b4deb9ca64929e9a854d5afefcc64b1aad662cec7741a7114fa6c9a1a62bac31e768a86e52e7265f56584f56eb54c584bc91a9c24e92714147133276af4c85fd3c3341556c642599390a4848bc49484c640acb7e9d13539ca49af40e1e64f0e0098f630211296ca5730e5ab9943a61fb9262dee7ddc355240adb46b9d1c493b6634a8946c6f040f21374f21e24242250589466723cf1b1897a4f34879a0ed28f1d3bf0614a31224fd8f6c2549ecc7452264777e828a1817b197a02e7809df79540c4098b28932737c994d7973887daede04d053d787c0919ec5d52868f905c883461abdc4cdab1fc19df4c84098b7872224b30c548562ba92993c9a5499ae2278d1151422946c22249c8622427892061d31493a5a0734a496a9d231039c29ec22775fa4f25bda18811d614314e26ea9e5067ba4811f62baf98eb94621d148810618b3b2a7658cae49bd393909ce263223284456ff4e079fa11434408ab473d277826ef9728c70f1d39283e7c94f0f851ee141f2840220809c66a9998ee9b4c8a227cb33b738a8f4986d182920f840063f313334ebadd53e7999ce2c3c79940c82fd65451a5c357f0f230e75043282021e9e13e4848427cb17a65d8209696ef82ae8ff5701f58bdd8720e3a474b2772316fbc583656ed9d50dbf909e22ed6f8b121f364f29a2668a28b4d136d733ef1935262938bcd37af9f58762ace2e5cace984d3279c6cf81493b7d836f39346944c41d5c616dba5e80f6aa6c944df580ec57183b31e3fca401b5008a9c51e548892f7e9bb893d86d062fb9d8fd17b32b2999bc5629e9b249f9c42ff8a13592cca82e690fab779b33fc10e314670c4624b9ae0c40a21f537ee3f7498f90f10203c84c0622713ec84856a08a13629879e8d8ce1011e3f7680a047c82bb64c26edcc3d2974b7e321ae58e35e7d127accdb43482b16273ae983d21cf40935b1620f16ba09e66492fc4bd72a169d94eafc266c8ac75f155ba9a4334627e6a6ed52b1a81437932b576f1a1dc748956004c74889318263a4c218c131522418c131522318c131522218c13152211829c1080811828a2dca7a6af2134b5ee918ad43c829d660e19be8513c553f648aad9a941dc4e7d1c9c4588aed42448fe58a22af47a458362f56795a86fc4d46eb28d9c14341b0438c0ba30525012044c828d63161397fcca428f66b7252af9d51551ec54048287632e93431ecc9d9e99c68054240b1e57932f1f45857f65a3eb179ceb14906d3a4caca78621195c3c9990c5ee34047e3c8181e18c1810e0e9090e4f8a1a3472221f141464827d6028f33a8045286b2481c0c0502410cc3000087f6e300831200000010140d4603f28844289cb80f148004443c2852343a242a1a14168e876281481c0c0443015118140804c3401445712853c29cab03f002de5f1005c13d419b60442bfa751d22992c3bb84c0a5d21f161672de39989a545a6aa7fffcf72bde1253b7c2b3f720cabed2afaa8b1ab2311c51d08252ec556d72faf0e17f021e9c9abb366b8e2fda76e0842f3599ce0e98438401a011f86be770cc7bf38433abba3415817c075057daf07f3c18b16044cc861440df08b4d5810d557ff32ce94e690c47baa2690525d86b1199101bcd6b17dcd1f2dc345d317adf50134f51480eefde33e15b4f388e74b40afc5ff318736a03c0c7aae000439382afb73eede83eba86a0bec9606b08e62d6f2d03a2cee82d141cd1be20b82f37cee4e9db3bdb44c7dc3ca62b492820a138823e0e78b5a9b7d59a4ad81ad32533784f2dd805fb77662216cd3f7ec1166503d47f4a65e72434f6700dcab7d8a273251ddb5600210ee52e3d836ee7c2ca650abdc6bd641f6250e8bf7dc4e19b804d3d3114c835045be72718e0a535176c4c8f0e89e76c9376e29d95b3809c1bf2ca278dc1748fa8acab51118582dbdbaf51d8ad4cd13787c153272382968583c25ca8dba193599a88b149c2a8c72189b3333373165ec8430d11b0b6085c6e8879cd7ceeb7d385af66b3c5226ed0b018348272d73410283a8c86d249c6010b03361fe073a7c51d4896fd5e36e80793183064f5377918d38ea2e6e28a21fbf1d0b32b088114b32092714eedceaafe138ca5003f714133b25d84ad8d7facf050dae5ce832863513588c134cc56a966bd480523e0e8bea7fcc0de719fd388d62a71bae11304c9d386de9a42e4f7bf33a4684634ed4b24f3f9e013e4b61cfe95784c268b69264f267b384618593da5a1050c75d77f2c0f5893aeaeff01834ee610cc87c2c48717c8678ec6b163b8572c5569bbc62248e58992628e08f62b453223f99d1ce1f9a5097107c469361918c9666265478f5419786b67aa1dcde259953402f4406c949947309dc0af40ae1119d6e2aa6287abea1e543fa30255737259704b72abb5af8f745b1d0e1c91d9e98df275de2596f6f75e87dfa9feda8cc00549a43473a59b229e5624ac9dd8b1336e53c85ef265964e166771b1abd32ca05c928f3c6733ecf3990456666da0b11704cb324821165466b704f249419f4f4f638e2daec00af6d39eb8875193cf7d2638fc04b016962508c911b764b1624c352960128b29bdefa988c9a653b94227484a8d243288aea110e8d1414700747fbe56c09804412b09a0783c444c5611dc06d3e87341c3e2cb5ec2822e15b8ca41a6731696852e4c645d6aae4ab1693ac9d4013b7d70d9680e78d3190d7c680b736b265a3491d597a4ce823676c2e94654a3afd365561539f60e11edc143f5a19142a7bc0ad1b2df36739eacf4cdbc4b1125f966bcef610d1667038e8fe345acf4cceddf488316422ff530d25021c35ae77822c3156d14be193f48b15402b4d2b9f0263196401cef79a8176398669d6166be9d0c0b47b93095c22fe4e4d62866f9724417da7129e44770fe87663fb4506e195138255ade6eab526d8b7160890a7792d0c923b18477212c819bac10048084ce43a65484d42954dbe863525fe1b24c49ce4cf17c921053c35a4cf23b125e7532bc93798383aaf20aac52e93b4e48b11ba05f9b7ea31f20404e2f6f9a0d17e0071f63f8f02bd12ca26ef0a1b022edf1f7eb015d025f56a08a92543b008c8e912c8bfe532d3f20305fc1c4bd8659f427ef1008d1eeb9102e9c9a606ad5dcf201c8a2111fd8c84464b6507fd49557464ee573fbb98c49464e8bef3a2660b7462490e409199064593bb81fa8fc7b112aca5670afbc31420e0260cad83a22692b78eb899edd4a20edf43d5faba75eaef28a1f7b83e8917d83030108d6cf7357a8e7040283e57dba34e3f556e3c4196f112cc3443c4f47c937314173566c651c1423fbfe8192fed93833610b01ac461ff9503db1d3ad84ead83cba5d2ee8cf3d9da4a38d2f1c14e48e78685fbe049088027f48c8308bae5c314b66bb7ef9dd05529b0f2d90edf7238c10d4197b043f0926a005be020ebb31c4357c32da7493c290e1054d99a105c68cefc01622be28fe504e672fcc8c1d6a6467898313d3cde1b5cd08f7c5e4c62a662300f58b4a5912ba618308a71d067b41dd4c675cc4972ebb1ce4cd2d40030490e0839935c7837568123c563b0c0031724353400d049cf2d27c3a58e2db141eff89ed97044b6100e8df1745aa928829b0a85342cb97931f64318cf44f298d543a6e6c64c5941b208e82411428b3dc11ba7eb91dc0317c1f9b9c78ddbe2ec689188f2db189502050ba02595fb06677e8b690f379992b1f81a49a4d066190ced091fa28f3d20db11d84015777bf074c4b4c8719606e0ec4692e210b17e32bf4a2b044b88a615f4fcb1357aa032046f34a1f9f1164e896907158c935bb8a09efa1838a22455fa278bd9a241bbbab3f36f7f86d76d54f2d9db2efedd0930aaa1e824e26476423423b124fc123e9226c35624594cc572bc37695a34ebcd922a420da4d6ceb513e873e5988d80d8652ca2b340b3acab2cacae532bd5d24b27407f51c64346f426c66e71e6f99be5c6d85f8ce6c66f1e9ccf12ea82f4477e7f0f71f3b9ae48a42a4b695269118fe48363e2e59e13f5e7a11f84442ecc5b3029f90b9e1cbf49eab425176ef6f323355fd852e6d9ce7a99aef11b853fe79dfbec1efc7cabc316a339f8014c4272ef06d15d668d7b5db1fa83944bb8f575e802b9faa56739875809de415a97919a73d802f25b723aa1c7a5019f804b30f5748750be338b450cbffb73ce17f10857daebfa09696e3c508537627fd376422ae9627f2c00165b5be65dc6298c4d17b47f99d3759cf1804e9e0a39434483e00e1804edf014adadeee38c2b8faaf484fd82136306ffdc59fe2abcc961a80569394e3a4832941eea296b6d66ed0527b0a3cd6940c01592b189069509d6ce49b226972f62b97c656f42b64e261dc9a9dafdb281a2cc590b5f08cc56dcd7d2adefb1941c0e868da2856c0b6bdcef641ea325830ac380dcc3b59e7a0db87870dc033229cafd6f72df880625be65b4f602805db6896a17771f7e7110f72cafcb184dc63573188b5a96685a9c09b1ab7273cb29f16962522aa5b1f231ea9f7ae66b8585d37a08755e042425f06ee98ad7a00ec91ab7040c501658ac3af433a8f27b76819c2afabda684aaaafa521aafa53ee6c30a6ea5c3cadd0ac34a7747e9b1cc7e2040181b88f1f554442c5cbe229e71fd7100a1f72979b4461472a821dac9fc047015567a53bae049ce8fc88eb4c62471120bb152431a473f3f863582486d6186fc7d8896b201850f2afc81e3046410713003d7335c3e9374b1b4e06c22d0065f3b7ac833f60f7636324ab01ceff1098e24bcead3aa77e1dcf06af52583390b65eaa0f7ea0df723763643c57e53eb0435571d7651b765d22428b73e5ddb8ed8ce8874adacae9c5d0dae0e0c67216617dd34a1965b761717ac7c9b13d288f299e822678002fbaf12cc9431666422ed926c48445dfa9e30f6a12c1af29fcd019bfadef9616716c9994d980b134fa8c52cb68c9b9029f61fa85faaeddeae7e44b1383c01fe6257bfd1a143e03e75080450a3a40babedae82dcaf9461410f41c9b4a85c36cb050cf821adeb1f764a325bb1c63420f87fcd3095ccd331f71fb6d048b0bc6ca29fcb6f5b90f0ad0050127fb1460c609ffd501c2d12fb05b6dcb4eaeba879ee24a39cbedea5f358eecca4d917f56c4fa1d364b3be19a5d0c39d5f6a825b9253d3c65c430fffdb96198839d49e38d0a8d3d258d46e91001702acf101e82080413b809cc9bbacf0ba6809756fab088d2cef3ccf83d6001a626feda6bb08af20771c9b3e900a1ee2a3d3b1ce1ea0a7b1d59b1f282094a13190df2796649890af121316b52512c70644301f1afdc92253ec8a32846bcaba29a25f84f020d176a6c2b82c9cdf35aaff406e7ffa620e14e46cb6b7ac27ad38724d38e561635b931043765aa37341042074f52d7de6a0ac6cc4dd06bdee4b5c34d6800c1b041df8339079800a8d86f840dfddc8605881570eae86c0819f121d806efa893a8ef809d82da0a5d8c4466834b5fad352359cc1140da10d05bbbf6ffa6e92cead8cff7ff9a17ae1aa79ecc242fa6a07e39805e41a80c657a8305efd8adda5231bb48ac806df27491db48225289c77239d7f398db5d33a45d1a1888b4c4de7c3e8802ddb6989fae2e9e1aaad251119b6759d9a13128fd4dd0b5248cf781158dd78aabc6a92155eef40fe1ae2ad78b992f7f3402d271efb4380c033a442df6d43429322c88dc56316327804d533af95373f618e8007b7ffd35649056b721017623adf92fc61cd665da3f1e72e1874780d13380544ac682c5d7c3d1b00728a00c890eda90ccec95b07c0c04a8c28dd7f1097d88200c0f0dd2211b09ad003ff859b72c1410aa94994dabfdfd9d7324a53825d833f61f2bcb356de9d16587663790cc74ae0fac56f656a7463a491975a72681f51ab1d1033eb58ebe7f3ad3a4a4ff10a70b206c741bdd451d2596c9d551f10011484ad9aa958ff4c9b84ed85bad557a447dbd15c9364d791784eff060480c82259113de2c14e77f1b76d77e3f29ce7a6550b1efc9200b64e040958c5f678e4de024f94deb6e7cd0211e3075bc54c813e443b81d1f5ff11dedb5e834c5446fee50d6b3a4d709963b2bdfcaa30214f226d0713b5b030302c23a86832ffdeb3a6a176ce0a07992f65185528e2e442a638febf251a7ab6e63170424df86876662683efb7f8307943eaa4686de02a78a391e70ee96e1e53d5242a8b98787fe8b18e1449bd735a7d1ab723e26f6eb5e6020444bd2f241b99aeea210ef444a321a2eff274a465f8c5a81bd1db9dc2d937b30d111ac7f8be04f2cc569529b537cc1ede09269500f5b231d42b0c42db2dfeeb9acbd0704ba977fb89bccc17e6f1ce35a06bddcf67e8e8264d3dd17e7c6219f582dc822d6a182649b66bdb02e20a04bbf9ac9e8cb83e1fb92382a90c4926d2a2f1ee861522e5db86e95364c082bf0bad7afac1a468e51399f1a369bddc458156e80083d249ce50b99497be26953416f45195ea61f5852e5cbeae1444dcda4f80fa9aa04509455c77d4af9f2369324500d4263ac0c2a6d1ebbe2ed3e54c5eda15d10c399f9688b982a030b1ba9c2245bea2a265f1955110addeb6ebe047d2f5fd8a6c8f57cda8d93f71afcf924321d5501acb0911dd3a2587420389e152455ffc7dc9bb888dee9cf121ee1b17e8438ba46dd9894f87cb9c61f25c325883c9bbb3d204cbb4782e8294c7b9376df47abc959bf38bb5d34708e474355dd154d103994ade72a1b9a0ea7b9524c12421166e5189274601bf2962687343ee220b91d2c17bddbeb1f8c44dcc06be71419f6d21e158d0a8d30a1a182a2e722e315257e6bb3d4dd6176d6213a755736bd8cbf558e5d559513740073ef768f305b1d79ccd0b603d7dc134bd510142fc457b566ac089ab074a3e77ae3f8c70bb4badf723b659bc7a9b382f05b998783846e99109e71979e2d7a08155375690287d5fd0e13ab5d0a89dc47b22741008f21458cffa3ab1e2ff2e4574c83650070cb5d802fa739c898ba83ae7a8ed24f86e4a03a4fead9c2913b4b805d2ee3540c15c1a7a1998cda15bde1e0d0c08342057076f0badd740a17e18cc392e62a0b2c000d164c6bf9b47634603e2186b10f95d4f24aca00b6bc335a6efa4db5686538c55edd3693c0ea119d5f99eb260245f8354dfd2857347f11c96d95bb2808384a352eb5d1cfe9d51922ceaacdce18151bb4fdc842e66384f3bb63d8b6f598ca9b1d01ee2e740be64b7f06e56f460e78df6b0c640c933a4cf406a05ee27c9309d213b9e0dcf14e274967821eaa4abef560c5f19aabcf97ad91d57480cccb0190ce3ed2302ca955a148557e6642f15c99cf65b74327e432083bf68311fb932f6ba0106ecd5864c417783ecb6ead9133554bd0cd6533ff0fa5c28fd0651b1d3dc49c5a68077a8c5be0c3ab48159f1d6cec2f497253d3bfb6cba1b7d200dffe7cc43de3e45ed53265cc0faad1a4b0e64a89bce36e259f39348c1aa288953f8ded0208708e2b44d380528db9d848946b37769d4df229016419fc363d5b1c758104dc1b29dc776aa63f9c2a2330fd4a71ea050fe1ac7f9266294af6e6c874faa1d517e919ed8639bb3df5f9b91814bfefd9555c24b87774009cfc2f241abb654e30abc0b0678111d80ea8d55bbb91429c865f3530abd111288e0dc8a6af1ea65aba2e68a2d7d0cde8d38ccc4d610600d5270626de2f6a135c55f953d1c8082edfafba064d3141c3c619aea7be4391f04998d0cf1618c044617a0a75f0ba79c18254fa91e215c4f6c74de34969b41007e2a9d0efdac702cc3439fc12417253907f270d788642de5211d7537a3ae509f252395380c7d7143b18b4be18007d23e803c465295059bf975d40f454d8f7ce42b8a50383a4b064e6c2c2267d5b777ddb66dc441da4d0e75436eefb0d8e1e7ca7e72572c3f7b6176fba577c74615c56030d2aba09fcf3c029cbff2ba9b425ab9ff58c5cc97972bc92190c743b16d7d350b0b3074919a14036cc9f366780c0171fdd0c2f81a810b761e35d7562fb1d2688478ba538d3f16fb6ac7ab9a326d543c0be3ce839373385c4c1d2935d1c0cebbf720446f4ab192d445ce3fe18df05a0f6a8e7748a158e183d4061fd5e24f583cad09c3a8eefb2317d70098782bdb2d8650e328831d910ae710995e44b330eedad3fd78bea97363e99c4252fe8c3a3771821f130a4b4cfb874873eb1223cef34b1161ba708473e1e32a35a4f0060f4645f066a79c7003e1ed7c1603540ac2d0c02cc416cab49c0c9855a979af8421c6261e88b0b05bf929a6af9cc81655c814c36c1d65ad05d28b16bca958555fe64566b1d5c45117ae022804398e888922e8ae1780c303afe24c22b444318909d11271108d1038f73a48f8e048f41d34186386784f9e758732980ce54a072a2e78993dc83659df2acb3fffac17f46160bab04e76c6b7ca6fd164deb26bf07c87ba221aedb4cd481b782f20ee26a4058e7b9d32434f6cee1af0d0c507681259e0af47d3fd88d8327ab8e7545b3f3bdc6995341f9dfe688ad3f00aeea24b45d609c903832a19bedb49cf318c089253729b322a44651352a92655cf274bc8e3bf00ed7c49caf0b736fea61d0817be4aeb9a8a72a51253c205e62cd7a1555ef912b5b8777983434bf4aea6063926e76a7195b630978b987e521c7d9b0ce661c0c48637def1d25c30385ba43404bbc9b272f60ab0be2000c9a7d688bd68fd76ce490b208e6e6cac4e15576fa9c5663ccb0751b2503be6471359dbb6a6c869dd5686c9a721ae14cb0be900a129958651ff74d08bc7cfebc8c129c2e4fcf009ec9e3358a7ba0c7ccb3a35237d6d3739973872aff172b4a5ec299c04ea12d330d5f0dc17f44f66cb746fddad21183a9f3faba0c4e9b27b098b801a2daf80ace7c6cdfe6670c07b22c1ce1f9158b60c79cab10f952dcdebc4cf566082ba873a6489ec14aec7956cf4dd830bf9b69707771871968e711467eea4d1a91f9a4e2deba6e4ac181436ac5f567d8ed0477cb8f3cceed3155218acbd6175408787b752d86ec14b623c0630651bb6efa536f162a61d50a9b54116f8f0f40d80d41343959c87ed4c7a2c952fbf816a18c175f9edea3142a50421fc096fc2f121443b438b9a84d11d508b32ee8436178760a171ec64c5ff320b3d09bc6be023b8f2dba1890a58fac8852805b669bfd9e5e7dfe3185e43ad036562b471c0428271a54390f5b04cb004209aa0ff686615a533f9c255b77b83a3dc32b333b59f19e61cc40171ddf1539f705c1a1cac61f94e5717a682775b3c1667b140b7179bbdccc3f0f71a21a578f76e876118789d9b61c13609a1f1af97c51f8cadb8df3849b8f01885cbb56642df0e6e06c5c18a1aaa7ced8ede6d90bd37cc454394726d29bb1d2e4982dc41a4ed59f13040b5f90842513ea749c89989346e38b21cf83d452102670c31c12b8c57d1b7f31312bac62131e184f4e52c43ae33b9465e8cf74046e6bd9fcf3bac20c64a8ad0686eb041dd7da1f13b2b039280a59baa6be0b1dd423c977f7231842e138df21d3ccfb2eedd908e0300103420c43f86b9d82d700eb1221111b409e661859a2dc2abdc8ebf42e87afd57ae2dfcb8477d6a0d7b105489e6f27d3ee879f93508154bb6a429b0295a60579eab95314f6eaf791fff39d11e107d9bc68a39c9ac7fe378ac5865ac29ee9a89f6fc2cba680717473384aa7b8a22db0adcc05b10dde44867ac72cae701c75c731e35408baae07a122a158c46002d84b41b0b40cd1b93cf8c294d1cd011181c3444dc66cf6cb5cf50590f523c409f67ac41a2b1926b5e795b239929fc98e055c634e5a952641a43908655942093c9c749b009d12d1aefc15d22eef639c25962961589305a2cb46b1c914136f3319be79c35baf402a275eac80e803c09b2ed8e8999675e7184dd9dbdff4a27793cdad27c93d0ae24c1734825e982bc130a584fdb3b696802088c96647a062c5d33859c1698fc02c2544a1c0628e4215018a73ce5cfd3f8342229f912287eef4f8352d8744e891a01a8a0326730f23e8e8675bc6ecb978c2084f1314a9336e1292091bbdbd99044211385fe35936a241508fadc4c4627100020d1c011bc93a267cc6890d0190dd36b77bbf15b30c3f00d019240356194287be21429a6674b7d808492c8a2ad41c918a6132dad89aff8cf91c7c2cbd503dae097a03216a164742931109e344e9896c48aae1dee24092ed2ac2f4ac2c94cc8969e09928467d1bc29458e896cebac89cb2ea49689a81981ed18fc151bf73e157da30baf56e731eba7cfe49f9016dfb45f31896e46a58bab2396c66ade4f5ac4eb4c46ba7864288047aeaab487896aec9e791a8da946483d6553c677955787be34c8a45208e0e4579ecc0a895c9f0140c83bbc3ed575ce7d61e6b412e7ba7ae117fb4921f5a19379459d278021552d71529c852729106f2a3d74abb2a6d147db05b8357ef443b360727c4e6c69cf817166d8f2f1211be9b15028f3f4e107de8912bf101e7c31ced047a41343a47a7db8ab41c0be178cc1820c32e852e16979f567811a10040699c7b3416b74da86c308719a1b932a2eb7cdf8bcf8b80d3c2ece080da638289f461b8189c402bac6bebc79362e63dfaceda8e7eb08029fcbdfeae0460d16d288d0e8d1f8a0814e636f83183af396f91eebdc90bd3be601215f6118a7b886e86596574d8d255169448768a9638d0cdf630d2836ea69fcc9ad622112ec00a2174129ed71316632ccda97472292f7dc24e977b11bb6396d58304cdaa29c042e26f5c8bff821e7ff86e3cf6c0a4a67662de826760b1a9de97bf0db685afa2de707a45178cebe04e35f461699d59d496ad5000f237aed77153b7c04674c8cd22b8ed98010c25330e88f8cbc0985e3dc8ae452c50ce4edf5238046883a34199f7c0fcb281da9cea0fa3caa90fa19e42c3bd333596ac6ee10709a3d206a8d5fd2bc5158972dabccc9b8d8bfd1dd170bfced2fbd4de81df8e855ea8346d269d4a61bea886e1af534eae88e9ba6be613d43b1b1eb885bac87815072b894a76f527c80bd41d0bddf4099f04450ed397fd9ce40f71c79b2c6d8837e4ce56b1296b6eedd31619ddad622c7b26db0e68f6c71e015776ff5a668eb061d85a1130c3f7a1da1a9b3c8c21f409102e84f3d5ffa04f216e21b42933176acb9e470a53bf476556331e9c9ef9fa50557ab96a70d152d6cf4ce8e9906c3939cb6f669e0074d8c3574b72630106a9a634440bef8af246e8976b33c593735a054f1d15462261983abd4417435246ac668fb0e77818c97b02976ccafe52bb9c93f8f59104c40345020e5087f06becc3f93e164cd72baa6d06afaf7e498894a4acf1c9a2357127a1400abb74e294f3ee0bb4b83e960bc176f66032d8bafbba0b75577fbfe04fa09e5cda58e202253f89771aed3d02d805fd93bbc1be07870717b0a924782fc3aaee6a6415691a7ceeca1a6dc8c11829f5bc43ea84a90378903054f46b75c76248041d16e6beced50c855506ea670d22c6038e486df9f5c05f988e72236534897a1ac332cb14d22858aaeab685fec5b5fe802343154f86672761ad2b7986afe04fdaf90077eaa3567de196377fc8f211f28e44080b844b0daef2f4fb74ab072357ae4a43d2fcebdc17448c5af2572b32b3f083d85e525a68dea29cfa3f69c47bbe0c82ceebd774e725adc2a886eb282e13eb5978564b86696deffb3214552a2805965926408a32084d0a1de2089858ae0234d8077e1262200a883dc181e6717aca51a4345129528df23d88de428d7279869abbb7ae5d318cd03e93663054d9fdc7357ef6e156085e35938fb3048fc6c34ad01dd5320a751a85a00a70edadab6c4c3078c13ceb8b6901b1534ca13df6c80eaeb2d55268ed6259c231faecc44aec5c80ea18018c036857aa2de6501744c07406da159ebddcdba7aa3f5a22753925c4c0c64be3cc3444027deda8460a04542d300a7a2c7b5120974e4d2a79b0375688416880d4ef13b4288f034e08773a15c0fdabc32fa9dbab4cb88d5cc490834dee911921c7efda6410f3242f998d8927255e2e11a8502100e21e8486109c29fc5d937641c399ada7bca160c2ae59597b41002d437f357821e43a18ee987b0d51db5fbc297f99d2b674391786444af195106cdbbed5f1d42d482ab243fd5bd84d7b22b7f0011a86c412b608ef287b661f85b17926c6f736d27b68a5317fe69f171017894a9e86c2004fe18551bfc997269317ab47f7feb77c548acd38591bffafd19ce3657e6d41e02a0102bedc838dc2b8fc5e3b0f5b23ced23ca0abdfd8a139b23edade29f2dba162e19231e014d4ac645f2edfe926a47a72eb19a0a92211e82e0a8512e7970cf0b8103454499289a1ae9a031ed3c5fe909a94a78a7162538d6cf65cd647534e66e422900adb70e26facede83d5c0f74a58e1c0548caf3c394cd28311e25cc1d9c4550084b46a268fe9b5804af223575f28c3f528896e8038d68edf1aaaa36b3b4817023a3dbc68a69777103bbe534ed26752a078270d61d19d938c2a281095bf1e7466581a28484aecb5d80befe2e0a98c42422d06171f6de6c9b93391483035725f80695d4c727a688fd66a3152d40c38e0e444ba1d51d275bc1ca44754b6381620f71a88059a880a4356047134f066dea2b58beea817c0ebef12c8efac2faf64cf01dde0544e63c41654bf768431fcb461705600e3329af9c80bbdf54cfd893b9df23326f73ae6f68f2d61b324b96690157cb573ddae1e1b8d5e56ba3f593bcc1c051475d53fb74e7e3c2b31f59e814422926668df80b0ad9791daba2f99fbbbcab2db6842bd3925a3d913787fa317cf4a1d24b16bf16449395ec5e9f20b2c510bfb6f72e346b300781d56c9a824280ee41a5dcec4a98e864b2dbcbb7847a43f81d4601ada23e740ffb14f00e017c9f08384878bb4a7cf3c5d04feba2fea7adf30ce2f2a9d28c4b05375606e1a32a3fc8feb711af27d53dbe69e9bf1f030eb11fa050609b6ad46547a06a79c45e81fd4cb335701a8422afa3dd182253a79088f25b57e74941c91d96608025569ea85cb9e2ca43080be45b16ad759b72d2a757317e4a8490417e1cac6b27f836bf91b3a32a29e836beeff2ff9dd09e27b659fbabda53722f5a7a097b6e380b0dbee9e1ff9682f73324d8dfdd1087587ed7eb96ad2468a1da258b069819a0dd916591e2350c910795ef99d9a51ab5e7e528a061556d7effde0f5d085f445012d6ebd3bc7e2994eae111699bafef291c8a2558b1524d0438b06a43b0bbb0b73000f201d38bca0b65ba282b1e8adacd34e5840e2ddc04734b278970a069d780fc3726344956dbddaaa5b7f52e26b27c6b8aae2538d55b3f3cf14e4d0864cd5270ea33f17a634d1efca09cc8d778fcdf3ca83df3a4dd9d79631cd513fab00a7477655e67fb081b89f1c76158255fa493a8ce7c257f154ec42b76bcb5da0ec927ee3c1013388165b5589d018d73ff1ff288a809394db48cef4a6ff8517ca39a8e0cc76559a391a9720fe889f855f9ff4620676597a4c697617317ef9ebcdc085abd3081b34a346f600da8936a425ed975729a5f2ce7adb66736906ed233ba4dd0de82b9cc01667eb05b75e3be60fcb5852bff69cbd3e494f058532af2cf03a6643d7ad7d077694b010b4e3c2fa2d0671cf53084718e1cad7091955ee69dc26c087bf0dec6028c300040654c02871e7ff9f151cd7295aa7f53aa1d54957a761eb74c35b277d9d0c554eb043391b5223789745bc58e42a25d73bb168c4aa23d65bc4186839349c38489d4082a6537a818de221617921cd052998c1653bc894d19e662e0038c8dfe37c25f5b9462c858f98aa78da29a1e96d8ae74f589506421ae6a213b29e98e0e55caf17f63aeaa2d7f694329509106f8adde2490ed0c311d48eec59da748a37a6f23c131cde7d0cabf719e3ba76150aa0f91fe2bafcdd865be3aca11a73bc555838cf8241874cd8b0abdeca96f922aa62780de39bb3148814de60caba335b07a4530ecc0a961b062f884581e5202fbafee812a16b115dd5a871a16b145ded59457804a784a81fbb70f9a76a1100883fccc97e8d25673dd981c5e40039630316143249b7cc5c1e23076e850a7ddf1200d1f3340879b5c8fa218449e5e40546130df869992c48b1187f91c72f2589176374cb3e1d9bb33c37ddef082dfd8a977453838025fbe34f5d834fa1f0af13da4e633da71f39d966a02e3ccd63a102507d3bd5dee90b27f570fa2d1a0895063fea6ce8e15416ce5b2d63fb9638932d78f7a2145c0356979149d1907e2e2e23c540b254ca2946fd938b16831d894805a2dcea071ae1ab4667c94b8b18e85b7e8f06055f1162a69644a13b226d70e6ae0960fe9af1e2524dce6b624c396a71965bce532de9b803cd4de8038b12bd1334a4c2071afcc2cea40929589fc27cc08ec78326e0f9ae7487a15130a5e071f1bf9ebd45fe11b3e60193fb2d88ce77a3e16c4db707735afc44c07ad5070d497b7337cb7a1c9c658db557e3aa671ea8db296e40bf50a803ee0332b4ad4c13ff20f95f3b818fc4fdc05c8158a6b401f274450b80103d4bb980299fbcff9b15155b0aa27dbc01363b27f07ec4f11eb6453ec58a5d0276f104085dc176f2762c8cdd57a20d2c73f5b716afb1de70a01f4f4f9961375233a1f81f20524761a2c790d63cbe76b3fb465dbb5e34ae9c2e9299f2f22adf8b4f7a7caea779a10c861666a34bba9c5aafa25734b874e0442bab47b4af6ee10f2751a6f6a6c099ba54d9c05468556a38ad577f8451e532133f6cb3e780bc5a59e6112760e641371abb3599a406c1e4fcc0fc6d10e0aadc513dc54528f3ca9379c655079e9c52151dc6f8b7f043e73e1b3dbb743948de1feb2bdf737e4c7a7c0d01bf8ec71bb1226a036383d6d629cb5277b21224bfad0a969a6f7effd2dfa7cbe2cae5d82ebd7302122ab82c027aa5ac420a006bd5a41dbe8fd7adf59f3f7a50a23e632690f1f72a6959a0530c82227f4fc3a788e85912938914dc1bb24a5c7e551fc8414dbe97a8b4e49b34b7e4190c8322fca457e314084ab701d77472e0b224e8f54d140427a75d72e31893eb148a100ec19ac095b8d07d206b0d6e1a83e199be92d0e0077989d8f291bccba1a180759068d93e9b6142a57662b3a8326a367198911d95549400e15007501a141d0485abe7a41ed68b05166446ec1e4eeba7a1e458d8465944b330e53f0930819cb6742cb8ec43e1e767a370a1f291908ba587918b0306b73be71a95d4b8b8ec873eb3f38ed9c5ca60004882dbd9169e4c33e4b0e8f22a56a96a7f4a40a2aec7fefbc3faef83f3dfbc8b54093a463ef90f215a0e9bfdeaed7c98b628e33f97030f85e907585de19188a386880fee10c1e154a7f783a5c6cd95309dbd329edf93a9065f1d92080b5f21f0567b67d64299e56542ae888674b329fbc85c8590c9f6ce5d24b59cb9209ede1f6c35c2e089e38dcb45a1f6db14bb2f737d9b96c3967f1492bd7caabab3468e7ee4efe1d060d0fd847424afd77bd31aa307ae9ba89dd70b1071678347accf144f73057736d4b5428e43d923c88d45141d0c0c1ce14206b7a05d13b02148040620f51ea3f7c9528b0fe68959101a4c7b1004dd5e5008be34517ceba6cc390f339599c9f56f498c0618882c2b8a450392bb9b7a8189e9c680bdcace5bb9635cc59d777e7d482b5ce5c9f47b9c52d4902434d52f70e0396c77a176451a5f4a326129cfc14cb39b82289f4d7a8a52b04b3630d8143d2e4c93a977c4aa9a1bc9f4d8ab57f0b4f8cfe02d4ea5612e7efa2e7679e75786a105e9468baf39697a46744c0a38576d12bbddbfb17525468f858bdfeb7685d596b170597f241e95c5196aecc61145a2630761535e354c9a45592427b09ca015687ff28273566c36137462324cb4988c72e669ebe18e1658916f783516d0d654b9270d1e1ed3368b11d81090101688bfc44d9ddfba905fb444c4081b5349fceaa5beb0459fec5ce293c7166fc9ca96fb852d3a564f00ac1fea4d720aa17b7b541f916757f3f5ca76e9a445ce5257ddfc0e5b634f30d435a13329b50ee84874211569afa5416668f7f63b57dfa97ef8ae7476e87023d35d923cdbdffb299c5187b3d263264e6fc78a965b921c6cf1c1232a87ea719849d237316cbc4b0be3d498798509f9023ce20c96ddfb7790a0b733cd2c573dfe596be78ad48a064acec653a9c32cd0805c790c786ce381fccf9fa9d505acdb6e274443a6bade0ec230225e895f8e1e80b1b0e64e8b76913f70baa6385c654199e6ba58162bd9a5007713cc6073fa4f0307dc43127f957365364938503452e9e8b59d9e25434eb611d821b415c68ba2446b108c82e9c4a21dba9ff6cd206aa15c4fccfe48a9bb32bfc69eb50a6594161858b1e3619d3178c48e7e11fa7330b27f5ca8f58fe89cd0ae0003326076123422ce39d112ed30cf3f72152908815c8b1597d5be0c2027d9359dd3c537f3034b8fad11c19655250e90f9cfb725a9dc2038e25f4ecee7c146a05bec0c45ad0264d8ca9b6b87ea4b4e2e6df4295c5dacae8a2d3e6af714e9a64ad80c776c493d0d815922b779248a748ed64caa392445c2d40464205783c11642a9898590a5486ca66607ab9daebef2768b11bafaf4013cfd77daf1f07551d2cb692351e9ed567404361067ee2f83e126a2d08a7e9325a2b0609c0f5214c9d4ba8b3af43e39c5ccb2d040b91a949a636273f996eae271f556320844f7b733c318066bd4259d6f4c0543805316db757992dfa7736bd6cf9c8809911e98c89b3f0fa10d1f2b0e2e6579cfb8a024b980d5521c3fc0890e99962d63b697183b478d205aab035c80d67a6062f16366e132a1a49b697422bc93d1457bbcec84c7c538ac1e78f1b592187eae7c3335ebcc2dfd227942deaa37ac1e03b70b356286ca5506979c4a3e348f33ab2d89082219238fb0d4a06bd41e4c66257770ab8e761395a5ca85416621dd37a56bfbb20dd4990651e02d89d2e8b074b63553a3a2f16615385d6e94cc89848456c4587f2041ecfa832ee793b1c72891ac699f693a9a7837e67bc580fc99c438564829ee52412d4d61abf9a33643e5e46383abd92f802a367b9e1868f248f35a62f5615bca8300e21116be350f075417c7100455b681b88893e21755c65907773f3a60834cc33014e6f4a4986f9daea24f5638da155d68017a56f6613b50b024e9f3ffffffffffff3f5a75dc64e6ffd0b64dd8d6acaf362153da64aa6631da90022ce04a99524a294536ad1406c4a981e02e36428a3d3f0f06061706f1058ad73a465d840b733dc943b361a46b121b5c90193a6a82877e3ea8129aa3c8327ff1401acac0e40e7d8bba724c4678f64e0b2e4cecd0bbcad4f8f27c0a7fc9aff182bfc0f226b0fb1a2f78f7581e062804933af4599072ba2d83b89e488756095fed59a86a128fcea1952df643a5143ae88f4ee4d08bef52f6730e4f3249993874f2a6ab5f060e9d8717fd15ea29ab93ded0885efd5aea8b9d64e41337342b5ad46f3ab233c6b30d7d5e2d335a284dcfe93fc848171ef8c0840d9d66a96ba65cea76195b43635a45965c3dda2a9a0fe6f32520395143fb514f4e680721a2828c9498084cd2d00beb9d62a25cc7930f0d9d346d328b392f68f925cfd0eac7b8ae55468947a5312666e85767b9da41630e71a2084988c862b687cad00bbf794d9614ba7d5532b4a51d7dbe53b3ec388fa1cf168312359ddf5f1cc5d04a55d5f9e596bba490c3d06f901ea4d4cf926f5482a11132fb08d78e599149932fb42e2274901b9b78a153ca75d26e4a8b52b38bc8a40bbda437af4cf12e848c41132eb44ac82c42eaf30f15ae2df45f72765bb75cb8a434d142fba3944cd3e37ba6d52c34a2fea9556749ca9ad2040bbd1ccb3b79f6ea67d2b16072855e0725e389ae0af3193b3a3a3aacd0bacbcc46ed498c6cb70a9dd8e052e876143daa35a1422ff473cf9f1ca185782753e8437b3cffcb31eaee4e071329f42ec89cb74d55355f7c12854e262d782617f78d7d49486a0114daa4cf5c2a29c2b5b48eb1c1e409edbc283e6a969c0e959138a10d231fd34535bbe99080c8f812908f2674ae33ffcd3465a8463d4a9ee447ee823061421b2ac36a59e7b3ec64d610f1f0f4239325f4f12d2af45cd854cff9605b194c94d068419c6f1c8db85dc824098dcee26761b2e775d626c81719c6648c5e6bb9cbabfefae2437ec430091324743ae48328b9bf224d76845eb5e4ad2575d4a183c7088df4d0d3a14ffec1c69322f45a56ed417f943ac3bfb6081322b4657222366657995933376332843ee7bebcd232b48e5aeb1c612284f63f89d16aba07a191528971793799f6aa1320347a72a2c4f774e8fcea1161f2837ec5bc65253754cc073fd846448cdd0a263e684f6c8c9959ec7c215b931ef4a54bcbe8c27772bded079788888c1c274c78d089792d6a2dbe8ed9735c111729f0b8c90efaf78e975a854ecdb2d89cc80ad900da62a2835e162d29d99895ae7b38c941fb237e85074fd79c632662b45aeeb1f2a5cca19a9fe0a0cdb298b5b01b57338a15321f4c6ed08abed635e1aaf55c09c598d8a04fdda76536317152cb59b42a345cd45097e5a3288b36a372316a17ef4909cf079bde5a09188f29d88845f3a9616526d129e4651016bd2cf36521ab3d42bf70e3157dc76f10675ace862bfa8f614597c8d5b2d0ac159dcef3da84562d4dcb723ed858d1896b41e643afdcdebc193656d168c9792db5d259cba1df05614315ad77abbeacbaaefb632b79a099b154f43147917b72e265dd59c0b0818a46f3aeaab869ef368cf722644fd1269961b398f93b88464dd199eae0a66567bb12a92c452f751027a58f16f4810d52b47e32c7c858dee92fe3283a2d89462fd91fa3cb9c45d1e7a885ceac75d2ab1fe30e6c84a271c95f983395396816f40d5034c2fd05f1e1e3cc85fbc1f6246668bdf1896684f4d52eb398926fc1838c743163c3136d0ea2f3a96275923f29d7c0838c74d1d1619d685e90fde2c6fc59a94b192bd9e044a75f12f2a949ab68eb3fd8508c8d4d74da348b1ef4cf548a93183634d1bbca756132686b2313ed661162a4ebec18265a1975788d139bd57479894e676741c755a2d7df3bc3c18625da98c5acfcd31663f490b4fc88c72134b751894eca75298f0d4ab431cb82e8d4397b5b6a7db0cd606312bd996cd93a7cd0c2db013dc4b6c6450a3c7e4312adc7183aeaec22b2257c12730f5202f2838d48344a879694106252ac4cdf21d1cbee2e9a72cd1a4b4b7c44ab3c66a5b6a842cb3c2a8f1b112921c17bd020b1400918ddd15102c63361c3118dcfcb6a9a65fff2331bd16892e526dce3b3987540d86044eba6334ef6282d67e245b4b9559b6f96595e753c031b8ae8d493ff887f5916dbc28968c4c9a02e8ae78f223d685bb08188fe73d62f17f6f376ee107dd0123a3a098d516718ea960fb691f3024a1c9a976597c5165a647ecd53e0d0c8a485724dcdae7df49437f45e9e746e7a10c50d7d78f9e3925c2d78f60ba50d8d6e0dd14a4a4f9ed41783c28656f8ebf8599775bb9cd305ca1a3aedfea8e49ebc901ea586364ba6265ad659c9724179064a1a1a29b37cd9cae38c4641431fbac77418214e9e8ea29ca1d1ebc24baec9fdd18d628656f59674a9528a6d15ca4821237c65e8e5782dc5ac661695a9c8d0ecae282d4b526bf125a9179431b4da3ca354a6525dd0f91a1431b4b27c64bf1ef92547138656e8f5cfd225e4bd5f4601436fa2b75c5c5466f6057f2f682f50bed08b62736cf0dcb14bb35c012fd29f809de28546e7f120a3c89432bac993888cfd00a50b7d8b55a149745d6495346a7878212222e398081cb005320a171a31e5aa5d9406d33f53b6d08eeed396a4ccd14227b4167f54479565328b0ee822031808e33b40839285e64c9c0725a3ac89080b9dfe18d5620a2d8f7bce15fa8def396cfe97655cc60a6d5611277794a8bfd0f2c136e3f90b4a15fa36752d79308d0b142a74bae598e8d65a8e52949429f4b2f239c8ac5bfbbf16302852e873c44f7a7ac69c6f69b428b4639eb3fc13ca747586840285f665adc5cc30de4a674c1eca135a552e6810cf6f1756fb6053ee41928c9154c00217f05f120d1284f11da001c509cd2bbda2a2cce583294d687d63521a94d48f88d821284c588330dd428608ca12da9c05f528856c0ba237e6284ae89314f285d01e2f0b32ea838d928456c6ffe924ef2221c708ca188d8869be16bc119105040f32d2050509fdc930ae32e7f883cd0e0a94233426640799b525d7f9c44668d344e4bc2ce3ebf911845284d6c5cf7221e7c3b91013a1ed141fb598bc853284fe5ffc9be76d9da95d1421f471b5357aa9164f36a604a173416a665fdfd91793284068c34573d145e70fb68e0e559303e5079dfa7bf40ceea15ad4a1f8a07f97a5662d683840e941a35dee8f525ff424b5a4f0a017859259ebbc3d6507ed7ffb8acf7216942aa9c92d42e001076060040e30435074d00b9e517514fea65c67e5a0d7af5b7416856a25834c11a34f1eae7ace5f8e6669808283de7ffefde5d311eda2dca095ee723c8b593299942836e854b43ba6cb2afdb3f02c5af973f19dff4af42f8b5669181d85f2a0492c7ae14569d2c55d6dc17cede8e8e820a121328145f3fe1d3c5f9974a935af685d6b69e51944a3a7c84e161357f4b27a5e8be9721798b4a25f99c5d0a76b4a756b9885092bfa6ca1a6a3b7fcd2e34835601598aca26f5fe1f3da2d6e327f8b0719e9c2e005c007135534264c8af6743954eb2a5282f62ec245be8b84e499a4a2cf50ca4babd851d12759f57449b6382b5f9353f4ab42bcb8dee1aeb733455b1abbb4bc7c2932c931a5e847b4bb9065ea321b0cf94264041352b45a4c615afba877ba46d12a7d4983c993e2494b5d0726a2e8448b91cf545197b3ac199a84a2571a44746a8cd692f983cdc343928c74088a66a5ee9ae9be7abf663bf944bb5a4b4a76569b66c31019292179674ff4797577f36731c4688449275a1defdda67135b5ecf931e144ef627073f11518206b13bdf2289ba54b5a3db88e26daa4da7242695988143d137db94b26f36bcbe6ce269868ff3c4797543256e7d52797e8c3e5c64b95d76d416b44c4e34340648480e4c412edb6d219a554fdd49031a944233f4fc37b67972bda84126d8e21de94c6cd161d1d9349742e4b379f96c4ebe857129d9a89ac36e97a5def129844a28f195a7cb66c9ab4d89940a251253aa97693b947cb8fa47531e281c923da759d5f4bfa6435ff693f48d2870b268ee8d47b83588f21ee1b73300c9346b4b9725bb607e1df529321e2c1c6885e4ebaf95f16a5e77897b660b2883eee69e145cdc977a488fe375f6b29364bb21bff60fb16842491124b44bf713a1e462899b4271d062688e82529f2b5d662cb31662ce40b11c543f43a5354aee96bf1a56a8b0f92a4817334d20c43b44a6795426bccd0129a49217a935765baa9f253c7413c0c041342f4497bcefc749599f3a88358687cd9b925931144739efd3b5fc768dd54203a73b147cfc50bad5180e8e4b4c93871de1fdaf8999592aaf9a1f3e02d74925aac0ffd4a25aefb65e9e92fc48756a7ef8bf30f32c8eca1d55276eb6c41c8d8440fb70ca6066f9ed470250e98cb6a51c3f94f83460d38b42d5b099fcfe2e12120eb2a6fe8c3b6b8419ca72a6ee85f33645d6c8d0c2a6d68e527a5a23543e7ea9e0d6d9e4e4fe932c7d3111a43650d8d267193a24946b6cb78580c2a6ae8e514191964338316afa4a1f75622f4c969ea1751050d8dfea9c6d3799e33345ad07a4d89485dd2257df0032a66e85bdc997f93d5318fab5286c6c73b5d63540b446490e17d39cbed59461fa88ca1dfd62952b78568699e268646066d5278c6534a942103c48b30f4efb248d1827849c991220143eb310ad5d4dd4a88f7bed02a132bcd65e46783ee853e33aede959e54b58ba3a0d2855674ebd37271a1dd2c890e9e26e59918b7d04af3111d574fb67ab9828a163a99c157f775140f427626a864a14d9a4c66cce0a2705989ad8b0a16fad4d75188bb98d56222b9421fabb3696f69525a9659a1cf2ec7922d26ad65f1af0a8dee8c32b3e83266d682a8d0ac0a511e63bf781d4b0c54a6d0e8d6e2bb2ef19c6b1e0e54a4d06b6608e9fe3acae4adae44a15155d74968959eb4ac8142a7bbc46a10f15f3aeb8e95a0f28456b949f1397ed209bd1cb39c4a13dadc5ace1b84d07234a505418509bd2c5234334b9a31b91c5d82a97628a1d72ab6cf65d3598b62e5e1b1a7814a125af5f0df17fb22843e6d8dca18bdd817eeab594568b95441422f74d054a5d3ad1ca197b33e9785d2c246e83bbbcd657d52ab9679111a999ef5e9a7ea2c491d5788d0ae56aeb9e36b2d26a32a4368b3706e1e42988cf29b8e0ead4145089d0cc295779b57094223457634e653a5538e60bc063a3ac0f88f0a10daac215384ecdcd8d06283ca0f3a31cf4a68950fc2c5aea3032b3ee8a590ab596e9df12c8bd28e4a0f5ad3e28feed714a35aeb3d4644acc2833637e648215dc8b860fcc7486507ad7bb78b59f8cf26f47e828a0efa159bda452d64a9872d05951cf47efadc63f706d99a71912d2a62b4d9a4d0de6288eade4e05079d3231152965cea531566ed008cf4d2ea96b9da6bb1011120e546cd0c87c66ca44cb7810266516bdb81debbaa3c8d4a0c9a2f31fd37e4a6584abba012e904089459f31e7cb29fbf34a8f29b0e87454b9ea5b9e63962ee5156dfcd272cb2ce9384a8a2b7a59b896fe6a1ecf534b2b7a5950de92eca8d6aedbb35058d1acde8ddda37f8466e147494949a2aca29131492dc8b85296961445156dbae4b2d145a60220945434daa3d2a05367ec7ca92384828ace35773d55c77239c81209094849489a71c22829f9111a5b238c11e422051e14a09ca2f10e716155b6b9644a53f45ad249f99be90e797a4707ba81528ac647b32077bc34cb1a2545a75b4b837a986ba9df283aed10da93d4625b4ebe285add12f54edde2579442d16972a5e5ceea624b0acd1528a0684468164b5b6741a8ceef3ed1aad2ef496759ce2964eece13ad8c424d5b88b8f83ac24eb4be42b8aa4c5dbadc855aa070a26da9dbc5f692afe5aa1037d19b698eaea3fc786146889a68658c763d29f23fa30c31138dce6edaf3a4fc9ce50b265af7d1e19b4109efdf2997e8fc833c2db98a96e8b524dff733474a257ad995942bbc458bb22d0a257af11eda1e5e18a9e25126d1fbaa6b8ef382fe8e67a624dacfd332e7b973efcf9168633cada75faba8408144eb4a988837d1ca4f4a0a944774da47c62c8c78139b521cd166c8ac0bb332b569e5189446b4512a3d5acee28e14bb6144ff2dbc9fc986295dba45342ecb75c8cea8758b1e452c65534bfac5d3424944bbe5e1e5b976395c932888e885cfa25e6d619494e1443944e3f3f24b775c9ee74931442ff38c92396bf26462a714a2195d4f5a6c8f93ea61205008d16a952b7f535c94f90e6510bdce8f152b4a8582688376a96511cdec778d12883e892fb127665200d1e6524a7bcf33c9869cf287f674d0b2a02fa60e5a2c297e683ef797ac6b52527d8548e943ab9d84674bcde042af287c685fb91c27ab95900c287b68449778b1e57466f1f27ae8b32c5f946a930ddd581eda962195d6390a653abef0d0e68cee311d77d7f1a2dca16d2da58ce2292ff66987563c658fabd8122f531d7aad5a16a327391f3af4dacb4c7a7e96b58cba9d43a7310b5722cba15fd95ad41d21c54b10608b009a08e4996bc0256473fff48006980ee60e63c05242526384005a84a12290002d48467ea9e122233410300112101a29015a7401005a004002140b00808444750c2000a924790701b44825c945463a0c0000012c0001235f12022242c3c38b25959078785000a085020c4063461c5a9793d69ba33438b4a9ef2d8e7c990aeddf60000e37b4415f5615ed1da588cb8c9fc1cbd18630682c6ce8c40997abeff2ca673496193f6367fc0ce558038294b8c80c352048090c40bc8687070238d2d0694144d344888fceec83cf598db3193fe2010310f7f08f0108b2921010240901291101071ad0e3001c67409092910f12191e1e08e030038294c8f820491e1e08e02843c993ccf81905e020439b3d458bd1b9f4cbd7738ca177f1efa084afc9f11322a121e26124c021863669e98d7d490a069f3212c80c919030648884e01f03e74830c011865e5e7d42655052f7cbc0d07f488f97265c5f3eff0bc817d5f1674fe9855e74295aabb864a6e51247175a1959dac445dd0eed7270a1d1d8b2d705973d298538b6d0e8bc3aa70ee2f2943cb5d077389de7c842ab63cb8f855edd5bcc3265fee8a62bb4418911f1cfa3d2756885fe738b579a7b5c6e515f85e694fae6aede1783cf54e8f5ee480f1dcd29b4264a9a877c415c7a96147a1132b347b4cb3a891885d6b3d0329c5c5da18510141ad97c416a19261b75fc09bdd6ac7c7eb4907b5ac8097dcf790c328bfac596d326f4e2af4e4a999c99d089f220b5e7f19660d0f192b6e4f2f8ec0b2e0e25f41e1a9e9527d59effc2918446e6ee66c94c5cebbc02e118a31323564f95aec69117a90b0e24342f079de4bae8cb5a8e721ca1f7d7d07e71f445a145cf54c061845e143a07a97465337527111c4568a58e598731a93db7441c44e864b82c29e51a442721e218422b2b574bd9ec9a4c9e520c0e21f432c4b48e3266ff65c911843e8b788e22f3b9a0b5280710da972532a7ca98839c0ec70f9a7f5f9df145950ffa9843370a97d94a8cb4078dd09be2a4c676e5a7e2412f72c5cb2d73f8fccc0e5a57b9b21da412abcca383e6f4775bf2ffa042ec39e864a4d25ae4fcc778e210a3558f3a26a5c425a565eed81b70e0a0cfd9a5de98d5d6ad8584c07183de5d0bda723c06cfe297040e1b74ca3beaf3d4963474668d5099455fc25c4621325ba7d03a48a8c8a219257bda9289bea434b1e857dbc4b9ac4d266dbd028bbe5d35af4c5abcc7ea9cca2b1a712275872f174457f4920c42ef6ba815cd997cfd26741059d166dd1e34094f269a52c455b45a842edf1ebde1ff85a88ac645758cd2b2a0e3670f31157d7c3926ade57841aca0a2d7b2acf398f438f2f93b451b857ef01339c2654c229aa2f3a037695d132f9d5ac452b461e5695c8d597ed54947a890a2d1199a2f0b22324bc21f452bc74db69c55b1db491551f44908152f2195abb7d009a1128ace6414bbe34acbafc5a4ac80a297b5fb6b1ccd42954ff4fafda75d7e522156ef895e6bf9da64aeca70c24a273a7962bef283542ec75ee144fff2e68e39ea6c13bdd4abe56e5127dda0a2894e5f922f7e5e1f6dfa729968438c8b1f9bafd23358c1442fc56a614dfef36b59ae72893e34bb187358cd9f65eace18154bf4ad237309df8f23e3a55289468a589d5dc9925ae75229d14baeff5a6ac984cbab328955d4519144e7ade6ab5d2e2d329b2261c8aca3fd5913abbbb253664b530512fd0621dbf9c7057d3ae5e1cc45e5119dbb7770dd1ef24447c711ad68fa7a76cb3157b570237afda8b143e57458d92e235acf7149f5abd03faad245341f334761fea6227a414891da724cc24a22fa24aac545354544f42e63b2b5bd93a9ac9543b451bc2c7e4c42688866bb648894274c15540ad186f595a5322aed925222219a0df26ae2c3f5e795421e449f2194d4d69f3f14441f5dd6e5b73693215b25109d784cf91679edb208106de806a97390a10f361210351382ca1f9a9323b5a0ea223673be8a1fda9ce18571f9f3953e742295d2f25c169be538e2c3314aed727b686695d0152133a232bc8a1eda7c1d21a2b56e772da792873e7e78e69d4fe52374100a153cf42b7377163b7c73d8633d50010b80c00319d83bf4627c699a6bdff0b2961d9a3f8fbdbfeb316490a943fbb15cd47de1e5cee37f21b24547c7172223237468feb352fa92fe9539f471736672e51b7ab48c1cfad66a62728700a8f3d7698e632006621806411044b16a297483124820182c1e8dc6a3f2906053753f1340410a64219128180b846114885110c7400c8330088220088418438c525049087d8c42284a9a5a80ce09c8f14effa35b1e5c0cf00fd99918a166d2e623d4fd31b0718d1fc19476a6f6f26340333cfcd205073f20cfd84930b953ba864c9560b497a0b478355c6098d00e44d00222b480b6b5cc54ae3d846dde73eeea6d9bcf80cf5e4320642b8ff07b7e53349e555ffca1bbc4295f7026d25abec0eb67c9624d453efb08594575ad7d86aa7c70b0210bc95211e6a1928a3672e9bc0978f1ce41cd2abbf40950e78fb39b125c1a754557cc4dd0875dd3cd4b41d53ad6d32b0bda68fd3769c3faa6f8d5edb4b9d3d24af350db83c5fa3566cc41a1da5c602f7c152e65ac0b176c3b5bc67a0884475d878e93de09c475201875df6ec959307df679c3720bdbd817c0f003a22c38fe1cc55c4b156a572f69490454e9953e1d8580742d29d20279465b33746ab312084c0ff55e2591fbca6d4c1a894dce061e5fea6907ddcccb397f5fb5a3241b20256067105e40e40f589b855f04a1a85625762390f25ef7908780a8e26731d53c91a005bdf765d48dbf8dacf0c780f80ac6f9c9e4ec8e52c58d4d0d31fa3f6ccc3cc15e6b4af5d33d04a946a7c90669eb9e20fbf6899354e1a5e9f9a2bf32d1a797260cb3787a1944cafd4f37f5547f8e55925d8bfed31dc2d681092575788e6384e501c8c9c354b71ce6f3c64a176e2303f1a95263743adb163895541b422b646a82d17519fd4b5348698c7d3ff45ab961104d68fc09083619b4b1cb43bfe873965164df7ab2416dce64e7cfc5300b80a93604134c9d86551795d2ba172cfb8a3021e01b6eeac39d602cb75f33050b210f574eac108ca730a094b33e338c7cdb0b44ec6f5f9f37b6eb8b76eebec1e6efb0ec82d58bb4654ae553dbbf2a7561190ec657286d13648c93d3927c0c816ef17c720a665e66819ec7c0c27e8201e215fbbcc0e7c5cdb7a4beb5d6e0614e48b3c95a668b6fa1a033b1c381307372e266bd9553da8aa43d49395f5d0d87756a24c3d70c70802de043304def10e516d82982f16628d008782471daf0a884de9ef933d6cd0113edf8233b9e7f29ef863f8077eb1c997d7f288a90f3ca9b9a29bd482ac24f78fff2524d9cdc283d7e907464670251172e85026735fd130337a2d367d08e7f29b87a62606a9a6ff7c78443b3b8fe8a1668107dd26fc802c14a435dc2f8a6f8d9b4d8c8c4fb95297e5f4b052c154e618e685350dfc075617607438acf71cb1466d758e5fddf4e45a8949450ee868cd5548e6896267740e2c7f068b4146dd8a6b7638bd50a438c19c7c5d350a2e2c4a7b6b406c5082dca7e42cf4e38c2ca08066ba4a933fa44f5e601c63bcb28096e46c5e5cc17d08576d17ea464d51e00739ad4f7df00400734594683cf23175c73d90e9495965d9ab000bef38ac00891389e5164d95084912ad9f87052ec61042091484ffc18b6926af68970c502b92fe83c52cfced0f24b1026f1735f144c8cd9c4101e4383e37ed0be3adf3fd939adda9d43cfdade02a688a89a66caf157617667747aa30433090dd89efe5600cadea8e43275106c72f39d079b9c8517d02583d3dd95e24a04670c8f202a9a0b026f32ed0ebd761fafebb7261375c848d7552246fffc821b4bbd56683a680fddb80f8676ff302371888d10e44ca4de4181836d4a908513b487d6f6cae53428c098a678eeefbbc2953ea9abb91cef264a61a5be777370e5139ba0803b36ae7d046205249ffb245a1059bfb34207166bd88001f7a33844b7de95532ac2d034196d081435b291b751ad1414362d5e29c8954ae1ff4258409b512d9a31364d18d5013f81c4fb70e9ba92d8642a7a6bfddbd5f999683fbf65b6e26813e72fd7a536a222347bbc3b849ecd1c65164bd2b208b9c0099d96685cc7cb7119a8b0cf8cea201c066a9e439e9eea7381dc299faa272d042b1b059646803b1d412d00f60177acc9047f44f16cb56068a646c65fa0db6903a20d9bc578e9f6fd79bda20d3a013af4e064cde8ac33b782b3cf10e4c4f8cfd5acd8834b249457194eedaa9f45944a40d3418922c96d8412cfdce54d263a8f19523c9124bb3cd008d100dd9cc28689123ecc6f520811727a7f342e3116dd4c8b0e6df1f4b5265ffd0ccb7fa19ee33c1a4523e35cdbeee225f736d1c3ad1063d9c95b92f5ee226d2de60aa1a1f9f1702e9597920cdb1f22ae3af2d017d406acda32818d593a43fe3bbe5d9b2c6080fe89ef8ff880d190666e9a182156398b7d084c3e1d8ac4a652ead291fc80270d6d0a70da12e92a50021d06dd7046c003a21841e8905ae1b0526aa4611a93390ba4f1fc4068c23353324628232058dad265055fc16935ff8d32b15605ed139ada7304214b5d9e077ca66d04a8120686f38d0a2b2f2c7d35f06f6cfb63e9c9407f4bea7f66257b5c5253ac772145736bb92e1519272335486343c401e3834f833119a9bae58804056ebc794ac47674bb643e4f1a5a97767c8997e12aeb294f2c2ce720dda9df94739659964cf2bceb4425e0116932ee737a3aac87c9a5d8ccf48603c19bae19676ecb9a54bdee176573fa196df720c58fc3c8023af80d3528c74d5334ace3bfba6db2e5f8cab477d76a89e035e7000179a56812e9aba40bdfd9429aa6f61f30e6c2ea9952b212b3a29b9e756a5d0eae834ac4d239d3a97e3c823f7ecd93b38a18a20d2fad3b8c8896e2b56745522e452b8e31a48133e7132cc63a9f038a34e6f69cf20f02bbc59162e421ac3d5cab2e14cd24d54950088273d8526fc9b8a9682e0ba8d2d99e28c1b69624fd042e55e6b5a82d4147e7662c5fd6f98965e961c7fe02f42e64bad67f51ed87f2e5b6ad9e28653006faabbe35caed86f1fff6aa0f7e17134710dbe53bda3626cb45c264fa95c82446f055d8160312e8f5643a5e46e3951baf3ab76b2771b305f429cec92ad8c85f7d840ad420c43710319422c19d2c0ec7bd329f76e0c5ecdabbbcb087ed83803fbdc7ad942bc7daf61305c81383f640af89cf15356268ca0b0a33a8649199f34f51a3b8ba5aa455c36379fcfded20fa89d55cb83dfe3b79443e877a87c53669ab8e8679b849918de8127c8d110fba5773d3316f6384784b4ec3a1fc13387dd737ca61b5b24ec0441cf78b49af0b62202d7900d452a36f66d46cadea0039bd97b75ecbf9eb6832b0dd69bb8b4e35a7e842a3ab28ba7e1d450d5128104e5a6921487c8bdc5dcce0ccc446aee3bf70123258bf44a0d5b12d41304d2cc90cff2885088dcb4e3602c0f467f5e84ac3b70d3da35fdfccb063206964a662db020dc12741959586a57515b7ba5fb5d230e94f4cf208643b233f759bb011e4c3281fd090894c900c14f5d828e03d8907caba45b0417061411298019522f061762c16d18fc9ca895380707409f7421ebdd5d7ce8e7522bf82ca92866161329a6fe9b8da926ef3dedbe6097cfb3119912b29a7f668b70123906f073d8a93b263e582cd07bd9f67ffc856b6668b4160ada286e748b6a6dd8c6f66103b86ae668b4ca7e1ae7560112ba2c5020fd0c40815cb312ab4071f3b6c65e8b4de298a5f7253c24f2fdb6ce22dc615fd07f6660df59340eebaee2c5df108b5bee781bf506968598c6d058d9e5c6433a6b596121413d8f29f374f07a41b1e23ed06ab60f939ab91e8f4199361bce396e002b9d3b9f6f0eca5d9d2cba910935b65b7c80f1d56a630568f528dadc45afcb54ead42c7e0ed30fb618a1c0a29d37152d4480f3a8e45794d0a6f8e25c4efba283bcc40206e727203c42ddfe8fd5f5b32eb506adcc6be860a7a14486cad48d3bdfb678252a09b0abc2c6cc129280925aa1e21224208b8858880066d9c43d47323335bf32a6f0e0eaef159ad5a0edcef19ff808f5553416839cb011a2920de7d84ce660fc97f42183e1c3d2f25a50f2f40280bd03a4882f6ea94473c602b4d781220593442116d58a7b060a31145d5338fa6d5fe1a3f28083bf7d5d2316995f2a0c25ee450268bcee0c422108fe00b787a8ed771dc09caa8a19e544155931e27a21a41af6c9e0da7aac85ed9f3231f19fb37755c27e5388fa398ed58a2779eb32c883b8b4cbbb19074d717401261ac140e30bf4d8e5595a28df0d16ef1837538686b7b0068a1c43d9d98297c1c27e6b4fe53623c181876aa00195dc252bc00c59e9903aefc70179a6d8f041938116ac79d10ee3053561f532d4ca0d4fa8ee0d07391c10d320025960e04413329ec44642929e0209309b156ebfc3a523802c76e97cb60c3f9ed14cd24504e750a40f9fd19cf55c851874ebcd0155f4d5c9b6a552c00026a0ed9502f73e0a61937b3ec62e31109e13fb149ba42c354e02b48017800af2fc093da1af277904e69b7d35519276303ea29cb93cc55b341879212c2d19775815c1ffed7a876aed6918a881c2a3c60411c39d7762c4430ab6335c6a63ba703539865dbb72c1b901c3473d38cc613edd91e6bdec19baf9471eb85799ab59b7c414f55c352c3932716cffa96206a540210b5e1a2fdff0c8e96347fa2a0386381a8c442ef0dd12845b7d5a44394d70c70356e5a59aa2d9562acab773217d3a5a995f9da3cf77c646950bacd3c1cfbc0a5207dd893b80ada78b5443a0e4e8b9f03d94b69d73f2204837a2732348ce2e7c3c882b3a097aaac57e50a59421a23a90cf935f54e04cce6525628a9a32d72047c09160021ab3800cecd21d69c819978aadb9b022949a4f64e2c58eac3965834984898b78fedaccd90ca9657f17a4e060a60d20b88b262665440cc3ea9538cdb481adb511a8bb1e77d7c32df1ab024b47792a490b94d59be789fa74e224a8a84158b0f59757b5f940d530a0f17228cfddad8fd244380a3f29e44eef1414fbd9595cf55b5facbb448fd064b866d3e2cd2e323da471c8a58153772a8a90c705d6782052093579e9ff8ad43dce41f9761135756be85a8f56b0a721612e6f1ef0a1952038ee6ce3aad87102315a21f931029ab1c69032342e1d5dc2db3ad0db122851ff15538b526cd2ba530065c9853b4881f9eb6adb50dec8424009ac088181fb129d09887bee4a80a9f6a2f087f4056545ed921b640993f22a786f29a4a0e4df652674cea284f0dd0ccbdc9caf7ac72dc28a68bb3937f4b91a684e55ad6d2de6a2bc5343a0872401dac70ac8fd04d175a64fe080a42856d905d5904ea5d9703bade82a32b0edf2530049026a3a3698648fa58315190909ec6c6c8bec9105ef0e42d4b60cff90232eeb69426d6c69c16a0aa89b9caef1987b78b76e168800584ab39dab625c2246cad95258463e668dfb9f07e7cbdeb69e9c3ee062dcaddf393600308d4cbc3c0a023dd9f5d426d188bf226cef27feb0459652f8cc6ea0d45e50366ea7218a53ebee918f0d459bbbf814d78050cf36139e0f67ac975d3d5302fe6610ad1e6b7ba3067daf178d8e94fb01ab949a451a4f243a052ea513a531570cf917711cdcf0be1fcae6459fc16d76a454c7e9d4a42b5f2fc1e0d7a860382d687745a5cedb6d2159295bafb054598c825e34f0ce3e0e6f4d6d9826eec0d69ca4f01dcc73b060de25b139b1a6c5bde6b25e32fbbd1f6ccd887d056d95830549b16a734ca8084c80271ae13476cfa3894b08498fd3792beab33a630ba0753598f69a3dc49a5ba40b68721bf7a83224684a265e8cd8c1da58f4d2aab9e8935e44d76f69007a5d3015aeb45f880a8d56540add2f1dfd0603c07b6a6b1919d3b3718ac9ae6739e4061cd01bdd125496d3cedbe3c30aa70b9169604fded10ee39ce1721728e7c0cc58406a0ce9fa27b48fda069660a9013d1204c38ba97daeb64205f8e5e17d9d230426dabb02ed0a28a39b617a43edf07e67e63e48bd526be19b41799ba284cae479416a672c6f23f5d45af0632fda329402eabc9cc9abce400aed3303a41f88e98c2c38a5abf6992047f3dca192dc49832712f771a7774719348cce5d5cde86c17a33238f55182a9a6b2934286a4bfc9984aa9d4ebb0d2d5e64474ba22afc371045dd9b74011b696e071603d71c3d18e6bcdaddc892aacba3227d1698503136b94049c940d4afb54d84e86368d49348b087c0675f1128d48b7d1af5748271f1ac745e7e69ca61af535c26e4d647273506d04b571ef8dd4fd19df2850ecc41d15f02497a7c8a55b821e61af08a36c31bae8af97cc5befa9958f42e1ec3b52fe31434c227f501c26ba6bda3cd5d25f130f0f0ef9eaf9426bdc0acab81a0d6fee554c741c03b21cdc635156d0acb0ab833776e236b6aa20db9b92118f1215472362b0d9c92d8798ee0a3e9fc2edc4133a6fd258f34dd2639cc01ebc7e4bdc735032ef4b7288cdeef2be7c8224689ef8a0cfa631ed89c7ecaa70373cccc2f88fddda0051f39d022228961d7f36fec1fe5150b47db8dec2cb11f9c84c10561446529f27abe5b8c61516625720d45980306d6e5801a4ae0ee88062d95670bfc255da801ffd8ca4f1533c46f9fdb227f3c43df4bde2d2031ae83d34e5a3befcabd580c0b2e0f68e62133f8fe9f413063c0783b8af300f27c8fc8099b3d2b0d18260b0d17ebee8575a82202cb5adfe58215f9ae5b630f79a09a28fdb6d2253d9e9a88890e6d9b7301e6e0308d46f6ebd90004431b0ccad3766ae687bca3754c66156dce32361f22d19a22b41dafb789e52419284f8970c11458aa29cee23c04a60d28a481678b9bfab05c69d2d3bca24784d24df9ffacf64ef2e58c6cc422b64fa8f94acdcfe7358d162dcaeef2f2385c5d1100472b6c5b4a39e2409645981e032ac4f4804615c609d557266737058dfb4df7e02d677f8268ceb8021d046e0e6d36939f33248e4836ca5971d9ead54b663ba78bad79db9ec2363ad84eee7965122f8c72bccc8c77e58ead69b7f75269bfa7a4ebdc0a8534a6a85463c508ae3c7b6ceac5098da26bbbeac2d0c4aa1350eac571dd8509c422dbfda1d620bd8e555150aaac5b45d14cf4330642961886caf4aa11e38870ba4ddbd5ebc6375da1f3161a272fde3850f17f9df4b22771ea04eebda35722991cb395eba03d4c1ead9e1c201cc2565d6e2a4f962c98608c316e8a5eb752ccc896c5372fb060a36f06fac899de4f5e321af499244712bb8f956c77be54b0bac8b95f82402060baaab4ba56dc6aaf169954f94061d016c1f3baa31ed36f6068f4e11f8ae5b31d3611526127c74eb99c12e473dd6e40b117eb232a21e162ca540fa5507273534d2a8945b9f703eb6327553a191fc7c0f1eb5ffcf7375a62ad474025829389049092851fed7900e99423283b38d197828c024bcab3f68d932478a143cfc44e08355a473221f2d2a596103ecf4adcbb0ac35945f5c825e17509d9c495b82b4074af63c08", + "0x3a65787472696e7369635f696e646578": "0x00000000", + "0x3c311d57d4daf52904616cf69648081e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x3c311d57d4daf52904616cf69648081e5e0621c4869aa60c02be9adcc98a0d1d": "0x1c6cd3a8447dd3cbde9a566f35589b7cf25e924bf194b8fca62f3f6797170afe0816dbd3631a6f0aa8831db582ef298fed529d4233253948c4660b47956c4dc01f9686fc719cfdcb5fd9ca74f36f149730171b5f307144ae40db51c3aeb506fa285282d2eafa50e9f77c6089baf9bd1a042d623b28151999ee24ed838e33ca6b64dac2170cc094d7a47fa2b1b8844d40f1a5c9b82358997809f4fa08b1c7e92d7b54461b86f1d81ae23ee86265efac1db524bded8f3eb443d059ab0dee2804f951a483fa77b505877527c4a44ee2ddd246ad66ac6c33e4349d4e83742d779b3a41", + "0x3f1467a096bcd71a5b6a0c8155e20810308ce9615de0775a82f8a94dc3d285a1": "0x01", + "0x3f1467a096bcd71a5b6a0c8155e208103f2edf3bdf381debe331ab7446addfdc": "0x000064a7b3b6e00d0000000000000000", + "0x3f1467a096bcd71a5b6a0c8155e208104e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x45323df7cc47150b3930e2666b0aa3134e7b9012096b41c4eb3aaf947f6ea429": "0x0200", + "0x57f8dc2f5ab09467896f47300f0424384e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x57f8dc2f5ab09467896f47300f0424385e0621c4869aa60c02be9adcc98a0d1d": "0x1c6cd3a8447dd3cbde9a566f35589b7cf25e924bf194b8fca62f3f6797170afe0816dbd3631a6f0aa8831db582ef298fed529d4233253948c4660b47956c4dc01f9686fc719cfdcb5fd9ca74f36f149730171b5f307144ae40db51c3aeb506fa285282d2eafa50e9f77c6089baf9bd1a042d623b28151999ee24ed838e33ca6b64dac2170cc094d7a47fa2b1b8844d40f1a5c9b82358997809f4fa08b1c7e92d7b54461b86f1d81ae23ee86265efac1db524bded8f3eb443d059ab0dee2804f951a483fa77b505877527c4a44ee2ddd246ad66ac6c33e4349d4e83742d779b3a41", + "0x6dd12b3ae7975bb95f841f4505bc193c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x7474449cca95dc5d0c00e71735a6d17d4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0x79e2fe5d327165001f8232643023ed8b4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x7b3237373ffdfeb1cab4222e3b520d6b4e7b9012096b41c4eb3aaf947f6ea429": "0x0400", + "0xb8753e9383841da95f7b8871e5de32694e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x00000000000000000000000000000000", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb32d8a863b519f21b700f379b621bd73c45c7d155d2a1fe6a04649e3ece7c7e03b70b3a6242bc7c127": "0x6cd3a8447dd3cbde9a566f35589b7cf25e924bf194b8fca62f3f6797170afe08", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb33e342a1016938ec896c8cf62f725741306fa59a240c8a721f1daa9a6374897e4530a33e5e0b0fe5b": "0xdac2170cc094d7a47fa2b1b8844d40f1a5c9b82358997809f4fa08b1c7e92d7b", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb343359886e6935e4e1a306dd46ee404511af11b9123964dbf1ec087aef60b766f04de5d9489101977": "0x9686fc719cfdcb5fd9ca74f36f149730171b5f307144ae40db51c3aeb506fa28", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb360dca291bc2a34a308c4107d205432aa56d2018d46daa0b820669d068b11abb5588584f05d493507": "0x16dbd3631a6f0aa8831db582ef298fed529d4233253948c4660b47956c4dc01f", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3a191710c236b8b5ce89a539b16e7cf02cde91ab273572701a7fb7bf712212a75d2d48cde142e2b40": "0xa483fa77b505877527c4a44ee2ddd246ad66ac6c33e4349d4e83742d779b3a41", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3a7500a3d1398ee4caaff773e3f134d4e0c90ef5e5f37adb603bb591b7aadf67a2a757101a1b70302": "0x54461b86f1d81ae23ee86265efac1db524bded8f3eb443d059ab0dee2804f951", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3d30ebbc69dfd05038eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964": "0x5282d2eafa50e9f77c6089baf9bd1a042d623b28151999ee24ed838e33ca6b64", + "0xcec5070d609dd3497f72bde07fc96ba04e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19501b00830156003f1d617572618054461b86f1d81ae23ee86265efac1db524bded8f3eb443d059ab0dee2804f951": "0xaaff773e3f134d4e0c90ef5e5f37adb603bb591b7aadf67a2a757101a1b70302", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19508c3336e1e98c9dc261757261806cd3a8447dd3cbde9a566f35589b7cf25e924bf194b8fca62f3f6797170afe08": "0x00f379b621bd73c45c7d155d2a1fe6a04649e3ece7c7e03b70b3a6242bc7c127", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195099bf45ac30c1b87961757261805282d2eafa50e9f77c6089baf9bd1a042d623b28151999ee24ed838e33ca6b64": "0x8eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950d68ba9279abdf09a6175726180dac2170cc094d7a47fa2b1b8844d40f1a5c9b82358997809f4fa08b1c7e92d7b": "0x96c8cf62f725741306fa59a240c8a721f1daa9a6374897e4530a33e5e0b0fe5b", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950ecd6beec3c27dffe6175726180a483fa77b505877527c4a44ee2ddd246ad66ac6c33e4349d4e83742d779b3a41": "0xe89a539b16e7cf02cde91ab273572701a7fb7bf712212a75d2d48cde142e2b40", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950f03f94250d72f548617572618016dbd3631a6f0aa8831db582ef298fed529d4233253948c4660b47956c4dc01f": "0x08c4107d205432aa56d2018d46daa0b820669d068b11abb5588584f05d493507", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950f2cfd82322aea31461757261809686fc719cfdcb5fd9ca74f36f149730171b5f307144ae40db51c3aeb506fa28": "0x1a306dd46ee404511af11b9123964dbf1ec087aef60b766f04de5d9489101977", + "0xcec5070d609dd3497f72bde07fc96ba088dcde934c658227ee1dfafcd6e16903": "0x1c00f379b621bd73c45c7d155d2a1fe6a04649e3ece7c7e03b70b3a6242bc7c12708c4107d205432aa56d2018d46daa0b820669d068b11abb5588584f05d4935071a306dd46ee404511af11b9123964dbf1ec087aef60b766f04de5d94891019778eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b86896496c8cf62f725741306fa59a240c8a721f1daa9a6374897e4530a33e5e0b0fe5baaff773e3f134d4e0c90ef5e5f37adb603bb591b7aadf67a2a757101a1b70302e89a539b16e7cf02cde91ab273572701a7fb7bf712212a75d2d48cde142e2b40", + "0xcec5070d609dd3497f72bde07fc96ba0e0cdd062e6eaf24295ad4ccfc41d4609": "0x1c00f379b621bd73c45c7d155d2a1fe6a04649e3ece7c7e03b70b3a6242bc7c1276cd3a8447dd3cbde9a566f35589b7cf25e924bf194b8fca62f3f6797170afe0808c4107d205432aa56d2018d46daa0b820669d068b11abb5588584f05d49350716dbd3631a6f0aa8831db582ef298fed529d4233253948c4660b47956c4dc01f1a306dd46ee404511af11b9123964dbf1ec087aef60b766f04de5d94891019779686fc719cfdcb5fd9ca74f36f149730171b5f307144ae40db51c3aeb506fa288eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b8689645282d2eafa50e9f77c6089baf9bd1a042d623b28151999ee24ed838e33ca6b6496c8cf62f725741306fa59a240c8a721f1daa9a6374897e4530a33e5e0b0fe5bdac2170cc094d7a47fa2b1b8844d40f1a5c9b82358997809f4fa08b1c7e92d7baaff773e3f134d4e0c90ef5e5f37adb603bb591b7aadf67a2a757101a1b7030254461b86f1d81ae23ee86265efac1db524bded8f3eb443d059ab0dee2804f951e89a539b16e7cf02cde91ab273572701a7fb7bf712212a75d2d48cde142e2b40a483fa77b505877527c4a44ee2ddd246ad66ac6c33e4349d4e83742d779b3a41", + "0xd57bce545fb382c34570e5dfbf338f5e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xd5e1a2fa16732ce6906189438c0a82c64e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xe38f185207498abb5c213d0fb059b3d84e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xe38f185207498abb5c213d0fb059b3d86323ae84c43568be0d1394d5d0d522c4": "0x03000000", + "0xf0c365c3cf59d671eb72da0e7a4113c44e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x2aeddc77fe58c98d50bd37f1b90840f91f7f3f3eb1c2a69978da998d19f74ec5": "0x10014c4bf7f93d0a5ed801ef778f8e7ef58201bdd7e33e167faf42a01d439283cb430000000000000000000000000000000000000000000000000112ccb53338ac0da571d3697548346fb5f0b637ac9412f8abbf6d13588be7563200e876481700000000000000000000000000000000000000010a8a307ef15b9f928697fa09dcc72a2c19a266c1d32fa158f9916b8b804e1621000000000000000000000000000000000000000000000000016c0197856b35c7f631f5aa8d9cfd83f7e75202b0d821e67d2f344e4e4b5fc10f00f2052a0100000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2006493592d2d556b7464ab5a2010fa1015e447e7b7a849d4489323a706823d8958db184c8c16713f1a6a49009f6da96e": "0xb66fc334c7c76cef9cc5ceac0f4b0837d845453a2e0e84703b280edf202c8f760b5554584f2d5374617368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20068043e94d92496a755395960c92c01727dba627f34c210eba395fc7f60d28b3a58c5dbd6b63fb4f9788ee764b2702a": "0x443c76dcde19df9387486ded7845c6d85ec2a4c17f38f8b1e7a0a14de7968d7d0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf200864d7856330936babd0f2130910648369e319d0c1e71ffecfe16b614f13253549f2ff0c6db558dafae395ebd5a300c": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033433", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2014724ea0c978db0335470e92fd7ffb0dc559c88e35aa258566bd616d0e31fac0efda3d881b52055a31b35892086bb1c": "0x08754abb6afba51a2f74f0b97bbcdb383f579a02a5e4541fee736710af562c6c05f09fa6be", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20151be65ed0e15cd19b69f1cf8e8d9c8587b19cc62e01cdc18a1499cda27b0fb33264d0c3817668609bb58f762012698": "0x4eed7cf3f4f6560d58db4eb78bd24b655bbd1d7a5c6b454e77c8dc5e2721a54d09434f554e54414348", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20173c5fd326bb9c3ad63ef958ba861ecaa29d60ab7eeb8c8ad1e7d37f8438bb02cc86c40c28218d4f183f110067cd368": "0x7059b7d9ad6e9f5bab40385874989cd04aabbe821094b7e45b5e4de5ecf2bf4a00", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2017d70cc4f902c5ec93f5a80574ca9bc6621dd4e5cdd0ba737c572710c13df35b316d39ecd12c1ae1320bd6db069a07a": "0xc5c184f0565e2192d6aedae584ee736cef875f0e1c558ee3ede26869acd0b4d6085368616e6e6f6e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf201b6d49bf7335fd2a47d244d1d3f6c8d2c2a55b4fc257dda3887031ea29fbe2a8ea74764db0f3ff3ee746b58365ef325": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033539", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf202166ab613084a5ece818b570161ed8642efa2e57a813989da4bac4551e4010ee45003fc3f360f5202a958b2b1a29918": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504636336", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2035cb8990d4714a895e508b555712507627922c9fc2d2f0b5707a3f0cf870fcbbc62ab06f4e4991cb04d376fa3593d6c": "0x922bc16cff1acfc4a08cb5bfcebadaa9eb182cd47a51b8b047a0202ae9624a1c05f09f8c8d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2050f0042bc78abf5811c975c536e15fc520aefaa9aa8f2c237f96957bc1858cce594c62126484c3cef56600e11580a77": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504763131", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2057979cabe7de93da0abb82a766b3b7efb944d7e992958540251fca02926063121bd452d21e0c20fedad450db1e5f713": "0x2c0d08e42e58247b57421f3239e0e192b21edaed4bca2458028c981634bdb607064f6d656761", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20583b3d9b1ed1c173fc50aac0402490d1234713d080856dba6865b23424e21b5fb50108669bc5762f955d207eadde13c": "0x561077519794c195b22f5058bd1195f6847aa6b5a749053d44468ba5db872d640233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf205ada907b9b2192a05c5f90bb405301e8b1789281b38392a08ab0516a21dee49fba6f5e55381106ff7ae190563cc84f4": "0xd0e903b51697fa10a7f8c7e5c750fb3c2f90424b749be8b6c0f0b120f5d7277c04313030", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf206a3f85b3cc4345cefeb37661d6ee78b9a7d620473c31a9f77379b12b25920a83b43e0f5700737d9e370dbdd9738c84f": "0x1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c41305504f4f4c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2070e3179221114d6c84429bef95284b31de154f8bc16e4a7bacf303141c913d91b1efdf4ae06c3a227f0a2877a19e90a": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2071560eeff6ae3b3b71d8401212feb5dc4826569e68b7eee1b5b93406e4951fcd7ab6b40be519a7db5c6732f66da1149": "0x9a8ead39ce1b44f37d16e98496441be79018e910d5f58c0fa1518d8fd7749550165354414b494e4720464143494c4954494553202331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf207d4eea50bc542582e7bd7f9ebd88127788bb550f52a25dfdfe1db243561efb956924b8f0a76c16c62ab47b9f6d1cc53": "0x766efcb5851054b4aeef694a3ad03d7bf36980a2094c07cb7b7cda28bde5e1490550563031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20871a5e64051b560e2cb21e54593d5b50361fd2cac02d6b4d6b0f31f3abe70104f00924a85bebed0b17267990b38c88b": "0x825872f7d324c8d97a9d5f5c94d918eea93ef783f305767b768a76f9fede7b4a08e29aa1efb88f32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf208fa00eaac2ff041dec4370d628e56932c2a55b5c60139f9572ec1f88f541744ad98ca9cd09b5641e84088ab0ab3920c": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033039", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf209aafad24b64b451542eaa9e53554c972acc6987e6d1c5087d414d72dd8ce665458dfd16d7447ee4b0336ee869e4d0f8": "0xb22f88d05ca6fdb70235b599b99c69f927ed71163c2ebc11c9649d678a8ba84e074265726c696e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf209b22346bbe4c12f40735b38d11550ca7c2496b1630a27a7946e2ac806c8e0cbc7d12702175153cd0eddff10898e9036": "0x4eed7cf3f4f6560d58db4eb78bd24b655bbd1d7a5c6b454e77c8dc5e2721a54d1447414c4c4152444f20434f4e54524f4c4c4552", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20a1820457ae2a0ec47f77b0c4fd7a90ef4fb68640df03aeecaa19d6eefddb11516c42b586d0ac0e56f354b43b70fbc22": "0x0ecd029fdf9259e900f08996fc9862ebfe100d49c439f19bef7084b258175a1e033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20aa75245f349ccc902ef28c8972ce22f2c2a55b59871ad2237ac147d19b7ebbbda39957b7d5881df0e5c849392556776": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033933", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20b1475172a54dfd1e398dfd955cac12f3e5e8732b01a310abc9d0ee2173b6e7f3d00b291f1ecb2f424499c353e4ad955": "0xf0de782e8bad3c663be60812f0a2ac63464f5da3ec448c73334c07d71ef27f2c0c636f6c6c65637469766573", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20b484764ce9ec38ca237e5e7ae691f50c65de6003709aa5a6b81354c00fb13e281ac05e852cb4194c69f78566e8ac828": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504636332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20b484d192ba61eb0a18c66d4510298951857d6c0ec8d629533be85a017b52214c8c4954769fce002fdf6073c0b177f3c": "0xfaff1c4b5a94649e0338783122b93a469eb9e2e375bb71c92028a8fe9b6e2f460c4e6f6d696e61746f722331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20b601d35d778df8c9ff4b4c804a7d416dba5e754de5c965c3a904ece87b7a0304c642664457bd2159f108cddd56d781a": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20bd1e276fd50ae93a76137748b58f99c021ba8ef466ccb7a06bfdefdba01817e620ada5954c34f617f6662e267dbda15": "0xd46cd0ae6eeab8ef19bf289712c9f2ae4272c663bfe0786d7c10d4ada52100030235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20c14f56cad3a694385e575ddb30439ad3ef37fce11457ebc5f00b154996471fcd30eae17efe69e5a39b12b76034dc7e4": "0x922bc16cff1acfc4a08cb5bfcebadaa9eb182cd47a51b8b047a0202ae9624a1c05f09f8f9b", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20c5eaa45a3c7028471bb1543db1960e4ba43c53c2e9bf804aeb0e0f3172195defa009198441a21cec8738d366105e447": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f88370574656368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20ca3ef735298d802137e17dbe7c40b1f2e544de1fc9198d35dd459c8ff8bf0a2c86eeaa4ed8ad9b32fb8d016e696ad77": "0xce44b6b392394133943e063102b113e0577108fb9cb3000fe04faec3a3ad393409495354414e42554c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20cc58ce868ad168d4f875a2ae0be02522c2a55b5de12066d4ae584016c6d556d36f74984dc2fb33b372e568e404c0967": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20d219ed091a75e123785a4792909748d90ed88ee1c02bcc5938985c79cd8bf1a048a9a01f6eecf8a3aec9a83aba8a20d": "0xdc3aee12519c19be02628b0f808bddda9aed564027ad809cd392c13e9b924b65095452454153555259", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20d2fc0f5be215d7720544394b53b3ec54cd38181e02e880a53114ccaf987a6f51a10bc1d172d509bab6f7e9d6eb2e00b": "0x946d9ac73a5f11a32e8c8709d631304d2db1ebbbca156fc86b9f4382863638140230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20da96916551e4252c33923bc9c88439a189ef65d1a77acbc1492c95ea3a58cb70b9ffff211190368bbfa21198c734c2d": "0x5ee1e16ea093ea043d7f67a6f34f440c5fb921b56b54e81c177898d348685b510a76616c696461746f72", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20dd3532aa765f11ae61cff441b8f57e89442a11a7247822dfa83dd5c27ea7249cf2458e60ebf82ed760f9e6d6f99bc7b": "0x5010efb7049583595fbe3da57dc5db048e590c28f107e5e4fa2bdcc4b1293f6f024a", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20e8997eb93d61a3983e2dc3309b6a1d99af6c56d6840c84e110de42cd72b4f82d0387238d2302a937026c23940d01241": "0x6495827bfe0b07d16c549eb10d7e45997e95788be44a3f277af6befec99fe62f033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20ef5aa56fbb147fd809ec0d34de57fb2a8fc72d20690562e27bb10f078d2de104192ad2d0cbfb4eec4eef42381f53739": "0x3a5e67c5be0b1a151232d17929a6479d7d7187544a40c059664c6315e94c977c0554696e79", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20f03b4daae0b5edd7cb1f9a43a5789f9221125c5934d75259f335bfdce9d6aab9e4c6b57724993f32f555ffc4e75d070": "0x7600c0c74304812e4928a503408a68c782c69a6af2fca55fcd9e48e095b448630653462d3032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20f538ec6d619042352eb413d7b99d47f6011856d19723839074419b4519ab65554fac975017c6f08293f0a0ba8ec9838": "0x0a4a3233cb4870d9f20b5c55e77f839ce96a26f0fd773d01917919757664476500", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20f695c13f73b9c2be723b0c2e989b4ac3562230e5122411d1c436c426567ebbe517120ac76620baef8d5d78b8a2db938": "0x32d4d1b0dcef676d9a72f6abf9aec55e129ef2de135ac172e19c28a9adbcad0b04303031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20fefac2555c2ed69906212c204ff33badce2db9e809d506f5bb1523baa031c25f48d3448eee538a23766c2686a7ffe2c": "0xbc1deacfc7e5c6e5f0373560c14fbce156ff2a0ed7e208d049ccd985dec85545065367722041", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2103db706f058fb143b85c4947343cea709e125c99b3b07749c78742584a990e78457e6424814870b165823547d3d6e29": "0x00004bcdcc7d30d597e19c7f87652b69736066b729f7e8543231a10760f8157a0230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf210ad3343fea5177276e8c0477a2931dec2eea43fd0e45e0e756130e01667533bcaa001e29e0192501e7ce2186ec3554a": "0x666c474e2f859bb39716a333ad449122df3605cf2d272ab876171d0a61cbdd070233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21123dca0f5481ee652641df8f8902ce6a6e11253e1600d4a54c1c233df15bc0a8b600e01f85ab764233da2dda657d439": "0x4eed7cf3f4f6560d58db4eb78bd24b655bbd1d7a5c6b454e77c8dc5e2721a54d14434f554e5441434820434f4e54524f4c4c4552", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2117d80b0e5656b05c7ae68162e784be2a83a9d38e1fcd76d6e82eaf458c9b71eba96a9e6540f39213fa01366fe0fb64a": "0xb4d599b32c954b0a9e554c96b248f3e66046a82f46ac914fc675938f771f8372035031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf211dc5a1593ab45d7628a26ac20ad6ea7c97b296323e5b62a72504892a3ccd4fc0b1b206f4de9ba0e9764d9ed9ebdc276": "0xaef6619eea08f01aef7e47d460f0730b02c075e446308892e55af56af15721680872657365727665", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2129c6c4278de6ae0e63d1213dce8b06a6cb7f28f67bdf8862d6ca0ca68932257d665d966222ff24f800291451121676d": "0xf3b15e49aede08aa29d7400da8d3b4fdbd284b5bb1f1af1a53a8c47398f1f0930650524f5859", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf212b57268458e88863db3a3246f664fb7e4fc83d05b1d8ac627cc89bbc95e7379aa395cb168db459fd18c6bceb6d15234": "0x986a4fdcd53d0e438f9694c9a6bb76665bc50acf76180049117caf3ca9bbcc6a06474f4b554e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf212e1ebe0cf66f108c421c8aaec37e4f620430a70d2db1bf57c424e5e81de47ade7f1f0ceae2b568b9182ecf9b025aa35": "0x26171b3ad75723bf624a27485e51e4c2fe38f4b2d24ee52b86a979fb772c513b1354616c69736d616e20476f762050726f7879", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2139adafa33f6c18088709ccbcc3b42887a33d68fb22e4ae32721ff41285cc493d664753a7d71234c77dc2eefc5782c0b": "0x86f68361d0a346a62be267558e72dfb9e3b5a04adcc2c9e46fb7b9482f7c876f06626f726f6e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2139e455f66860eb4ec2dc909d5e10310adcea185416af2d3e8df8c1c8ee8a634bf1c3275b3820cb6d935300d42c73b2a": "0x5a5f7eb7050fb96d8d7895d9afce428a064ce66e3b094805bcad9a8e68cb993419426966726f7374204465726976617469766520566f746572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf213c2c879ac14d17b989296183c4c2e8f6881000dfa449822280d217523794e016588e4a6c4d9c14e79161ecfc085e72f": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf213eccdc1d0e24a1cf5c23ef55b31ddc4a082ef6765a3eef5cce291b2507c5ac3d6ffe5e10ecec2525d1554b8d2db1440": "0xe043d8f7872cd895f8957c9179c4264816be3e649713cb3bdc523f752602cc3a03320a", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf214478ae78e9c797f4e889eb575b26a1cbc1729a527ac8770c18456f142dc57b24069c9ff1032d6c3a1572d84b811ac7e": "0x5c5062779d44ea2ab0469e155b8cf3e004fce71b3b3d38263cd9fa9478f12f2804763038", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21480139f39d0cf727f90e16e6e9c79252c2a55b573dcfe35afeb7bffb31da83e9df9ce87ca0ed20d9751b2e823963342": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033535", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf214a23f710bf657cbbe2e97111e100040927d335e751bed3dd0da74a10e610fd2996eea79b625bfe519e8b9d2b96ec75a": "0xfaff1c4b5a94649e0338783122b93a469eb9e2e375bb71c92028a8fe9b6e2f460f506c65646765204163636f756e74", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf214b9473e6abfab914fc53e79bf75c3c614860e374c2789388379dc1cdfeceac093c9cee7a2ae8579736323c589c59e42": "0x3c017930b46ab5a4413bf3153b001287ed5ff7fdbd2734cf69abc843f4ee044711f09f8c8a4164726961746963f09f8c8a", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf214d858e92dd9a7f8ec1fa8d00a47f0439c14dbe4982ae73a084bafe1f7eea2d51f3819088f08a10eb2fd7a1343c5140b": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504636338", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21536cf1c289719ddbcd93b9c88453e80f0cab0c194935f449b3baef742e992ebb801fe38ab5c345d7a6195740399cb50": "0x561077519794c195b22f5058bd1195f6847aa6b5a749053d44468ba5db872d640d56616c696461746f72203033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf215932a8a0140c5ca04b27c0de3c002e22c2a55b5b35dc5768afba71d0baf2377ee6f8e235c27d04ed90d75e0fff80625": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf215c6f0e69b0626090d1d8a1d5b91572deaeb8cfd46b3d6a0abfdf3961d572ddf2303545b03f0b1870563d38c69de4f20": "0x7a895955042cb3fe863f3564e7b30e9130e37b6d905be11c0cf91064de1cd83a0530312d63", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf215ce3a42d473cc74319c2a7c9c1fc302be2daf84705de34c1930370f53566524b08145b4d192d6cdd5a35cc71930e240": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb3893450563633131", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf215f325f62b3381ffbe480cb4e965c038daf47069cecf5c31da9a1cfde3732d2b701bf9f94c77ba7e99335d6b30ad080a": "0xdaf47069cecf5c31da9a1cfde3732d2b701bf9f94c77ba7e99335d6b30ad080a074d756e696368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf215fb270af184e461f951197eed4f0365b4b3a27f1b0da0e787c0863ce2307f5617f485a8c27f0b17c2d3176e788c3e6e": "0xe21727312b2b7ce579dc0f82f129d4edecbcf00abca607d73ccf16e8352cc77705706f6f6c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf216373727b49bad30b97a966db68486122c2a55b50302080081e20a336b40dac9b5ae2ae80692b653c2b38131047d797a": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033438", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2165f2504526b6cb7a840e50f0c3dba82d8c67a57859b28434a12f1a078e2979d8c1dbb2404c0e15fe75c1c94e39b2061": "0x2c81fc1faa024d3d1a727d953187860b45bcb185d046631ab98261eb6f2b8d5416f09f90b620536f6e206f6620612042697463682d32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf216a16a003b0fb10dc916b9dc13c064b804587d42f37709c7342f3e915b5a1c6f64ca916b9fa8279480c8602c600889bd": "0xc804531378242158a794bd06c1e9ef0e569f60bb32758597af80e5e70c07a64f037031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf216cb2cf29041c3fe48a99e396bb1021e2c2a55b5e1efa4babefcdae07c4ce9c4682b1f57b0f3080ff2ead5ea06624b6a": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e08436f756e63696c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf216cbfd899588e8acb3f3f52a415f933ee40db41d7f07b2b867fae0d7b8ed6767d23f7b53b032710dc5b5043474bf1d11": "0x666c474e2f859bb39716a333ad449122df3605cf2d272ab876171d0a61cbdd070235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2176d35ae3da51e17d64a315dfabcd4fd2c2a55b56da37e71236c50ab586ba5ba55e3479c375ff4b9246082b5d21b4b7b": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033534", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2178451b572b6a54120a14059926a330bbf10d082fee91854f7a6a6c56ebf8bf0d65bf914a683ce4ae1db5ccece06ad27": "0x7042bfc6e75e1277fdefbea917f6b7ca8c36b3e0ad7286d66974c8f2b4cb96720d434552554c45414e204f4e45", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2182542d27fa1883f8607a2f851a2a82e4c4bf7f93d0a5ed801ef778f8e7ef58201bdd7e33e167faf42a01d439283cb43": "0x922bc16cff1acfc4a08cb5bfcebadaa9eb182cd47a51b8b047a0202ae9624a1c07e29c8defb88f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21833ae47b521ef27e9ceddb1aec06a2e0d92a2524d501daccb88d86720079731f9b53038e0aeddefb8828afbafa5eacf": "0xba57da1251d785b2d433ca687c510a82c284826b9b79859b5774a84f7000e9281e5b315d206269742e6c792f6265636f6d652d612d76616c696461746f72", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf218b2fe7149f81b3bd02be7ec2b961d783856d90462030b27957c425b33bf8f8f669ab715580e7f64f36999a74cea3936": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf218d2efa59b90164b82e2b35a855561252c2a55b5cf8d00511ef54ac7a60773810e906befb1b322f2d58199963dc97307": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf219694aa2e266a931182f4a75c123a8f22c2a55b5b1da68fd2ca56d83bafdbee8ed436709542031e625723d4cb0a01b31": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033431", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf219a6b776ce41fe6ce413efbfcdd807c5a61fb8e0537d0f6c8d4f94d0466859215b77e5e53c44981253983062b7a46f72": "0x6610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21af083704411c31490ba60a373f73db91c6ea9855f8f85002cb80858c01488a8ec5f459b1265248752b967a685eec446": "0x589e41f29ab08f2d0e4e4bdf3d1c8a868162c720f9c31e22733f8d633fba901e0b4d6f6869742042686174", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21b35ff62ffdb14bcfdf065e0f57d762356196c14df0a7036b943ecd01396685e799f786c0f131796c06850ec9342ff01": "0x666c474e2f859bb39716a333ad449122df3605cf2d272ab876171d0a61cbdd070231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21bbbb23d04ad5dd2d4e8508f5969106846351b08b39356e218524151eb16da7d6678c6066a831d6ad9b9ceea25d6df07": "0xbe776c10ad0e1fe7f606cfe42448e02cdb640c21214ea6c0c99df36ec0ee3d0d0233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21c045bf7d075ed7c91a36c40a14cb9263c235e80e35082b668682531b9b062fda39a46edb94f884d9122d86885fd5f1b": "0x6464f15335eee136dd7c216b994ea6ac3394eb723590e9e065fd9061e05d00350b46656c6c6f7773686970", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21c06bc31ba96a7f758a0e14d5ec4526428599b35f8830b27f465e77733dab096524c56d03921532c474f06775af121fa": "0x1a0eb7fdecee073651f1a21b9779b7bf5670493a0e35a53ab83b3cabab814a77033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21c12ba9744db9abc0b25d514a40f6fa0ae60938e514a0fc95200df7940bd0fb0f983090e91043b76f3186c6300ed7437": "0x5e34b19d7230f1ea5da6d4b8fe6ede9d05c2e55b0189f75b967862c1c43d9a1f06f09f92b032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21c36c43f322a7b65e863e6f4038d8093e272df04c4d1eef779341d14da26699e3832ed5a73ceda96a206ef1c4569f477": "0xf85bd4ec9a558cde3f05e33b0b74f9e732cc41f904894873247d4c435a3b8b630c53544154454d494e542d31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21c40f05bfadfec08638bee9d955d3ee1eeeaf12276eba3a08a26a606cf4c7cee9c3c0cf56a781899afa463104cdcf842": "0x3e8faae4c5713c72aea65d52aa1616d3e918dee3819fbbe08cd4c76dbd754a5005504f4f4c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21c75c2a4ae6a5d39f23cd563ff56276b2c2a55b58a05d949b1ebe3d18f1d3f4d43ff93cd8005b9cfdd884a901761ea3b": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033733", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21c80938d9854f378c6fe5a24ce100925b6c1880096a49c2719e0d6d8e863ccbd075aea064a47cf81c96ca5ba5d45f83e": "0x6e53696350731ed439f8c353b0b69b40b324fcdcb435ba225fbc22a33c9fe15407444f542f3033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21c83a483946d3f1c3aa060b653146cfac2de6256e9ff0ba9b97f862290f69ec0f72b31fa0a6843e0175e9e81a0165d6b": "0x96e24e9b5ab82dc275b82318a52cebed1cae3e25be096d5f288229b256359e43054f50454e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21c8fa480da0eb301487c191a5a50264cbc61f6c2ba5b42da936c12c7e5c33f6cc573988521e5350de5887b20ae9cae49": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb389345076c646f743032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21d0913a4692809429ee2d8bc2051cbd15c5c5a4a025f3d8be84fa9ea36383c2cd168c8a018d50c88a34154afe9ecf04f": "0x09cb20eb25e42c2fa106d75ee4d44b9c2bac20323a540529e9f4f40da5337bb304474f56", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21d302f9eb23c25a19e4b78c34d8dabfe2c2a55b4f956b33fc6d43013d320b87c2eddba31b9ded535099734d6f3aba80e": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033533", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21da37359eeffa7892d596bd8440f1f52d7264854fc5645d065341b90947bd9be1564df8220073eab4043f4022e633e8f": "0xf8f0244b95932b7a67caffd31de91edc5cfb3aa2a13f6199f127ce51c558204a04313032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21db168782360a02e0679d89652545d7eed6f8c70207598bc9899581a491dd8577e82f0ab65d5a78318b74bf51315841e": "0x0bb5e12d2f6ada25c3b64171730f1c9efcf76d3bbccff01abd9f92a9aaac10a7085354414b494e47", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21e28beeb7fdd0adb92e733b92ace02f951dad69a99af405193f3eec7593e9baff022b7fa55de147d1b4f9d2147103885": "0x2c81fc1faa024d3d1a727d953187860b45bcb185d046631ab98261eb6f2b8d5414f09f98ba2050757373792047616c6f72652d34", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21e3c9fa5071901dd03fecb41ee97416cfe08b40ca50585eceadf8c27c0711d8cad57d20cf68114b8f7fd6ab32534dd25": "0xb0b000e408509bb033443af0bc700ec11894f81c090d58d7dc2ae3174c54902b0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21f5caf66504f9b5c55c013d59b368bb3d44533a4d21fd9d6f5d57c8cd05c61a6f23f9131cec8ae386b6b437db399ec3d": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f88370235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21f69f16bffec7fdeb53ba4f6835f36450a2178b090386d0e2645866868143abc5bf6c91af252b92c0c38174200f42904": "0xb204051d55c2c80cdf6e0d3346944e921fc97f0b86a4cc5eb5547982fc475d6803434c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21fe6c0847625867e501f08fac1f82bba698654b9b352da92d00844ba8bab505a2cefffaa6269cdd2d407cc866440fb88": "0xbcf647b00211b2d6c8cdb9e091b95ba03ac8bc6a4dd0124f1f09f8c917d1d2700d44454741204953504f203031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2202d3104effde185b2c83268c09720f15a482942379643a03b8eca91f12ef9ed1baf5437080664727117fd2ae6e7dc56": "0xdae2b867564f01654946a095e69f0f49df1eb5c0efce5730cc3d1d83da3f4b0912303520f09f908a20414c4c494741544f52", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf220670ee6720bc60b6e5d4994782c129d0792d0467f5422f1617840e11eccfcc8bd24bab23b0ea04de920c1109e1e14fd": "0x00555ee596210f641d2d48b9a1e2b258aead3fe8de4e973bcaf5f24674044367033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22105fc080f09ad9a9af4ab5073f49241b023d129d9a0cb9490d097dbd3ca947d4830d3a6d7e0fa9975ff2789d9d97352": "0x9eee1e58c17ff7b037f2da5766e9bc78d5568c58d45cf363b9630ef32b2ccd79033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2210a4cf516e742ca4c85e9446ad650b40a7f29211d50461588ec3c6857c9ca25474c650c7d2048ef2283a2245ceaa831": "0x6c695c4e546c6889ca591b582eee8b49ba68d8485a3732e08d232b2f28f2342e032034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf221f2017acea08193896886ba2d42fc3652ff057f98f0c1bed31b2fd1ccd8de4d4acf957e79b3f71eb69820bf0dc1d22d": "0xd2eb07f02043788e254d9e2df57be11566d241c56302b91199b4647947af30200232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2225a8729dee127dd905734cc5723d49f2cce76137e2e2d9bb63e081d4074cfa4688d7d9781d2888f36634f646da62561": "0x02385caf9a08b92ca458a0b817a8cc303cefd5a0c6e108cb939e04242b9e007d14537562517565727920486f742057616c6c6574", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf222642465200f772b3b2b1edd1bf3e5b4e33f4520b7954cb5fee8778b44283deb0948c23c6b432058b21ee84e92085f3d": "0x7cdc1a6a5a7f23437b6528edcdf553d0685f940a4e6e85579727ef3dc574563a04563031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22289e37568ffd6e589cedbae8f8bd08b50ec868243f5ec5af29a7c679163a34978815b6f1d6e2b871f1f361cb7a1f905": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504763036", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2228f19ef28c6437f274bbce95bb9abc52c2a55b5a609baff13899d4ba4bafec105038d66a716494968fae1a849d2dd5a": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033138", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf222b1830f288a869371d356dff4b9de2d2c2a55b572c2850205aae1bb28cb0f6fe1c0e606353f9dc420b3796317bac454": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033935", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf222bdda5695f76397063f5274d21e8eef58cac93e1f29e4fac5351cd9879164bd90286cfb45af827fc732fbc462d2eb2b": "0xfea885b4e897d4fe908db6abeb39365ccc4689c2b6437dba675a4a0a0c0a6610033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf222bf1f493b44e5bd3fa974b18a6f8902c4bdda1c96506117589bfc216f9e5e79510c179b367f31401e01f1997b47181b": "0xaa6646d5b85790bc0ab869d80385fdc10e1f4befa7f8a4bf31848f73012d2823036e31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2231fca99ee3c9a15da8a33fa1566cfb508eae5dfcdcc8e1890cb16ac515d4669ed0653e98623be435327545c72f5aad7": "0xac133ebfde441672c055b79ca9a6059850984eead1ae036f48ca1230e7f0556f08436861726c6965", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2232e0329385e5d391761079dea3d56802c2a55b558917616097dfee7c9142497c66c77b194cd9113d0e65a11ba27660b": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033436", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22362b72d0d51c3061db69726c0af97b5e27cf0ba46292cc95548cd67e3e29036b0eaf1ab66a4a6f5d7065408d50b9759": "0x986a4fdcd53d0e438f9694c9a6bb76665bc50acf76180049117caf3ca9bbcc6a054d494e54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22410999d9e4425e03a0412208d1d1c260238a0a2b0989bb426df8ac92118b4228a81b354d0c87d8acd25c8de509f2226": "0x3e1630f099540e76e98b9fb0002c3a5ae3f40b6ec180df68fe5cd9bd2088fa18037031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf224d956ca739cac656cf377d51f15ca192c2a55b5e3110687784ba7063753757ba409052b2989ab9def09a684e8aefd6d": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22534923a0207bc8d69878844e0a5a08da4c5b68728f7fdbdb4426714a385017a471d5cd22a156acd30a40277e6417b60": "0x127a30e486492921e58f2564b36ab1ca21ff630672f0e76920edd601f8f2b89a07415a494d5554", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22586d346a46a84b96f49520a635b61a9b0583167a388bf2ec1c4ce53d17be27a15b23abdd97265571a5c65bdeabd24a0": "0x1ea80b0dde0e207c8ec57ac05fbec636502cb216bb423642919679fe8f074051164e6f74696669636174696f6e7320626f74204b534d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf225ea69f6ea3dc893c1ccd4a4f289aa91c83b0bba37f25f365e26efbe6c9ecfa7905dbdc0b0e3ae60b29980b42c509c6f": "0xa471c55caca4be7b4e60c6e94b20f9028883f8c64287d4454130c657383c3442035633", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2281ddc7d5bf747f585a24d4c7fe7a0bdf6be65cc16c65708bb6a0e4b9958ffe23d1c56ee5683670a69dbbbb70c10d507": "0x127a30e486492921e58f2564b36ab1ca21ff630672f0e76920edd601f8f2b89a0a4c554341504f474749", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf229093cd71dab62c83c7998ad273215375c2721c659829b4fd0d827879873fbd8763969b48a7724633b1e3d4c3b360961": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033330", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22914b827b96f4be7c6ad605f529ea76f0a3c9a0dc2a4578d4b58cce45258b3ebb0644502b355ce1241f8a38bbd1c0a72": "0x8e07d43b19d901badf3a7f57155ca84f2f835448e93a141bbbd33eac4b767d150233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2292060b3ec84919e065fc880f1789cc72c2a55b53f73b4d26ce6c62b0082194560e4a186f3491e8347218c775dca4830": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033530", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22921ebe021aa3387530a48171fdd40bfa26d8e7561ea8e813da3ee0979be1b5190fcc5d2d1375dd5c2e6b2f417aa8153": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033532", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2298cfc99ac1dde155aeae1c27164ea68b64c29324eb942fab6b41cc041f0e099f35d5c7fec824bae17717c5fa68cb83e": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504763039", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22a27a2cef808327c413d2bb72bec75b92c2a55b50699f7db6f499718d572de81b0d1843c146624daa99edd9a6609ef64": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033730", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22a7915e444abb79d13c0ef789c8ba605822058fa0d13ffcf079d48b96c07f71f6cfd7fc9abfadd85e205ae7a18d7bb3d": "0x1ecec4f3062f61988b13e9dab318860bd0fffe5b7b37880d50a614a0a20c250215504f4f4c20343220f09f9a80f09f9a80f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22aa8d84b13d7d95d38edda8f7ddc26dc8413fca2f93b3526794f655fc3504b40e0dff0648a4999f10f8eca7c21d1c21e": "0x5c3739d60301126756a7510e34f9d656d4435cd4fe64bbd001f1f3473bc9c33304763031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22abcecf1355c686248adb72f696863f73091c08dc07b367c41b57585aeda74490c1850166bcfac4081ed66117f668361": "0x561077519794c195b22f5058bd1195f6847aa6b5a749053d44468ba5db872d640232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22b4ed39fe63efba483fb4613a76d2cb644d9acd86b036eae410384c8fa0d073d47e74712a5787451463fbd717770ec57": "0xf0673d30606ee26672707e4fd2bc8b58d3becb7aba2d5f60add64abb5fea47100ff09f94a520486f7420f09f94a520", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22b6f378e7c033da5bd805ebedf69877992a8511f5619229d4e1bef8344cd9a5f85468e238fd95f843dd555b204d0f00b": "0x1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c41304554b32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22bee25df560006547c2bd09e33dc95698818f1b289df88876f0199aa1fd723dbec6e7bbc5b08e5eabb89edebfbe3983a": "0x807e371d9df95983e2b9face8efb67f962816f1a0c6681cb1e5455127ab45c09033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22c4857f7714c26e3c24e22139345ecde482a064f119738425180e442727eded171c8091bd90182c3071f37199d954158": "0x5010efb7049583595fbe3da57dc5db048e590c28f107e5e4fa2bdcc4b1293f6f0242", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22c8bf0692a8248b3dda3221d989cfa3b607262b83b9349efcad72b5f2a0cbc80b1fdb622aa81a861a56209014e568337": "0x2cd49434353de1d51598b44df15fcfed1e26224e055923acc9f9af881dc31d5a0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22cd9bd13911d8c2e382a171aa28b50c480bb3bb99df51400d9aabd8e0e6b6610d3d4f5512ae4d46e03f20ed14eb0cb3e": "0x08ec72cbf62bb66f416f46f988e130585c834a381efdbb0755e30f47a2a0da5a0c46555455524550524f4f46", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22d0e467198929274bef8f7dd5e84b23796cd6f382ca54348f9bc846929ae16bd49da6ef76b19211da8afc0a1f1c31d32": "0x7e878e54c1374b30df335d3a193f3e6b1f84db6c2270ee634cec769d7e33e2440e434f534d49432d474c4f42414c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22d80678c14147d5cf8aab732d29ca19802e358bc31b7ccb578dcc5c36ba2908f311ac5ab2ba8c1483595268a7189fb02": "0xc5c184f0565e2192d6aedae584ee736cef875f0e1c558ee3ede26869acd0b4d605476d6248", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22dba51d56b92dc14d744bb0a1b35fee52c2a55b59c3999f441a596b34e41f0d55a88c0f9fb7af4c76241a6f5d3a3e514": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22df2e6889d45ce8ff1467a26a17375ea4a8de2c6b6c1690a27aaa4cb64e0168bced54ab568958965187646f06442be6d": "0x666c474e2f859bb39716a333ad449122df3605cf2d272ab876171d0a61cbdd070232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22e83214fba4f42a6cbbffb08454263dd3cb64a5829fe55a733bbc427b0489da973cbd6b3bbeae722ad4fa58eb8277a30": "0x43fa61b298e82f9f207ddea327900cee26b554756c4a533f36cd875e3e7bcf0612506f6c6b61646f7420416c6c69616e6365", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22e8b2c14c8f8828884c50fc3909c081c2357d8ee622168c14c8d3b65f311c42d67023935eeda34bfe81c8ed779103238": "0x2c81fc1faa024d3d1a727d953187860b45bcb185d046631ab98261eb6f2b8d5414f09f98ba2050757373792047616c6f72652d31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22ea1ef09f4cda3cd0c101bc367eb16b508104ce4b326f4b31735dfd06fdfb1ccfbad16740364d8bf0f917f32c090f362": "0x3e8c72ac1b710bbce4e7c190568bf560d89416696ac2a4700406487cde98df04104d454e47204c4f4e472050524f5859", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22ef8756fadab2eae5b9e3cc461c747052c2a55b59f26d98880fb604cdd7848e4c1576a990b0ba8468dd4222aa27f9e22": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22f76dc97329983ce3d527493564453774cb0f7f17953e529b8106c743f78d238e3dd6a90f421d32bc920ce120682c801": "0x7682e4e399a94b0dfc4a9bc476e0bc69f25413687d2b1c29bb7139dcc8e8714a0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22fb04932bcad4f50f2b7903a3446987e2c2a55b5f1b5e1c45738e2352b3d00673a40f451add21cf8e6a0c3eae6bb6824": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033336", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf230323bbc825966297d4132e73e9ac0f09ed22cfc6877c1961ac2cdbe5536684b0761074b8ea475d0c2f173f5989be904": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504763135", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2307e1831a66e34d18182de7ba5a1fd84da4c4087c6c624a12ce0c066b04f71d81735ed6a252c0f63e55188be16be4f47": "0x5010efb7049583595fbe3da57dc5db048e590c28f107e5e4fa2bdcc4b1293f6f0243", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf230836429701e9ef6dd3cb5826f47654444a1336854e44cdbfa929ad12e913e4a1870c590a6dc5e3983a6fd416b927f53": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504763033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf230e8e0ed55084fb5c09720fc6145dc130277ce02b2ac78ceeb9ae4fa0a595005489bf3f5f77898415e32a3e9504a5314": "0x544e2e588c90a2e53e051d2f87d40e222e1f034913a30f95a9a2f39114e5be3818546578617320426c6f636b636861696e204e6f64652031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf231bdd1ee816fb4ddde9cf92d60e77172c3590205a4e4844653590740c64ec31e5d2af126cce71bc60df95bad639749ea": "0x7e569787b1b323854ac9a8c40914d400b6fc23a2fedd24321f814ce7db7f65630231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf231ebf87d898b03dceba03d3e98e6a91ce4afcec3862a48c276628c97bec157c563a74bd8ab3c7abc9d7fae99fff38268": "0xb22c2075548019dd268e74f3aa69c9703b129e989d230f935797975d5ed9247d033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf231f763c6f1ba726e99814b8a2b7487df2c2a55b5d7c788d0d4bd1f7cab8c7e7a6d131e3ec396056d62d1376d21177941": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033330", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2321a3c23e0895caadc2cafee7f5a4f3942cbafa9669c25868ae5ef66a62b96169f9d56f9b1dd27aedb241d86bcb2dd68": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf232a159fd0bd78dc27bc0e043b43ceb7e9effc7fb904ca3d8cc4f45b464ee4dac705c89888d298bc9dfd2ba563d5b3e3f": "0x5c5062779d44ea2ab0469e155b8cf3e004fce71b3b3d38263cd9fa9478f12f2804763032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23368a94490cff214e159dba0f70e115d5ed6f4b68a60a117a32059e96678f22fa086c505f7a8ece13c7a2e78b4788f15": "0x946d9ac73a5f11a32e8c8709d631304d2db1ebbbca156fc86b9f4382863638140236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2354c7e586c4f812b2fcc1ab9f7ff6951a64c092cd19a2779a2fc967ea1be4727ab3b29858a2a6f46af009daa35d84121": "0xd46cd0ae6eeab8ef19bf289712c9f2ae4272c663bfe0786d7c10d4ada52100030231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2357614d1d04105c49a3c0b1b79cfa4ab58a0a27aedec30fb5c0fa2dfabff0b7370f69e2a8505d714f7b2ce37a99f0d07": "0x3817e559bdeb521169c4801d70a1dfefe94175d15666a1ae70719a3594a57c1604303030", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2361f1f219be184ea435c0d209db0f9546a6d9f13f448628beeaa0e4c8e47341163ce0eb14c612d882799b9eb4152d71b": "0x0cf6b6cdababf69c2af37a41a2f360820bb7dff2f61c20bb61a9503a8901ee20067374617368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23652b8b9660430d578d4209eacf59280ed959fe3d9afc671f1b0cde07de829b2120d7da25d5f84f4e0a86e3bb940bcc1": "0x043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d073034f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2366434e22dc11ed36c7fc4483b89f3cc364c29bfbc9f06a42b5cf37ffd831e91c843cc25d8b90071546810ecf279e458": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504636334", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf236b45fdc27494fc1783947e9703bf7442c2a55b5c7a1c48e176aaeaff69a017d85b27a49f1fafc160725a3376f417d00": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf236d99ec400101b8d759bc939b72d57f96a7fbe4110d7ebecc8cd2101113549d90cd477c766e02a52856dfb5d9977030f": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033430", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23786e839ef62a0a379d944c73fbb9273a471c7aa909cc665212bb36003c52c5d3eeec39f96556a8242e861c5dd7dde41": "0xa471c55caca4be7b4e60c6e94b20f9028883f8c64287d4454130c657383c3442035631", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2381907fcbd0ce09177388618368116ed28996c52694155d7ec9082650fbf108f69da60c44a4b2565fce4e03f9bbb0178": "0x6c695c4e546c6889ca591b582eee8b49ba68d8485a3732e08d232b2f28f2342e032033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2381ca18820b278a00faeab03d52440be00f379b621bd73c45c7d155d2a1fe6a04649e3ece7c7e03b70b3a6242bc7c127": "0xe64bc946c10a1f75e683f236e72a44d6d61b3bdcf72ffd8c738e488efc6e15670c636f6c6c65637469766573", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf238329bbba5c700a76835a1f661b6e4ab6eb3bf6204b55f63a2ef87543b26d158230eebb149a8b9df86555fe3f02ecb6c": "0x561077519794c195b22f5058bd1195f6847aa6b5a749053d44468ba5db872d640d56616c696461746f72203038", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2391b5b0353cc7a179d9964a856db5830768659892ca9fab8d64efd188054b2280efcc36942c84616653265d417fe966b": "0x8e07d43b19d901badf3a7f57155ca84f2f835448e93a141bbbd33eac4b767d150232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2392e34504353df51b35b300a5914a6fc7883180d8cea922c0648533d6b2be8949765483e833ec49e8dfd10a0ea61a03a": "0x5a33766207d51925e4b9a2302870bf737305cddd5bb2df2dffa379963e5867710474776f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf239358f6e6a083b53a55ab46a8012eac1ccdce2bc61518838d34314c620b7c88040c38c784e0eabe838c17192be7ed91c": "0xa66e0f4e1a121cc83fddf3096e8ec8c9e9c85989f276e39e951fb0e4a539876309466561726c657373", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23937d53bd543669ab4a709f7aed69b582c2a55b6094cf557bc85fa401951b4d4844146211f845e1c212640685d42057b": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033135", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf239672122e445e0134396dc1a76a9b84f20e1d9db00b7eaaac9d3f4a95ba206feeb6f606e16f9af3f2ac24c1c57941e2e": "0xd46cd0ae6eeab8ef19bf289712c9f2ae4272c663bfe0786d7c10d4ada52100030234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2399b9287f0e2d363ab2d35f07b9843c6eae07a7b7adf896a2332b5bd2e366474eab97e137c155f8741a9c6b4d30db700": "0x726a98c27f84bf42fc842794a925418335fc9fe3badb1f535dce9c9d9efcc02d0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23a0ea3a6a115e71c72a824c36d1b9c4e8a1ec46479fec3c43eea382d637de8f295ccb2c0b6f6fdd4c5d34a687737a601": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504636339", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23ad1e8e1d94e40076e37461627e008dae6d97bf878b1012927ae6afb7e092c541a5abc3904656981beaefb9ebb781d1c": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504763032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23b3ab2b6fd4850a8142d624d091576c6c235b0e23ee7b2bcceb64fd0e126b965204f7069aa3b4fcbadb8d658e2ecf86b": "0x58a74372b1f0a88b1df304584326ff69a68e9470d42687e12bf5dfac375d49110231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23b42f4d2e5019b0e65ca1514f08ff2868e5df47c25340b48d443389c64abf88909ded6b6dd62c01548840970cc4f14a5": "0x1c2a5f648afea2a94286c17f6c60d16c9ef8511fa4ae88a54ce2748b6c8fa90f17476f65726c692044657a656e7472616c2067476d6248", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23bd81eff8cbbab65308778f5254bf30df836649df542b24a1b63d80916ee743d4734640aa796648649685dbdd430c362": "0xa02f7333e25590e4f568ae8a2ddc93a879e92e48fa3cf1666ac56e020c106d55094752414646495449", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23bf16ed79df138132a2fccefacbb1d0cc28804ee5c2389c20b837475af5118a2576b88baf216e87684eccf9c282d8b2a": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033333", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23cc78501874040a79e85e92a504fb0ac92a11c7b27f2e0db0137d0745780fe21467bfad9bb6ba3e523b8e2dced7d60ff": "0x086de7162fbfa0b91a67eee94b697646028edcf484ae78fdc0627e7eef1b224703444a", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23d68e0cc11f62b9bdd663bbbdbcdd049326020faf1443ba7736e9f4b7a442db507e4a2054ec3a19f985d2c44c30b3043": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23e1813125abf1cbff4abf7ed4a1da61dd19f8df3cdb194db075979039a6fd4d912298356bb2931c08c35db4903f53345": "0xd824263a2ba0b39e43b2a1fb591c68743ca504c2ce6c3c2aa96e58b6269d3115035631", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23e609f9530b24ec687f468ddffcfbef674eb76dfc265812c8f4f9b98b54e25c319719e1a3593b7f0e743cf8525206178": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033136", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23e7237354e5ba368cc299c75ac95d8722c2a55b5d10904ce8daf9095a573253bd66fec7e96557836f664a49e5b89553a": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033239", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23e78ea26acf41810d7291f8cefd34b89b4c24dc7c3bc7ef831df7637143bb554db602d209f58c93c3dc2af04dc386669": "0x5010efb7049583595fbe3da57dc5db048e590c28f107e5e4fa2bdcc4b1293f6f0249", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23eab38c7c2943807005f335cdcd134507a2f97c76dd2d0ee3baf2ddf3b0aa1942b47ca79a3d1e2178ac5c1c37a056139": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837067465636832", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23ed7e94851c7256b8c7e2359d8fd78a77ad1704a69927d8dde4807b1c67fdaf26718755a742f7994158c8f79749f3a04": "0xdae2b867564f01654946a095e69f0f49df1eb5c0efce5730cc3d1d83da3f4b0904424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23f0f1b51a25ea0c3f24d3db2aa987b456b973df13cf0190a75f17633f8a391020df8bac9aa9e4c50670e0dad135bf726": "0x182fe099d0c1787bb1b88de855537dcce095204028736ecfde09dd115c498f2a033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23f639b045975e0b1c2a3ecf5741b894446779e4754580b4e94ac22e5da499aa39cf1aece35d5162db15003b14110f31b": "0x4cf2e774e34c3603b2428a690c058d2ab826b39a2eba4e22b3aae85f9bfa780209444f542d312d4e4c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23fa2ea1116374127e8e095cb6bb5bdc24431708b474e888318f65c93f0049fa3043df9d7f1ec1f5f3d7d5e1493359e58": "0x2c81fc1faa024d3d1a727d953187860b45bcb185d046631ab98261eb6f2b8d5414f09f98ba2050757373792047616c6f72652d32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23fd4d7d6d83dba0ba49ae52ea3646d56783770544556ce47aae6e9e9c6cc32bb84a3df7ab11a5d30b0618e00e109d66c": "0x561077519794c195b22f5058bd1195f6847aa6b5a749053d44468ba5db872d640d56616c696461746f72203035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23ff1515342297e95f6481a8b7d2809312c2a55b60a32545c89a8d2ba5d04cde08adeb0e91bc2d0cd909d166db15e0f7c": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033134", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf240042a224d4954573fe0c30db26f93b2207c5841ccd565eff0f8e15ed5d3b1752749e2fc9e3f574c8434bd09d7f8f815": "0x666c474e2f859bb39716a333ad449122df3605cf2d272ab876171d0a61cbdd07033131", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2408b7bb25867493ede69fe026e67eddc2c2a55b510651d026a38ce4568ab7ce806bb2983d1846191cfd29b6b06e10946": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033538", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24094d87ff94b8805f0e07825cd1029aacd0b6229844999d1cde6c2e74ff90057d24e5875b891f645e2fb4a47ab90745e": "0x22b7a9ef681c4a3c1743e5c343ff5b6f8aec3dc43bb0d49e29243d79ed406365033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf240ddde62c43dba8cbdd11a9179cc340a9695d7445e6e6b293f6fcb0aba94ba7b76431447abab31430eb99a63934cdd3c": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24153db0616bf10bda91bfd32053b04aeb7972e09702baf7eda528c6894408b1e9c702e5f54674bcf6de1b55b3aa16365": "0x985be267f05f586da7ab52e4430c2f6d461f396b9d6cf4f1eb5362066f7cd82f094a616c6170656e6f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2423272c97dd2f222f8da3fb92989a8512c2a55b5d133442ac56db7e5ebfe739897a98a37c258accbe3697d0d7f29a373": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf242504f570a11c91b58fca3962a3aae5e3619289cb2e660dbc1c5747506a37df7a4d311aac8f29c69be8b710495e51623": "0x0cc0424184702e27c49fb859c93f07d8bb0adf2a0824ada9f01db9bf76b7025f0548454c31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24272dd00c8ee9debc33f31257bd6e25c2c2a55b57ef9ffffa47f4d6fc6750f15ae53863a1d0fd99d8386a70054d55e4b": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033839", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf242d47606328d06ba64f3efc8e8d02c29ecdd548c83457ab43caf7867e2bef91ef783025db9659afd89794ec1220acf29": "0x2cd49434353de1d51598b44df15fcfed1e26224e055923acc9f9af881dc31d5a0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf242e42af440c994fbdf3465d43e6c485820857206fde63ea508a317a77bc1ca2a795c978533b71fc7bc21d352d832637c": "0x666c474e2f859bb39716a333ad449122df3605cf2d272ab876171d0a61cbdd07033130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf243068a2209c8aa06281b5dab90c6aa7109b072ba1658a3946b1f7a82a7c135c33a41ac8e6ac11407d910d4baad3e6c42": "0x09cb20eb25e42c2fa106d75ee4d44b9c2bac20323a540529e9f4f40da5337bb3064e504f4f4c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24365577f7ddc1775c40ee9f59dc1d3372c2a55b4f7af0b8559bafd9332fe78fef55b0979b53217b3f8355382ba989031": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033437", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf243a8420256bfb245551d2d45f48f58a404926296ae6c9155557a6c5aac98d9775664efd8607e894ef210fa2c80b65941": "0xbae335c017512a43fcaed23efec97d80e088bb8f7b93ee837cba5416ca51037f05f09f909d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf243b718225680fd482895b25914d18193508f2cb4567caff040d0a47db244d7ea791d9ec23f0d5d33928a7c6a62b3077a": "0x7a895955042cb3fe863f3564e7b30e9130e37b6d905be11c0cf91064de1cd83a033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf243ccfa90dba62c7eecb208771c4ab15f2c2a55b5b7e13a772e0b693c3b351d2fb5e5b4da18ac379ebdb2f1f2e7559776": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033139", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf243d2a5c1e1b0125a45b283222ed4d54be693f8c8c6043a5d8c8ed64d56523d157625011947a8a79881987d9e9100963a": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f88370232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf243edf09e07e0b49da67583ea78c544158e2499f22749aef04333796fe92b73c06cf4e358a552604ff3e550725774f924": "0x74db9a1104a31f8b431ece5bcabbe3e508d22fe13670d32875ff6347a88d138807576f75746572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf244175ab241b696d9e6a1246873b367047d80b43f7b596676b4a6714cc5034708a9d651e55c030c2a0b04d8152a8437b5": "0x4eed7cf3f4f6560d58db4eb78bd24b655bbd1d7a5c6b454e77c8dc5e2721a54d0947414c4c4152444f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2446fb9c1f64231ba01e6885df09d999442d1b7759bba592a85972e3c6a9bbb419de5df76c57324d98c2d11810bbf4f13": "0x604189f1ea74bc439b18060c58f352db2880dd4c835df7ebb26e020bf11e7969074c6564676572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24472ccb3bb0aa8cb14f001497cebaaefa09b87b34880c5375ecca849557dc87a00a6243938d5882017fa0d1f60193815": "0x0a4a3233cb4870d9f20b5c55e77f839ce96a26f0fd773d01917919757664476500", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24490823f910054ad342b544618de7e4d545e8064f8898a29d4811e09b207cf3302e5cefef16615f8580fcd8fa63a624e": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f88370237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf244e4289bc529f199c16215001de50d3f7600c0e901b4341203f21f410f3da01ae4a45d194fd2c0693c6e0ec5980f4c21": "0x7600c0c74304812e4928a503408a68c782c69a6af2fca55fcd9e48e095b448630653462d3035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24514434f629431aa53550a7da9668f472c2a55b5a6392305c60fbcfcdf77a4041507f2bd1976c05dc149d2239d158221": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033335", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2452ad5e8e4e5b8cd84739b98245393fefc80cf0973d64eb59f1fb930f3107e9f8ced4aa69907717312f0c5015706f458": "0xb22f88d05ca6fdb70235b599b99c69f927ed71163c2ebc11c9649d678a8ba84e08466569204c6975", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24554433becff001e411b2f26115efeaff0ef72b01055276dae281f6da1a1dd14c6276142afd3aed8f8b6c94b36d2a717": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033138", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2459e87ab7d28a91cc6a000806c52034eb0adcdefee88f852a85ce03afe5d4403875fcbabc350bcd5d1b94c7ce68eec02": "0x946d9ac73a5f11a32e8c8709d631304d2db1ebbbca156fc86b9f4382863638140b6163616c61706f6f6c30", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24680ced073e9aade1b5605cc0f9b86f9ccd841dcfdb3ca84d8e995a2df2660d35f56952ec7a5cc18c8b0e33a71e34965": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033438", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf246d15db4941658f2122c77a23a5c36b81aec17785fa10a655d77b8850a0b7c5ac3ce5c0389555ec7d8f303092552cea7": "0x09cb20eb25e42c2fa106d75ee4d44b9c2bac20323a540529e9f4f40da5337bb307424159414b41", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf246f29a2f89305d9c14a12e64e837772b2c2a55b548ad46013efd1c045ec47aa4ef52b075a2fa3de11c486dee807c890f": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033632", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24748debb1a2e9d09a1bc28aed9474a55e8b6a4eefeb4942bbca2bee6baee73280d49c1b7aff8d1aa7616d06bc173ad7f": "0x666c474e2f859bb39716a333ad449122df3605cf2d272ab876171d0a61cbdd070239", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf247714dd6a1914aa7ee510444367f24eaa459c65e21e9f36c344f9def7e0ef28e96f6e1fe02f8e3aa798a8fe9cf906453": "0x986a4fdcd53d0e438f9694c9a6bb76665bc50acf76180049117caf3ca9bbcc6a064f4e452d54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf247cd033aa5760530bb024ffc1b8d150482c35d711666a25aeef2933e8c52be35e409e288120a6555139b0c45d90c140c": "0xbe776c10ad0e1fe7f606cfe42448e02cdb640c21214ea6c0c99df36ec0ee3d0d0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2482fc4f6cc89ea50673ed04de1d8b8dab2a9dcb35e27b71b75bdabf1cc706c567e50bbb20631e4f94d5ef6aad740fc6d": "0x3674aa73951219dbd27b3e3fc5847b806c68c1de38fd4f22f9493a461c80e90311535745455420484f4e455920f09f8daf", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2483a52eefaac1601602ae57282cc8dda2c2a55b52b81262e103c0657041660ac9f500aefa757a2c8343326d0a525f512": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033638", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf248724e6c4a1e4a8d0d707fba3df2abe0ca44000a7a16d0e5c56d22a707e7cefdbb237b9d20de2c46a53b551ec0cf1c40": "0xb42bde3f29708150bd47382f10fa4eba1c27a068653cfc4e3787b7fe05fe6e7d035631", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf248958a4a6b513199ef2b775e8a369e4b7cbfaaf0fedba11f23780e8b1bfcac5e92a85f56835027e83bd203bab86ccb07": "0xfcba1bf303b55be82bf6e48504909dfb85be27bcbbb2a330e9f4fc1261d8f02a0544413031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf248b7f5f33dc48b7f64a284b87211b9bb8ad3ba81e44bd11349a8d48bb168d583decd0257d3237df7d55bba5051f5254a": "0x9e4e7009937c56d267338762a60ed004293afd40e7c2081847c12cb63c76a8180841636164656d79", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24997c7a30b4f80e1cc80fbe180533c4706e11fd0d4df6c4765eb346aac47682cb7871da9ecfd235255f6eadb8392b20d": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504636331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf249ae6790c8b76029052974dca38bb2e254730499c6c53dd16d1e3f8007b64be019cc9229db22d36a12e44eff1670cf5f": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504763136", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24a945be2a7e7f62c4371175cf087af052c2a55b595b09d23cb9ea051e7655f90215123b6cf4edc6bbfafc3a99e366708": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033836", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24c0254aeb0f63a7ef97ee7249090c66d94211c46d7bb07c67c2bc80e7d5ba4623f8ef0d565d266723ec60497f0375b3b": "0x8a56b1da8dc3f4bd58630c15f5754ee634528a007ab510c86a7e1fe6e62f4166065a454e4954", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24e1c5184bacb25d01d56ef92471cb065dc46b7f9c2debfe58700f30be615154d6e38f059a682ca0b5049285180675c0d": "0xb204051d55c2c80cdf6e0d3346944e921fc97f0b86a4cc5eb5547982fc475d68065354414b45", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24eb15877fe5eaa93352c331f64661d75b4fc817716823ab3322f35702e26df4fcff8f577aea26e05bce9bef8b51b6707": "0xf3b15e49aede08aa29d7400da8d3b4fdbd284b5bb1f1af1a53a8c47398f1f09305504f4f4c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24ef54d965f89550dc64fc5d503df3c647c426559413ab646ae9152a606fce1486f754412a7e48f81e41786dcee8b7800": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033339", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24f66cceda2fa463c6e061bfeed16278cf68fafdda61f708ae4dc2e384c8012719774376e478bdc857f7191ef449ab522": "0x0a4a3233cb4870d9f20b5c55e77f839ce96a26f0fd773d01917919757664476500", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24f98bebdfef8ac2b8ccfa999893dd1076cecea2c48271687c926a72814cfccede993dad2b803ec0d546d2bafa586c11d": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb3893450563633132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24fdc47e9772b90bf5fc792f782ada6e82c2a55b50e45380d2db51edfa07ff46d01bbc34f908f7aa6b470c1593576ac35": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033835", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24fff7d12b0ff46b399caefface22445ef54df5a1ecdcbdc84dee4ff7821578632b9d6d884b9bfa5c52f7164c57d3fdee": "0x9ce3de1cd55ad6f4ab351ab212431d94cec798e1727176cca174fa661c8f636e033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2501083fd03ada04313b2fdf14a1772cf48b2cc621a25ed86391676c3686bc2cf76f06edc66a4c3c21e2452618ee1bf4e": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504763035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf250487c54a0b45aff5e09308bec36ffba6e28009eb2b8b7785246c452948c27169c4e3ed258ad7a707fb64beb9442fcfa": "0xac1aee6b509bdaa6aeb4718c2218bd7e78a3d6704bf886375e4c243b77a66b34033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2514d805b025f0256fdbcb8d66348bcc4ae34148366325c0ab46d5c086e05c87c76b58125490dababb7899e9efa41f53c": "0xf0de782e8bad3c663be60812f0a2ac63464f5da3ec448c73334c07d71ef27f2c0a53746174656d696e74", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25276c817edfa8a3bb8e54024fa886eefbec6a380acb8489f21891545cfb9b4964bf0f3170c5deddea166cd8f87bf2078": "0xd46cd0ae6eeab8ef19bf289712c9f2ae4272c663bfe0786d7c10d4ada52100030238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf252b88b0a68d17f8a6cf5d3c4a232d3c3c88bc26c3cfb3797c1b2e2c9e7fd0320d9899271ba9255a2408c4feeb33cd425": "0xdad042c036fcd9897945a880458b8e7104b30617a9640eaa22b7e23e675e0a02035031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf253ba16c02ca30fef215fb6400b506655c804d9b3aa2f285568305291efb2e0a6b70aebdd5b04ce6a5506c0a8678fe604": "0x986a4fdcd53d0e438f9694c9a6bb76665bc50acf76180049117caf3ca9bbcc6a0550555a5a", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf253deffa69e616326106cf9583610d7cd82c38ac61bb075ef3c6f745af4fc8675526b69e7a66c05e777e15bf3df99302f": "0x5010efb7049583595fbe3da57dc5db048e590c28f107e5e4fa2bdcc4b1293f6f0248", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2540ef2326634c6ae2404af890bc2c8b13e1f45bd8fa191f3441574abbe1f4ef3bc6eb07bd224560f30e45909eb0c8e45": "0xdae2b867564f01654946a095e69f0f49df1eb5c0efce5730cc3d1d83da3f4b090e303220f09fa69620542d524558", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2540f37eabde2631c3d6fca30b6983017c60f58cfada1c6dd1a8ad7625f8a184e6424e37c0ffaa604718981c1454ccf2b": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033531", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2541cc1ec3fed671ce229b12b481e90b0d0ed5a8ce0c20c3da0dade9db4969d52b6bcbe1f8914d3d9a2019526c9cb0b27": "0x2c89cb8652eff8c73266de06baa3760534e7f37fecff971c028c2910efd6a9470a4c6567696f6a757665", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2542904a84f009bbd8242464f4a4171c347500d616a78d59bd887bcde41d61f4ec880d0496fb4d9482f6f637f55cc1b29": "0x4026c99cba12d64d1d0e7a7a620bf54374603fcc056e1601e3713f992167112017747769747465722e636f6d2f706f6c6b616c75636b79", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf254aa3c4c23bf218e87a074430435c29182b224471e6d4cbe8d9d084d445bac45c91e88679cd3c22937d5e56da60e2bb3": "0x5e34b19d7230f1ea5da6d4b8fe6ede9d05c2e55b0189f75b967862c1c43d9a1f06f09f92b031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25526967f8d1abc061473b8c8ad563b9338f4dd8e0bd0a47c6263b31add7a887956da435cceec4750540743f0235c003e": "0xd401f460e0251ed41d7fb32ca463b5233b620cb9569eef5327def27fbd7c7b570b4341424c452d58203031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25539e7dce3e215002ae5e289a9015e183f24c61f66f5c798cc97adf5258664937f3c16d0b35121a8b45cc81611bc8e59": "0x3898b6f62b50749101446132f77fa6dd77a3895674fa8dac87e6c375ea85234604313033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf255e5c4a4b17e55b69ffb6138c9e216f82c2a55b52aad5c3cfb8bf4c7c478aa2b21b8fd9597fe2706a11457d23e10323e": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033736", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf256752f9f8d5ce6b947829aafc1b19e944e1f1d2881471357ea697093e5e68d46712d2b0e5b650945c4ecb571ea43757b": "0xd6c29a7c39cee45b0e045a94081bc188ef73be2be086d66aefd850fc7eeacc45164f6e46696e616c69747920486f742057616c6c6574", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf256d246a63af0871e9175cf3322bd75e15485545d9937d865c9fe34b5b3723ce78729178a292681d43bcfd35076a656e4": "0xd2a0035cec74b2f90f7e72cab1fb16b6ba8317631976b138f7cced3e00668b0b134d61676e65742d5369676e65745661756c74", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2576ff602f27ea4445af62da6e6b627aa2c2a55b5a0ac2e467c72c205ae9252a4e8a0c206703950f095c31ea3f022493a": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf257b6470a1a16508b722b109c9556b41d2c2a55b517d1c1a30c70133ca54050b2d409c86e87e4ba23b564c185f1d05978": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033636", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf257e15394857cd91d6fd1d468f950b52c447e00d54ea8610f6d515b7d7964b1aed5838c2971e585143807084c2a799311": "0xa2b06daf782fa5142e365d1fea0f4a418687f53f201f185bf314c37581677b37044d5058", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf258720a657c68526a344d9154d2ff4f772c2a55b55169b48ba48e99dabb61807463c1f91bce2ec9919c16f0fdf3616166": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033637", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf258e8f00f39a788bcc479b89a304f1f9c24f8b3dbcb13ea214b670cb611fe7939e20a23db19647485e01206502e64ef7b": "0x86f68361d0a346a62be267558e72dfb9e3b5a04adcc2c9e46fb7b9482f7c876f0748656c69756d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25993b1b6f0559e550406e90d54b7e2cf7cea95ce431976642559cd8c64177ac1a51ef6c8dba625d3d021fa8807c1a137": "0xd46cd0ae6eeab8ef19bf289712c9f2ae4272c663bfe0786d7c10d4ada5210003033131", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25a5a0e9efbd3efac0a11d330fc0c4a3b4d0887549eed4b4479973f77c05a3f40c7d182e983c3bd873789a519f5cf7ea3": "0xc48d1c4fc44dbbc10b86e40db24f95f8924efba2b31eecc6a7c32bf2b8a4481a074c4544474552", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25ac36e6880bdee3cfad25d4a3dba84866feb764cf5265d8f491f921d51c20318870ffb669b059c7a5b951d9291636b8a": "0x86484f63c9e0ae1f460dec3b53307478f5ce3ffab22a1334d34a52da7527ec6408f09f9181efb88f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25b50d8b53d5b8f5ad90ad0587de5e8492c2a55b528d6e2e0e0b7d4538eb005a63202ab1bb9fd8e23cde888bc573f6714": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033338", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25bbbb7f85791609f5509511a24485ed6962f61510310bf29eb0c0170a23fcfafbabf3d0b088e69d1982b2a31b0d7de46": "0x2c81fc1faa024d3d1a727d953187860b45bcb185d046631ab98261eb6f2b8d5416f09f90b620536f6e206f6620612042697463682d33", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25bdbb7dc8567ef315019102aaff7c7bf2c2a55b59a282fb173b7faf6e82984686f6fb83b0293dd498db6329464a45d1c": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25c1039d7b772c17eae4a70c176a843f266ced89b9a76de4d3dc384b45fdf0bd2f1629f15dd3e44ea14c31ba16181a255": "0xec05f950e080aa04f8ef335280637c8c80fa6b8bf54d5a3bbfa746b9f9da586005e29e9556", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25c44cc24df1b8c918f3f4b7debe6c94800831e9a6121a6d5002d53a89ce1d209d1e3359420a90620a022b22947d41140": "0xb2e07be4d6d82f546ec91d6009ee215bb736be5b4362e66e7b466ec72d47624f0b476f7665726e616e6365", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25c9c3f86fc5cccdc2784b49fd64761b446059d2f1a61eacb55d5c4c211d0b35cf3c3f4fe1f2601cd8bf49f30ac370c49": "0x09cdd094e9a51d26bbc6cbb71d3f7c5b8edde629402e3e5370e7f6904512fc4a033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25d00a9a66b9b640a8446bf2336b62596b4a302cab1fb0489c4211db08beae0bf7b5432416b299f57ce785b037c297a46": "0x74db9a1104a31f8b431ece5bcabbe3e508d22fe13670d32875ff6347a88d13880641726a616e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25d523d8838a6068649028f12e0c439042a1202907ebf57434db992641143ac78c8631a1e412d8934e5167153caed0645": "0x807e371d9df95983e2b9face8efb67f962816f1a0c6681cb1e5455127ab45c092020726577617264732e61706572747572656d696e696e672e636f6d2f646f74", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25d56cc1f2a7db8fca1e344d75c83e6e814bca285494baba8c77a19f94848063b287f169a57d42ed48b409eb5554d1d0c": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033435", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25dcc9fffed71542cca82764f881633e74a45b84757c48776f4c5d887e269e8e6c3f2fc55f75adf222662f129f9fa5b40": "0x986a4fdcd53d0e438f9694c9a6bb76665bc50acf76180049117caf3ca9bbcc6a0752414944454e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25ece685d5cd33482a8021f353de43ec1acb22f070631059ce62f6e0536e561bb5d470d2bd236985b0dcf42cc3e446c68": "0x2eeb1a6884bf369c7d1ab3f9ff75b79dd0f6c6a9792834e026a8d2f7ef049e4d033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25edb035a75e00aea3effc3d3db4468fb084361c7e80bd43ac0aa2917200339e51e45284349a264184ba0befe3e2cfd52": "0x6c7fdb8b8eaad1af9faaf918493606e1a3e8c20f9d852773ab5ebfbb93bd19480957454233474f2d32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2601a9b0124023ec68b73d6fd9f54dc32b0614de4de8cfbd7c760fba99b446a030b0ddd8f00a0dd84dfc88c7875d80c07": "0x726a98c27f84bf42fc842794a925418335fc9fe3badb1f535dce9c9d9efcc02d0230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf260cf06aff75e3e7a5b9f00bc5ef1d850a225b0e7cf9cf454c3ecf0d3477cd774c612795c312dcba6d09beea92aaf2a6c": "0xc804531378242158a794bd06c1e9ef0e569f60bb32758597af80e5e70c07a64f0d7379732d636f6c6c61746f72", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf260fd70358772eea75f1b119e85ed70f812c8663dbe1a18335ef5b7731a7ba8c0f25c0fcc761623af5159ec6eea586b28": "0xb8e06dc2e6bb6bd269319ace4cf8f663338f8f285a0564d6a139063c985d23100235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf261ab7a6d5c53256cf112113d5307a1362c2a55b5feb0eb28fc697566384dab127170f08c1c2a6febdfb4cb3185ef8917": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033136", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf261c54c7bd272264261bce1472d00c41400cb68a2c03e666f346a277036e8f27c912baee3c7b41c5c19123840f3a8e8fc": "0xfa5e6f955d973efaca30897c4a3e4fbec88186ae72b8b331408804d73dfc275e037031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf262f7d26efd475a6f12c57341aa4781bfd8b5b26b1cee228c6ece5a4b44db258985abbc9f0168950d744269bee80b1852": "0x8488bea263878e7e16be0a8c4705f9729a5f25462bff7dc7f2d8346370c8ef651453504143455f494e56414445525f5354415348", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26396f848202862f75e3181d145e563470a776e233546799e6f48a26bf32c080bd40e35986f608353c5b61b3076503472": "0x6e53696350731ed439f8c353b0b69b40b324fcdcb435ba225fbc22a33c9fe15407444f542f3032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf263c67dc518c9a200dad59de0615719ea76729e17ad31469debcb60f3ce3622f79143e442e77b58d6e2195d9ea998680d": "0x5ac4bbe840e332da2656c0e760904003fa7a2123a216a33e81b8531400600304033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2645b62e54b242fc3fbbe28cb0b35e2ee90cbf37b94fbb758804f3f06510840b6649c0a2cacaaadda6849c9dcb766b767": "0x664513c046d4497ba05c19efac47cb0dbe498e20b089dff25aa08d1a77ec970b0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2646b77305fb63b2adea883a08333b7f4fea1c72d488cbe5955b1eb68d746792321b1eb06616bab281f5d4838e0421c6a": "0x3296c9b3a6546d2319a764e00e1126215b776cb27571db2ef0392bbfbc66d45f04203032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf264cfee90d2adb3f3d5f42f2d9bd586e86492e3ea0e62e4e357e57c5b6732776f069e996133a08953b1c1ebcf967b647b": "0x2c81fc1faa024d3d1a727d953187860b45bcb185d046631ab98261eb6f2b8d5416f09f90b620536f6e206f6620612042697463682d34", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf265a8cf2580aa4be041af3cdc5c472db5ad21c2f113facb0631e7145ab7f255c3e46b49904587d6aa6116c56ad615fb1c": "0x22b7a9ef681c4a3c1743e5c343ff5b6f8aec3dc43bb0d49e29243d79ed40636504423032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf266608206f5eaadf361eb029c69e6fcec2c2a55b50279b01fc376a1b5e4e6670a8c247f00ca6c1569a9fd92ae18fd1031": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033432", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf266b542cb40878ffaa3b6eb0ca5973488eadae1c87f39ff2b60465c9640a1af260a815725f9ce3fdda291f92f7769e3b4": "0x0eb83479fa34dc63024ed44efa464427375a44de486e8d6007c7842b45ce817f037031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf266b6113765a3ae804d0c0a367181ecd9d66dba2833b102712151bbcfe1286506937ed28809693e730b622b3adb93e36e": "0xfcba1bf303b55be82bf6e48504909dfb85be27bcbbb2a330e9f4fc1261d8f02a07444130322d43", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf266f1255f7aec0e5f2f52ef440812bd4056613c69103858e51c79e3525fcfbc8315d93383b9280f0acd551bdc75a91463": "0x80d8a3f4317249a895e4b49badcfa7293cfbd215d6e552d1c07024d36acfbd5d08636f756e63696c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26792e700996f4c48444a1154cb56660d16b94e2d5d12d60c7314cca383bf185ddda83f413da740a121601e3277d3083e": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2686e757f35e373de52861a594acb4c7dbee56ca36a0a5393bf9bfbe5d2079e31d4359d35388df257e23793c7b195b855": "0x4056f76b206c306712a75e10ece4cffe091b1a49b0ba4c505f2ae4ee673c576a0e5a4b56616c696461746f722032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2697e24555d8adfb67c5a99ed9ef04acbf50556e30130b7c23f4ec520332817629963b2a69e5b024aafc29fe7bef6905b": "0xc8a5bf93006b7fd50ffc2abaffd57ef06c67f2171b5097070892fa1a195d920f044d4331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26989b179d681f768d5f039a62c4b362a24aa9e7b57a0e49b834fd499464cc0c83135679ac384abd9e6d7f07a8def164c": "0xe21727312b2b7ce579dc0f82f129d4edecbcf00abca607d73ccf16e8352cc7770232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26a845598a4beff519823c3245a375f96b8815e0e6280e1a3ff96f62dda149363592236eec3df9d48aafe8796c22e1d41": "0xc44ee45000531bbf1aa4c23540940eb10599e14b4fbed5267c42a0ebf5d09f6600", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26aa91e2f85720c7b9e54841b60aff4b62c2a55b59ed1954e80bf1349ee5882d429d261cf9962bc5d88a1fc176e60c918": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26bd12d2e9c4446aec63d3cab87d3cfa246b00fc11146ea6ce12405e83ec552c9f3d66dcf81ac4fd874e24db1484f4041": "0x0cc0424184702e27c49fb859c93f07d8bb0adf2a0824ada9f01db9bf76b7025f055a524831", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26c03b239a4bd4aa6d90d5ee1c3bfdcac0edaa0d08e8b21d6e8f946eff381ad4be29aa63569a54a6a75c91b878b463033": "0x127a30e486492921e58f2564b36ab1ca21ff630672f0e76920edd601f8f2b89a064c55434b59", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26c34abd7525397291b54e3a7714bfd4030e9bd57ca72b2de9928df65ac7974ccc0fe678a64c2df03e2159aebb4e8a525": "0x82c5c0e26848d49b32a7ae09a67f6822f2a18310b69a3ed9c31ee021440208260b636f6e74726f6c6c6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26ce021714ba84dbec5f5b95b28f2a4d306cf58e932ba9179e8493d36dd0c02918e37649bfff2bcc24d4fc19d47492564": "0xa2b06daf782fa5142e365d1fea0f4a418687f53f201f185bf314c37581677b37064a5542414b", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26db4c875f9716d75c900918cfca41e6b2c2a55b5f19e53bd8bb08c1cf5d540f88c25b52a10c7c5816bf906b0ce20877c": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033934", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26dc4fe62186bdd4aed984c5be39192ef2c2a55b50d3c4b8b607d14c312d6e25fbe0a9a585bafd68f597ad37989f9c406": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033639", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26dc8711e6d710264dd5e8322faf0ca872c2a55b5e347cbea568da1dc296c13b681ee4b655108e78bb9c33980d45e2500": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033439", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26e10ffdaebfc791b4782085c4ee3e7f42c85bbe77e464b97ad4d36a49bc2b84566c38b9bf6eff49aaf005c672fafe752": "0x3e3a490c516b2a3582e6400e33f3eec42a12589958cbb86c87b23bc94710d21b0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26f250de59e16551d7912972b2d280a21d8a03bce1c529217f76264985b1f082f154dad529677f85dcadc3c04c4c77d59": "0xb204051d55c2c80cdf6e0d3346944e921fc97f0b86a4cc5eb5547982fc475d68084e4f4d504f4f4c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2704a0ebe4aab907b0f82f628ca6ddae62eef2aee654d4975535f2701af86ba6d169c2c9a1599b16635a2a5e4640db94d": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504636333", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf270ba6779177c38560ef3de1244a7ad2c8e9b0b6b26839418f4baad18a9c3ffbfa413d65cde8010bf7b9b9db0dd23e005": "0x5c5062779d44ea2ab0469e155b8cf3e004fce71b3b3d38263cd9fa9478f12f28077061796f7574", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf270ca2b9faef23df18a77926ccd75e1027c8c3a92d8feb9d27f32f3ec67bcc6792f8496f7ed86d1b249c54205a39ee30c": "0x4056f76b206c306712a75e10ece4cffe091b1a49b0ba4c505f2ae4ee673c576a0e5a4b56616c696461746f722035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27149ed8fe6bcc8cbeba9ddacf8638fc13ab79a63ae81a8f096efbfb44d958cdd0253e97775b908d73de31a5d9cb00e44": "0x08ec72cbf62bb66f416f46f988e130585c834a381efdbb0755e30f47a2a0da5a0d5745415448455250524f4f46", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27157164a73e51400806e78b5fbcda4f9fab573fbe3296563205563eb39965933d33ea5a591c45af07f0eee2272ef6723": "0x7600c0c74304812e4928a503408a68c782c69a6af2fca55fcd9e48e095b448630653462d3031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf271bb90452019d586af6778148333f6e9c0afed691a6eaadcf94bda09fc7b713aca337f9eea5e7a02b1a6aafbb1a44873": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033432", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf271c97ac8ca71c03bc78ea90c3fd225152c2a55b554384ce603e7018c1bd0df5cf1a8b1f6154a761132c003486a723e27": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033738", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2722834a39ddb7b18e6c5c20e02957f4652057768741d83d391203c6abbce429b05bb6d148239c08fd104e6b65c531251": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033535", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2728e20fd18f59a839dcbd25812fe9dac1e503909a89514337bf9ce931876a08003396a9def52f867e123cf1420a0f70b": "0x7a895955042cb3fe863f3564e7b30e9130e37b6d905be11c0cf91064de1cd83a094173736574487562", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2729cdb4350b5c69a2d206102f47ac9497c2241b8ad2176aa340dea400bd84fc389091a7511086bbc78fa98a7356e630a": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504763037", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27356514c77e1f6a759420b0469e0b00b26a81cc7f1e72380949491cb9538d125d40de48e631e0e8bc40964fddee59bcc": "0x4eb32a5fbbccb1d97d31237172fbfd92945caa6822d5f8afb558aa7b89bc5a110230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2746e45dd2f0eac81eadc8e0f40c69425da0afe4e85d09d168759ffe74af6049d1001ebb6d16a0427e40a4e494a7372c3": "0xfa5e6f955d973efaca30897c4a3e4fbec88186ae72b8b331408804d73dfc275e037033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27488fef533c1b07f5346bdefb6485a4b8c038403fe48ee0068a652cfe2593d30d5701f508e38ef676f392fdc85f80658": "0xc09033af1dd99c3727bd222c35d9d34e8e4403441792399b08df0d60544fbd4811f09f8d8020444f5420303120f09f8d80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf274f64102879491d317fbfd224ac8cb2303bcad4ae89b033d823dd32ad149177e99e47f1c1edbfe9e5281f585bc406558": "0x2c0d08e42e58247b57421f3239e0e192b21edaed4bca2458028c981634bdb60706416c706861", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27575fc2108aacb1baa021fc45f5592b85ae7010248daf19a0b83b3d131f63a693785222293af4354035b8dce851fb02b": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033135", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27649915cca519cd532106f5a0c5794e8487a87b4140abf956405e80acb86bb44586a8089e79b476516c6ff9b601dbc38": "0xfaf5f68fe828f5af8d69c116efd937d90f1956b0edd94e05d8b5285a8eb2a66305706f6f6c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27678b5c55f424bb242a9b9a65fb5cb3f9e2691c29d062502fade8144a0eac25be3369a271b3fdf2208a9d86cfec6f948": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27720e1b29336a317dcf0f7f2c7cbbd2d640574072818008b0ffaa91a3d5febf7cf106a9285e35003fd7b55e2c1ae8b6d": "0x9a2cb674ea2f4866664769a1663fd6aa321d9cfb89b67c402c881891700c0f57104d757272617920526f746862617264", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf278125fd27774a31e80ce4957881386190a016b7d735f7a0c5e7987f99b8e46137b6668a6593c064d42d050979935793b": "0x140be3ffc8865dd47a8d044916b26936a579433599bebca9d3ba1d6eb772271004313034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27854176f581ccba42b32ced2bb079c5666d0425af5558b202c277f282e0d55775eb9fe23e0c68b7a10cfb7f59202b402": "0xaa6646d5b85790bc0ab869d80385fdc10e1f4befa7f8a4bf31848f73012d2823036e32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf278d66265f3f443034a03e439baa8fc6747e503b630c37057023c04ea57149dc70ae19f186db24f59881c55cb61da522f": "0x09cdd094e9a51d26bbc6cbb71d3f7c5b8edde629402e3e5370e7f6904512fc4a033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2793f9ce6c95d41e649650c39a2ad8b08078447732a649b7bf6970bbbbac8df97ce628b139a8407fd7d051f40a0258f93": "0x1232508adcaf57c6e78a850f9d715e3694b52000ce537832eb55c7a59f859e1306646f743031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27970d47b90813e971a8a0f16041df7cb00b03b23766d70d0445943b290606521acaefee7660d521950faf2801c79d428": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f88370234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf279ab4cc0637bfa6a0af4122c141e61372c2a55b585dd3e7bf5cc92d3eea96cd13018755382f0ba1be21ec1866b043212": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033833", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27a319d2a73687c9bfa3b053e9103dabb1a356596f667e9330b60d055872640198b86485ac1721c37fdfd468157a17a45": "0xb22f88d05ca6fdb70235b599b99c69f927ed71163c2ebc11c9649d678a8ba84e0c56616c696461746f722d32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27ae2b908a33c5ed18881a29cc36193b5b0ec35caca1aab56df7814b80ea0585eae79ec6f58cf03a8be0c40a5c6707711": "0x1280a479ee3beca7af1636aca17582f30829782e2c9b1b9c72aaf8060563ab37033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27b71a04416fffbce603e09de5a8178ce02aa5256d804b33717f1d338eef9901e89682b80c81e3b1138a02079e0848aa0": "0x30cfdb48ff7f33b08499dfc618a8ef9699b8345fa65f0b1339eb8eec3c0e45550231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27b855f3aa400faf901f706ee3942185d2a211b13ae9c29f805070d21d5e5e007db8ab2566e1031b6ec22733f1f3c0877": "0x465c6be30d314cf647a8fa10212bcb84318394659c46fe75d03640cebb39595e1a416c7a796d6f6c6f6769737420636f6e74726f6c6c65722030", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27be9a3f8da53c454bff90ae9ba01dd96b4de0e0553f854c72746045b90c8e5c67d74f5d8a52d4134b259ff562e4b1409": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb389345076c646f743031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27ca1f946b86dafb5047b0c68ebb6f07378c505721568ecb57fe677b4c24e670079e8c342cfbc7b312c146067a2dc02a4": "0x6610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f380777616c6c6574", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27cd11db5821a7f19322ac30eaeaec8192e001e3f827e6eed45a60d131d97df1a5b429ed1d0f89fdedf3eda0a16502d3a": "0xb346948ec9e4cf84b965ec17a752b3e8eff098934aaad42ec50a347dd7936583064b616d696c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27d31ff5a817bcf68f902fa99253a4268f8720c905d7ac1acab25c4f353df9eb759e0141e4732540d163ac444260f0177": "0x946d9ac73a5f11a32e8c8709d631304d2db1ebbbca156fc86b9f4382863638140234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27e65087dd946c27bb1e415ac33130b0fa65bbeb4425c55a611da4116e848b0cc39686a11f88dee6aacceac6bc5eca657": "0xda9f7fd3d9612a68d2ead69dde53297b172b7db514d0d261e7c5be987df7f32a04314b56", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27e7a14ff98ceda0098f284ce8eafbddec880ad522ee62f59ec14aea01214fb737df562d1a9bffb35d70d35bfd2c72432": "0xdae2b867564f01654946a095e69f0f49df1eb5c0efce5730cc3d1d83da3f4b0910303420f09f909420434849434b454e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27ef31002060ecd1375d54d35f3c7afdb22e84530cce98a0af194e12c568c8923fe6d138dcd6e19fadcece6c0a5f10e87": "0xa24fde6343e2bf0aefa296afcedea6f16d37c5e1c0d8b6511e7055cf7282b60c1053756c74616e4f665374616b696e67", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27fb6191430b9e8731f77bb822cbcb63631918cb9b9c9414a2cd4dd7f720cb98fe98cf852636fc4860845767989127e7d": "0xc5c184f0565e2192d6aedae584ee736cef875f0e1c558ee3ede26869acd0b4d6054e617368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27ff5e411dd09d48e564e8e5d339786892cc16da9d1f7271475075aa8eb5c6667714426b8c41dbecf92bdedfa462b7163": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f88370236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28000519116f8a1f19043cd513af0b2abc07244af8ac9b81030b3c47c23cd5b10701d4a5490790e20d12a583e5e606823": "0x825872f7d324c8d97a9d5f5c94d918eea93ef783f305767b768a76f9fede7b4a08e29aa1efb88f31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf281043fcb3cfc5cb4e0e03206a24d135d2c2a55b5f64fedb5e9a535e4358cf539e294ccdddc753610fbe8c25ed72f9409": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf281b653ca735cfdd41d4e90fab3490af3d68d71f02028d8c8d8a76dcf0eeba7f93ad6b2a6e2f8363ccdad5fa580705211": "0xe4bd04a7052f76425c60648c528535285bc2a23ab28db060db34f7c5e5746aa909434c41494d424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf282576488c56e00b214d585a717339dda8c5917b51ac796f4dbb53a35008c1e0cc5a8e3aaa1300cc2e845f8e7702cd4e5": "0x3c84767978ada6355ac3719ea8f978244b16d7e8c00552c3a189760b55eeb404033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2829d6f3b7b3efa8f10f9077fe36a82e498a8cd51a12a19dd5440fde5e43cb50f9d48d95ea5c5ee3618eb0b2945f02f21": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504763132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf282a5417b0e8372e7cfa89e428887784f2c2a55b5e1d0f2cabfbdca681bac43c1f684748d18c03b0e04e28b2fae9cd704": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033939", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf282db2fcb58fad99c289f7a86656931e12eab66a1c3116f15f55dd2996db419e367106043a4c5491a5eeab1d33a17460b": "0x02bf32e061073c44300056b416cd66a4fde1e6c120dbc0089bb65134f5693a3b14636f7265626c6f636b732d6d756c7469736967", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2831ad22a3ac7b99bbe1efce6cdb4db35aaff773e3f134d4e0c90ef5e5f37adb603bb591b7aadf67a2a757101a1b70302": "0x7a895955042cb3fe863f3564e7b30e9130e37b6d905be11c0cf91064de1cd83a1050656f706c652d506f6c6b61646f74", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2834a4e0a38c3e40a86c37d60c5bf2b1f7e74e295c040927de4200c770994a314185d3ee447be3d70c79ed056fdd1ac53": "0x5002926543d8b8887044442834d4fd5fe3d6eb257719daefd3f2aed28eeaee690231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2836c70c471ff3bcb9c9b3970765eb06594ebb855993bf0568b71fbf4197fdee4cb44a39bd46fa5969bc5c372ae101367": "0xc09033af1dd99c3727bd222c35d9d34e8e4403441792399b08df0d60544fbd4811f09f8d8020444f5420303220f09f8d80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2842bcb5bee0cfd16df02dc65ce8fb10a785c76e65b2f38d3dcea220f148f8d4b42046ddd61eff8af6828d24f633a9c47": "0xd46cd0ae6eeab8ef19bf289712c9f2ae4272c663bfe0786d7c10d4ada52100030232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf284840437a62edbd7601338ddd95027f4a9695441f301ba78bd00ce015f2f1da14eb8914531fa38695502369de72c256f": "0x8c085e6bde4ac25702f54f46fa3c1b0a6170bd346103c2c6339911e00306a0540231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf284cce806eaee977df2ffe64300cbac9fd071e04ec30e105db26f05b81646219bc57909c674c2a081e48906e604f9867d": "0xb2e07be4d6d82f546ec91d6009ee215bb736be5b4362e66e7b466ec72d47624f05506f6f6c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf285190df364d7a748b874cc7ee3c24062fe9d714ec9ee0f74e33282dd9e411fd0f47c1aa17553392642df99d1440df951": "0x946d9ac73a5f11a32e8c8709d631304d2db1ebbbca156fc86b9f438286363814033130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2853aafa32e9618dd96acd68a704bb74bba318e50a4896c8228b14dbdca63c64b9a4fe82ee967a41612c4a55909daa960": "0xf0de782e8bad3c663be60812f0a2ac63464f5da3ec448c73334c07d71ef27f2c0b706f6f6c2d61646d696e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf285f2ea0dc6f1ba18380d529259c4a2982c2a55b58f78423fa34f63da52ccb699e46952f94053123661ab8316d4f78e07": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033731", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28602d0517cbc0f0b26b18babded8bc622c2a55b5e4935526d6400d729ce52f5065327b414a971c69fcb85eef3d5a9401": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033931", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2872b81b0d92a731a6d2ce1955c86f1342c2a55b514ea318202f6b920073d878c2c9c94fb38a48e4c7b3d4874f755c06e": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033339", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf287ac14ce59b2db48f1386aa4d8361162eea674f13649b25e552a59b65dd203fd45055ae7f39b5a6551cafc9d4eab3776": "0xbc1deacfc7e5c6e5f0373560c14fbce156ff2a0ed7e208d049ccd985dec85545084a757069746572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28954782c43b8bb9c87f90ccfa4352c1c7061c3799bd2b1d70aa6c8014a0012ea494f4455d60e182dd1cc393d37f8604f": "0xd45548e42d7f5d5aa35ffc16ff29396c99936f0c1eae84d452f1daac87c3c566064d65646961", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf289551daf6fadbe86a54a27a1280f9027149fd573a4ad8eb5dd80a1b70e89362e72f0fb2512075b4d9a52e7d23c0c776f": "0x3c84767978ada6355ac3719ea8f978244b16d7e8c00552c3a189760b55eeb404033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf289a625ffd867d7cfcc361cdf39c00b28c215be73d91712a74db57cf18209ec172e9a3215ce6ef5cf5b0292177d3e1140": "0x7cbb0ed8bf228935241774290753bf282020d73e45f6724b0196c97b3bd534620a627269646765687562", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf289e9e9cdd1da3bea187471c581cd43572c2a55b5d60f8f51745d9b979ea7dddb0f79692d51cca14c4791e72da59ac963": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033932", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28aefb3ff9897f97f9a756efdd5f1f2cb2c2a55b536cb66c8bf2894af968ada12c6e7db4bb028a57b2247333440458469": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033831", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28b37f7b59891ba4b1fcc3d9e618d854618c0445577a970766dfbbd43589ffdbfb1bae33e8f286969539300c6a49d0962": "0x18c044557335d26c3a538ec7a2699ef5665cca1d17755cd6ae53d41f5bf316230b476f7665726e616e6365", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28b7ea082adc3324e5b78fd6df0b54fb4c2975211d5ab22d276be7dc90646aaac121341cd5c033b2ad6e1a43d23d2b43a": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033439", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28bc458b9c4ab0df59fb5255f34b4bb9c18cfd7be6a32e4e3ab369f7be8a880a70f42a0ef260ae11a740b1feb7dc47969": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090b6e702d746f67676c6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28be0e4e81f83977ffa5879c873f9a3af9890fd3e365f6954b5bcab3c8195024da5188beaafb1b13d954c0281647ba535": "0xfa5e6f955d973efaca30897c4a3e4fbec88186ae72b8b331408804d73dfc275e0c636f6c6c65637469766573", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28c1df885366c4853b057f114e18be01ab6ac93bc22957dcf5ea1a84b1ff7e60ad872eaa73f3d176ecf7b980cd33b8b00": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28cf1ec94779b507b452c5a8d569635a52c2a55b5079b0d798a442d87e4bf664a01d50c11af9ca230ee4738b19aa95b6d": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033737", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28db0ce9a26f228a1fee649279def89540aeeb3fa38505a54f76f2a27321f9b5b875635d3b05a0f4bd92710105f377f01": "0x6e53696350731ed439f8c353b0b69b40b324fcdcb435ba225fbc22a33c9fe15407444f542f3031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28e23857eb94353aca0e54d2139f418bf2c2a55b5baad165d64eace5f75642ac4612ec1ef12bbc1cb27a0137473788257": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28eb702b000ac07c484f721d86ebcac24c63d29b9669894bd812dffb0a0206bfaddbf728741b3219e9ade9937bfb1874b": "0x5010efb7049583595fbe3da57dc5db048e590c28f107e5e4fa2bdcc4b1293f6f0245", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28ec2e6f95318a0783a464b6de2c96a7a5ac7f6af5aeb5364188840d02f0e74e813e6d9cc0398d6994b66727658a4fb30": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28f901de1e12520d1a72618f666f08716f2e78c673a855ce341b8d431b3e2ce293e812236e2e42682047796fe599bb734": "0xa80ea94af8a39eb7ba8d9afb913147e67eae84f48aad7b9ce6ee05094fe0394e07476f4f70656e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28f9f94d9cb3fa7cc5c1578d471b1dc673a92d9b2a48ee9adca77ffd658b1e273434924a7b3b456693219afbc32279e10": "0xb8e06dc2e6bb6bd269319ace4cf8f663338f8f285a0564d6a139063c985d23100234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28fe0ba25b107b745ffb6f32ca8f1ae85c85cbec6e7576580deab57475b75d3456c379f8c4abb617969fbf99aa4e8c076": "0x1280a479ee3beca7af1636aca17582f30829782e2c9b1b9c72aaf8060563ab37033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28fe3f5cb994e72633471458e82ff1381aca4f84ed6959bdee967c0bc4d289bf3fad8671f5ce7068072a7dc34964a8d0c": "0x561077519794c195b22f5058bd1195f6847aa6b5a749053d44468ba5db872d640234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf290b45f1b25bc12b37bbd4713609287d62c2a55b5b05723585c7421428d9ef451313e33e13803424b0f8cabd383d0df37": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf291300ad34b9ea09a8d8d4b867e87c876ad0992e51165d995e649d0a90b3c349ec9694d84ab1c3294e4a9c58839e7b4c3": "0x1eb38b0d5178bc680c10a204f81164946a25078c6d3b5f6813cef61c3aef48430b46656c6c6f7773686970", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2913678ec80e3bfbee95e5895fe707d35e0ca65cc737d7d170d9f7b09247f9cbc52142c62a6bcb4d8a5bbf29e6cda7e05": "0xaa72c321b20bbd5b78b14f6fd800017bca47190956eb42ada2a4d8f8a8ca994d164d6174746572686f726e20436f6e74726f6c6c6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf291b7d14915b81b93ff85d756391526573ef0a4136babea739fdcdc300f622f23d9a7fd229dd90c8f3c9e3d75fdeeaedc": "0x1ecec4f3062f61988b13e9dab318860bd0fffe5b7b37880d50a614a0a20c250219f09f9a80206a6f696e20504f4f4c2034322026206561726e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf291e0b9d1df879c873e96ce1f8fde9d7a081c5466574f932ef5e1469e984d5d39ad5946468f0ab9d06c454f74cfc2f16c": "0xd4539a7dceeeba9999b6387e9431e83c53f4b884edf5cf049623110eae5701250545505631", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2924d38edce0e39108ea6be45077495860a8a307ef15b9f928697fa09dcc72a2c19a266c1d32fa158f9916b8b804e1621": "0x984e16482c99cfad1436111e321a86d87d0fac203bf64538f888e45d793b541305f09f9383", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf292e1e7a922ca653422e42711cc29cc538cda73070bddbcd243f2d1f25982dbee2a0961b277ec209756bf794c2d0f7f78": "0xb08b555a5a3b2725e01ba15eb40aa32dc5b781532854b797808ed45e752b047c0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf292e313c38979b8bca120e2d5471df17d6af358e5650b61943ba709efc5dbc501405e04d5de5798087d6c727027511a65": "0x946d9ac73a5f11a32e8c8709d631304d2db1ebbbca156fc86b9f4382863638140237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2930c4917f16a6c61684103d1d981796c2c2a55b5ffdca266bd0207df97565b03255f70783ca1a349be5ed9f44589c360": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf293ccb275d05874df082d79db1d3bdc3076c26a1fb9acbdd56be00d4c44901856929b9d2a879caad6119ad0417e994949": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f88370239", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29432d823f39f0985388d21e1330c779a2c2a55b582572ea3a02d92d1f303959ed8d301f20cf7377795bba4e77ca5f059": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033739", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29499859860e76d338d9a9e56fce67bdc780946289b4befff0da9911c013aacd2b280ec0529a759b94c67e4899b9b7058": "0x5c5062779d44ea2ab0469e155b8cf3e004fce71b3b3d38263cd9fa9478f12f2804763039", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2951d5278a8e74b67f202716b3fe4e163049a9687c22bf19c419cfcc79a77b60b07faa3df2034d7cfa4635350571cbd32": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033239", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2953380a1930e1a615abf34008ca176ee2c2a55b5af6d74281de0813a60beb2a89ef39c6b2a10a35427c683d61e98f170": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033434", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf295475914bf4f6e47667439674af275652c2a55b545afbf04bb687cbfe5f7a4fee66f0f0e9036072dc3ef88be6f3c6c36": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033837", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2959646c7eb21bfaf835cdf5321d10c972c2a55b572dd8f780415f21ee812b5bb32d6baa791ce4c8fdb04a13eb21d3f09": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033337", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf295f3374a3a2708d729b249f44f5d74f7c3405f63dee12641abec6c12b29453b7065da04a95c09998673aca6f0c4a164e": "0xa6c5f0595d6ed85d6260bc682d4a68a4b4e605d43c67d56f2765d19698549772065374617368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2976d81795a66d60beee052e684e8cd4bfa5be617ad31f9c9a41041cac3ad8ace2c550c28c73afc8e34367d64b50a6679": "0x561077519794c195b22f5058bd1195f6847aa6b5a749053d44468ba5db872d640d56616c696461746f72203036", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf297bb9c1b69660dc90493b5840f176cc32c2a55b5451bb1d573ede48bcf7ebf76950aeb780120ecdf3d328467d62fd929": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033537", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2983e6a30e5b52f58c129cfe267c0323b703bd4afb52b696047f54d9c991cc8fa8d7a7734f034a008c630c97f95250568": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f883706706f6f6c31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf298c6979151fb437f7d051660f84e2a6bc08d5de7a5d97bea2c7ddf516d0635bddc43f326ae2f80e2595b49d4a08c4619": "0xbc1deacfc7e5c6e5f0373560c14fbce156ff2a0ed7e208d049ccd985dec85545094c616e69616b6561", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf299339913f2ea3776e109aac28a60ea1d80d57608c732427386079d29d65035cfc02b3221ff32cfe73b540d849aa00462": "0x561077519794c195b22f5058bd1195f6847aa6b5a749053d44468ba5db872d640d56616c696461746f72203031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf299647f0ce03184e7b26905d6dd31c6616a66d0c75a897e62aa4e9cdead9f50760db6e7beae858c1bc3dcb1d1ce601e58": "0x86f68361d0a346a62be267558e72dfb9e3b5a04adcc2c9e46fb7b9482f7c876f086c69746869756d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29989d353f6de2de2c9299baa910c36663c92bc22c4934341504e8b6f0755bb76906171bcf8a55c49a78e2055ddd28802": "0x043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d0a506f6f6c20f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29a4392a681901e7e99bb41ef9de7150e888f666828e8328a33647a47bc97574a6a5671819270cc01e66c7139a1a6911a": "0xe8c7ad65c15fa3ba64424a61b177382a0c5468135aecca9ca454f5e7ce4d305b00", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29a756a8f12d432fa50b944ce913ad2c2e417170e6d77f90f6d7b308bddb8a414f44a87623704da628229ba777b644647": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c0cf09fa69020534852494d50", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29a8b6cfd4ad6e629f434a37da2ae59fdead7c523761f8ca72780d241f11dfb4b3543c4a1e17263274d34f468001d571a": "0x8e07d43b19d901badf3a7f57155ca84f2f835448e93a141bbbd33eac4b767d150231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29b341a8e37405326ddf25244c70c5aa24c1bdac31e30cd50156586f5009d576c2efdc103be5ef0649d55d3b53941760e": "0xc6477bfd57c12587b1075a80d944c7829784eed61a5c8b8255817e1d62d1070e0c56414c494441544f522d32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29b6792186b130db777b313c57c8c6c156e306a119e947513f180b430e3e75bc8c476a8b61e8348d1f87e490121601b5a": "0x5010efb7049583595fbe3da57dc5db048e590c28f107e5e4fa2bdcc4b1293f6f0244", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29b6c7d30389e104491c2397c994076d94877511245f8954e48858da743b9eb3544681c27ffd8802c8ea1669e961a2b61": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504763034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29b6f49c1c3cea48fe030ea8f448a6f542c2a55b5a6413894e13836fb0165e6adce7d77c06dccf42b3b288397a27ddd3b": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29c3d2817eeefc70b333c5e44e079e6ba8ae437cc2420c617f2cdec05405db6c449bada7d2b2063eadeae636a25c5ca79": "0x22b7a9ef681c4a3c1743e5c343ff5b6f8aec3dc43bb0d49e29243d79ed406365033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29c56a115b77627119d1abd9375e625892c2a55b5bb604a28edf5e8b24c72f0c851a6440c1889346d8ccfcd298b601e25": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033433", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29cd1fa0b313309eb252fc2216d869b058595dbf64624ef80da7a916f139b607fe8ac19aed219da7c7f9990be2c214d1e": "0x5efbe83a561d19b1d21126af5f1608ed28e56f4f70251cf965fe3dcb4901a26b034b31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29cfe8a4e14b7806a1c3022948146ec15a160a7305cb5b47a2903f6648fbb6ba1ad24d72fd49c39ec7f9d21e184f3dcc7": "0x6610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29d62ec2f1c1a1b440508c50c06d174f058ac509e6e93bcf6ac0800a070f28bd477fb9e9717ff7779d035094e361b1504": "0x1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413063151554944", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29d63ac56016d275d23e7b3d913045a0cef7550d2801399e7f9b263d92c33ce0eef338eb5527760235e4ff5219bd44c9e": "0xb45f7d4b6bd58cb550270c1ba3d9d97b6766787966b0b5c52c79b4d3b51d9a43033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29dc4559e1187878664e74a61da9447c632f5040e4ff22a9cea43f7cfd1242e3ae0e57140c2f4b985e83ffde5e5c4492c": "0xa4731404eb64407b76d75dd815a3267e2dce24d8c2054f3d45d83ea11c8d707a056b656669", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29dc6f90ae9ad151eb3ddf552adbff75e5e348817abb98cb962fc0780a47ebd471d9c318395fa80b4529a64cfabb2e32c": "0x4056f76b206c306712a75e10ece4cffe091b1a49b0ba4c505f2ae4ee673c576a0e5a4b56616c696461746f722033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29e4ca2c4c5877d06609b129963d870f744e2fc205de7ec0dfc49f2e05c64555cbfc897602413c712c93967b59257e537": "0xdae2b867564f01654946a095e69f0f49df1eb5c0efce5730cc3d1d83da3f4b090f303320f09f90b220445241474f4e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29e758ec7459726d3a561d0e141080d46d4171a4d884070585e1bc36f234a9db406e6a89575ee9e5ad24605e146dc4c28": "0x3296c9b3a6546d2319a764e00e1126215b776cb27571db2ef0392bbfbc66d45f0a504f4f4c2023203134", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29e7a3f75224238db6e3758836b8f9461a8e87388e083b3f1a9dfeef27977d883cf10e7c94acdf0c60f57f0a9621d4539": "0x4056f76b206c306712a75e10ece4cffe091b1a49b0ba4c505f2ae4ee673c576a0e5a4b56616c696461746f722031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29e870d2b0cec845a2caf420bd3b7ddec8a64dca67c64d9361901a1415bfb3469b000d0bf7f1d439824cec71f87022159": "0x946d9ac73a5f11a32e8c8709d631304d2db1ebbbca156fc86b9f4382863638140233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29e8947cdd87ebb2864e85a33f3dddc376e32fb9cce7edb56991320b049369ce553a5ba93c5d262dcbe796a9b9f3f1524": "0x5efbe83a561d19b1d21126af5f1608ed28e56f4f70251cf965fe3dcb4901a26b034b32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29ef9cf0b7a6ab68867f5055b6222b644605fd1308af1ce85bab5ba3fb19b330ab7dac29e01ad501420560f44df7e0e1c": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504636337", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29f8a1dba08e7b6c0bb2ad1343251c54b1aa604e30e2baa8547c93923bf8be8c08efa12efaa6b444e214a3d631ed54c04": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033338", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29f905c1baa64d9a27dfd9b4ca546b0de2c2a55b5364338fadf45981d173acd75651f8ef41b57931694c3870cbcc54870": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033732", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29fc537374bc9891d40a39204c7093f312c2a55b505d8d997b80d747395c1471ad1e1e8aa57319c5727c6f178bde2422b": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033838", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29fd0b6b8355915ce3ffa826e5b38279e7e726af71a51eabcd429888bbd0e46ce1e63b3322d0683994ca825dad3d3716b": "0xb22f88d05ca6fdb70235b599b99c69f927ed71163c2ebc11c9649d678a8ba84e04466569", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a0505d22540321748210e91a159ca996faeb0076ed1094419bd13e852c388586de314e8437d9c0e315884c10f1b5520f": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033534", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a08e557c63b7a8007ff6689842110e61a28942a9d2e8c8501860b847eecedc45d602e614b8b0849b959607d0dec3d071": "0x666c474e2f859bb39716a333ad449122df3605cf2d272ab876171d0a61cbdd070234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a15ff7725017f89eb1a3e7fd12423158468eee3d896dc822a496e712d1116e0731235c54bcec12e41eb133bf9c98cc15": "0x3c82ab06b794c99f14a161973be7aa6012568b1c491d45ec969ed7420bcfaa5904563033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a1d210e875e95a48beeeb7de06a63a8dae1595f870cc27a34374a6b819a554e242997efeb760433c6fdb4372c2f28204": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb3893450563633130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a31f5cbf4475bfc9efafc13b1b0c25c7c0a05f52c96d2af9862c7b89bd23a92c7e8345b92f1115d368b6548a58aa8f28": "0x8e602e63afb364ac583747b0a8bab092d5b20ee98f0495ce7562a8c992ac9f171050617468726f636b4e6574776f726b", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a40eb48b4152b4473297c29ec09686691a7eb7be90a60ea3c4b467df2f8fd89288ef44f581426bd98cc34a0b67bb959f": "0xe64bc946c10a1f75e683f236e72a44d6d61b3bdcf72ffd8c738e488efc6e1567033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a41f147666b3bc8614da9accb6345eb3640d12a59e7ac3ab24ad5c33dada639c058006c59fba147ce8caac535e801415": "0x091bb84ac5b08adf128e855e1cb079ed594be42af19d09d680dae982ac209ffb04474f56", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a447ce4afb0ae4367d7392a01823a74b6c9e3102dd2c24274667d416e07570ebce6f20ab80ee3fc9917bf4a7568b8fd2": "0xf65f3cade8f68e8f34c6266b0d37e58a754059ca96816e964f98e17c795050730767677770657a", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a47564e9fd9e709bdc7f4b0f17b513d19a9c5706a3b70b507dcf6b013c69ef08af652b1997d6fe82d5ba6975a2581b21": "0x1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413064354524c31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a5ed7d2724d100d2d05bdc1789317d1965819df33c22d72346bb95afd79e55414f35acbf0997c6bbaeaddd1d3688506a": "0x7ccb1907030863dd708764cc88a4b4d09dc5bb0f4c9ef5f4e73cfc0aa4bcdf3c0c426c61646552756e6e6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a61143348f4f5d9480149096130d207f1baa453966c043ca367ccfa19f450244447b9d32f4b7af2d9749e55a57ac09cc": "0x09cdd094e9a51d26bbc6cbb71d3f7c5b8edde629402e3e5370e7f6904512fc4a033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a712d143d4d87ce437f368647a2bd84d0cc89d59de520e70fc4b9bb9a43b41b2b748ab0dd51ea18326e8ce755931ea0f": "0xac133ebfde441672c055b79ca9a6059850984eead1ae036f48ca1230e7f0556f06427261766f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a7c5daa2edcf3e3f0564c7916ec616c22c2a55b9020732ceb7db3ed3ad35a2ada31a65bbe0ac94ee072d92cd27a38f7b": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033938", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a8241236ab722210dcb57860ad26dfc420df777c881c5f4eed3f1c75e29c65fa681a63dc612cfabc5217f4308924e62f": "0xfcba1bf303b55be82bf6e48504909dfb85be27bcbbb2a330e9f4fc1261d8f02a0544413032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a8e619e1be259276e1931733fd74468913be73ce92b712d00931d4980713bf4be8974255e1e51a7ed71ed2ea37f035dd": "0x6ef40ac7b3e092d0eca77ad072cd317683ab9d24aca4025788421d4276527d57064652414e4b", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a8ee49496c11e988c1de658b6e0d91892c2a55b527a77c6ce5976953b4b0bfd3f7db8a96d27fae160f24a0a6759cd466": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033735", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a90be8e2b61f9112e1ead4d7fa120b6cc676e6031d0f7fb3ead234afe813ecec2d6e3b47fcee702981feb2c168e2c37e": "0xc09033af1dd99c3727bd222c35d9d34e8e4403441792399b08df0d60544fbd4811f09f8d8020444f5420303320f09f8d80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a921bc99ba337c424ac2e016f6ea4d330aa18c1ff67dccbb98cbb86ea9808b63dc72582c602fb0dcd7e6716dd9ed9c75": "0x09cb20eb25e42c2fa106d75ee4d44b9c2bac20323a540529e9f4f40da5337bb3074b415a414b49", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a92f96adef1c22eca20f96605e019b3132aee225f2714c573eec965a9dd1e1ca399636d9158ce068842f0558f360a435": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a92fa064bb4fe97cfea5fa57b0ef07ee98d7bbcdd3c7fe6e9bf7de42bc97968143fb02ce4c7f2382552237dd13982559": "0xfcba1bf303b55be82bf6e48504909dfb85be27bcbbb2a330e9f4fc1261d8f02a07444130312d43", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2aa0d24943c155775d7f5956b228aef940ec3f7291f82335606f98e16f5480b38b3da95d2e7ee9489a89a8a39f9dac956": "0x666c474e2f859bb39716a333ad449122df3605cf2d272ab876171d0a61cbdd070238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2aa1d8432f3ae2dbfe11172e994ab5a6e223188d5f28ee27f7e9067e89bc52fca8f1da20c6a7548a21cef18d8934f820f": "0xf0de782e8bad3c663be60812f0a2ac63464f5da3ec448c73334c07d71ef27f2c124c6974656e7472792d636f6c6c61746f72", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2aa452ceef83f65de0ade28ef358d5b37102df685c4659f9c242ff9ac8a4ee5305770ede106db7a3cd5d3e8823e33d001": "0x3c82ab06b794c99f14a161973be7aa6012568b1c491d45ec969ed7420bcfaa5904563032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2aa534b6d5039aadd4851037521484c4c2c2a55b5976eb2e7893f7c3f875b3b1cf3d653df30a0a58125d9fe0f8b87b832": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033930", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2aab63b090fe2eeecd42800f5b691cc732c2a55b56936ce0a4d5292c66857a725cd7b30a6d305922f4631380666e5ff2e": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033634", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ab89d60f1f71d97cf57fc21e5c05f15f2c2a55b592b0caf0f0440b89aa8c1d713be7b3a16d79b3c56eed19d7acdb6e08": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033830", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2aba55d6a30b782ecdad58fac612e470c24f7bf2054bd95b8304900a908f8b298ddf79ccc09931f514305c490d047a63e": "0xcc52156f09978540d3163b798f65a8788bd04d828f366674bf9ea1f88e96f5190a444f545b315de28fa9", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ac1d7c3437476e392cb67606eda3c34a30606b4c1b89b4e562efafe76bec80154ac8b3e16e04c2e0f619bcdc0a5eef52": "0x3c82ab06b794c99f14a161973be7aa6012568b1c491d45ec969ed7420bcfaa5904563031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ac40882e593b56d2274898a5cf71e2542caa5b3f92b80dc21b417252e93eb55ae8c6e6ea96c7424bc80d00cade786627": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033431", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ac82a1e1a0c89cbfabecf8bd0837093f24172a563943291c97d252def71e17abf467a1626bca358728a90a82b3de3118": "0x6c695c4e546c6889ca591b582eee8b49ba68d8485a3732e08d232b2f28f2342e032036", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ad6a2ad55ab8a74da4f11b3b65d69ca2be4c6b203c1e605511cfb8db27330ffa7abbaffcba5836a0d6f3151ee8eb993c": "0xd46cd0ae6eeab8ef19bf289712c9f2ae4272c663bfe0786d7c10d4ada52100030233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ad805490353f543cfbb0ed9476d0ee357ef6c750071ec4ea673adf3a02c82062d042aca83eab159f599434894946423d": "0x3e8faae4c5713c72aea65d52aa1616d3e918dee3819fbbe08cd4c76dbd754a50033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ad8d5ecff0cf8666df907974af5f0c9a866d1837675e6c261632fc872c66e779df05bca99fed82db1f5cc4c329beb520": "0x8b63cf648fa2a43a82671762a02da41dc6abbd1e62a376b3af7c2d09abf5120c09476f7373616d6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2add6d6b7da83a91122ecef9b7f1f8ed22c2a55b53b42cea8ef1a2b6f7f66895b8904a4764bcc5da3d23f941953076c48": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033536", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ae064ed9a95815109a28d1341b38f77f0e49baba2f2c359d846db58da8cb83c820aef3fbaa7b2164444d4946dc047e08": "0x4421050207b47ba1bddef66d1e1deee5b27d27d7fc526cfd68e4be18a5b9b146094b415252414e5a41", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ae25c26c4d55e92a8baa81c8ccca2202bc81d1b8a3c50fedf5323698e1fd52fecfcda7436b8ac0ac6f663e146f4d4f5c": "0x8e602e63afb364ac583747b0a8bab092d5b20ee98f0495ce7562a8c992ac9f171070617468726f636b6e6574776f726b", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2af2cb88bec0fd6d9d870ed0cb9e6b44dd62a2b80ebcda1b2f14d2a903088759ce56482401fb4130cde32775d6d210a6a": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f88370233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2afa7012257eee9779458ee194e0b6a5144ab70adf9b1a6402cf14b3c61f98acf5bccabaf0030d537510166a21ee44d16": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f88370238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b030bcfd4d04ca2771966077d88e8ca4824f5bcb1f267ea5a74e1a1c444c937eb29cbaf0fc98f293eab5275aeff5dc51": "0x043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d073033f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b035f15b888e0ad82dc423c5e7b66dbf6b05609a9079e0e03bcb50ab1676122a5fef12c48bab67b95d4d0ffe58ba7df7": "0x043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d14476f76204465706f73697420f09f8f9befb88f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b06d49d722afc851487d64d0443da49c128865fced1fe2ad870d0f1ef6ac3c73c78012dbaf73ee9db06ba403cb73a523": "0x666c474e2f859bb39716a333ad449122df3605cf2d272ab876171d0a61cbdd070237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b09e1ef1249e67d9b5b08826659bb27a442afde41c8d0cff9680849824712996d0cd96906dba9697aa5110cd6d025e15": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033134", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b0e45cea75dd9a6a2fb59626aa0d17fd7c73d0b870509f5c2ce7ef8313ac58becd9dea02162a270f9913116d690f0904": "0x20b456b7a8651f0b81f4517ffc79737cc392230cdd92a5b4bfa09ac728a0b10e033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b0f6b2e285b92b32889b0381bcdff93a2e2409b5ef509e1e584584edc945545f42fcbb3f288f3355e9194206b4ce773f": "0x946d9ac73a5f11a32e8c8709d631304d2db1ebbbca156fc86b9f4382863638140231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b112d8e01e5b200440094fbd1752bdde946d9ac73a5f11a32e8c8709d631304d2db1ebbbca156fc86b9f438286363814": "0x946d9ac73a5f11a32e8c8709d631304d2db1ebbbca156fc86b9f438286363814033131", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b1bdb2a978b70c9c8ed058b2e17b652b2c2a55b5b86d232309cc2d8aedf4c647656fc6a40e2cdc299020174154a7fc42": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b1db55e6d201f24c25972d3b93600bfa2c2a55b5c4fa92b88356b2666fdbf58840b50813143d93c886f60a39b8eb204c": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033137", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b2022ec7aba6817b8cd6c3743dae52dbf3717672dfd677afa541355ced152c72acf081107fbecbc9e0acef5b54b51223": "0x0c618307d00b3354999ae280858c01fceddd77a25b5bc665fbd4634bf86a41780e4f70656e476f76207374617368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b2e8ff0ead7eecbc8150d40440d9a34fccbf40cc53a67fedaff6111ffcf4d618af1ef8258560609082989fe66911233c": "0x6c42f37017f31d6c9ba5dca62626e6fb434d6edc31bfc9aa49f001a6ced27876037630", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b2ff9f39e4b4f2dbc2910bbe4598c2732c2a55b5f917f0ac6055619baeff392603206df4007063317d30f823537ef234": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033333", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b340047c4e17520d4d652bdd615fa3c8802bcb2d54cea58ca2d0af13a85daf28ccb873d31de2a277ca03bb185e41a25f": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033530", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b36890ca82312edfce5360970c393151f09bafa226f3e27f549d4fe85723533c0f0e54e366f3a87614ca08443b06cd54": "0x522e16fcd83f6d6e08fe2b44d56b5d0bdaf33527b49e8832928d003d8097ca630676616c2d31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b393c14ba1c4a4bf502f1689557b3313ca67e0639a4112b0f7cdc7a7cb9ca5d55b8fdb35862eaee46c8bd34720783d73": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033139", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b4010745c44b5b43598903b7096fe882c4896d44835fe17827b4af77172094f91a1b17ec3524949c2d626ce7314a440f": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090d6e702d6e6f6d696e61746f72", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b401f35f10e20d172e577821098954092c888948530df2b5b3322b8f999dfbeec62bebb555351839993a10c2412c387e": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033437", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b47bc046571621dc5753fd0b932bb7ac74edbae75103b891bf37c39e91cc489a6f68f7b6756b32875d5c5e28c1730272": "0x984e16482c99cfad1436111e321a86d87d0fac203bf64538f888e45d793b54130232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b4a894d95a70cf19ef095db1a9f9f8f89e447cad47afa21f342083e9ef18cf04a27d81fbd0cd742e8ec36528c4514269": "0x1a0eb7fdecee073651f1a21b9779b7bf5670493a0e35a53ab83b3cabab814a77033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b4abbd8736dc65a25c47575bb9ec8e1c2c2a55b5eabf99708c2a9f1e21a3bed0fa589b18286225ceb1bc9e28ff06a04f": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033133", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b50f5b869e807abf7cb2f1ee7ef6845c2c2a55b5285b5050bfaf7c602b3748dfcb3306896ae8429c2c0ad8104c503401": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033435", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b5642c854a53817aa071ada8e9bd62a4a100d0eb4c4ad076d10849f54ddfc448b83596f24f71cc49ad4c0390ac489010": "0x22b7a9ef681c4a3c1743e5c343ff5b6f8aec3dc43bb0d49e29243d79ed40636504423031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b57102bf290cb640a422734d07fa643ef61b8042ce3e6f4c3731471c6a57e4a8ae30a1ffa5870db5043b933dde89af1b": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033436", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b5f83990f376bfc67e6b72cf9245fb42600ff061b1d97f28da91ad5b3eb7cc5dedc5431b2935a0440c02a6a82a3dd49b": "0xccb38aa8821510b7cc609cd55fd19c0f9c3594d49fe8db355bb2e7fb2324c948033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b61448b0855c8703eb3b665287ce3c226ca8fe9e98a7d7fb4269fe93c638a2e388c6085e74c18bc220c125fd7f0b1b68": "0x3c017930b46ab5a4413bf3153b001287ed5ff7fdbd2734cf69abc843f4ee04470ef09fa59753616c6164f09fa597", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b625f92500c01f436f0e71f0a9bbf2a3209f9f598ee545bbecc4993b7dff86f89d4b3a1dfffa7dae7e31f32c4b9d2c47": "0xc44cd5285e160a2184f3f5801cdce8517ebffdb591177acb17cff2db2ffd9371033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b6eb1d049af0ffae47c2af03b5b04ac9d6b0e114db8fce63ffc070a452ffa1f47f0f7ca51f32809a624323f51c146d2d": "0xface99d3401cb9b45ee1bc0ec52f4cb35914dc5ad27806230534230eedb8413d034444", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b6f2c4862edfcd63814ea4570e540b357091f937fba948654220a41ede536b0d62cc30d20274a28005b8026564db8d25": "0x0a4a3233cb4870d9f20b5c55e77f839ce96a26f0fd773d01917919757664476500", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b78425e582538dc4c288486af28286bef43e114e579d7503e86bc631c58415cd1cdf864d0fcf512bdd5cfae51aac062b": "0x2c6f57e9289919d242aa985c1963f2b4040ddc57df3682d890657d130c0355760c63686f7275736f6e652d31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b7d7f9b15ea68fc3a3bd7ac0e0bde394320145f6b95e9a687429cab758eea7c9cf2375c09ee12b7973e85c7f8476da7e": "0xa4848ac04c2ad298cfcbf27ade0ddebb2cc3b37b090dd933a1e988b7a3ead0750243", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b811ae831b53a9fcc4e215d67815d9ae1a58ec699c897903d28984e42202dc216e2e8f7023c846926179c0c38562e4e0": "0xb2692080bd814373a7c780dcc62922ba2e770c11a50bb1bb38fd3e69f0192a7114416e756269204469676974616c205374617368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b85ced93d80542a7b97d4ea4e8ac7e90743a504cd053c4bb4b70c29cd59bf38cc92d1f51784969c0094d010525b54145": "0xd573535a40bb01903e616a383deed22b5e3ff30e552017d2395e3e75a8e786130232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b8ca7b51ee7f82178fcef96f9c679abd34e6b8b209b93f5f68b7abba7c3e17a84af77819e98b05a0d828f0b9b2b92578": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033131", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b8dc0e3687e1477644166ec179afebfa37982501b1c242d5d23a353d2b44e7ef342d32adc991306632ba6f3c61d4487d": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b9ef0050bbb06da457001b37138b12922c2a55b5a116a4c88aff57e8f2b70ba72dda72dda4b78630e16ad0ca69006f18": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033036", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b9fa89d1dd18608cf05ba581ebb5bf1a9819a1a845833b4fbfb1a911e2332fe3abb3e09acdff60b492680c6189629b2b": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2baf6acf18406a0ac71738890c9e1ad0dd4bb93b20f1a0f4d41cc2b066ec844343f3a6748e75b3c5a4018533d0c882675": "0x18a5d639662da95bb4924c48441fb432047e77613263cf1438ce8a14fc34c432033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bb9a49de5d2039aafbeb82b8401e673020ac6c23e69518f5c048cdd4341f431d23f1bdcba3abfaf7349241db61ce1317": "0x5c5062779d44ea2ab0469e155b8cf3e004fce71b3b3d38263cd9fa9478f12f2804763033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bc3a7a7e8db2a65f1ce6ffc95b13a5b662ed2bb3fe57066f0c015e18bf443b1d384119ae9a0eafd276064062e73a1b31": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bc71f2cf237219176ab15a40a6712bbb2c2a55b6068e3b8626608321044a89b82fc4898ece34524659f48aa72aef556c": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033131", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bd33bc5082da8415d4508b956b762f6b2ed9b8035e0bb64685f561677349c54d0ae8806f1ea86b74c12b51dc8154bc9c": "0xb64a86ea0e91047a3ffbbc68c36ea9ab318ee06c8bb4a354dd3a716956c9eb550231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bda61a4f13fc3742a03a47f801b0279ab4dc28082fccb1f21f1728e29c178004bde0e64385194ac7600cc222b8bb9a20": "0x1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413064354524c32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bdfa0648392ee33f09ad376deec2286e2c2a55b5c7e135ae443c6ed951338d4b32be6cf61ac5bd000b7a11c26b307820": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033038", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2be55a78a142cae9a56448e35fb0f3180760f9c3a5299a87661dd13e267572ef052d2c2383fa8f77f45c25567a6e27f75": "0x043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d0d3032f09f9a80202d20314b56", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2beaf3d87df59f54760ad106c3f97757a40e1ae3e3d1e6fc5dd9c3a0bdb1c0d03772a3c69ce5b4efd1d8653ece57cf539": "0xa4a7835edb8c6b0d10b32c76ddd9560feb4894fcfb61593accd8c7451e96562e05706f6f6c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bf1b1a4220f2551ed3b4c82cbcb2cb6d38a295559d8977464fd8cdd133f8805f2388e42a6e009219247048a27d9ac06b": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504636335", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bf8b91717fc4b3b889245634525a2b2498bb3be2e039d66d581ffe74cb449689ac74428512b67e033855de5d75b84d08": "0xaa72c321b20bbd5b78b14f6fd800017bca47190956eb42ada2a4d8f8a8ca994d0b4d6174746572686f726e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bfe1e70f1c70d00b88827788b71b101774065a60fa33d4c2c8926d0d761d133a305f500880fa95ad86acd865f274414c": "0xfa5e6f955d973efaca30897c4a3e4fbec88186ae72b8b331408804d73dfc275e037032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c015e16e71fed001efbbd731b1a14ffd70119b7481293f5e919dd9f0c078a5b285f9ab78fd05fe73b9b4dedd595b5c38": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c0acadddf3aeb1876f2c7c88daf7ca952c2a55b5629e69cf9c08b4b926e7e8503cf4d337fc62677f40409a68fe9b9a1a": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033531", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c0e57bca92853c3bbd9179917407577d9208af2fb9f1511facbd517ba7ec0296d6fc9fd010896eec0f43a415b68b3706": "0xc290e73cd4a89b696210d9f712410463c89368b6fc4d22ce10207d8f31e5e73900", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c0e772fb88e288ce6c003ea0435930d6ca0c59a8141101a8f9c99e3f8a85c77b0ccb57ca6121cf9edc436092e9bbd17c": "0x628f36dddf8cdb0242104a2531e7d3efd4860a9a4633be69aaf30f63ccb25a5e09696e204461766f73", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c15da76d7063a20d2105a731e85b952b55ce3d06cfa21735e2f8b652b7886a9a91a53c2e6ddf1bae4ee86ef2209fd0bd": "0x8122315b758fe65626b7d0f7c8f5d0758b235f22df56cbf73610916a88520efc0646554e4453", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c2abee6fe4293d17c3395bb0ae324cb8ca38730919998d8ddcf5e729a8a275769b1ae064d1e0f5528db03eede05d5e24": "0x5c5062779d44ea2ab0469e155b8cf3e004fce71b3b3d38263cd9fa9478f12f2804763034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c3440f1ad4617fff4320dbe3d17d539988072cc906cf4513caf8aeb6ae323c8b7e57bf5581da1aaaa8d1363dac664266": "0x561077519794c195b22f5058bd1195f6847aa6b5a749053d44468ba5db872d640d56616c696461746f72203032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c394f9702c31720b76d50596bf1a0b3e8b7602f67d9d61682964f3b5989f357752f75dfba430603da1384059b79f1535": "0xa23809a947f2c06542cbf2fafe17fd7d84c460d51fdd69d01f53a5ca050ee7090231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c3abad1b49578e95c1aebddc2b5893dea82456d51e83aa6dbf7a473b5776454fa175d5dc9775629aa05bb09b28fe4509": "0x5ac4bbe840e332da2656c0e760904003fa7a2123a216a33e81b8531400600304033034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c3cf4e2a0ff55f643892e2a52a20693e0c789dbc85d3a4a498e13f720f71110577461e834d356ca361d49a45ef609b6b": "0xf40cd7a2181289e32776625b9f3a193f749e33ce1bdeb76cfaabece606c7324c1968656c69787374726565742e666f756e646174696f6e2f32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c40abcd97ec4dd18da9ecd6c8d6af226a37a1021f6eab9a2658f2f6a5e08f5851de80230d270662dfe648c0c7bec2e46": "0x043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d073031f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c41de75982653ee203e85ae8b3491a626cf627b193bf62d66c08afc7b08095f2c12178597925fac26265bf801079ab22": "0xcea3dabe52b2a665b1e19bf8c6913a5d54e06d6413ca3ddbec8f9a22415ec4770248", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c4cbbc94ab26be6a5bdb9daee5cd70725ecc1d4e60a92262c1bec62d034c979f42cbd3fb1c28570d5baed6e5ed20d533": "0xa471c55caca4be7b4e60c6e94b20f9028883f8c64287d4454130c657383c3442035632", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c51e4cb74629a513ed40913f5fd048062c2a55b5e0241fe92a75c23c49cc15b355a4f52c934719b1b7382c5c2b859a46": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033734", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c58ed9577b53cfdd09c2a60325ae4555cc2dde4403d477d784abb0486ce18908af209f2c9d8581d33f7e847608b5d124": "0x5c5062779d44ea2ab0469e155b8cf3e004fce71b3b3d38263cd9fa9478f12f2804763037", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c5e24722f48f114eb319513abecd93415010efb7049583595fbe3da57dc5db048e590c28f107e5e4fa2bdcc4b1293f6f": "0x5010efb7049583595fbe3da57dc5db048e590c28f107e5e4fa2bdcc4b1293f6f0241", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c666dd6bd1e6196f18935a711ca0128c484cdc76e0b6b2cb4e30850327cf37e717d91e343a62bbfaded38aa8133cfe34": "0x946d9ac73a5f11a32e8c8709d631304d2db1ebbbca156fc86b9f4382863638140232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c673d8e3bc8bb8b1aaec7e4f1da7b00004704197ea07678709bffe4d7cc4a0203e5f92da2f681cc5e5ebd399b83b3949": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033335", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c6972e264d3a6b5fea949ee6deb8b99a388bf0fc0110c1b18dcab471725083bc6b0b52edabeab0c3e73e506a54f9e04d": "0x5a33766207d51925e4b9a2302870bf737305cddd5bb2df2dffa379963e586771044f4e45", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c6d5accb29b732a3b28e7e07c00e51f404db71328c96f1654885de2d1f577621c524e4515416b0f861dfce55a3f72167": "0x545b7958451cd22afb0367d6c99af1360190813571c47b8a94a055d575d38249033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c6e6930f38fc96ca1527a23b891a6d69982aa00fdf3835f109ab98a569a0476af2e87c92bbf3cb6c399254fd9b31c900": "0x4056f76b206c306712a75e10ece4cffe091b1a49b0ba4c505f2ae4ee673c576a0e5a4b56616c696461746f722034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c7a14b30fea636224fddd038c66ceb362c2a55b56f24b35dda6da7aef24974dd6501d9c857f8d41d66cf88d5bd053044": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033635", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c7a412119faf128c3bcb5450745613970ca0db0283dbf8d123602a2ec334ab5c3fd9e2540577e0955eaec679cefa4f0a": "0x6c695c4e546c6889ca591b582eee8b49ba68d8485a3732e08d232b2f28f2342e032035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c833d839589168d31a513ba57eac40f9aee72821ca00e62304e4f0d858122a65b87c8df4f0eae224ae064b951d39f610": "0x6c695c4e546c6889ca591b582eee8b49ba68d8485a3732e08d232b2f28f2342e032032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c861e9da3cf1b67318847bb703c39631d84ea2d7257eeb646fb4e0d2aeee35a3eeaea22b897d8ec95f42d5ffd2251430": "0xb8e06dc2e6bb6bd269319ace4cf8f663338f8f285a0564d6a139063c985d23100232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c89deaedb1f96fd0140b01c7396300216202474a3d821e3d2df95b4eb0f8405f1a086cbbbd25c4425bc978ce8da1b3ba": "0x22e8d22a7fe2768c944dad8af7829d96eac8644f06643ea8ae68bc3c1e9053060231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c8cc9ad6de4a02498a86b05233f8b7642c2a55b5c69b5e131fb0f65ac7ca707f4bc53e4d991a2d1971ab5e702f69f45c": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033037", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c8dac5d09880fcf7669cd1f88ee32646005fa73637062be3fbfb972174a5bc85a2f6cc0350cb84aa9d657422796bfdf1": "0x264319ed6a0895c04112917fc9bdc0771f4a4773aae014a99d25bbe06fa1057a0243", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c91aeb4ffae7eeb153ce2284e565a46d2c2a55b4f853af67dd7217983b8928934bedd57f2aa6717b4570ff9cf8c55d33": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033834", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ca2bb1fdef2defe515e9aba1f30778f91e7aedb71a237b95e3b805a77c031dac6a8a675441390e66bc1ddec7a41a1e54": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea259385609086e702d726f6f74", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ca49b8ecb7983e1ccd3083c5f08607620c7fa2b79d310ce32237db73b1e3d581a979b3bbd7f19ec44ff1d37b87dd3750": "0x3c82ab06b794c99f14a161973be7aa6012568b1c491d45ec969ed7420bcfaa5907424f554e5459", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cb1b50885d1cb48212e41c3140ac8ae370519f42b7684d1ef3dce95d87895e447b390bc1089606d1a499c18d08bc511f": "0x08754abb6afba51a2f74f0b97bbcdb383f579a02a5e4541fee736710af562c6c05f09f8c8d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cb689f2fd08e34f3e90238d841086e91d8151ecb8e8d11e6c6bd81ae49216b9ef92d2b83b3ae39702a397922f1477768": "0x7a895955042cb3fe863f3564e7b30e9130e37b6d905be11c0cf91064de1cd83a064672617a7a", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cb7824c3c4a36969f8b1065499761b832e6991a3223f09ddea0e0b1fffcffbed3f768d40231db602a030b7fba52c7d08": "0x465c6be30d314cf647a8fa10212bcb84318394659c46fe75d03640cebb39595e19416c7a796d6f6c6f676973742076616c696461746f722030", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cb9b5eb59ddf49669ec0c9df7987f371aa41228830918cc1cf16e50df86ba154a483d77ebe3182bacfb876af4fe9ff6b": "0x3c82ab06b794c99f14a161973be7aa6012568b1c491d45ec969ed7420bcfaa590e434f554e43494c2d50524f5859", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cc71e745770be3a4327ac3e6e61c637a3e184eb35acff823bcf5199a3eec9d0a6aadcad642fe08451772a51c4215583e": "0xd45548e42d7f5d5aa35ffc16ff29396c99936f0c1eae84d452f1daac87c3c566074576656e7473", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cc80e8459e5fce01f1c58b4e2a8953ce0af17b8dab92e7ab018e1189cf597b4e2ca38e0d00716172adb26073867ab92d": "0x561077519794c195b22f5058bd1195f6847aa6b5a749053d44468ba5db872d640d56616c696461746f72203034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ccf2e9d8958e5b865afe2e0cbf30ab902c2a55b5a3e5f8bb0fd6155ce85668d8e606d7defec7044d8615225bb9769a6e": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033430", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ccf825de56b61fddcde1bcf452e38a1fa2fafeae641e6e264d77723c00ab05f503db48ca3597cb3242c2b54d90abd01d": "0x666c474e2f859bb39716a333ad449122df3605cf2d272ab876171d0a61cbdd070230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cd2a7f639619333a601b9e944ddbd08568f26829ec470fdad2e63d97741a88df1243ea147bfb4639b97a4c816f9605fd": "0xd016feaa68e25739dbc4035faf2577d17ec9d7ec2125a99a6770b5be093f6e3204445331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ce122712cd338ac4433aaed5fe788634f415f3ade9353f49fffd2f3f2ebab33ab5f1b94390ad5758fccf5a00e9441e01": "0xf0de782e8bad3c663be60812f0a2ac63464f5da3ec448c73334c07d71ef27f2c0a627269646765687562", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ce59cabc41ff067a260befa5b4d22c06d97d35c31f6d0b75bfa93ec1eec8823651d1582368679c44f00ded1f5401b5e7": "0x7a895955042cb3fe863f3564e7b30e9130e37b6d905be11c0cf91064de1cd83a033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ce9c51078fd9ce38eba0e7f6d7324d0fe0855069a59fa0ddf72205213ba6d7bc3bcfc44316af9684bb215f815fc0113f": "0x922bc16cff1acfc4a08cb5bfcebadaa9eb182cd47a51b8b047a0202ae9624a1c05f09fa6be", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cea748c3b2ba59842163a012dd3fa089b3988a6af22247249717bd8602b7ac3e0fc63f469ae9ff8e9d022aa504d61b5e": "0xa4a7835edb8c6b0d10b32c76ddd9560feb4894fcfb61593accd8c7451e96562e033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cec0021475b40ca2d74cb08a8f4168e0282a194090fd6715e06430d8a6e9c682f021eaf398830b10db94ca8c27c9ae4c": "0x5c5062779d44ea2ab0469e155b8cf3e004fce71b3b3d38263cd9fa9478f12f2804763031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cedc7b9f5e185052276ff40cead4c032149ccce9d526a65ba54fccc24f5d1dee62f9b87915d4004eb932959d468a9e62": "0x18d54ea25ad26acd7094fba6bdb278e769f9ac350cc36b2f631da13fa92bed79124c6974656e74727920636f6c6c61746f72", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cfae23c09122f09f79bb0e3306b2b74836fd9b64e99689363368298680cb35750a594103048bffd839af770fe5536c6c": "0x946d9ac73a5f11a32e8c8709d631304d2db1ebbbca156fc86b9f4382863638140235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cfbf707024d3f7f987d6231d10e0e1a23e9520e4e74fd47da1dd509ef04dc9b14215a35e7d207fdb2c99f732ff5cac16": "0x36aff2ede1563784631d6149024982108f661b079b6b79f3d042041a9da11e2a094c6974656e747279", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d03c012a3925866fc83b45604288b687114f710e9094d174ee537a86a7eb9ab2004e6405626a843d4ffea72694b9e23e": "0xb690df84dc61bb1b04bb3e5483678390a44eca9ee4a748e98f526e126c19c7020258", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d08ab4f04d24a26306b6e8849841da8792e594db8b26bc07fd45cc783db49313f17183491f1826d417155a95d5f7d85c": "0x986a4fdcd53d0e438f9694c9a6bb76665bc50acf76180049117caf3ca9bbcc6a05504f4f4c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d0e7cf7abed89ce05a639e6d088a035544ebd2b934606a30469bfd509293c34174336f974709964a18bf40d99a0bed0d": "0xbc267fea33668e3515a7c01f4acca67d73d30574b600a404d2b7210aaac855690de29d84e29d84e29d84efb88f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d0f86a770b0362a67e0b80f83a93995472284f32719a49037a79da881b91b44bf642395ecba92b241619e21fb1c8a57a": "0xf65f3cade8f68e8f34c6266b0d37e58a754059ca96816e964f98e17c7950507304626f74", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d13aaa4ce8a3a68e5b852c21463efb531a9490a6fa5ca6353651e0384ff371db3aaa0d2fd20e6ba91c8733a17f581602": "0x5010efb7049583595fbe3da57dc5db048e590c28f107e5e4fa2bdcc4b1293f6f0247", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d16685a34b78f937300cd3a3c3bfe0639f958e6a1f4ff8a986a4e7d76c417bcfe8affda4182e66b9952dee757d7e577d": "0xa6c5f0595d6ed85d6260bc682d4a68a4b4e605d43c67d56f2765d196985497720b436f6e74726f6c6c6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d1b99fe0be3362b9f171c5d2737212fc2c2a55b54dba6c93fda08f30f8fd6be0e47bf66f3fd31e2e1d72b970b3ff1154": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033631", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d33371148f6e156ce9e4018a98d91a4208a73c9c3083971fa2ec757d38c8e7858df8076aca40ce176faef81fcbfbe258": "0x984e16482c99cfad1436111e321a86d87d0fac203bf64538f888e45d793b541305f09f9396", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d3a35414cfcf6a6cd5be058a4734f75974fd218ac454949ceee42deee0ed129de80fad49f579870d7ee9d4a2d1e0e27f": "0x7269f7eab2e5f91f9efe10d0dba0e7256d9433230a8f9fdc1c4af10981853476067374756479", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d4064446373efe5e2d35657a95221e10a06c4e59af8d86d8b552887762255c830d79b847a6648210ca6b24d0dbba0e2d": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504763038", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d41bc04620b2161b34eb34e6a47af25a3a337becdfacffca71fe67fec208733754f035958d349d36b30225fd47798f6a": "0xf857311106c8d7b0daf6e096db9a0d759b52403e439ab23fd6559780a8b1c803064249534f4e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d421cfb48fad0754e91335eb0722ee11d05490aa747179f2b895c2c5171e9cb10a474fd07d1a8069389678e165369e56": "0x1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c41304554b31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d43a2b5bacb2a5a913735d81b9183d6a730800477a5fb0302fa9ff4b5623662a27719a304dedb3e12eb004f48ecf6b29": "0xa4d813e676d81d97479f9f15572d9eadcaf4503b654c0f6e7baeb49e84510e690231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d4eeb7647278f476f14736144be90ffdb6612cc74066b95fb08eb5978781b15169170cce9f5493f6d8f74013ee4e6e4c": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033533", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d5912e8857d3fd846b9b7afb3d401568d091cf86d04141b1c17c70826c08d074cae1b00d6f82de1b8a5406ea10ce723b": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c095452454153555259", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d5c42076011c041f810f01bb5ecedede01f8b3c479e6400cdaaba7b54357ef912ee1ce5b803db86506805054070ea176": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d6227a681a80f70d5b679ffc134fc506c0532217caad133c16b24a5e3b2da932b83aae63356a787e1594e71317df7cf0": "0xac133ebfde441672c055b79ca9a6059850984eead1ae036f48ca1230e7f0556f05504f4f4c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d71c5e81f0ab3d464dc034191d86d5f5908626870725d87736e1476482cc7df7bf32f03f83ed8cb6db40a830067d973d": "0x08754abb6afba51a2f74f0b97bbcdb383f579a02a5e4541fee736710af562c6c05f09fa6bf", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d8558f24642f1ec38c8f05a6a65118884793061e5121c9561a8dd25c2e64df912f5939a096bde10bf9c5cd06f753f6a7": "0x463a9cd3e7cec50ccc93515557ab58221d20c67a409583428ad67caff9415107065374617368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d8ad31739c149623bd78d39f54c5f51b2c2a55bd3b0028726bf7764e3a604421e98e930f851a2bfafdf5d29eb694d275": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033937", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d8c5bfd4bc0ef3b8e44f737ad8be140f78c7dc6b311bc7e44dc95793f0b8e1316ab1447073728470fe08e0b4a8dd243b": "0x264319ed6a0895c04112917fc9bdc0771f4a4773aae014a99d25bbe06fa1057a0242", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d96660089dd600c4539c167feb8a18a42c2a55b615f9b64ac6a84fc4513c431a7b6e0bd3812a4821392a462d049aaa3a": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033334", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d989677538850769066111c948cb30682c2a55b4fa84e9b7e85c6a3bb37f4bb3831bb51a5bbb1666ff92c8b874dcb42e": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033633", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d9c47225dc4b565f343d7e58210a682c224963ab92b30f5a7c91256507aa6375320e32514e54eb988386ccd3654fdc84": "0xfe1f35d3b712d9b87e9dce926d8772267bbbaeb776e9b2a8615b29d6594c4621033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d9c62ffc145fb75512af8ff50ac058ee48e77b8c0864277405a333a644bb283a03ade9c351473f7c167b309ba4cda308": "0xb204051d55c2c80cdf6e0d3346944e921fc97f0b86a4cc5eb5547982fc475d68033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dadb90787d37d7ac651f6e2941b2d550981d5e90031eac279276782d0d15ab97fb30898a69abc4eefaa797c572823b2c": "0xb4d78a8bb35a7b0ff8ae6a7808f9b17c83efd28b8612c2388034d0e35ce513760232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2db0e6c637e12549ff30cdb5c7a3b2532be6c22b41a47d782268a2d1eecf5e623ae6b984591db92f77de07a27a447f87c": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504763133", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2db818395f4d30882473aa682f1d36e9b5613fa8d949d17f4bd3ecfd6b7cb550072f4559c4c3f01250379945e44cb3235": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033434", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dbb2c86ebf000e28b914ca30a0c394591600e09e1d8a1324934f83d55d5f6f503e2d91bf4270eeaefd462f24e4487e29": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504763031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dbd0604a8ca46a0f5076f8140d75ac7d4a1585474299b9deb690132a6d586e8bedfe4d8e75ec70c2dcbd2dba24269215": "0x040d1324a05bb9a0b86d9eabd01245ffcf277f4611f9750dfe465761481ba053033038", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dbfa7057505189b4af689b9ae4d384128a4c3a7b3f2b3cb525ce315f859de83c51410fc29ac88734be346709d0798a20": "0x3e3a490c516b2a3582e6400e33f3eec42a12589958cbb86c87b23bc94710d21b05706f6f6c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dca1cd7196a14a851b5a275585eb732bc203687a31c85ac0dce32725c354a515d8c027681db49edbbda4e3804e5dec63": "0x1a21174f3333c2bb416072b2c31d8f1e60f8e4ad3cf9546ab47e5b6fd060d3030e6b757a6f207374617368203031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dcdb7e8983f1dc27a7169e03dc11b6dfa2b3963c9d349de4363ce38f5f9854fccc0636768d947108b7f219c240837855": "0xa02f7333e25590e4f568ae8a2ddc93a879e92e48fa3cf1666ac56e020c106d550a627269646765687562", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dcf24a1420a437a2315ff698af59a553685f836cdb8f2749ca5a225297e1a8207fed4511b575448e09bec5a870480c6b": "0xd46cd0ae6eeab8ef19bf289712c9f2ae4272c663bfe0786d7c10d4ada52100030230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dd287caf54b991ee49d16dfccfc25d2c10a767cf483ca0629c6cb5dbfd20f5f9d8468b153b90bf3c40443bfba9354a14": "0xf0de782e8bad3c663be60812f0a2ac63464f5da3ec448c73334c07d71ef27f2c0233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ddc46103873fabdcbfd43afdd5fbdc87724e0032275bac5598878e5dee08149d11c44700c9c4626d1f339ff1be715f30": "0x6c695c4e546c6889ca591b582eee8b49ba68d8485a3732e08d232b2f28f2342e032038", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dde3f4916d4134ee96557d32c2798be38e6c97add8c5563d923d9b702f854b15ae59ecad39578845a04239c594046044": "0x64e6db572dcc9e5dc57445ff7c68ce85e42527aa74b2ed5d1e2bceefd308ed05033230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2de1810815b4181d78b34a31b9a5f85e4ba3e9b87792bcfcc237fa8181185b8883c77f3e24f45e4a92ab31d07a4703520": "0x3c82ab06b794c99f14a161973be7aa6012568b1c491d45ec969ed7420bcfaa5910544543482d46454c4c4f5753484950", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2de2150bff9da75d3f86fe07f2279f5192c2a55b52656178628dda04be1e16aab15775638cfd3bac25a59164631a06b1b": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033532", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2de4b76f552b266b54b14e30d6052fc61e0512205b8cbb851e7b9d862d204b1df2d7598e03041c7e70b373ac45b1e6cfc": "0x64e6db572dcc9e5dc57445ff7c68ce85e42527aa74b2ed5d1e2bceefd308ed05033130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dfc40f350cc4563ad9ddff5ad92944278eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964": "0xa02f7333e25590e4f568ae8a2ddc93a879e92e48fa3cf1666ac56e020c106d550773797374656d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e053e352d49371178913f8a7c80be39b6a4fe76ff9e27c148bf2c24e2f85fe56b4eea5bbcdc159430c18036e0f940f27": "0x5010efb7049583595fbe3da57dc5db048e590c28f107e5e4fa2bdcc4b1293f6f0246", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e0894c7505c4ccf600b4e887725ebd7b8c23324b0cb29e4fd1a68cb08febe58b50e39d8afdb5f752d6c26c8ba52fc002": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e12b82edfe2c5df8bc459adc5dde162f44e9eb2333d2ba5032cb999fc5815802139a4f0b1abbdc6fc9669fa0d3e9ae55": "0xf65f3cade8f68e8f34c6266b0d37e58a754059ca96816e964f98e17c7950507304686f74", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e20a5666049eb6eb1d793e56dbbd540994c8f2aa65dff23f542ee99d7191e88eecf45b3a61b7350dc3d48804107e393d": "0xf0de782e8bad3c663be60812f0a2ac63464f5da3ec448c73334c07d71ef27f2c0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e243d9597e1ff02bcc83e65fe97ebecf9970b2d4d682818fe75bf20d33d350798f984ae009b8e8e127c1847461357ec8": "0x5002926543d8b8887044442834d4fd5fe3d6eb257719daefd3f2aed28eeaee690232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e287427a545f07fa7bf625be98536e33b6f0f10eec993f3e6806eb6cc4d2f13d5f5a90a17b855a7bf9847a87e07ee322": "0xdad0bc6a0aadf06c56416e83bf75e865d41ccb5ffd74eabf9e81d47574b430491143554c54555245444f54204d2e532e58", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e2cb581353e109d4244df722361162fd828ad82b9738a507bf481d6c3feb4e50855378b588a653e3033f5eab788c335b": "0xac133ebfde441672c055b79ca9a6059850984eead1ae036f48ca1230e7f0556f04537973", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e3178c61a0f52ecfd1d1b69fbc8d1582c9108836cc5003906b107d31fe5c7b5d1211a4f71bee14f068d2fa04551387b2": "0x06c7ea7684b6aac6cd63cf88c92b0f05398bc3e13e0b0c5936c3027b8e0c7e2f00", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e3c3bdfcaf035a202a03474869a5028cce79383a5d77f974ba22bada735faa2075716e442079b7d58ff1fd898b63251d": "0x7600c0c74304812e4928a503408a68c782c69a6af2fca55fcd9e48e095b448630653462d3034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e44a61acf949dc5e6246ad785d8ef21cb054f58645b2774a05e70ab4f9b59dfa46ed60acd0668713e921324a933e2027": "0x5ac4bbe840e332da2656c0e760904003fa7a2123a216a33e81b8531400600304033035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e4598a627b033d5dfec8bc9280097cc1f6b2256178f0210557ddcc138e8b264204e4674fb2d73a8190faf4ac3724722f": "0x666c474e2f859bb39716a333ad449122df3605cf2d272ab876171d0a61cbdd070236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e4b0112f6842e05fbfddd3e76ff53f58d6ce187276961ed56ae9a29566279cf443df42f82d9890b02de9c11e4d288e13": "0xa0db8c6cb723c474639931cae07e095e6e8d9b870c90f5b499bd8e6fdf4bd54f064368726973", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e4c4990573c19a77cfc77c7f474604153ac9ec7da0888dc010574b11d9d0dfd62446ca38a63819937aa91f40f6901d58": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c0df09f9099204f43544f505553", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e4eda3996223cfeedc9689417aa91cd35607fa03519626bba53d0d71b008694a205e566c653b766c9f1c60edee39ec22": "0xa4848ac04c2ad298cfcbf27ade0ddebb2cc3b37b090dd933a1e988b7a3ead075035331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e4f5cdd468e167da392ba6e10b53ee3e6a0da15516a63ecc95cccffecec2a2aed962e92cab661af4b1f76b65e429cf79": "0x5c5062779d44ea2ab0469e155b8cf3e004fce71b3b3d38263cd9fa9478f12f2804763036", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e5992f79ed312340ce56189dc4f562739653bcf18e30531092fdc1c52afe06cf61f56fb1fa5d719078cd6914d395ed0f": "0x3640b7b7fbbecf967f99ec9516a74f9e255efa5c8529751a383afccfe936175e042f3234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e59be3727eef8dea84201471915ad11a80833b98deaa7ae201c9d2aabba6d7cbdc14ecfe1548c52b8ac4907acb14c863": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033133", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e6c96e874922674a2cff73001f49441ade1894014026720b9918b1b21b488af8a0d4f15953621233830946ec0b4d7b75": "0x3eabb0f32cb0695fedb8d25f6299fe51f90b1e26ed858c1064aeeea0977c1e670243", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e7379ab3911997c3aa7bdf8347caa100e44b76584cf228a713f627f36b58ebb282be3a162e6f24d54a15d1082006a208": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033334", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e78c9f13a47a426fd81f851d5e4a4e328a32f59713f0a129fbc395dbc853f51ab53d45d1684c4bc8ddad89fd55fc096f": "0x5c5062779d44ea2ab0469e155b8cf3e004fce71b3b3d38263cd9fa9478f12f2804763035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e7ca06f4e64071a61cda312f78f7a8548823139e30d401f7a9422e68208ff3ad2f8e40e92c83af26e4002734760cb87e": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033337", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e8071600e92b47d24031ea725c59eca4e07628deaa9c6fbbf2288f879396ff3566871c0dbce85c9e23764d15b810657f": "0x9a8ead39ce1b44f37d16e98496441be79018e910d5f58c0fa1518d8fd7749550165354414b494e4720464143494c4954494553202332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e8360b2b0337af76720b8a8c4bf432a0e23e7ebb9b8462643b8df28f53dc2dbdebb20bd0cf8fcb41d7d09db59d46a505": "0x666c474e2f859bb39716a333ad449122df3605cf2d272ab876171d0a61cbdd07033133", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e87b7c876df80669b1ea78e67a83b8bdd6d1d0ca917751d6148063b9e1fe8a22f74396e63a2f72e149b39e44a0e77c7f": "0x321d847f8a53927fe1132754a7708c61049b2d4816ab6ce7195a8308e97c3d410ff09f8d80415448454e53f09f8d80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e8b6c9ec21445bfdd558ec3ed91799202c2a55b51baa94ff2dc4feae28c5ecccb774c622545b0a127dbd5ae8e2c8e115": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e8ceffcd95ae97cf0d36a8aa052be87d782f3f9bd84fa8b7b659bae702b90ee402c45067cbad3d97c89ada7db6e0fa67": "0xb204051d55c2c80cdf6e0d3346944e921fc97f0b86a4cc5eb5547982fc475d680e434f4c4c454354495645533031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e929174dc9c4928bf7afa39c5375dfa326a944c20d0609837ab990ebb516c30f230f1d29be7d63f7c368c9a499be4f22": "0x466a9934facf9723f7ecc237cf0afaca23a6e832780616e432f3eaf19d8ff94904303031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e963eb3a31c188236411e5403a65a1f6bac6ca95205b7d29a9f95adf28d5f94ba010ebb51f414163a48747436c9f9cab": "0xa2656a3bbbea71626facc2641a9d9f744c87c393778020354714974894b7b27a0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e9c8e89fbc1f9352f2bb567add0aefa4add1d40ef104fcb24be637eaeb9704064663df235fea0799829e270333774f3b": "0x74b0c404b20bac28ded8d662e2eae7ddc52988cd5a22d5de09259258395dc45d04313031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ea718457dfeae31df87972c5e1528d84e081dbce8eb0905bfe321ca87d5a426435e7cf499020c644e9fbcba9a0345fa7": "0xf476394d38a2202be9ac84607ce7fa0a7a53981920999c231210fda7fca3604104505631", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2eaaaf45051dff93df16e63c768d773fe11d3e37f3547a962068f9d46c046759e8a866b64c844b0fe7426d95fc1b599c2": "0xd016feaa68e25739dbc4035faf2577d17ec9d7ec2125a99a6770b5be093f6e3204445332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2eb2b549672b19b67afbd9e3fc4b568ebd00de863a4e1cc8c2b2050ba4be784b313caa1e51167abacf392c1f07270834e": "0x5ac4bbe840e332da2656c0e760904003fa7a2123a216a33e81b8531400600304033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ec0d25e0e8b30cf77df449e358e3b18556c031a86027cfcb114d40812f06d9f462a8354171478b00dd075d9271db3872": "0x6e53696350731ed439f8c353b0b69b40b324fcdcb435ba225fbc22a33c9fe15407444f542f3034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ec5037705c8d82366c308213ec87dd35fab574220e94c5e2a4f8fcfc9f0e7192116b24eb5df2632396d94dd43401a252": "0x7600c0c74304812e4928a503408a68c782c69a6af2fca55fcd9e48e095b448630653462d3033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ec8413880bb125c95625f5a40e86558852a63150e02f15706d9ccceabf476a79dcfae5bba86e66ece74aa031da5bce36": "0x666c474e2f859bb39716a333ad449122df3605cf2d272ab876171d0a61cbdd07033134", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2edb14628d7e37cbb87c519385e4e16a9a4dab34de26e570e8fb301f9c947c6f5f862dfbb27c9de5cf473675cc244213a": "0x946d9ac73a5f11a32e8c8709d631304d2db1ebbbca156fc86b9f4382863638140239", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ee9be1d4255e938947c92e123cf2d82f2c2a55b508174009ea498f934dfefc1a023e9d03b43bc601a2f7fa0844126160": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033630", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2eefdafbe6888bb66d3584aebc2c916a4f5c0dc71bff8cbdce6c32ae5260549ecce90af19512e7da031f2dd02fd920689": "0xfc8163c92cac3dd1d5c2c0a049c3652a8b3b8b6cb8a0867a5e494c650b4de3710231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ef9c24010a7d87b2d6696a19e87491d2944519212916c8838efd27a63122a176c83e9e0dc68ad20c29a1257166d7ec17": "0x561077519794c195b22f5058bd1195f6847aa6b5a749053d44468ba5db872d640d56616c696461746f72203037", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2efacfb219480b68325adacca873693d62c2a55b55a05a6a02b7b3ba6539f3744bed7a3ebf4a86a75986e404553bf0635": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033832", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f078cef6bb5ade7a68f37d2cf9e834bb34fa4e10f24341696e46d61b982f279969608b00edd5d32298f3cab0afbb695a": "0x2c81fc1faa024d3d1a727d953187860b45bcb185d046631ab98261eb6f2b8d5416f09f90b620536f6e206f6620612042697463682d31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f0c0dc3560195888d3828d9767ed964be02374bdfa92d9969c3c6f8c313bed2e8165040d3ef604001ba1d9c838e9dc5d": "0xa849437f5f8b602fc9a4210d6a9834af4adc6ce7492861bd0f5b88d11919cd7b0656414c2d31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f183a365116212f639e2d31af122c16e92070ebf24c4c84a47db97b62d308834c3f258a9d96aafd6bd11eca52bd6ce4b": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504763134", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f18978cb1bed20a6759302de04ffe38d0e2d58494df50bbe553b779921de400483c550c57a9c7b5e7ef9735958228e34": "0x6464f15335eee136dd7c216b994ea6ac3394eb723590e9e065fd9061e05d003504486f74", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f20562184074892fd5273476a9079b73907559ce75b9e6531397c0050be2cdf9d982a2db041a099526baba91b8d25409": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033336", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f3759ae1aad2e4accd167f7617254a8d2ac73c24bb740376a5b0f44814e8ce8b34f23be0650e99b7ac81e1159f9c3151": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f3a2ea4f7e87660b8de6205e32768eed14307eae2db6e460778426604acdb1215d1a38ae54aaa0ee1664646776557d05": "0x3c017930b46ab5a4413bf3153b001287ed5ff7fdbd2734cf69abc843f4ee04470df09f8c8a504f4f4cf09f8c8a", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f3fc4d95dda4fef3c64f3e37dcfca37c60971394debc5f36af7ce9cc93a3f5cfdc400c830b8a8510d105de4364e7cb0f": "0x86f68361d0a346a62be267558e72dfb9e3b5a04adcc2c9e46fb7b9482f7c876f07636172626f6e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f4e3472ccbcc90b51cd9bc48554ec8297c103bb33a2f4f6ff86f2f6e11e9488d6eeaebe52bbf31291fa00e46ec26ad60": "0xb8e06dc2e6bb6bd269319ace4cf8f663338f8f285a0564d6a139063c985d23100233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f623b20438f6af5d88c978d9cb8470307677c2a4deb2689377319a8e830d5d9ce0ae32b95f096a7447f8f711b7f0333f": "0x946d9ac73a5f11a32e8c8709d631304d2db1ebbbca156fc86b9f4382863638140238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f69833f1ae9dbbb00dae666f139773905009e192ec169788c9c1f0202fe7c2bc79405ff8b6e1d1ac78fd6152006e606d": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c08e29b93434f5245", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f6a8ba389384cd6e3068fb6cf37e87dd18fab09febf634c47cc08a08a95988723b43f5ab499c4925d08793f3f701df5a": "0x82ecbf12e0965d08387b8aca42993392dbe5ddd0de48393b96075c641f2c940804443054", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f754bdf453d4e84560fe79ab039139fec4e4ff6adcb360ec9eb50d5e04ad47aec66a30055222dc13c6215b5f2db59767": "0x6c695c4e546c6889ca591b582eee8b49ba68d8485a3732e08d232b2f28f2342e032037", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f7c3b18f75237ef0c0b19cefd274264582fdd15d55ddeeda8100a274f8872503fda6e267e345f4edd9fad26229604c0e": "0x796b851c8164a129b23282ca4b3bb694364b0bfb504e98b5d2ffc5140d58078e0c636f6c6c65637469766573", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f80f919e92527ff0b3f38a865198b4c5e05c542ad7369509f498cdea5f5c427f2fd0b3051884184b294d9ac10fe64e34": "0xcc95d7d061fc6a655b795794b9b1614d0a240e13e81de9dce3f2b184f653da7c0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f8c2f2927526f62e9c9ec02461c15d20dc0293434648638559e1a4cf30e829f17d2695980d5a3374af8d663bd5214905": "0x86f68361d0a346a62be267558e72dfb9e3b5a04adcc2c9e46fb7b9482f7c876f09487964726f67656e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f8daa14742583f2f5c0f9fe03ff22b9d9c6a3401d06cef30fdbb33901328f3611dae8253708779a5d66179c967582635": "0x96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837033137", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f8fcbd529f3814b1082ca36f9bc8e31f4108a93c4704dcaa30f7b5f245de48d736164bd554743cd4bcfdf1ced6f852ab": "0xb22f88d05ca6fdb70235b599b99c69f927ed71163c2ebc11c9649d678a8ba84e0c76616c696461746f722d33", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fb35f965a2e1b5ae1f4f332ab4843aface3268d415f136dab575d25dc0b1932b736c7cc785a1ccc04f0474b458115f0c": "0x666c474e2f859bb39716a333ad449122df3605cf2d272ab876171d0a61cbdd07033132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fbe7c8aa7eb18460ce203ce4c80180417a813a8832981068f9b921dded7aafe83cf89eba4c91ac5460c65d76a61d465b": "0x6295f0214abb5522cf3becf82504ef7c87036236e6b9afd263697a99bc5d5a301631efb88fe283a331efb88fe283a336efb88fe283a3", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fc0e0ce33806f3824459bc37c3bd7122f2497cdc525e2b482ddec24761aeb31826701c5a6e35919787bfcb455c62d774": "0xb2e07be4d6d82f546ec91d6009ee215bb736be5b4362e66e7b466ec72d47624f0c534158454d424552472032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fc3ef9f2768893bd98dc2460ab9d9ae1a0209c10c7d6633de64e166a68d9b45e7f02aacd9497f5c552e577abcdb17d28": "0xfaf5f68fe828f5af8d69c116efd937d90f1956b0edd94e05d8b5285a8eb2a6630a76616c696461746f72", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fc742294b2823241347b13728377c9e288ac52f4800ed8569280dd140faae0b0ed5613aa77e57a592cb9af8127dfae2a": "0xfaff1c4b5a94649e0338783122b93a469eb9e2e375bb71c92028a8fe9b6e2f460d56616c696461746f72202331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fcdf79da273ebe1bc5b7ff0707cbe95c34bc6fb5ba6e2150087c96fd4852ec188aba74a5a383a22ef66b12c588cea00d": "0xe04ca25cf1cbc516ed1c138492a7f2e606f60c5a9ac96cb405eaa3914fd129730231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fd2862f10100ae5b231586b302448ef6bf7105cdc60a8125bc7d465c5587c26d9954572b8579bd176052bfccd2847506": "0xf58927b296a23cbf25794b7cbb8fe31c5e68f2bcd2c2483e9c9cd0712216f2320547545332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fd525643583f149f8e68c3d89c7cc0782c2a55b5f323b09d3dc6c092ed0e988463188613232235e6d6cdd03085885529": "0x2c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e033936", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fe257e46e780cc22f4c52b7d3917a0788c2bae6068de838d1fc684db669d5ad1dfe26f37887ce815734145764b7e7124": "0xae0d1db9082bdce75480ee80c3bf3c6496de1ef8171951de2edfe49fdbe30a6705f09f8ca0", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fe7a2f19451f39e782aa158587f5104091e1331ab2af4b510ca29f5e5dcc8e71d1fc6cc70ab24e2cf8513d540fa388ee": "0x2c81fc1faa024d3d1a727d953187860b45bcb185d046631ab98261eb6f2b8d5414f09f98ba2050757373792047616c6f72652d33", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fe873b3279a034ae64f9fda42b000854a81b8a2a03afd92af18f0338e43afc504c6018aca6d9197c0d3a149ce65efa0e": "0x0a4a3233cb4870d9f20b5c55e77f839ce96a26f0fd773d01917919757664476500", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2feac0f58276d8e619cf093b7ecccc1efb05cb292c73a8d41d50181bbd829f14afa9464b6b710cf241ad1b801b0b1e654": "0xb22f88d05ca6fdb70235b599b99c69f927ed71163c2ebc11c9649d678a8ba84e0d48616e77656e204368656e67", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2feb19c835d73b7b4e7772d1ceb85a24d88d74924b788c1f7ec64a54c63eccaddca748f588f67c26e5595870acecd9259": "0x36da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb38934504763130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ff9f5c222ec1d9624cb2b58612a8f347588ab6bb059d351e9de8b2e3daa0f7dca462a8ed9ebd49ae10c3f753fe2dc84a": "0x86f68361d0a346a62be267558e72dfb9e3b5a04adcc2c9e46fb7b9482f7c876f0a626572796c6c69756d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e00123d83b036c82d5c5062779d44ea2ab0469e155b8cf3e004fce71b3b3d38263cd9fa9478f12f28": "0x0000000000000000000000000000000028282a194090fd6715e06430d8a6e9c682f021eaf398830b10db94ca8c27c9ae4c9effc7fb904ca3d8cc4f45b464ee4dac705c89888d298bc9dfd2ba563d5b3e3f20ac6c23e69518f5c048cdd4341f431d23f1bdcba3abfaf7349241db61ce1317ca38730919998d8ddcf5e729a8a275769b1ae064d1e0f5528db03eede05d5e248e9b0b6b26839418f4baad18a9c3ffbfa413d65cde8010bf7b9b9db0dd23e0058a32f59713f0a129fbc395dbc853f51ab53d45d1684c4bc8ddad89fd55fc096f6a0da15516a63ecc95cccffecec2a2aed962e92cab661af4b1f76b65e429cf79cc2dde4403d477d784abb0486ce18908af209f2c9d8581d33f7e847608b5d124bc1729a527ac8770c18456f142dc57b24069c9ff1032d6c3a1572d84b811ac7e780946289b4befff0da9911c013aacd2b280ec0529a759b94c67e4899b9b7058", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e015b6bef29d45538bae335c017512a43fcaed23efec97d80e088bb8f7b93ee837cba5416ca51037f": "0x000000000000000000000000000000000404926296ae6c9155557a6c5aac98d9775664efd8607e894ef210fa2c80b65941", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0173de88215548e9f65f3cade8f68e8f34c6266b0d37e58a754059ca96816e964f98e17c79505073": "0x000000000000000000000000000000000c72284f32719a49037a79da881b91b44bf642395ecba92b241619e21fb1c8a57a6c9e3102dd2c24274667d416e07570ebce6f20ab80ee3fc9917bf4a7568b8fd244e9eb2333d2ba5032cb999fc5815802139a4f0b1abbdc6fc9669fa0d3e9ae55", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0264d5f165d70fd8604189f1ea74bc439b18060c58f352db2880dd4c835df7ebb26e020bf11e7969": "0x000000000000000000000000000000000442d1b7759bba592a85972e3c6a9bbb419de5df76c57324d98c2d11810bbf4f13", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e02c2da93a5b6fce008754abb6afba51a2f74f0b97bbcdb383f579a02a5e4541fee736710af562c6c": "0x000000000000000000000000000000000cdc559c88e35aa258566bd616d0e31fac0efda3d881b52055a31b35892086bb1c908626870725d87736e1476482cc7df7bf32f03f83ed8cb6db40a830067d973d70519f42b7684d1ef3dce95d87895e447b390bc1089606d1a499c18d08bc511f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e03456c855e9a00037e878e54c1374b30df335d3a193f3e6b1f84db6c2270ee634cec769d7e33e244": "0x000000000000000000000000000000000496cd6f382ca54348f9bc846929ae16bd49da6ef76b19211da8afc0a1f1c31d32", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e04322a3587052539a23809a947f2c06542cbf2fafe17fd7d84c460d51fdd69d01f53a5ca050ee709": "0x00000000000000000000000000000000048b7602f67d9d61682964f3b5989f357752f75dfba430603da1384059b79f1535", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e04d5e25d603189573898b6f62b50749101446132f77fa6dd77a3895674fa8dac87e6c375ea852346": "0x00000000000000000000000000000000043f24c61f66f5c798cc97adf5258664937f3c16d0b35121a8b45cc81611bc8e59", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e05d8bd6067f6ae29c804531378242158a794bd06c1e9ef0e569f60bb32758597af80e5e70c07a64f": "0x000000000000000000000000000000000804587d42f37709c7342f3e915b5a1c6f64ca916b9fa8279480c8602c600889bda225b0e7cf9cf454c3ecf0d3477cd774c612795c312dcba6d09beea92aaf2a6c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e05e989f2a5137a8f22e8d22a7fe2768c944dad8af7829d96eac8644f06643ea8ae68bc3c1e905306": "0x00000000000000000000000000000000046202474a3d821e3d2df95b4eb0f8405f1a086cbbbd25c4425bc978ce8da1b3ba", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e078c7addc0fece8f18a5d639662da95bb4924c48441fb432047e77613263cf1438ce8a14fc34c432": "0x0000000000000000000000000000000004d4bb93b20f1a0f4d41cc2b066ec844343f3a6748e75b3c5a4018533d0c882675", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0823dc59ec2f7a204eed7cf3f4f6560d58db4eb78bd24b655bbd1d7a5c6b454e77c8dc5e2721a54d": "0x0000000000000000000000000000000010587b19cc62e01cdc18a1499cda27b0fb33264d0c3817668609bb58f7620126987d80b43f7b596676b4a6714cc5034708a9d651e55c030c2a0b04d8152a8437b5a6e11253e1600d4a54c1c233df15bc0a8b600e01f85ab764233da2dda657d4397c2496b1630a27a7946e2ac806c8e0cbc7d12702175153cd0eddff10898e9036", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e08db713c2bbf4320a4731404eb64407b76d75dd815a3267e2dce24d8c2054f3d45d83ea11c8d707a": "0x000000000000000000000000000000000432f5040e4ff22a9cea43f7cfd1242e3ae0e57140c2f4b985e83ffde5e5c4492c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e098de700b0bd1b5ca2656a3bbbea71626facc2641a9d9f744c87c393778020354714974894b7b27a": "0x0000000000000000000000000000000004bac6ca95205b7d29a9f95adf28d5f94ba010ebb51f414163a48747436c9f9cab", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0a6e3cf2b2ed68b7f476394d38a2202be9ac84607ce7fa0a7a53981920999c231210fda7fca36041": "0x0000000000000000000000000000000004e081dbce8eb0905bfe321ca87d5a426435e7cf499020c644e9fbcba9a0345fa7", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0be961ab1f92f2a95002926543d8b8887044442834d4fd5fe3d6eb257719daefd3f2aed28eeaee69": "0x00000000000000000000000000000000087e74e295c040927de4200c770994a314185d3ee447be3d70c79ed056fdd1ac539970b2d4d682818fe75bf20d33d350798f984ae009b8e8e127c1847461357ec8", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0c7c6da4442b90353296c9b3a6546d2319a764e00e1126215b776cb27571db2ef0392bbfbc66d45f": "0x0000000000000000000000000000000008fea1c72d488cbe5955b1eb68d746792321b1eb06616bab281f5d4838e0421c6ad4171a4d884070585e1bc36f234a9db406e6a89575ee9e5ad24605e146dc4c28", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0d9954f2f20d04e36495827bfe0b07d16c549eb10d7e45997e95788be44a3f277af6befec99fe62f": "0x00000000000000000000000000000000049af6c56d6840c84e110de42cd72b4f82d0387238d2302a937026c23940d01241", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0e032212504d7709ba57da1251d785b2d433ca687c510a82c284826b9b79859b5774a84f7000e928": "0x00000000000000000000000000000000040d92a2524d501daccb88d86720079731f9b53038e0aeddefb8828afbafa5eacf", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0e6e902c97ee9286b42bde3f29708150bd47382f10fa4eba1c27a068653cfc4e3787b7fe05fe6e7d": "0x0000000000000000000000000000000004ca44000a7a16d0e5c56d22a707e7cefdbb237b9d20de2c46a53b551ec0cf1c40", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0e7a2d3832f0ab5118c044557335d26c3a538ec7a2699ef5665cca1d17755cd6ae53d41f5bf31623": "0x000000000000000000000000000000000418c0445577a970766dfbbd43589ffdbfb1bae33e8f286969539300c6a49d0962", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0e9a3c3e586a908f8122315b758fe65626b7d0f7c8f5d0758b235f22df56cbf73610916a88520efc": "0x000000000000000000000000000000000455ce3d06cfa21735e2f8b652b7886a9a91a53c2e6ddf1bae4ee86ef2209fd0bd", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0eb83f2c7db87e68e043d8f7872cd895f8957c9179c4264816be3e649713cb3bdc523f752602cc3a": "0x0000000000000000000000000000000004a082ef6765a3eef5cce291b2507c5ac3d6ffe5e10ecec2525d1554b8d2db1440", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0f16205ef17fe25d2eeb1a6884bf369c7d1ab3f9ff75b79dd0f6c6a9792834e026a8d2f7ef049e4d": "0x0000000000000000000000000000000004acb22f070631059ce62f6e0536e561bb5d470d2bd236985b0dcf42cc3e446c68", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0fd49b70acd3290232d4d1b0dcef676d9a72f6abf9aec55e129ef2de135ac172e19c28a9adbcad0b": "0x00000000000000000000000000000000043562230e5122411d1c436c426567ebbe517120ac76620baef8d5d78b8a2db938", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e10a8fd5f177733e23640b7b7fbbecf967f99ec9516a74f9e255efa5c8529751a383afccfe936175e": "0x00000000000000000000000000000000049653bcf18e30531092fdc1c52afe06cf61f56fb1fa5d719078cd6914d395ed0f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e11ce0c03039f6a489e4e7009937c56d267338762a60ed004293afd40e7c2081847c12cb63c76a818": "0x00000000000000000000000000000000048ad3ba81e44bd11349a8d48bb168d583decd0257d3237df7d55bba5051f5254a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e11ec48c6e9cf67fb4cf2e774e34c3603b2428a690c058d2ab826b39a2eba4e22b3aae85f9bfa7802": "0x000000000000000000000000000000000446779e4754580b4e94ac22e5da499aa39cf1aece35d5162db15003b14110f31b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e143c9b2402368042140be3ffc8865dd47a8d044916b26936a579433599bebca9d3ba1d6eb7722710": "0x00000000000000000000000000000000040a016b7d735f7a0c5e7987f99b8e46137b6668a6593c064d42d050979935793b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e148cd021e35e23e4f0673d30606ee26672707e4fd2bc8b58d3becb7aba2d5f60add64abb5fea4710": "0x000000000000000000000000000000000444d9acd86b036eae410384c8fa0d073d47e74712a5787451463fbd717770ec57", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e16ed9307fff94f1f0cc0424184702e27c49fb859c93f07d8bb0adf2a0824ada9f01db9bf76b7025f": "0x00000000000000000000000000000000083619289cb2e660dbc1c5747506a37df7a4d311aac8f29c69be8b710495e5162346b00fc11146ea6ce12405e83ec552c9f3d66dcf81ac4fd874e24db1484f4041", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e18b47e3024d66dfe628f36dddf8cdb0242104a2531e7d3efd4860a9a4633be69aaf30f63ccb25a5e": "0x0000000000000000000000000000000004ca0c59a8141101a8f9c99e3f8a85c77b0ccb57ca6121cf9edc436092e9bbd17c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e19627e3b0a1fe44f466a9934facf9723f7ecc237cf0afaca23a6e832780616e432f3eaf19d8ff949": "0x000000000000000000000000000000000426a944c20d0609837ab990ebb516c30f230f1d29be7d63f7c368c9a499be4f22", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e198703ff0791c2de1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413": "0x000000000000000000000000000000001858ac509e6e93bcf6ac0800a070f28bd477fb9e9717ff7779d035094e361b1504d05490aa747179f2b895c2c5171e9cb10a474fd07d1a8069389678e165369e5692a8511f5619229d4e1bef8344cd9a5f85468e238fd95f843dd555b204d0f00b9a9c5706a3b70b507dcf6b013c69ef08af652b1997d6fe82d5ba6975a2581b21b4dc28082fccb1f21f1728e29c178004bde0e64385194ac7600cc222b8bb9a209a7d620473c31a9f77379b12b25920a83b43e0f5700737d9e370dbdd9738c84f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e1a0b756d13ed752dc09033af1dd99c3727bd222c35d9d34e8e4403441792399b08df0d60544fbd48": "0x000000000000000000000000000000000c8c038403fe48ee0068a652cfe2593d30d5701f508e38ef676f392fdc85f8065894ebb855993bf0568b71fbf4197fdee4cb44a39bd46fa5969bc5c372ae101367c676e6031d0f7fb3ead234afe813ecec2d6e3b47fcee702981feb2c168e2c37e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e1a61ab35fd1e09085e34b19d7230f1ea5da6d4b8fe6ede9d05c2e55b0189f75b967862c1c43d9a1f": "0x000000000000000000000000000000000882b224471e6d4cbe8d9d084d445bac45c91e88679cd3c22937d5e56da60e2bb3ae60938e514a0fc95200df7940bd0fb0f983090e91043b76f3186c6300ed7437", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e1c6684bc5e5975f29a8ead39ce1b44f37d16e98496441be79018e910d5f58c0fa1518d8fd7749550": "0x0000000000000000000000000000000008c4826569e68b7eee1b5b93406e4951fcd7ab6b40be519a7db5c6732f66da1149e07628deaa9c6fbbf2288f879396ff3566871c0dbce85c9e23764d15b810657f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e1e681645b60ebbd6a2b06daf782fa5142e365d1fea0f4a418687f53f201f185bf314c37581677b37": "0x000000000000000000000000000000000806cf58e932ba9179e8493d36dd0c02918e37649bfff2bcc24d4fc19d47492564447e00d54ea8610f6d515b7d7964b1aed5838c2971e585143807084c2a799311", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e1fda62d62fc07febbc1deacfc7e5c6e5f0373560c14fbce156ff2a0ed7e208d049ccd985dec85545": "0x000000000000000000000000000000000ceea674f13649b25e552a59b65dd203fd45055ae7f39b5a6551cafc9d4eab3776dce2db9e809d506f5bb1523baa031c25f48d3448eee538a23766c2686a7ffe2cc08d5de7a5d97bea2c7ddf516d0635bddc43f326ae2f80e2595b49d4a08c4619", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e23484ecafdeafb8d3c84767978ada6355ac3719ea8f978244b16d7e8c00552c3a189760b55eeb404": "0x00000000000000000000000000000000088c5917b51ac796f4dbb53a35008c1e0cc5a8e3aaa1300cc2e845f8e7702cd4e5149fd573a4ad8eb5dd80a1b70e89362e72f0fb2512075b4d9a52e7d23c0c776f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2398aeb1ef43f542c44cd5285e160a2184f3f5801cdce8517ebffdb591177acb17cff2db2ffd9371": "0x0000000000000000000000000000000004209f9f598ee545bbecc4993b7dff86f89d4b3a1dfffa7dae7e31f32c4b9d2c47", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2492dee6806c086baef6619eea08f01aef7e47d460f0730b02c075e446308892e55af56af1572168": "0x0000000000000000000000000000000004c97b296323e5b62a72504892a3ccd4fc0b1b206f4de9ba0e9764d9ed9ebdc276", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e24df16db48272ad68c085e6bde4ac25702f54f46fa3c1b0a6170bd346103c2c6339911e00306a054": "0x0000000000000000000000000000000004a9695441f301ba78bd00ce015f2f1da14eb8914531fa38695502369de72c256f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e25b20afe8011ef7d040d1324a05bb9a0b86d9eabd01245ffcf277f4611f9750dfe465761481ba053": "0x00000000000000000000000000000000044a1585474299b9deb690132a6d586e8bedfe4d8e75ec70c2dcbd2dba24269215", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e25ecccdf058700718b63cf648fa2a43a82671762a02da41dc6abbd1e62a376b3af7c2d09abf5120c": "0x0000000000000000000000000000000004866d1837675e6c261632fc872c66e779df05bca99fed82db1f5cc4c329beb520", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e26968cb24b23a08fb64a86ea0e91047a3ffbbc68c36ea9ab318ee06c8bb4a354dd3a716956c9eb55": "0x00000000000000000000000000000000042ed9b8035e0bb64685f561677349c54d0ae8806f1ea86b74c12b51dc8154bc9c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e28047368e108b3b06ef40ac7b3e092d0eca77ad072cd317683ab9d24aca4025788421d4276527d57": "0x000000000000000000000000000000000413be73ce92b712d00931d4980713bf4be8974255e1e51a7ed71ed2ea37f035dd", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e28db6c1e91cbc43002385caf9a08b92ca458a0b817a8cc303cefd5a0c6e108cb939e04242b9e007d": "0x00000000000000000000000000000000042cce76137e2e2d9bb63e081d4074cfa4688d7d9781d2888f36634f646da62561", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2a679b6bc1ea7234ccb38aa8821510b7cc609cd55fd19c0f9c3594d49fe8db355bb2e7fb2324c948": "0x0000000000000000000000000000000004600ff061b1d97f28da91ad5b3eb7cc5dedc5431b2935a0440c02a6a82a3dd49b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2b031c075ea343ce443c76dcde19df9387486ded7845c6d85ec2a4c17f38f8b1e7a0a14de7968d7d": "0x0000000000000000000000000000000004727dba627f34c210eba395fc7f60d28b3a58c5dbd6b63fb4f9788ee764b2702a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e304630d144e59358fe1f35d3b712d9b87e9dce926d8772267bbbaeb776e9b2a8615b29d6594c4621": "0x0000000000000000000000000000000004224963ab92b30f5a7c91256507aa6375320e32514e54eb988386ccd3654fdc84", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e31053eabded94fa87600c0c74304812e4928a503408a68c782c69a6af2fca55fcd9e48e095b44863": "0x0000000000000000000000000000000014221125c5934d75259f335bfdce9d6aab9e4c6b57724993f32f555ffc4e75d070fab574220e94c5e2a4f8fcfc9f0e7192116b24eb5df2632396d94dd43401a252ce79383a5d77f974ba22bada735faa2075716e442079b7d58ff1fd898b63251d7600c0e901b4341203f21f410f3da01ae4a45d194fd2c0693c6e0ec5980f4c21fab573fbe3296563205563eb39965933d33ea5a591c45af07f0eee2272ef6723", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e31ef141127f82186d45548e42d7f5d5aa35ffc16ff29396c99936f0c1eae84d452f1daac87c3c566": "0x00000000000000000000000000000000083e184eb35acff823bcf5199a3eec9d0a6aadcad642fe08451772a51c4215583e7061c3799bd2b1d70aa6c8014a0012ea494f4455d60e182dd1cc393d37f8604f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e32ac541eb6aa1242ac1aee6b509bdaa6aeb4718c2218bd7e78a3d6704bf886375e4c243b77a66b34": "0x00000000000000000000000000000000046e28009eb2b8b7785246c452948c27169c4e3ed258ad7a707fb64beb9442fcfa", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e361d0f16c34b17763817e559bdeb521169c4801d70a1dfefe94175d15666a1ae70719a3594a57c16": "0x000000000000000000000000000000000458a0a27aedec30fb5c0fa2dfabff0b7370f69e2a8505d714f7b2ce37a99f0d07", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e363df5d8dc0e8fe77042bfc6e75e1277fdefbea917f6b7ca8c36b3e0ad7286d66974c8f2b4cb9672": "0x0000000000000000000000000000000004bf10d082fee91854f7a6a6c56ebf8bf0d65bf914a683ce4ae1db5ccece06ad27", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e37cd5a422db43856985be267f05f586da7ab52e4430c2f6d461f396b9d6cf4f1eb5362066f7cd82f": "0x0000000000000000000000000000000004b7972e09702baf7eda528c6894408b1e9c702e5f54674bcf6de1b55b3aa16365", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e38533548d44cc8d84056f76b206c306712a75e10ece4cffe091b1a49b0ba4c505f2ae4ee673c576a": "0x0000000000000000000000000000000014a8e87388e083b3f1a9dfeef27977d883cf10e7c94acdf0c60f57f0a9621d4539bee56ca36a0a5393bf9bfbe5d2079e31d4359d35388df257e23793c7b195b8555e348817abb98cb962fc0780a47ebd471d9c318395fa80b4529a64cfabb2e32c982aa00fdf3835f109ab98a569a0476af2e87c92bbf3cb6c399254fd9b31c9007c8c3a92d8feb9d27f32f3ec67bcc6792f8496f7ed86d1b249c54205a39ee30c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e3b8fa2e75a1b9c5bcea3dabe52b2a665b1e19bf8c6913a5d54e06d6413ca3ddbec8f9a22415ec477": "0x00000000000000000000000000000000046cf627b193bf62d66c08afc7b08095f2c12178597925fac26265bf801079ab22", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e3c096cf3f561e3834026c99cba12d64d1d0e7a7a620bf54374603fcc056e1601e3713f9921671120": "0x000000000000000000000000000000000447500d616a78d59bd887bcde41d61f4ec880d0496fb4d9482f6f637f55cc1b29", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e3c790f30d60af3f382ecbf12e0965d08387b8aca42993392dbe5ddd0de48393b96075c641f2c9408": "0x000000000000000000000000000000000418fab09febf634c47cc08a08a95988723b43f5ab499c4925d08793f3f701df5a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e3e843a37d45e41d726171b3ad75723bf624a27485e51e4c2fe38f4b2d24ee52b86a979fb772c513b": "0x000000000000000000000000000000000420430a70d2db1bf57c424e5e81de47ade7f1f0ceae2b568b9182ecf9b025aa35", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e3e9ff1da508f2a3c7ccb1907030863dd708764cc88a4b4d09dc5bb0f4c9ef5f4e73cfc0aa4bcdf3c": "0x000000000000000000000000000000000465819df33c22d72346bb95afd79e55414f35acbf0997c6bbaeaddd1d3688506a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e3edfdd48fc779cd5a80ea94af8a39eb7ba8d9afb913147e67eae84f48aad7b9ce6ee05094fe0394e": "0x0000000000000000000000000000000004f2e78c673a855ce341b8d431b3e2ce293e812236e2e42682047796fe599bb734", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e42f5d87995df46aba849437f5f8b602fc9a4210d6a9834af4adc6ce7492861bd0f5b88d11919cd7b": "0x0000000000000000000000000000000004e02374bdfa92d9969c3c6f8c313bed2e8165040d3ef604001ba1d9c838e9dc5d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4316433e1f50b4c3a66e0f4e1a121cc83fddf3096e8ec8c9e9c85989f276e39e951fb0e4a5398763": "0x0000000000000000000000000000000004ccdce2bc61518838d34314c620b7c88040c38c784e0eabe838c17192be7ed91c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e44646f06f20d51883c017930b46ab5a4413bf3153b001287ed5ff7fdbd2734cf69abc843f4ee0447": "0x000000000000000000000000000000000c14860e374c2789388379dc1cdfeceac093c9cee7a2ae8579736323c589c59e4214307eae2db6e460778426604acdb1215d1a38ae54aaa0ee1664646776557d056ca8fe9e98a7d7fb4269fe93c638a2e388c6085e74c18bc220c125fd7f0b1b68", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e45d43cb8401e3564f40cd7a2181289e32776625b9f3a193f749e33ce1bdeb76cfaabece606c7324c": "0x00000000000000000000000000000000040c789dbc85d3a4a498e13f720f71110577461e834d356ca361d49a45ef609b6b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4692967bd2332c08b22f88d05ca6fdb70235b599b99c69f927ed71163c2ebc11c9649d678a8ba84e": "0x0000000000000000000000000000000018b05cb292c73a8d41d50181bbd829f14afa9464b6b710cf241ad1b801b0b1e654fc80cf0973d64eb59f1fb930f3107e9f8ced4aa69907717312f0c5015706f4582acc6987e6d1c5087d414d72dd8ce665458dfd16d7447ee4b0336ee869e4d0f84108a93c4704dcaa30f7b5f245de48d736164bd554743cd4bcfdf1ced6f852ab1a356596f667e9330b60d055872640198b86485ac1721c37fdfd468157a17a457e726af71a51eabcd429888bbd0e46ce1e63b3322d0683994ca825dad3d3716b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e469f989f6ca51c58f3b15e49aede08aa29d7400da8d3b4fdbd284b5bb1f1af1a53a8c47398f1f093": "0x00000000000000000000000000000000086cb7f28f67bdf8862d6ca0ca68932257d665d966222ff24f800291451121676db4fc817716823ab3322f35702e26df4fcff8f577aea26e05bce9bef8b51b6707", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e46eb4c71c2ad15c3f85bd4ec9a558cde3f05e33b0b74f9e732cc41f904894873247d4c435a3b8b63": "0x0000000000000000000000000000000004e272df04c4d1eef779341d14da26699e3832ed5a73ceda96a206ef1c4569f477", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e46f59e6d908bc0ec8488bea263878e7e16be0a8c4705f9729a5f25462bff7dc7f2d8346370c8ef65": "0x0000000000000000000000000000000004d8b5b26b1cee228c6ece5a4b44db258985abbc9f0168950d744269bee80b1852", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4825a3675ceeb1c2561077519794c195b22f5058bd1195f6847aa6b5a749053d44468ba5db872d64": "0x000000000000000000000000000000002c3091c08dc07b367c41b57585aeda74490c1850166bcfac4081ed66117f6683611234713d080856dba6865b23424e21b5fb50108669bc5762f955d207eadde13caca4f84ed6959bdee967c0bc4d289bf3fad8671f5ce7068072a7dc34964a8d0c80d57608c732427386079d29d65035cfc02b3221ff32cfe73b540d849aa0046288072cc906cf4513caf8aeb6ae323c8b7e57bf5581da1aaaa8d1363dac664266f0cab0c194935f449b3baef742e992ebb801fe38ab5c345d7a6195740399cb500af17b8dab92e7ab018e1189cf597b4e2ca38e0d00716172adb26073867ab92d783770544556ce47aae6e9e9c6cc32bb84a3df7ab11a5d30b0618e00e109d66cfa5be617ad31f9c9a41041cac3ad8ace2c550c28c73afc8e34367d64b50a6679944519212916c8838efd27a63122a176c83e9e0dc68ad20c29a1257166d7ec176eb3bf6204b55f63a2ef87543b26d158230eebb149a8b9df86555fe3f02ecb6c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e48b1dce0478b5f30daf47069cecf5c31da9a1cfde3732d2b701bf9f94c77ba7e99335d6b30ad080a": "0x0000000000000000000000000000000004daf47069cecf5c31da9a1cfde3732d2b701bf9f94c77ba7e99335d6b30ad080a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e48c106532e2fbcf5ec05f950e080aa04f8ef335280637c8c80fa6b8bf54d5a3bbfa746b9f9da5860": "0x000000000000000000000000000000000466ced89b9a76de4d3dc384b45fdf0bd2f1629f15dd3e44ea14c31ba16181a255", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e490130ac826416f286f68361d0a346a62be267558e72dfb9e3b5a04adcc2c9e46fb7b9482f7c876f": "0x0000000000000000000000000000000018dc0293434648638559e1a4cf30e829f17d2695980d5a3374af8d663bd521490524f8b3dbcb13ea214b670cb611fe7939e20a23db19647485e01206502e64ef7b6a66d0c75a897e62aa4e9cdead9f50760db6e7beae858c1bc3dcb1d1ce601e58588ab6bb059d351e9de8b2e3daa0f7dca462a8ed9ebd49ae10c3f753fe2dc84a7a33d68fb22e4ae32721ff41285cc493d664753a7d71234c77dc2eefc5782c0b60971394debc5f36af7ce9cc93a3f5cfdc400c830b8a8510d105de4364e7cb0f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e498085158358a41ed824263a2ba0b39e43b2a1fb591c68743ca504c2ce6c3c2aa96e58b6269d3115": "0x0000000000000000000000000000000004d19f8df3cdb194db075979039a6fd4d912298356bb2931c08c35db4903f53345", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e49aa36a5cacb5456d4539a7dceeeba9999b6387e9431e83c53f4b884edf5cf049623110eae570125": "0x0000000000000000000000000000000004081c5466574f932ef5e1469e984d5d39ad5946468f0ab9d06c454f74cfc2f16c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4b11703c47136f3474b0c404b20bac28ded8d662e2eae7ddc52988cd5a22d5de09259258395dc45d": "0x0000000000000000000000000000000004add1d40ef104fcb24be637eaeb9704064663df235fea0799829e270333774f3b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4dabfd58e995e46fa4a7835edb8c6b0d10b32c76ddd9560feb4894fcfb61593accd8c7451e96562e": "0x0000000000000000000000000000000008b3988a6af22247249717bd8602b7ac3e0fc63f469ae9ff8e9d022aa504d61b5e40e1ae3e3d1e6fc5dd9c3a0bdb1c0d03772a3c69ce5b4efd1d8653ece57cf539", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4e5736534181ad78b690df84dc61bb1b04bb3e5483678390a44eca9ee4a748e98f526e126c19c702": "0x0000000000000000000000000000000004114f710e9094d174ee537a86a7eb9ab2004e6405626a843d4ffea72694b9e23e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4ed12f7f95496d053674aa73951219dbd27b3e3fc5847b806c68c1de38fd4f22f9493a461c80e903": "0x0000000000000000000000000000000004b2a9dcb35e27b71b75bdabf1cc706c567e50bbb20631e4f94d5ef6aad740fc6d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5010d8218a994822c290e73cd4a89b696210d9f712410463c89368b6fc4d22ce10207d8f31e5e739": "0x00000000000000000000000000000000049208af2fb9f1511facbd517ba7ec0296d6fc9fd010896eec0f43a415b68b3706", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e505d0ff0b2ffbc1700004bcdcc7d30d597e19c7f87652b69736066b729f7e8543231a10760f8157a": "0x000000000000000000000000000000000409e125c99b3b07749c78742584a990e78457e6424814870b165823547d3d6e29", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e512ee0fca2d67ab7d573535a40bb01903e616a383deed22b5e3ff30e552017d2395e3e75a8e78613": "0x0000000000000000000000000000000004743a504cd053c4bb4b70c29cd59bf38cc92d1f51784969c0094d010525b54145", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e54aeea67769129fb946d9ac73a5f11a32e8c8709d631304d2db1ebbbca156fc86b9f438286363814": "0x00000000000000000000000000000000344cd38181e02e880a53114ccaf987a6f51a10bc1d172d509bab6f7e9d6eb2e00b2e2409b5ef509e1e584584edc945545f42fcbb3f288f3355e9194206b4ce773f484cdc76e0b6b2cb4e30850327cf37e717d91e343a62bbfaded38aa8133cfe348a64dca67c64d9361901a1415bfb3469b000d0bf7f1d439824cec71f87022159f8720c905d7ac1acab25c4f353df9eb759e0141e4732540d163ac444260f017736fd9b64e99689363368298680cb35750a594103048bffd839af770fe5536c6c5ed6f4b68a60a117a32059e96678f22fa086c505f7a8ece13c7a2e78b4788f156af358e5650b61943ba709efc5dbc501405e04d5de5798087d6c727027511a657677c2a4deb2689377319a8e830d5d9ce0ae32b95f096a7447f8f711b7f0333fa4dab34de26e570e8fb301f9c947c6f5f862dfbb27c9de5cf473675cc244213afe9d714ec9ee0f74e33282dd9e411fd0f47c1aa17553392642df99d1440df951946d9ac73a5f11a32e8c8709d631304d2db1ebbbca156fc86b9f438286363814b0adcdefee88f852a85ce03afe5d4403875fcbabc350bcd5d1b94c7ce68eec02", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e55ebf22a3378f22de4bd04a7052f76425c60648c528535285bc2a23ab28db060db34f7c5e5746aa9": "0x0000000000000000000000000000000004d68d71f02028d8c8d8a76dcf0eeba7f93ad6b2a6e2f8363ccdad5fa580705211", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e56305c2c3bf8f20e465c6be30d314cf647a8fa10212bcb84318394659c46fe75d03640cebb39595e": "0x00000000000000000000000000000000082e6991a3223f09ddea0e0b1fffcffbed3f768d40231db602a030b7fba52c7d082a211b13ae9c29f805070d21d5e5e007db8ab2566e1031b6ec22733f1f3c0877", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e572aae990801cce1043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d": "0x0000000000000000000000000000000018a37a1021f6eab9a2658f2f6a5e08f5851de80230d270662dfe648c0c7bec2e463c92bc22c4934341504e8b6f0755bb76906171bcf8a55c49a78e2055ddd28802824f5bcb1f267ea5a74e1a1c444c937eb29cbaf0fc98f293eab5275aeff5dc516b05609a9079e0e03bcb50ab1676122a5fef12c48bab67b95d4d0ffe58ba7df7ed959fe3d9afc671f1b0cde07de829b2120d7da25d5f84f4e0a86e3bb940bcc1760f9c3a5299a87661dd13e267572ef052d2c2383fa8f77f45c25567a6e27f75", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5749edf76d87f942544e2e588c90a2e53e051d2f87d40e222e1f034913a30f95a9a2f39114e5be38": "0x00000000000000000000000000000000040277ce02b2ac78ceeb9ae4fa0a595005489bf3f5f77898415e32a3e9504a5314", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5a54b00d6ab21bbd58a74372b1f0a88b1df304584326ff69a68e9470d42687e12bf5dfac375d4911": "0x0000000000000000000000000000000004c235b0e23ee7b2bcceb64fd0e126b965204f7069aa3b4fcbadb8d658e2ecf86b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5ae8d02fc1cc6b946e53696350731ed439f8c353b0b69b40b324fcdcb435ba225fbc22a33c9fe154": "0x00000000000000000000000000000000100a776e233546799e6f48a26bf32c080bd40e35986f608353c5b61b3076503472b6c1880096a49c2719e0d6d8e863ccbd075aea064a47cf81c96ca5ba5d45f83e56c031a86027cfcb114d40812f06d9f462a8354171478b00dd075d9271db38720aeeb3fa38505a54f76f2a27321f9b5b875635d3b05a0f4bd92710105f377f01", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5b4c4e58d29949859a2cb674ea2f4866664769a1663fd6aa321d9cfb89b67c402c881891700c0f57": "0x0000000000000000000000000000000004640574072818008b0ffaa91a3d5febf7cf106a9285e35003fd7b55e2c1ae8b6d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5b6407bdc635903a666c474e2f859bb39716a333ad449122df3605cf2d272ab876171d0a61cbdd07": "0x000000000000000000000000000000003ca2fafeae641e6e264d77723c00ab05f503db48ca3597cb3242c2b54d90abd01d56196c14df0a7036b943ecd01396685e799f786c0f131796c06850ec9342ff014a8de2c6b6c1690a27aaa4cb64e0168bced54ab568958965187646f06442be6dc2eea43fd0e45e0e756130e01667533bcaa001e29e0192501e7ce2186ec3554aa28942a9d2e8c8501860b847eecedc45d602e614b8b0849b959607d0dec3d071e40db41d7f07b2b867fae0d7b8ed6767d23f7b53b032710dc5b5043474bf1d11f6b2256178f0210557ddcc138e8b264204e4674fb2d73a8190faf4ac3724722f128865fced1fe2ad870d0f1ef6ac3c73c78012dbaf73ee9db06ba403cb73a5230ec3f7291f82335606f98e16f5480b38b3da95d2e7ee9489a89a8a39f9dac956e8b6a4eefeb4942bbca2bee6baee73280d49c1b7aff8d1aa7616d06bc173ad7f20857206fde63ea508a317a77bc1ca2a795c978533b71fc7bc21d352d832637c207c5841ccd565eff0f8e15ed5d3b1752749e2fc9e3f574c8434bd09d7f8f815ce3268d415f136dab575d25dc0b1932b736c7cc785a1ccc04f0474b458115f0ce23e7ebb9b8462643b8df28f53dc2dbdebb20bd0cf8fcb41d7d09db59d46a50552a63150e02f15706d9ccceabf476a79dcfae5bba86e66ece74aa031da5bce36", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5bd6a3e1e8406faa3c82ab06b794c99f14a161973be7aa6012568b1c491d45ec969ed7420bcfaa59": "0x000000000000000000000000000000001c30606b4c1b89b4e562efafe76bec80154ac8b3e16e04c2e0f619bcdc0a5eef52102df685c4659f9c242ff9ac8a4ee5305770ede106db7a3cd5d3e8823e33d001468eee3d896dc822a496e712d1116e0731235c54bcec12e41eb133bf9c98cc15ba3e9b87792bcfcc237fa8181185b8883c77f3e24f45e4a92ab31d07a4703520aa41228830918cc1cf16e50df86ba154a483d77ebe3182bacfb876af4fe9ff6bba3e9b87792bcfcc237fa8181185b8883c77f3e24f45e4a92ab31d07a47035200c7fa2b79d310ce32237db73b1e3d581a979b3bbd7f19ec44ff1d37b87dd3750", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5c66629676bdc5f4766efcb5851054b4aeef694a3ad03d7bf36980a2094c07cb7b7cda28bde5e149": "0x0000000000000000000000000000000004788bb550f52a25dfdfe1db243561efb956924b8f0a76c16c62ab47b9f6d1cc53", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5d3dec38e02e37251c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea259385609": "0x00000000000000000000000000000000242ac73c24bb740376a5b0f44814e8ce8b34f23be0650e99b7ac81e1159f9c31511de154f8bc16e4a7bacf303141c913d91b1efdf4ae06c3a227f0a2877a19e90a1e7aedb71a237b95e3b805a77c031dac6a8a675441390e66bc1ddec7a41a1e54c4896d44835fe17827b4af77172094f91a1b17ec3524949c2d626ce7314a440f18cfd7be6a32e4e3ab369f7be8a880a70f42a0ef260ae11a740b1feb7dc4796937982501b1c242d5d23a353d2b44e7ef342d32adc991306632ba6f3c61d4487d6881000dfa449822280d217523794e016588e4a6c4d9c14e79161ecfc085e72f01f8b3c479e6400cdaaba7b54357ef912ee1ce5b803db86506805054070ea176dba5e754de5c965c3a904ece87b7a0304c642664457bd2159f108cddd56d781a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5fc4a5c686ea5a40b346948ec9e4cf84b965ec17a752b3e8eff098934aaad42ec50a347dd7936583": "0x00000000000000000000000000000000042e001e3f827e6eed45a60d131d97df1a5b429ed1d0f89fdedf3eda0a16502d3a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6277dfd6b7b21ca2faf5f68fe828f5af8d69c116efd937d90f1956b0edd94e05d8b5285a8eb2a663": "0x0000000000000000000000000000000008a0209c10c7d6633de64e166a68d9b45e7f02aacd9497f5c552e577abcdb17d28487a87b4140abf956405e80acb86bb44586a8089e79b476516c6ff9b601dbc38", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e62a40c29b1fd2c93b204051d55c2c80cdf6e0d3346944e921fc97f0b86a4cc5eb5547982fc475d68": "0x00000000000000000000000000000000140a2178b090386d0e2645866868143abc5bf6c91af252b92c0c38174200f42904d8a03bce1c529217f76264985b1f082f154dad529677f85dcadc3c04c4c77d5948e77b8c0864277405a333a644bb283a03ade9c351473f7c167b309ba4cda308782f3f9bd84fa8b7b659bae702b90ee402c45067cbad3d97c89ada7db6e0fa67dc46b7f9c2debfe58700f30be615154d6e38f059a682ca0b5049285180675c0d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e62d8d4af4eadb392cc52156f09978540d3163b798f65a8788bd04d828f366674bf9ea1f88e96f519": "0x000000000000000000000000000000000424f7bf2054bd95b8304900a908f8b298ddf79ccc09931f514305c490d047a63e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e633914b3a4ceda021eb38b0d5178bc680c10a204f81164946a25078c6d3b5f6813cef61c3aef4843": "0x0000000000000000000000000000000004ad0992e51165d995e649d0a90b3c349ec9694d84ab1c3294e4a9c58839e7b4c3", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e657bab39f52fddf58e07d43b19d901badf3a7f57155ca84f2f835448e93a141bbbd33eac4b767d15": "0x000000000000000000000000000000000cead7c523761f8ca72780d241f11dfb4b3543c4a1e17263274d34f468001d571a768659892ca9fab8d64efd188054b2280efcc36942c84616653265d417fe966b0a3c9a0dc2a4578d4b58cce45258b3ebb0644502b355ce1241f8a38bbd1c0a72", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e668bbbac68a19cb7a02f7333e25590e4f568ae8a2ddc93a879e92e48fa3cf1666ac56e020c106d55": "0x000000000000000000000000000000000cf836649df542b24a1b63d80916ee743d4734640aa796648649685dbdd430c3628eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964a2b3963c9d349de4363ce38f5f9854fccc0636768d947108b7f219c240837855", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e66eaee046d4f02542c89cb8652eff8c73266de06baa3760534e7f37fecff971c028c2910efd6a947": "0x0000000000000000000000000000000004d0ed5a8ce0c20c3da0dade9db4969d52b6bcbe1f8914d3d9a2019526c9cb0b27", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6773244509d0e7c8d46cd0ae6eeab8ef19bf289712c9f2ae4272c663bfe0786d7c10d4ada5210003": "0x0000000000000000000000000000000020685f836cdb8f2749ca5a225297e1a8207fed4511b575448e09bec5a870480c6b785c76e65b2f38d3dcea220f148f8d4b42046ddd61eff8af6828d24f633a9c47021ba8ef466ccb7a06bfdefdba01817e620ada5954c34f617f6662e267dbda15bec6a380acb8489f21891545cfb9b4964bf0f3170c5deddea166cd8f87bf20787cea95ce431976642559cd8c64177ac1a51ef6c8dba625d3d021fa8807c1a137a64c092cd19a2779a2fc967ea1be4727ab3b29858a2a6f46af009daa35d84121be4c6b203c1e605511cfb8db27330ffa7abbaffcba5836a0d6f3151ee8eb993c20e1d9db00b7eaaac9d3f4a95ba206feeb6f606e16f9af3f2ac24c1c57941e2e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e682174f20abcb7fdfa5e6f955d973efaca30897c4a3e4fbec88186ae72b8b331408804d73dfc275e": "0x000000000000000000000000000000001000cb68a2c03e666f346a277036e8f27c912baee3c7b41c5c19123840f3a8e8fc74065a60fa33d4c2c8926d0d761d133a305f500880fa95ad86acd865f274414c9890fd3e365f6954b5bcab3c8195024da5188beaafb1b13d954c0281647ba535da0afe4e85d09d168759ffe74af6049d1001ebb6d16a0427e40a4e494a7372c3", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e68b2359cc10fae926295f0214abb5522cf3becf82504ef7c87036236e6b9afd263697a99bc5d5a30": "0x00000000000000000000000000000000047a813a8832981068f9b921dded7aafe83cf89eba4c91ac5460c65d76a61d465b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e697ead568e820ccfd2eb07f02043788e254d9e2df57be11566d241c56302b91199b4647947af3020": "0x000000000000000000000000000000000452ff057f98f0c1bed31b2fd1ccd8de4d4acf957e79b3f71eb69820bf0dc1d22d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e69e34466005457c2c48d1c4fc44dbbc10b86e40db24f95f8924efba2b31eecc6a7c32bf2b8a4481a": "0x00000000000000000000000000000000044d0887549eed4b4479973f77c05a3f40c7d182e983c3bd873789a519f5cf7ea3", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6a2d4f462a713142b45f7d4b6bd58cb550270c1ba3d9d97b6766787966b0b5c52c79b4d3b51d9a43": "0x0000000000000000000000000000000004ef7550d2801399e7f9b263d92c33ce0eef338eb5527760235e4ff5219bd44c9e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6c4d2026575763437cdc1a6a5a7f23437b6528edcdf553d0685f940a4e6e85579727ef3dc574563a": "0x0000000000000000000000000000000004e33f4520b7954cb5fee8778b44283deb0948c23c6b432058b21ee84e92085f3d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6c5088428455187bcc95d7d061fc6a655b795794b9b1614d0a240e13e81de9dce3f2b184f653da7c": "0x0000000000000000000000000000000004e05c542ad7369509f498cdea5f5c427f2fd0b3051884184b294d9ac10fe64e34", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6c7206770c39d9295a5f7eb7050fb96d8d7895d9afce428a064ce66e3b094805bcad9a8e68cb9934": "0x0000000000000000000000000000000004adcea185416af2d3e8df8c1c8ee8a634bf1c3275b3820cb6d935300d42c73b2a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6ec642500076ba25a6c5f0595d6ed85d6260bc682d4a68a4b4e605d43c67d56f2765d19698549772": "0x0000000000000000000000000000000008c3405f63dee12641abec6c12b29453b7065da04a95c09998673aca6f0c4a164e9f958e6a1f4ff8a986a4e7d76c417bcfe8affda4182e66b9952dee757d7e577d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6f73628ca952be18dad0bc6a0aadf06c56416e83bf75e865d41ccb5ffd74eabf9e81d47574b43049": "0x0000000000000000000000000000000004b6f0f10eec993f3e6806eb6cc4d2f13d5f5a90a17b855a7bf9847a87e07ee322", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6f83ccad3981de4b7e569787b1b323854ac9a8c40914d400b6fc23a2fedd24321f814ce7db7f6563": "0x0000000000000000000000000000000004c3590205a4e4844653590740c64ec31e5d2af126cce71bc60df95bad639749ea", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e704dea62a3fb9e66a471c55caca4be7b4e60c6e94b20f9028883f8c64287d4454130c657383c3442": "0x000000000000000000000000000000000ca471c7aa909cc665212bb36003c52c5d3eeec39f96556a8242e861c5dd7dde415ecc1d4e60a92262c1bec62d034c979f42cbd3fb1c28570d5baed6e5ed20d533c83b0bba37f25f365e26efbe6c9ecfa7905dbdc0b0e3ae60b29980b42c509c6f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e71352c2eb5ded5f286484f63c9e0ae1f460dec3b53307478f5ce3ffab22a1334d34a52da7527ec64": "0x00000000000000000000000000000000046feb764cf5265d8f491f921d51c20318870ffb669b059c7a5b951d9291636b8a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e720cd28dcf99c07dac133ebfde441672c055b79ca9a6059850984eead1ae036f48ca1230e7f0556f": "0x0000000000000000000000000000000010c0532217caad133c16b24a5e3b2da932b83aae63356a787e1594e71317df7cf00cc89d59de520e70fc4b9bb9a43b41b2b748ab0dd51ea18326e8ce755931ea0f828ad82b9738a507bf481d6c3feb4e50855378b588a653e3033f5eab788c335b08eae5dfcdcc8e1890cb16ac515d4669ed0653e98623be435327545c72f5aad7", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e72111003b96bc266a24fde6343e2bf0aefa296afcedea6f16d37c5e1c0d8b6511e7055cf7282b60c": "0x000000000000000000000000000000000422e84530cce98a0af194e12c568c8923fe6d138dcd6e19fadcece6c0a5f10e87", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e72f593a2e278eb75522e16fcd83f6d6e08fe2b44d56b5d0bdaf33527b49e8832928d003d8097ca63": "0x0000000000000000000000000000000004f09bafa226f3e27f549d4fe85723533c0f0e54e366f3a87614ca08443b06cd54", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e74782af8e47bfcfc0a4a3233cb4870d9f20b5c55e77f839ce96a26f0fd773d019179197576644765": "0x00000000000000000000000000000000147091f937fba948654220a41ede536b0d62cc30d20274a28005b8026564db8d25a09b87b34880c5375ecca849557dc87a00a6243938d5882017fa0d1f60193815a81b8a2a03afd92af18f0338e43afc504c6018aca6d9197c0d3a149ce65efa0ef68fafdda61f708ae4dc2e384c8012719774376e478bdc857f7191ef449ab5226011856d19723839074419b4519ab65554fac975017c6f08293f0a0ba8ec9838", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e754cb56cf6c9489ed016feaa68e25739dbc4035faf2577d17ec9d7ec2125a99a6770b5be093f6e32": "0x000000000000000000000000000000000868f26829ec470fdad2e63d97741a88df1243ea147bfb4639b97a4c816f9605fd11d3e37f3547a962068f9d46c046759e8a866b64c844b0fe7426d95fc1b599c2", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e75d112c2582d6bc3922bc16cff1acfc4a08cb5bfcebadaa9eb182cd47a51b8b047a0202ae9624a1c": "0x00000000000000000000000000000000103ef37fce11457ebc5f00b154996471fcd30eae17efe69e5a39b12b76034dc7e44c4bf7f93d0a5ed801ef778f8e7ef58201bdd7e33e167faf42a01d439283cb43e0855069a59fa0ddf72205213ba6d7bc3bcfc44316af9684bb215f815fc0113f627922c9fc2d2f0b5707a3f0cf870fcbbc62ab06f4e4991cb04d376fa3593d6c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7629d0fa8c9ac2292c81fc1faa024d3d1a727d953187860b45bcb185d046631ab98261eb6f2b8d54": "0x00000000000000000000000000000000202357d8ee622168c14c8d3b65f311c42d67023935eeda34bfe81c8ed7791032384431708b474e888318f65c93f0049fa3043df9d7f1ec1f5f3d7d5e1493359e5891e1331ab2af4b510ca29f5e5dcc8e71d1fc6cc70ab24e2cf8513d540fa388ee51dad69a99af405193f3eec7593e9baff022b7fa55de147d1b4f9d214710388534fa4e10f24341696e46d61b982f279969608b00edd5d32298f3cab0afbb695ad8c67a57859b28434a12f1a078e2979d8c1dbb2404c0e15fe75c1c94e39b2061962f61510310bf29eb0c0170a23fcfafbabf3d0b088e69d1982b2a31b0d7de466492e3ea0e62e4e357e57c5b6732776f069e996133a08953b1c1ebcf967b647b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7642074451d24466b2e07be4d6d82f546ec91d6009ee215bb736be5b4362e66e7b466ec72d47624f": "0x000000000000000000000000000000000cf2497cdc525e2b482ddec24761aeb31826701c5a6e35919787bfcb455c62d77400831e9a6121a6d5002d53a89ce1d209d1e3359420a90620a022b22947d41140d071e04ec30e105db26f05b81646219bc57909c674c2a081e48906e604f9867d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e76d10d82508ddae096e24e9b5ab82dc275b82318a52cebed1cae3e25be096d5f288229b256359e43": "0x0000000000000000000000000000000004c2de6256e9ff0ba9b97f862290f69ec0f72b31fa0a6843e0175e9e81a0165d6b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e77300f589b9251ff6c695c4e546c6889ca591b582eee8b49ba68d8485a3732e08d232b2f28f2342e": "0x000000000000000000000000000000001caee72821ca00e62304e4f0d858122a65b87c8df4f0eae224ae064b951d39f61028996c52694155d7ec9082650fbf108f69da60c44a4b2565fce4e03f9bbb01780a7f29211d50461588ec3c6857c9ca25474c650c7d2048ef2283a2245ceaa8310ca0db0283dbf8d123602a2ec334ab5c3fd9e2540577e0955eaec679cefa4f0a24172a563943291c97d252def71e17abf467a1626bca358728a90a82b3de3118c4e4ff6adcb360ec9eb50d5e04ad47aec66a30055222dc13c6215b5f2db59767724e0032275bac5598878e5dee08149d11c44700c9c4626d1f339ff1be715f30", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e78a2b18d6db0a15e0bb5e12d2f6ada25c3b64171730f1c9efcf76d3bbccff01abd9f92a9aaac10a7": "0x0000000000000000000000000000000004ed6f8c70207598bc9899581a491dd8577e82f0ab65d5a78318b74bf51315841e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e78caef8fe8bb73f2a4d813e676d81d97479f9f15572d9eadcaf4503b654c0f6e7baeb49e84510e69": "0x0000000000000000000000000000000004730800477a5fb0302fa9ff4b5623662a27719a304dedb3e12eb004f48ecf6b29", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e794c7db721956af68a56b1da8dc3f4bd58630c15f5754ee634528a007ab510c86a7e1fe6e62f4166": "0x000000000000000000000000000000000494211c46d7bb07c67c2bc80e7d5ba4623f8ef0d565d266723ec60497f0375b3b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e79fa24e506fa3936321d847f8a53927fe1132754a7708c61049b2d4816ab6ce7195a8308e97c3d41": "0x0000000000000000000000000000000004d6d1d0ca917751d6148063b9e1fe8a22f74396e63a2f72e149b39e44a0e77c7f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7b1b6d2a1ef31b0a3e8c72ac1b710bbce4e7c190568bf560d89416696ac2a4700406487cde98df04": "0x000000000000000000000000000000000408104ce4b326f4b31735dfd06fdfb1ccfbad16740364d8bf0f917f32c090f362", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7ba825eccf7c1a59b66fc334c7c76cef9cc5ceac0f4b0837d845453a2e0e84703b280edf202c8f76": "0x000000000000000000000000000000000415e447e7b7a849d4489323a706823d8958db184c8c16713f1a6a49009f6da96e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7c4a65539d0e9a75fc8163c92cac3dd1d5c2c0a049c3652a8b3b8b6cb8a0867a5e494c650b4de371": "0x0000000000000000000000000000000004f5c0dc71bff8cbdce6c32ae5260549ecce90af19512e7da031f2dd02fd920689", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7c90c43e925f2226fea885b4e897d4fe908db6abeb39365ccc4689c2b6437dba675a4a0a0c0a6610": "0x000000000000000000000000000000000458cac93e1f29e4fac5351cd9879164bd90286cfb45af827fc732fbc462d2eb2b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7ea9886926039761182fe099d0c1787bb1b88de855537dcce095204028736ecfde09dd115c498f2a": "0x00000000000000000000000000000000046b973df13cf0190a75f17633f8a391020df8bac9aa9e4c50670e0dad135bf726", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7f38100bed09f866b0b000e408509bb033443af0bc700ec11894f81c090d58d7dc2ae3174c54902b": "0x0000000000000000000000000000000004fe08b40ca50585eceadf8c27c0711d8cad57d20cf68114b8f7fd6ab32534dd25", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7f6122436697b141faff1c4b5a94649e0338783122b93a469eb9e2e375bb71c92028a8fe9b6e2f46": "0x000000000000000000000000000000000c927d335e751bed3dd0da74a10e610fd2996eea79b625bfe519e8b9d2b96ec75a88ac52f4800ed8569280dd140faae0b0ed5613aa77e57a592cb9af8127dfae2a1857d6c0ec8d629533be85a017b52214c8c4954769fce002fdf6073c0b177f3c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7f88ca6ada2372bc1a0eb7fdecee073651f1a21b9779b7bf5670493a0e35a53ab83b3cabab814a77": "0x000000000000000000000000000000000828599b35f8830b27f465e77733dab096524c56d03921532c474f06775af121fa9e447cad47afa21f342083e9ef18cf04a27d81fbd0cd742e8ec36528c4514269", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e816f363193f343a643fa61b298e82f9f207ddea327900cee26b554756c4a533f36cd875e3e7bcf06": "0x00000000000000000000000000000000043cb64a5829fe55a733bbc427b0489da973cbd6b3bbeae722ad4fa58eb8277a30", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8179afc2191e064c0ecd029fdf9259e900f08996fc9862ebfe100d49c439f19bef7084b258175a1e": "0x0000000000000000000000000000000004f4fb68640df03aeecaa19d6eefddb11516c42b586d0ac0e56f354b43b70fbc22", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e83da9cc355d0681680d8a3f4317249a895e4b49badcfa7293cfbd215d6e552d1c07024d36acfbd5d": "0x000000000000000000000000000000000456613c69103858e51c79e3525fcfbc8315d93383b9280f0acd551bdc75a91463", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e85c4e925378eb4916c42f37017f31d6c9ba5dca62626e6fb434d6edc31bfc9aa49f001a6ced27876": "0x0000000000000000000000000000000004ccbf40cc53a67fedaff6111ffcf4d618af1ef8258560609082989fe66911233c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8640e8e247a0e20f30cfdb48ff7f33b08499dfc618a8ef9699b8345fa65f0b1339eb8eec3c0e4555": "0x000000000000000000000000000000000402aa5256d804b33717f1d338eef9901e89682b80c81e3b1138a02079e0848aa0", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e87258a23c1cc74c20c618307d00b3354999ae280858c01fceddd77a25b5bc665fbd4634bf86a4178": "0x0000000000000000000000000000000004f3717672dfd677afa541355ced152c72acf081107fbecbc9e0acef5b54b51223", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e87537aeb7813f75e5efbe83a561d19b1d21126af5f1608ed28e56f4f70251cf965fe3dcb4901a26b": "0x00000000000000000000000000000000086e32fb9cce7edb56991320b049369ce553a5ba93c5d262dcbe796a9b9f3f15248595dbf64624ef80da7a916f139b607fe8ac19aed219da7c7f9990be2c214d1e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e87d2f749afa8b991984e16482c99cfad1436111e321a86d87d0fac203bf64538f888e45d793b5413": "0x000000000000000000000000000000000c74edbae75103b891bf37c39e91cc489a6f68f7b6756b32875d5c5e28c173027208a73c9c3083971fa2ec757d38c8e7858df8076aca40ce176faef81fcbfbe2580a8a307ef15b9f928697fa09dcc72a2c19a266c1d32fa158f9916b8b804e1621", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e897931e60764d4ea8e602e63afb364ac583747b0a8bab092d5b20ee98f0495ce7562a8c992ac9f17": "0x0000000000000000000000000000000008bc81d1b8a3c50fedf5323698e1fd52fecfcda7436b8ac0ac6f663e146f4d4f5cc0a05f52c96d2af9862c7b89bd23a92c7e8345b92f1115d368b6548a58aa8f28", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8a3ab59566c3860f1ecec4f3062f61988b13e9dab318860bd0fffe5b7b37880d50a614a0a20c2502": "0x0000000000000000000000000000000008822058fa0d13ffcf079d48b96c07f71f6cfd7fc9abfadd85e205ae7a18d7bb3d3ef0a4136babea739fdcdc300f622f23d9a7fd229dd90c8f3c9e3d75fdeeaedc", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8b299234c2604004face99d3401cb9b45ee1bc0ec52f4cb35914dc5ad27806230534230eedb8413d": "0x0000000000000000000000000000000004d6b0e114db8fce63ffc070a452ffa1f47f0f7ca51f32809a624323f51c146d2d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8d47493ee3a600117269f7eab2e5f91f9efe10d0dba0e7256d9433230a8f9fdc1c4af10981853476": "0x000000000000000000000000000000000474fd218ac454949ceee42deee0ed129de80fad49f579870d7ee9d4a2d1e0e27f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8ec37554e12de10ab08b555a5a3b2725e01ba15eb40aa32dc5b781532854b797808ed45e752b047c": "0x00000000000000000000000000000000048cda73070bddbcd243f2d1f25982dbee2a0961b277ec209756bf794c2d0f7f78", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e90f81dd1ff30118bc44ee45000531bbf1aa4c23540940eb10599e14b4fbed5267c42a0ebf5d09f66": "0x0000000000000000000000000000000004b8815e0e6280e1a3ff96f62dda149363592236eec3df9d48aafe8796c22e1d41", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e912655d634b54e9a086de7162fbfa0b91a67eee94b697646028edcf484ae78fdc0627e7eef1b2247": "0x000000000000000000000000000000000492a11c7b27f2e0db0137d0745780fe21467bfad9bb6ba3e523b8e2dced7d60ff", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e92a9b8874561dc036464f15335eee136dd7c216b994ea6ac3394eb723590e9e065fd9061e05d0035": "0x00000000000000000000000000000000083c235e80e35082b668682531b9b062fda39a46edb94f884d9122d86885fd5f1b0e2d58494df50bbe553b779921de400483c550c57a9c7b5e7ef9735958228e34", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e93d0e54cd18f21273eabb0f32cb0695fedb8d25f6299fe51f90b1e26ed858c1064aeeea0977c1e67": "0x0000000000000000000000000000000004de1894014026720b9918b1b21b488af8a0d4f15953621233830946ec0b4d7b75", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e94770065de5e75f5d0e903b51697fa10a7f8c7e5c750fb3c2f90424b749be8b6c0f0b120f5d7277c": "0x00000000000000000000000000000000048b1789281b38392a08ab0516a21dee49fba6f5e55381106ff7ae190563cc84f4", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e95e5354b81f0f460da9f7fd3d9612a68d2ead69dde53297b172b7db514d0d261e7c5be987df7f32a": "0x0000000000000000000000000000000004a65bbeb4425c55a611da4116e848b0cc39686a11f88dee6aacceac6bc5eca657", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e98d18fa62c6f4741589e41f29ab08f2d0e4e4bdf3d1c8a868162c720f9c31e22733f8d633fba901e": "0x00000000000000000000000000000000041c6ea9855f8f85002cb80858c01488a8ec5f459b1265248752b967a685eec446", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9bd6b99bd8180aace8c7ad65c15fa3ba64424a61b177382a0c5468135aecca9ca454f5e7ce4d305b": "0x0000000000000000000000000000000004888f666828e8328a33647a47bc97574a6a5671819270cc01e66c7139a1a6911a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9c21b6ab44c00eb3127a30e486492921e58f2564b36ab1ca21ff630672f0e76920edd601f8f2b89a": "0x000000000000000000000000000000000ca4c5b68728f7fdbdb4426714a385017a471d5cd22a156acd30a40277e6417b600edaa0d08e8b21d6e8f946eff381ad4be29aa63569a54a6a75c91b878b463033f6be65cc16c65708bb6a0e4b9958ffe23d1c56ee5683670a69dbbbb70c10d507", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9d430d0bdbcfdbc6f0de782e8bad3c663be60812f0a2ac63464f5da3ec448c73334c07d71ef27f2c": "0x000000000000000000000000000000001c94c8f2aa65dff23f542ee99d7191e88eecf45b3a61b7350dc3d48804107e393d10a767cf483ca0629c6cb5dbfd20f5f9d8468b153b90bf3c40443bfba9354a14ae34148366325c0ab46d5c086e05c87c76b58125490dababb7899e9efa41f53cba318e50a4896c8228b14dbdca63c64b9a4fe82ee967a41612c4a55909daa960223188d5f28ee27f7e9067e89bc52fca8f1da20c6a7548a21cef18d8934f820ff415f3ade9353f49fffd2f3f2ebab33ab5f1b94390ad5758fccf5a00e9441e013e5e8732b01a310abc9d0ee2173b6e7f3d00b291f1ecb2f424499c353e4ad955", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9d8014dd68872e0de21727312b2b7ce579dc0f82f129d4edecbcf00abca607d73ccf16e8352cc777": "0x0000000000000000000000000000000008b4b3a27f1b0da0e787c0863ce2307f5617f485a8c27f0b17c2d3176e788c3e6e24aa9e7b57a0e49b834fd499464cc0c83135679ac384abd9e6d7f07a8def164c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9da48123ab54b499c6477bfd57c12587b1075a80d944c7829784eed61a5c8b8255817e1d62d1070e": "0x00000000000000000000000000000000044c1bdac31e30cd50156586f5009d576c2efdc103be5ef0649d55d3b53941760e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9dcc277753735b96e04ca25cf1cbc516ed1c138492a7f2e606f60c5a9ac96cb405eaa3914fd12973": "0x000000000000000000000000000000000434bc6fb5ba6e2150087c96fd4852ec188aba74a5a383a22ef66b12c588cea00d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9ea70d098f006161264319ed6a0895c04112917fc9bdc0771f4a4773aae014a99d25bbe06fa1057a": "0x000000000000000000000000000000000878c7dc6b311bc7e44dc95793f0b8e1316ab1447073728470fe08e0b4a8dd243b005fa73637062be3fbfb972174a5bc85a2f6cc0350cb84aa9d657422796bfdf1", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9f053c2746e722456610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38": "0x000000000000000000000000000000000ca61fb8e0537d0f6c8d4f94d0466859215b77e5e53c44981253983062b7a46f72a160a7305cb5b47a2903f6648fbb6ba1ad24d72fd49c39ec7f9d21e184f3dcc778c505721568ecb57fe677b4c24e670079e8c342cfbc7b312c146067a2dc02a4", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea0425165102d0e25091bb84ac5b08adf128e855e1cb079ed594be42af19d09d680dae982ac209ffb": "0x0000000000000000000000000000000004640d12a59e7ac3ab24ad5c33dada639c058006c59fba147ce8caac535e801415", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea0b881b0063a363a02bf32e061073c44300056b416cd66a4fde1e6c120dbc0089bb65134f5693a3b": "0x00000000000000000000000000000000042eab66a1c3116f15f55dd2996db419e367106043a4c5491a5eeab1d33a17460b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea11a320b9a8feb01f857311106c8d7b0daf6e096db9a0d759b52403e439ab23fd6559780a8b1c803": "0x00000000000000000000000000000000043a337becdfacffca71fe67fec208733754f035958d349d36b30225fd47798f6a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea20d0b846e3d907e00555ee596210f641d2d48b9a1e2b258aead3fe8de4e973bcaf5f24674044367": "0x00000000000000000000000000000000040792d0467f5422f1617840e11eccfcc8bd24bab23b0ea04de920c1109e1e14fd", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea3f67b4c0527d154dc3aee12519c19be02628b0f808bddda9aed564027ad809cd392c13e9b924b65": "0x000000000000000000000000000000000490ed88ee1c02bcc5938985c79cd8bf1a048a9a01f6eecf8a3aec9a83aba8a20d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea6eb394e364b8f9c7682e4e399a94b0dfc4a9bc476e0bc69f25413687d2b1c29bb7139dcc8e8714a": "0x00000000000000000000000000000000044cb0f7f17953e529b8106c743f78d238e3dd6a90f421d32bc920ce120682c801", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea91237ad3fc3e223ae0d1db9082bdce75480ee80c3bf3c6496de1ef8171951de2edfe49fdbe30a67": "0x00000000000000000000000000000000048c2bae6068de838d1fc684db669d5ad1dfe26f37887ce815734145764b7e7124", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea93c6e207f351cebc5c184f0565e2192d6aedae584ee736cef875f0e1c558ee3ede26869acd0b4d6": "0x000000000000000000000000000000000c31918cb9b9c9414a2cd4dd7f720cb98fe98cf852636fc4860845767989127e7d02e358bc31b7ccb578dcc5c36ba2908f311ac5ab2ba8c1483595268a7189fb026621dd4e5cdd0ba737c572710c13df35b316d39ecd12c1ae1320bd6db069a07a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eab7e3e98c718729f7a895955042cb3fe863f3564e7b30e9130e37b6d905be11c0cf91064de1cd83a": "0x0000000000000000000000000000000018508f2cb4567caff040d0a47db244d7ea791d9ec23f0d5d33928a7c6a62b3077aeaeb8cfd46b3d6a0abfdf3961d572ddf2303545b03f0b1870563d38c69de4f20d8151ecb8e8d11e6c6bd81ae49216b9ef92d2b83b3ae39702a397922f14777681e503909a89514337bf9ce931876a08003396a9def52f867e123cf1420a0f70baaff773e3f134d4e0c90ef5e5f37adb603bb591b7aadf67a2a757101a1b70302d97d35c31f6d0b75bfa93ec1eec8823651d1582368679c44f00ded1f5401b5e7", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eacdb8f7d99b9b4f82cd49434353de1d51598b44df15fcfed1e26224e055923acc9f9af881dc31d5a": "0x0000000000000000000000000000000008ecdd548c83457ab43caf7867e2bef91ef783025db9659afd89794ec1220acf29607262b83b9349efcad72b5f2a0cbc80b1fdb622aa81a861a56209014e568337", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eae60b338fc29997e986a4fdcd53d0e438f9694c9a6bb76665bc50acf76180049117caf3ca9bbcc6a": "0x00000000000000000000000000000000184a45b84757c48776f4c5d887e269e8e6c3f2fc55f75adf222662f129f9fa5b40e4fc83d05b1d8ac627cc89bbc95e7379aa395cb168db459fd18c6bceb6d1523492e594db8b26bc07fd45cc783db49313f17183491f1826d417155a95d5f7d85ca459c65e21e9f36c344f9def7e0ef28e96f6e1fe02f8e3aa798a8fe9cf906453e27cf0ba46292cc95548cd67e3e29036b0eaf1ab66a4a6f5d7065408d50b9759c804d9b3aa2f285568305291efb2e0a6b70aebdd5b04ce6a5506c0a8678fe604", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb045191cd50fbf997059b7d9ad6e9f5bab40385874989cd04aabbe821094b7e45b5e4de5ecf2bf4a": "0x0000000000000000000000000000000004aa29d60ab7eeb8c8ad1e7d37f8438bb02cc86c40c28218d4f183f110067cd368", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb1580a59c1acfdc54421050207b47ba1bddef66d1e1deee5b27d27d7fc526cfd68e4be18a5b9b146": "0x00000000000000000000000000000000040e49baba2f2c359d846db58da8cb83c820aef3fbaa7b2164444d4946dc047e08", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb2867f14046b21d05a33766207d51925e4b9a2302870bf737305cddd5bb2df2dffa379963e586771": "0x0000000000000000000000000000000008388bf0fc0110c1b18dcab471725083bc6b0b52edabeab0c3e73e506a54f9e04d7883180d8cea922c0648533d6b2be8949765483e833ec49e8dfd10a0ea61a03a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb2c78530b4a796f2f8f0244b95932b7a67caffd31de91edc5cfb3aa2a13f6199f127ce51c558204a": "0x0000000000000000000000000000000004d7264854fc5645d065341b90947bd9be1564df8220073eab4043f4022e633e8f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb49940857135462fa0db8c6cb723c474639931cae07e095e6e8d9b870c90f5b499bd8e6fdf4bd54f": "0x0000000000000000000000000000000004d6ce187276961ed56ae9a29566279cf443df42f82d9890b02de9c11e4d288e13", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb4a5da87e533f5dff58927b296a23cbf25794b7cbb8fe31c5e68f2bcd2c2483e9c9cd0712216f232": "0x0000000000000000000000000000000004bf7105cdc60a8125bc7d465c5587c26d9954572b8579bd176052bfccd2847506", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb51eff5e9260eafe64e6db572dcc9e5dc57445ff7c68ce85e42527aa74b2ed5d1e2bceefd308ed05": "0x0000000000000000000000000000000008e0512205b8cbb851e7b9d862d204b1df2d7598e03041c7e70b373ac45b1e6cfc8e6c97add8c5563d923d9b702f854b15ae59ecad39578845a04239c594046044", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb67813127799c8e920b456b7a8651f0b81f4517ffc79737cc392230cdd92a5b4bfa09ac728a0b10e": "0x00000000000000000000000000000000047c73d0b870509f5c2ce7ef8313ac58becd9dea02162a270f9913116d690f0904", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb85669beeb21dd0baa6646d5b85790bc0ab869d80385fdc10e1f4befa7f8a4bf31848f73012d2823": "0x0000000000000000000000000000000008c4bdda1c96506117589bfc216f9e5e79510c179b367f31401e01f1997b47181b66d0425af5558b202c277f282e0d55775eb9fe23e0c68b7a10cfb7f59202b402", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb8a74d4a444db6f1bcf647b00211b2d6c8cdb9e091b95ba03ac8bc6a4dd0124f1f09f8c917d1d270": "0x0000000000000000000000000000000004698654b9b352da92d00844ba8bab505a2cefffaa6269cdd2d407cc866440fb88", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb9aa88162953b359807e371d9df95983e2b9face8efb67f962816f1a0c6681cb1e5455127ab45c09": "0x00000000000000000000000000000000088818f1b289df88876f0199aa1fd723dbec6e7bbc5b08e5eabb89edebfbe3983a2a1202907ebf57434db992641143ac78c8631a1e412d8934e5167153caed0645", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eba7663c3b3aaf51b09cdd094e9a51d26bbc6cbb71d3f7c5b8edde629402e3e5370e7f6904512fc4a": "0x000000000000000000000000000000000c47e503b630c37057023c04ea57149dc70ae19f186db24f59881c55cb61da522f1baa453966c043ca367ccfa19f450244447b9d32f4b7af2d9749e55a57ac09cc46059d2f1a61eacb55d5c4c211d0b35cf3c3f4fe1f2601cd8bf49f30ac370c49", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ebac296575a7da3090eb83479fa34dc63024ed44efa464427375a44de486e8d6007c7842b45ce817f": "0x0000000000000000000000000000000004eadae1c87f39ff2b60465c9640a1af260a815725f9ce3fdda291f92f7769e3b4", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ebc7126812bf1df493e1630f099540e76e98b9fb0002c3a5ae3f40b6ec180df68fe5cd9bd2088fa18": "0x00000000000000000000000000000000040238a0a2b0989bb426df8ac92118b4228a81b354d0c87d8acd25c8de509f2226", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ebd45ee52acd85afa825872f7d324c8d97a9d5f5c94d918eea93ef783f305767b768a76f9fede7b4a": "0x0000000000000000000000000000000008c07244af8ac9b81030b3c47c23cd5b10701d4a5490790e20d12a583e5e6068230361fd2cac02d6b4d6b0f31f3abe70104f00924a85bebed0b17267990b38c88b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec0095c67a6440edf74db9a1104a31f8b431ece5bcabbe3e508d22fe13670d32875ff6347a88d1388": "0x0000000000000000000000000000000008b4a302cab1fb0489c4211db08beae0bf7b5432416b299f57ce785b037c297a468e2499f22749aef04333796fe92b73c06cf4e358a552604ff3e550725774f924", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec029ee460555e12cb2692080bd814373a7c780dcc62922ba2e770c11a50bb1bb38fd3e69f0192a71": "0x00000000000000000000000000000000041a58ec699c897903d28984e42202dc216e2e8f7023c846926179c0c38562e4e0", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec038a43990a07bb81280a479ee3beca7af1636aca17582f30829782e2c9b1b9c72aaf8060563ab37": "0x0000000000000000000000000000000008b0ec35caca1aab56df7814b80ea0585eae79ec6f58cf03a8be0c40a5c6707711c85cbec6e7576580deab57475b75d3456c379f8c4abb617969fbf99aa4e8c076", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec07bdf560316d32b08ec72cbf62bb66f416f46f988e130585c834a381efdbb0755e30f47a2a0da5a": "0x000000000000000000000000000000000880bb3bb99df51400d9aabd8e0e6b6610d3d4f5512ae4d46e03f20ed14eb0cb3e3ab79a63ae81a8f096efbfb44d958cdd0253e97775b908d73de31a5d9cb00e44", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec17b80d313e3c78cce44b6b392394133943e063102b113e0577108fb9cb3000fe04faec3a3ad3934": "0x00000000000000000000000000000000042e544de1fc9198d35dd459c8ff8bf0a2c86eeaa4ed8ad9b32fb8d016e696ad77", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec19ae875baf61fab3e3a490c516b2a3582e6400e33f3eec42a12589958cbb86c87b23bc94710d21b": "0x00000000000000000000000000000000082c85bbe77e464b97ad4d36a49bc2b84566c38b9bf6eff49aaf005c672fafe7528a4c3a7b3f2b3cb525ce315f859de83c51410fc29ac88734be346709d0798a20", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec1e0ca80539b15c8796b851c8164a129b23282ca4b3bb694364b0bfb504e98b5d2ffc5140d58078e": "0x000000000000000000000000000000000482fdd15d55ddeeda8100a274f8872503fda6e267e345f4edd9fad26229604c0e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec237c8c9d7bd4904bc267fea33668e3515a7c01f4acca67d73d30574b600a404d2b7210aaac85569": "0x000000000000000000000000000000000444ebd2b934606a30469bfd509293c34174336f974709964a18bf40d99a0bed0d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec2a5b45c043e387bd2a0035cec74b2f90f7e72cab1fb16b6ba8317631976b138f7cced3e00668b0b": "0x00000000000000000000000000000000045485545d9937d865c9fe34b5b3723ce78729178a292681d43bcfd35076a656e4", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec3aa97983f6ecffc96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837": "0x00000000000000000000000000000000e4e693f8c8c6043a5d8c8ed64d56523d157625011947a8a79881987d9e9100963ad62a2b80ebcda1b2f14d2a903088759ce56482401fb4130cde32775d6d210a6a00b03b23766d70d0445943b290606521acaefee7660d521950faf2801c79d428d44533a4d21fd9d6f5d57c8cd05c61a6f23f9131cec8ae386b6b437db399ec3d2cc16da9d1f7271475075aa8eb5c6667714426b8c41dbecf92bdedfa462b7163545e8064f8898a29d4811e09b207cf3302e5cefef16615f8580fcd8fa63a624e44ab70adf9b1a6402cf14b3c61f98acf5bccabaf0030d537510166a21ee44d1676c26a1fb9acbdd56be00d4c44901856929b9d2a879caad6119ad0417e9949495ac7f6af5aeb5364188840d02f0e74e813e6d9cc0398d6994b66727658a4fb30ba43c53c2e9bf804aeb0e0f3172195defa009198441a21cec8738d366105e44734e6b8b209b93f5f68b7abba7c3e17a84af77819e98b05a0d828f0b9b2b925788c23324b0cb29e4fd1a68cb08febe58b50e39d8afdb5f752d6c26c8ba52fc00280833b98deaa7ae201c9d2aabba6d7cbdc14ecfe1548c52b8ac4907acb14c863442afde41c8d0cff9680849824712996d0cd96906dba9697aa5110cd6d025e155ae7010248daf19a0b83b3d131f63a693785222293af4354035b8dce851fb02b74eb76dfc265812c8f4f9b98b54e25c319719e1a3593b7f0e743cf85252061789c6a3401d06cef30fdbb33901328f3611dae8253708779a5d66179c967582635f0ef72b01055276dae281f6da1a1dd14c6276142afd3aed8f8b6c94b36d2a717ca67e0639a4112b0f7cdc7a7cb9ca5d55b8fdb35862eaee46c8bd34720783d73b6ac93bc22957dcf5ea1a84b1ff7e60ad872eaa73f3d176ecf7b980cd33b8b0016b94e2d5d12d60c7314cca383bf185ddda83f413da740a121601e3277d3083e3856d90462030b27957c425b33bf8f8f669ab715580e7f64f36999a74cea393632aee225f2714c573eec965a9dd1e1ca399636d9158ce068842f0558f360a4359695d7445e6e6b293f6fcb0aba94ba7b76431447abab31430eb99a63934cdd3c42cbafa9669c25868ae5ef66a62b96169f9d56f9b1dd27aedb241d86bcb2dd68326020faf1443ba7736e9f4b7a442db507e4a2054ec3a19f985d2c44c30b304362ed2bb3fe57066f0c015e18bf443b1d384119ae9a0eafd276064062e73a1b3170119b7481293f5e919dd9f0c078a5b285f9ab78fd05fe73b9b4dedd595b5c38049a9687c22bf19c419cfcc79a77b60b07faa3df2034d7cfa4635350571cbd325c2721c659829b4fd0d827879873fbd8763969b48a7724633b1e3d4c3b3609619819a1a845833b4fbfb1a911e2332fe3abb3e09acdff60b492680c6189629b2b9e2691c29d062502fade8144a0eac25be3369a271b3fdf2208a9d86cfec6f948c28804ee5c2389c20b837475af5118a2576b88baf216e87684eccf9c282d8b2ae44b76584cf228a713f627f36b58ebb282be3a162e6f24d54a15d1082006a20804704197ea07678709bffe4d7cc4a0203e5f92da2f681cc5e5ebd399b83b3949907559ce75b9e6531397c0050be2cdf9d982a2db041a099526baba91b8d254098823139e30d401f7a9422e68208ff3ad2f8e40e92c83af26e4002734760cb87e1aa604e30e2baa8547c93923bf8be8c08efa12efaa6b444e214a3d631ed54c047c426559413ab646ae9152a606fce1486f754412a7e48f81e41786dcee8b78006a7fbe4110d7ebecc8cd2101113549d90cd477c766e02a52856dfb5d9977030f2caa5b3f92b80dc21b417252e93eb55ae8c6e6ea96c7424bc80d00cade786627c0afed691a6eaadcf94bda09fc7b713aca337f9eea5e7a02b1a6aafbb1a44873369e319d0c1e71ffecfe16b614f13253549f2ff0c6db558dafae395ebd5a300c5613fa8d949d17f4bd3ecfd6b7cb550072f4559c4c3f01250379945e44cb323514bca285494baba8c77a19f94848063b287f169a57d42ed48b409eb5554d1d0cf61b8042ce3e6f4c3731471c6a57e4a8ae30a1ffa5870db5043b933dde89af1b2c888948530df2b5b3322b8f999dfbeec62bebb555351839993a10c2412c387eccd841dcfdb3ca84d8e995a2df2660d35f56952ec7a5cc18c8b0e33a71e34965c2975211d5ab22d276be7dc90646aaac121341cd5c033b2ad6e1a43d23d2b43a802bcb2d54cea58ca2d0af13a85daf28ccb873d31de2a277ca03bb185e41a25fc60f58cfada1c6dd1a8ad7625f8a184e6424e37c0ffaa604718981c1454ccf2ba26d8e7561ea8e813da3ee0979be1b5190fcc5d2d1375dd5c2e6b2f417aa8153b6612cc74066b95fb08eb5978781b15169170cce9f5493f6d8f74013ee4e6e4cfaeb0076ed1094419bd13e852c388586de314e8437d9c0e315884c10f1b5520f52057768741d83d391203c6abbce429b05bb6d148239c08fd104e6b65c5312517a2f97c76dd2d0ee3baf2ddf3b0aa1942b47ca79a3d1e2178ac5c1c37a056139703bd4afb52b696047f54d9c991cc8fa8d7a7734f034a008c630c97f95250568", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec562a9eed81aa2dadae2b867564f01654946a095e69f0f49df1eb5c0efce5730cc3d1d83da3f4b09": "0x00000000000000000000000000000000143e1f45bd8fa191f3441574abbe1f4ef3bc6eb07bd224560f30e45909eb0c8e457ad1704a69927d8dde4807b1c67fdaf26718755a742f7994158c8f79749f3a0444e2fc205de7ec0dfc49f2e05c64555cbfc897602413c712c93967b59257e537c880ad522ee62f59ec14aea01214fb737df562d1a9bffb35d70d35bfd2c724325a482942379643a03b8eca91f12ef9ed1baf5437080664727117fd2ae6e7dc56", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec5b2faae0caa0f972c6f57e9289919d242aa985c1963f2b4040ddc57df3682d890657d130c035576": "0x0000000000000000000000000000000004f43e114e579d7503e86bc631c58415cd1cdf864d0fcf512bdd5cfae51aac062b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec78dbbfac53841cd2c0d08e42e58247b57421f3239e0e192b21edaed4bca2458028c981634bdb607": "0x000000000000000000000000000000000803bcad4ae89b033d823dd32ad149177e99e47f1c1edbfe9e5281f585bc406558fb944d7e992958540251fca02926063121bd452d21e0c20fedad450db1e5f713", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec7b59ed3c46118b33a5e67c5be0b1a151232d17929a6479d7d7187544a40c059664c6315e94c977c": "0x0000000000000000000000000000000004a8fc72d20690562e27bb10f078d2de104192ad2d0cbfb4eec4eef42381f53739", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eca08516f7be365cf1a21174f3333c2bb416072b2c31d8f1e60f8e4ad3cf9546ab47e5b6fd060d303": "0x0000000000000000000000000000000004c203687a31c85ac0dce32725c354a515d8c027681db49edbbda4e3804e5dec63", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ecbd0c872a0daf479a4848ac04c2ad298cfcbf27ade0ddebb2cc3b37b090dd933a1e988b7a3ead075": "0x00000000000000000000000000000000085607fa03519626bba53d0d71b008694a205e566c653b766c9f1c60edee39ec22320145f6b95e9a687429cab758eea7c9cf2375c09ee12b7973e85c7f8476da7e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ecd624b47e3069b393e8faae4c5713c72aea65d52aa1616d3e918dee3819fbbe08cd4c76dbd754a50": "0x00000000000000000000000000000000087ef6c750071ec4ea673adf3a02c82062d042aca83eab159f599434894946423deeeaf12276eba3a08a26a606cf4c7cee9c3c0cf56a781899afa463104cdcf842", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ecee83f43ea0dd41a22b7a9ef681c4a3c1743e5c343ff5b6f8aec3dc43bb0d49e29243d79ed406365": "0x00000000000000000000000000000000108ae437cc2420c617f2cdec05405db6c449bada7d2b2063eadeae636a25c5ca79cd0b6229844999d1cde6c2e74ff90057d24e5875b891f645e2fb4a47ab90745ea100d0eb4c4ad076d10849f54ddfc448b83596f24f71cc49ad4c0390ac489010ad21c2f113facb0631e7145ab7f255c3e46b49904587d6aa6116c56ad615fb1c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ecfa782accd3d75bebe776c10ad0e1fe7f606cfe42448e02cdb640c21214ea6c0c99df36ec0ee3d0d": "0x000000000000000000000000000000000882c35d711666a25aeef2933e8c52be35e409e288120a6555139b0c45d90c140c46351b08b39356e218524151eb16da7d6678c6066a831d6ad9b9ceea25d6df07", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ecfac989e84b5ad935ee1e16ea093ea043d7f67a6f34f440c5fb921b56b54e81c177898d348685b51": "0x0000000000000000000000000000000004189ef65d1a77acbc1492c95ea3a58cb70b9ffff211190368bbfa21198c734c2d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ecfc0cc32c14f6b1b1c2a5f648afea2a94286c17f6c60d16c9ef8511fa4ae88a54ce2748b6c8fa90f": "0x00000000000000000000000000000000048e5df47c25340b48d443389c64abf88909ded6b6dd62c01548840970cc4f14a5", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed1067d55a33c02831232508adcaf57c6e78a850f9d715e3694b52000ce537832eb55c7a59f859e13": "0x0000000000000000000000000000000004078447732a649b7bf6970bbbbac8df97ce628b139a8407fd7d051f40a0258f93", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed4f4dfc6da461b20aa72c321b20bbd5b78b14f6fd800017bca47190956eb42ada2a4d8f8a8ca994d": "0x0000000000000000000000000000000008e0ca65cc737d7d170d9f7b09247f9cbc52142c62a6bcb4d8a5bbf29e6cda7e0598bb3be2e039d66d581ffe74cb449689ac74428512b67e033855de5d75b84d08", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed509c5c59195b1ec5c3739d60301126756a7510e34f9d656d4435cd4fe64bbd001f1f3473bc9c333": "0x00000000000000000000000000000000048413fca2f93b3526794f655fc3504b40e0dff0648a4999f10f8eca7c21d1c21e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed7906ae903234547463a9cd3e7cec50ccc93515557ab58221d20c67a409583428ad67caff9415107": "0x00000000000000000000000000000000044793061e5121c9561a8dd25c2e64df912f5939a096bde10bf9c5cd06f753f6a7", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed9cef13374a70e655010efb7049583595fbe3da57dc5db048e590c28f107e5e4fa2bdcc4b1293f6f": "0x0000000000000000000000000000000028da4c4087c6c624a12ce0c066b04f71d81735ed6a252c0f63e55188be16be4f475010efb7049583595fbe3da57dc5db048e590c28f107e5e4fa2bdcc4b1293f6f482a064f119738425180e442727eded171c8091bd90182c3071f37199d9541586e306a119e947513f180b430e3e75bc8c476a8b61e8348d1f87e490121601b5a6a4fe76ff9e27c148bf2c24e2f85fe56b4eea5bbcdc159430c18036e0f940f2782c38ac61bb075ef3c6f745af4fc8675526b69e7a66c05e777e15bf3df99302fb4c24dc7c3bc7ef831df7637143bb554db602d209f58c93c3dc2af04dc3866699442a11a7247822dfa83dd5c27ea7249cf2458e60ebf82ed760f9e6d6f99bc7bc63d29b9669894bd812dffb0a0206bfaddbf728741b3219e9ade9937bfb1874b1a9490a6fa5ca6353651e0384ff371db3aaa0d2fd20e6ba91c8733a17f581602", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed9e0312b39961bc6726a98c27f84bf42fc842794a925418335fc9fe3badb1f535dce9c9d9efcc02d": "0x0000000000000000000000000000000008b0614de4de8cfbd7c760fba99b446a030b0ddd8f00a0dd84dfc88c7875d80c07eae07a7b7adf896a2332b5bd2e366474eab97e137c155f8741a9c6b4d30db700", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37edc6d83874526905136aff2ede1563784631d6149024982108f661b079b6b79f3d042041a9da11e2a": "0x00000000000000000000000000000000043e9520e4e74fd47da1dd509ef04dc9b14215a35e7d207fdb2c99f732ff5cac16", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37edc7d270f233cb625a6ac5af2b37a6bb6d5c9cbb7fa56748fb1c9cf9ad1ef43334efa76a431aa3d22": "0x0000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eddd17007ceeb939fb4d78a8bb35a7b0ff8ae6a7808f9b17c83efd28b8612c2388034d0e35ce51376": "0x0000000000000000000000000000000004981d5e90031eac279276782d0d15ab97fb30898a69abc4eefaa797c572823b2c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ede4e384e5c5bcda65ac4bbe840e332da2656c0e760904003fa7a2123a216a33e81b8531400600304": "0x000000000000000000000000000000001076729e17ad31469debcb60f3ce3622f79143e442e77b58d6e2195d9ea998680dd00de863a4e1cc8c2b2050ba4be784b313caa1e51167abacf392c1f07270834ea82456d51e83aa6dbf7a473b5776454fa175d5dc9775629aa05bb09b28fe4509b054f58645b2774a05e70ab4f9b59dfa46ed60acd0668713e921324a933e2027", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37edeb3e9bfbd8d3c590cf6b6cdababf69c2af37a41a2f360820bb7dff2f61c20bb61a9503a8901ee20": "0x00000000000000000000000000000000046a6d9f13f448628beeaa0e4c8e47341163ce0eb14c612d882799b9eb4152d71b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee050fe4b1877288206c7ea7684b6aac6cd63cf88c92b0f05398bc3e13e0b0c5936c3027b8e0c7e2f": "0x0000000000000000000000000000000004c9108836cc5003906b107d31fe5c7b5d1211a4f71bee14f068d2fa04551387b2", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee18d41e2249b70ec4eb32a5fbbccb1d97d31237172fbfd92945caa6822d5f8afb558aa7b89bc5a11": "0x000000000000000000000000000000000426a81cc7f1e72380949491cb9538d125d40de48e631e0e8bc40964fddee59bcc", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee26d187c65071fe036da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb389345": "0x00000000000000000000000000000000781600e09e1d8a1324934f83d55d5f6f503e2d91bf4270eeaefd462f24e4487e29e6d97bf878b1012927ae6afb7e092c541a5abc3904656981beaefb9ebb781d1c44a1336854e44cdbfa929ad12e913e4a1870c590a6dc5e3983a6fd416b927f534877511245f8954e48858da743b9eb3544681c27ffd8802c8ea1669e961a2b6148b2cc621a25ed86391676c3686bc2cf76f06edc66a4c3c21e2452618ee1bf4e50ec868243f5ec5af29a7c679163a34978815b6f1d6e2b871f1f361cb7a1f9057c2241b8ad2176aa340dea400bd84fc389091a7511086bbc78fa98a7356e630aa06c4e59af8d86d8b552887762255c830d79b847a6648210ca6b24d0dbba0e2db64c29324eb942fab6b41cc041f0e099f35d5c7fec824bae17717c5fa68cb83e88d74924b788c1f7ec64a54c63eccaddca748f588f67c26e5595870acecd9259520aefaa9aa8f2c237f96957bc1858cce594c62126484c3cef56600e11580a7798a8cd51a12a19dd5440fde5e43cb50f9d48d95ea5c5ee3618eb0b2945f02f21be6c22b41a47d782268a2d1eecf5e623ae6b984591db92f77de07a27a447f87c92070ebf24c4c84a47db97b62d308834c3f258a9d96aafd6bd11eca52bd6ce4b9ed22cfc6877c1961ac2cdbe5536684b0761074b8ea475d0c2f173f5989be90454730499c6c53dd16d1e3f8007b64be019cc9229db22d36a12e44eff1670cf5fb4de0e0553f854c72746045b90c8e5c67d74f5d8a52d4134b259ff562e4b1409bc61f6c2ba5b42da936c12c7e5c33f6cc573988521e5350de5887b20ae9cae4906e11fd0d4df6c4765eb346aac47682cb7871da9ecfd235255f6eadb8392b20dc65de6003709aa5a6b81354c00fb13e281ac05e852cb4194c69f78566e8ac8282eef2aee654d4975535f2701af86ba6d169c2c9a1599b16635a2a5e4640db94d364c29bfbc9f06a42b5cf37ffd831e91c843cc25d8b90071546810ecf279e45838a295559d8977464fd8cdd133f8805f2388e42a6e009219247048a27d9ac06b42efa2e57a813989da4bac4551e4010ee45003fc3f360f5202a958b2b1a29918605fd1308af1ce85bab5ba3fb19b330ab7dac29e01ad501420560f44df7e0e1c9c14dbe4982ae73a084bafe1f7eea2d51f3819088f08a10eb2fd7a1343c5140b8a1ec46479fec3c43eea382d637de8f295ccb2c0b6f6fdd4c5d34a687737a601ae1595f870cc27a34374a6b819a554e242997efeb760433c6fdb4372c2f28204be2daf84705de34c1930370f53566524b08145b4d192d6cdd5a35cc71930e2406cecea2c48271687c926a72814cfccede993dad2b803ec0d546d2bafa586c11d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee38e649e5f9f7676b4d599b32c954b0a9e554c96b248f3e66046a82f46ac914fc675938f771f8372": "0x0000000000000000000000000000000004a83a9d38e1fcd76d6e82eaf458c9b71eba96a9e6540f39213fa01366fe0fb64a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee5018c1728c62231664513c046d4497ba05c19efac47cb0dbe498e20b089dff25aa08d1a77ec970b": "0x000000000000000000000000000000000490cbf37b94fbb758804f3f06510840b6649c0a2cacaaadda6849c9dcb766b767", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee5a27d3189e99969dad042c036fcd9897945a880458b8e7104b30617a9640eaa22b7e23e675e0a02": "0x0000000000000000000000000000000004c88bc26c3cfb3797c1b2e2c9e7fd0320d9899271ba9255a2408c4feeb33cd425", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee61549e518cc68adc8a5bf93006b7fd50ffc2abaffd57ef06c67f2171b5097070892fa1a195d920f": "0x0000000000000000000000000000000004f50556e30130b7c23f4ec520332817629963b2a69e5b024aafc29fe7bef6905b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee7b5d2aa3f9d8295b8e06dc2e6bb6bd269319ace4cf8f663338f8f285a0564d6a139063c985d2310": "0x000000000000000000000000000000001012c8663dbe1a18335ef5b7731a7ba8c0f25c0fcc761623af5159ec6eea586b283a92d9b2a48ee9adca77ffd658b1e273434924a7b3b456693219afbc32279e107c103bb33a2f4f6ff86f2f6e11e9488d6eeaebe52bbf31291fa00e46ec26ad60d84ea2d7257eeb646fb4e0d2aeee35a3eeaea22b897d8ec95f42d5ffd2251430", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eea0e1b22a44d19352c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e": "0x0000000000000000000000000000000091012c2a55b59c3999f441a596b34e41f0d55a88c0f9fb7af4c76241a6f5d3a3e5142c2a55b59a282fb173b7faf6e82984686f6fb83b0293dd498db6329464a45d1c2c2a55b51baa94ff2dc4feae28c5ecccb774c622545b0a127dbd5ae8e2c8e1152c2a55b5b05723585c7421428d9ef451313e33e13803424b0f8cabd383d0df372c2a55b5a0ac2e467c72c205ae9252a4e8a0c206703950f095c31ea3f022493a2c2a55b5a116a4c88aff57e8f2b70ba72dda72dda4b78630e16ad0ca69006f182c2a55b5c69b5e131fb0f65ac7ca707f4bc53e4d991a2d1971ab5e702f69f45c2c2a55b5c7e135ae443c6ed951338d4b32be6cf61ac5bd000b7a11c26b3078202c2a55b5c60139f9572ec1f88f541744ad98ca9cd09b5641e84088ab0ab3920c2c2a55b5a6413894e13836fb0165e6adce7d77c06dccf42b3b288397a27ddd3b2c2a55b6068e3b8626608321044a89b82fc4898ece34524659f48aa72aef556c2c2a55b5ffdca266bd0207df97565b03255f70783ca1a349be5ed9f44589c3602c2a55b5eabf99708c2a9f1e21a3bed0fa589b18286225ceb1bc9e28ff06a04f2c2a55b60a32545c89a8d2ba5d04cde08adeb0e91bc2d0cd909d166db15e0f7c2c2a55b6094cf557bc85fa401951b4d4844146211f845e1c212640685d42057b2c2a55b5feb0eb28fc697566384dab127170f08c1c2a6febdfb4cb3185ef89172c2a55b5c4fa92b88356b2666fdbf58840b50813143d93c886f60a39b8eb204c2c2a55b5a609baff13899d4ba4bafec105038d66a716494968fae1a849d2dd5a2c2a55b5b7e13a772e0b693c3b351d2fb5e5b4da18ac379ebdb2f1f2e75597762c2a55b5b86d232309cc2d8aedf4c647656fc6a40e2cdc299020174154a7fc422c2a55b5baad165d64eace5f75642ac4612ec1ef12bbc1cb27a01374737882572c2a55b5cf8d00511ef54ac7a60773810e906befb1b322f2d58199963dc973072c2a55b5c7a1c48e176aaeaff69a017d85b27a49f1fafc160725a3376f417d002c2a55b5e3110687784ba7063753757ba409052b2989ab9def09a684e8aefd6d2c2a55b5f64fedb5e9a535e4358cf539e294ccdddc753610fbe8c25ed72f94092c2a55b5de12066d4ae584016c6d556d36f74984dc2fb33b372e568e404c09672c2a55b59ed1954e80bf1349ee5882d429d261cf9962bc5d88a1fc176e60c9182c2a55b59f26d98880fb604cdd7848e4c1576a990b0ba8468dd4222aa27f9e222c2a55b5d10904ce8daf9095a573253bd66fec7e96557836f664a49e5b89553a2c2a55b5d7c788d0d4bd1f7cab8c7e7a6d131e3ec396056d62d1376d211779412c2a55b5d133442ac56db7e5ebfe739897a98a37c258accbe3697d0d7f29a3732c2a55b5b35dc5768afba71d0baf2377ee6f8e235c27d04ed90d75e0fff806252c2a55b5f917f0ac6055619baeff392603206df4007063317d30f823537ef2342c2a55b615f9b64ac6a84fc4513c431a7b6e0bd3812a4821392a462d049aaa3a2c2a55b5a6392305c60fbcfcdf77a4041507f2bd1976c05dc149d2239d1582212c2a55b5f1b5e1c45738e2352b3d00673a40f451add21cf8e6a0c3eae6bb68242c2a55b572dd8f780415f21ee812b5bb32d6baa791ce4c8fdb04a13eb21d3f092c2a55b528d6e2e0e0b7d4538eb005a63202ab1bb9fd8e23cde888bc573f67142c2a55b514ea318202f6b920073d878c2c9c94fb38a48e4c7b3d4874f755c06e2c2a55b5a3e5f8bb0fd6155ce85668d8e606d7defec7044d8615225bb9769a6e2c2a55b5b1da68fd2ca56d83bafdbee8ed436709542031e625723d4cb0a01b312c2a55b50279b01fc376a1b5e4e6670a8c247f00ca6c1569a9fd92ae18fd10312c2a55b5bb604a28edf5e8b24c72f0c851a6440c1889346d8ccfcd298b601e252c2a55b5af6d74281de0813a60beb2a89ef39c6b2a10a35427c683d61e98f1702c2a55b5285b5050bfaf7c602b3748dfcb3306896ae8429c2c0ad8104c5034012c2a55b558917616097dfee7c9142497c66c77b194cd9113d0e65a11ba27660b2c2a55b4f7af0b8559bafd9332fe78fef55b0979b53217b3f8355382ba9890312c2a55b50302080081e20a336b40dac9b5ae2ae80692b653c2b38131047d797a2c2a55b5e347cbea568da1dc296c13b681ee4b655108e78bb9c33980d45e25002c2a55b53f73b4d26ce6c62b0082194560e4a186f3491e8347218c775dca48302c2a55b5629e69cf9c08b4b926e7e8503cf4d337fc62677f40409a68fe9b9a1a2c2a55b52656178628dda04be1e16aab15775638cfd3bac25a59164631a06b1b2c2a55b4f956b33fc6d43013d320b87c2eddba31b9ded535099734d6f3aba80e2c2a55b56da37e71236c50ab586ba5ba55e3479c375ff4b9246082b5d21b4b7b2c2a55b573dcfe35afeb7bffb31da83e9df9ce87ca0ed20d9751b2e8239633422c2a55b53b42cea8ef1a2b6f7f66895b8904a4764bcc5da3d23f941953076c482c2a55b5451bb1d573ede48bcf7ebf76950aeb780120ecdf3d328467d62fd9292c2a55b510651d026a38ce4568ab7ce806bb2983d1846191cfd29b6b06e109462c2a55b4fc257dda3887031ea29fbe2a8ea74764db0f3ff3ee746b58365ef3252c2a55b508174009ea498f934dfefc1a023e9d03b43bc601a2f7fa08441261602c2a55b54dba6c93fda08f30f8fd6be0e47bf66f3fd31e2e1d72b970b3ff11542c2a55b548ad46013efd1c045ec47aa4ef52b075a2fa3de11c486dee807c890f2c2a55b4fa84e9b7e85c6a3bb37f4bb3831bb51a5bbb1666ff92c8b874dcb42e2c2a55b56936ce0a4d5292c66857a725cd7b30a6d305922f4631380666e5ff2e2c2a55b56f24b35dda6da7aef24974dd6501d9c857f8d41d66cf88d5bd0530442c2a55b517d1c1a30c70133ca54050b2d409c86e87e4ba23b564c185f1d059782c2a55b55169b48ba48e99dabb61807463c1f91bce2ec9919c16f0fdf36161662c2a55b52b81262e103c0657041660ac9f500aefa757a2c8343326d0a525f5122c2a55b50d3c4b8b607d14c312d6e25fbe0a9a585bafd68f597ad37989f9c4062c2a55b50699f7db6f499718d572de81b0d1843c146624daa99edd9a6609ef642c2a55b58f78423fa34f63da52ccb699e46952f94053123661ab8316d4f78e072c2a55b5364338fadf45981d173acd75651f8ef41b57931694c3870cbcc548702c2a55b58a05d949b1ebe3d18f1d3f4d43ff93cd8005b9cfdd884a901761ea3b2c2a55b5e0241fe92a75c23c49cc15b355a4f52c934719b1b7382c5c2b859a462c2a55b527a77c6ce5976953b4b0bfd3f7db8a96d27fae160f24a0a6759cd4662c2a55b52aad5c3cfb8bf4c7c478aa2b21b8fd9597fe2706a11457d23e10323e2c2a55b5079b0d798a442d87e4bf664a01d50c11af9ca230ee4738b19aa95b6d2c2a55b554384ce603e7018c1bd0df5cf1a8b1f6154a761132c003486a723e272c2a55b582572ea3a02d92d1f303959ed8d301f20cf7377795bba4e77ca5f0592c2a55b592b0caf0f0440b89aa8c1d713be7b3a16d79b3c56eed19d7acdb6e082c2a55b536cb66c8bf2894af968ada12c6e7db4bb028a57b22473334404584692c2a55b55a05a6a02b7b3ba6539f3744bed7a3ebf4a86a75986e404553bf06352c2a55b585dd3e7bf5cc92d3eea96cd13018755382f0ba1be21ec1866b0432122c2a55b4f853af67dd7217983b8928934bedd57f2aa6717b4570ff9cf8c55d332c2a55b50e45380d2db51edfa07ff46d01bbc34f908f7aa6b470c1593576ac352c2a55b595b09d23cb9ea051e7655f90215123b6cf4edc6bbfafc3a99e3667082c2a55b545afbf04bb687cbfe5f7a4fee66f0f0e9036072dc3ef88be6f3c6c362c2a55b505d8d997b80d747395c1471ad1e1e8aa57319c5727c6f178bde2422b2c2a55b57ef9ffffa47f4d6fc6750f15ae53863a1d0fd99d8386a70054d55e4b2c2a55b5976eb2e7893f7c3f875b3b1cf3d653df30a0a58125d9fe0f8b87b8322c2a55b5e4935526d6400d729ce52f5065327b414a971c69fcb85eef3d5a94012c2a55b5d60f8f51745d9b979ea7dddb0f79692d51cca14c4791e72da59ac9632c2a55b59871ad2237ac147d19b7ebbbda39957b7d5881df0e5c8493925567762c2a55b5f19e53bd8bb08c1cf5d540f88c25b52a10c7c5816bf906b0ce20877c2c2a55b572c2850205aae1bb28cb0f6fe1c0e606353f9dc420b3796317bac4542c2a55b5f323b09d3dc6c092ed0e988463188613232235e6d6cdd030858855292c2a55bd3b0028726bf7764e3a604421e98e930f851a2bfafdf5d29eb694d2752c2a55b9020732ceb7db3ed3ad35a2ada31a65bbe0ac94ee072d92cd27a38f7b2c2a55b5e1d0f2cabfbdca681bac43c1f684748d18c03b0e04e28b2fae9cd7042c2a55b5e1efa4babefcdae07c4ce9c4682b1f57b0f3080ff2ead5ea06624b6a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eeec11b5fca7cddef5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c": "0x0000000000000000000000000000000010e417170e6d77f90f6d7b308bddb8a414f44a87623704da628229ba777b6446473ac9ec7da0888dc010574b11d9d0dfd62446ca38a63819937aa91f40f6901d585009e192ec169788c9c1f0202fe7c2bc79405ff8b6e1d1ac78fd6152006e606dd091cf86d04141b1c17c70826c08d074cae1b00d6f82de1b8a5406ea10ce723b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef1c80fdef53d785909cb20eb25e42c2fa106d75ee4d44b9c2bac20323a540529e9f4f40da5337bb3": "0x00000000000000000000000000000000105c5c5a4a025f3d8be84fa9ea36383c2cd168c8a018d50c88a34154afe9ecf04f09b072ba1658a3946b1f7a82a7c135c33a41ac8e6ac11407d910d4baad3e6c421aec17785fa10a655d77b8850a0b7c5ac3ce5c0389555ec7d8f303092552cea70aa18c1ff67dccbb98cbb86ea9808b63dc72582c602fb0dcd7e6716dd9ed9c75", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef3a8cb14bfca5d3d82c5c0e26848d49b32a7ae09a67f6822f2a18310b69a3ed9c31ee02144020826": "0x000000000000000000000000000000000430e9bd57ca72b2de9928df65ac7974ccc0fe678a64c2df03e2159aebb4e8a525", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef3e3959f84b063bcd6c29a7c39cee45b0e045a94081bc188ef73be2be086d66aefd850fc7eeacc45": "0x00000000000000000000000000000000044e1f1d2881471357ea697093e5e68d46712d2b0e5b650945c4ecb571ea43757b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef5d0ba7a9e0e043b545b7958451cd22afb0367d6c99af1360190813571c47b8a94a055d575d38249": "0x000000000000000000000000000000000404db71328c96f1654885de2d1f577621c524e4515416b0f861dfce55a3f72167", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef78baea38e12315a6c7fdb8b8eaad1af9faaf918493606e1a3e8c20f9d852773ab5ebfbb93bd1948": "0x0000000000000000000000000000000004084361c7e80bd43ac0aa2917200339e51e45284349a264184ba0befe3e2cfd52", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef7f8fa46e9ed81a89ce3de1cd55ad6f4ab351ab212431d94cec798e1727176cca174fa661c8f636e": "0x0000000000000000000000000000000004f54df5a1ecdcbdc84dee4ff7821578632b9d6d884b9bfa5c52f7164c57d3fdee", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef98bc77ab23b03eed401f460e0251ed41d7fb32ca463b5233b620cb9569eef5327def27fbd7c7b57": "0x000000000000000000000000000000000438f4dd8e0bd0a47c6263b31add7a887956da435cceec4750540743f0235c003e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37efa4279b211bd820ab22c2075548019dd268e74f3aa69c9703b129e989d230f935797975d5ed9247d": "0x0000000000000000000000000000000004e4afcec3862a48c276628c97bec157c563a74bd8ab3c7abc9d7fae99fff38268", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37efad7d2ce54667f8c1ea80b0dde0e207c8ec57ac05fbec636502cb216bb423642919679fe8f074051": "0x0000000000000000000000000000000004b0583167a388bf2ec1c4ce53d17be27a15b23abdd97265571a5c65bdeabd24a0", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37efb0bc5a64f81e0ca7cbb0ed8bf228935241774290753bf282020d73e45f6724b0196c97b3bd53462": "0x0000000000000000000000000000000004c215be73d91712a74db57cf18209ec172e9a3215ce6ef5cf5b0292177d3e1140", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37efc06d1b8b9ab844be64bc946c10a1f75e683f236e72a44d6d61b3bdcf72ffd8c738e488efc6e1567": "0x00000000000000000000000000000000081a7eb7be90a60ea3c4b467df2f8fd89288ef44f581426bd98cc34a0b67bb959f00f379b621bd73c45c7d155d2a1fe6a04649e3ece7c7e03b70b3a6242bc7c127", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37efc6a42b3b802fc9518d54ea25ad26acd7094fba6bdb278e769f9ac350cc36b2f631da13fa92bed79": "0x0000000000000000000000000000000004149ccce9d526a65ba54fccc24f5d1dee62f9b87915d4004eb932959d468a9e62", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37efd9785f8772870809eee1e58c17ff7b037f2da5766e9bc78d5568c58d45cf363b9630ef32b2ccd79": "0x0000000000000000000000000000000004b023d129d9a0cb9490d097dbd3ca947d4830d3a6d7e0fa9975ff2789d9d97352", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eff643fe3320aabbafcba1bf303b55be82bf6e48504909dfb85be27bcbbb2a330e9f4fc1261d8f02a": "0x00000000000000000000000000000000107cbfaaf0fedba11f23780e8b1bfcac5e92a85f56835027e83bd203bab86ccb0798d7bbcdd3c7fe6e9bf7de42bc97968143fb02ce4c7f2382552237dd1398255920df777c881c5f4eed3f1c75e29c65fa681a63dc612cfabc5217f4308924e62fd66dba2833b102712151bbcfe1286506937ed28809693e730b622b3adb93e36e", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471400123d83b036c82d5c5062779d44ea2ab0469e155b8cf3e004fce71b3b3d38263cd9fa9478f12f28": "0x04010000000200000000000000000000000000000000054a61636f1644616e69656c204a61636f627573204772656566661a68747470733a2f2f6769746875622e636f6d2f6a61636f677219406a61636f67723a6d61747269782e7061726974792e696f00000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714004b6afd076a2dc82e33c5e14a53e874caa8e7c6d30bd20f6c51cda7dafaad1c465ca004fe61a63e": "0x00000000000000000000000000000000000976616c656e74756e0000154076616c656e74756e3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140069066ec36235d3c278f83039076e64ffb94cd1f3333887f8c91d99a1b979db5138c60533776b06": "0x040300000002000000000000000000000000000000000c63756a6f72616d6972657a0000001a666162696f40746865626c61636b646f75676c61732e636f6d00000c63756a6f72616d6972657a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714008f3c4dd5a156f727dad3917fef51edd3bf9c675241fcb86d296a690fc3d909a1195758b831cdf6": "0x040000000002000000000000000000000000000000000c646f746265726b656c65790000000000000d40646f746265726b656c6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714009c7552e843cd3a5ac75bc572e195144b05ded3548b218377034460f9d7506f4a36b57b837d9974": "0x000000000000000000000000000000000014506f6c6b61646f74204053585357203230323314506f6c6b61646f7420405358535720323032331968747470733a2f2f776562332e666f756e646174696f6e2f001761646d696e40776562332e666f756e646174696f6e20000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471400d8c318b5f5bd3a609438d7aa30cbded1219230de200a98951d9ecf005606eb8415f386148a4279": "0x000000000000000000000000000000000007426f6764616e194768656f7267686520426f6764616e20546f6d6f6961676100001a6768656f72676865626f6764616e74407961686f6f2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140138f06b2816b46fecd06f79f6e28d47c2bcfca46173aa3a12d950f5637a8d65bda37e283c983e5d": "0x0403000000020000000000000000000000000000000005526973680852697368616e7400001672697368616e747374657240676d61696c2e636f6d000011406f6666696369616c6c795f72697368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471401443af96cf425c84c48963fc0f3c072e7a3eae4c1014e6bf7333cb7513e7bd0c2042fe86784812e": "0x040100000002000000000000000000000000000000000c41574f524b45522d30303200001a40636f6f6c6c696e656d655f676d3a6d61747269782e6f726715636f6f6c6c696e656d6540676d61696c2e636f6d0000094062696a69617969000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714014c4a8a6cb20d5f04740a3f003b7aa86a3d40f9b65c2d650035580220c2525a19f3b251c0956e40": "0x040300000002000000000000000000000000000000000d616e616d617269655f636f6d0000001c616e616d6172696a612e6265676f6e6a6140676d61696c2e636f6d00000d616e616d617269655f636f6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714015b6bef29d45538bae335c017512a43fcaed23efec97d80e088bb8f7b93ee837cba5416ca51037f": "0x0400000000020000000000000000000000000000000014f09f909d2043525950544f424545532e58595a0000164063727970746f6265653a6d61747269782e6f72671e63727970746f2e6265657a7761784070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140167d7d8c6597960f482d165f7921558a0bb9b28f66ff64161ba6576f1b854fe4fcf825c00860407": "0x000000000000000000000000000000000009416c65782d646f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140173de88215548e9f65f3cade8f68e8f34c6266b0d37e58a754059ca96816e964f98e17c79505073": "0x040000000002000000000000000000000000000000000b4f4c4956455220e29aa100001d406f6c697665722e74616c652d79617a64693a7061726974792e696f126f6c697665724074617374792e6c696d6f0000000767677770657a0000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714018d717cb9219f862cb783d5c0ddcccd2608c83d43ee6fc19320408c24764c2f8ac164b27beaee37": "0x04000000000200000000000000000000000000000000056b6174611041647269616e20436174616e67697500124061647269616e3a7061726974792e696f1a61647269616e2e636174616e67697540676d61696c2e636f6d0000000a61636174616e6769750000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140191249b095df776704f6c600c82c4c1048f35c857e92484df9315a7e0bc298c405f808676869a7b": "0x04030000000200000000000000000000000000000000084b434d574d50520f4b6174686572696e65204d6161730000106b634077616368736d616e2e636f6d000009406d6161735f6b63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471401e66931ebe7cc802a82fb6c3dd0269f6977b022fc3abfa2f1ed9783de2d7f26672b7eebf4fa783e": "0x0000000000000000000000000000000000057072657300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140200a531a02ceab0f2f2ee56200c11091ffd9e394076723bd1e948832da89bcd746eb2e3868e8969": "0x000000000000000000000000000000000010e381a8e38282e381a1e38283e3829310546f6d6f6b6f204e616b61676177610000136d6a68707231353640676d61696c2e636f6d00000d40746f6d6f746f6d6f43454f0009746f6d6f746f6d6f00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140250733e6e15b29ba4385c957aa511e5628d26e48cfaf2e46d3313011823a9272ed754019a67207f": "0x00000000000000000000000000000000000d45726d616c204b616c6563690000184065726d616c6b616c6563693a6d61747269782e6f72670000000d404b616c65636945726d616c0c65726d616c6b616c6563690000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140251fe16ba336a2a1eb4f7030a34dc1c72a29f00bb174eae301af0ec88fb34557c084cac25da977f": "0x000000000000000000000000000000000008486169204c616d0b567520486169204c616d1c68747470733a2f2f6769746875622e636f6d2f56554841494c414d00146c616d76683238313240676d61696c2e636f6d00000d4048694c6d56373134373932000b6861696c616d3737333500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140264d5f165d70fd8604189f1ea74bc439b18060c58f352db2880dd4c835df7ebb26e020bf11e7969": "0x040100000002000000000000000000000000000000001b436972636c65496e7465726e657446696e616e6369616c4c4c431e436972636c6520496e7465726e65742046696e616e6369616c204c4c431b68747470733a2f2f7777772e636972636c652e636f6d2f656e2f002174726561737572792b706f6c6b617373656d626c7940636972636c652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714026cd546f7bcbf83ecfa264fd1da282eeb7b06b8c7fd5634e9f5da8eb1163c79b789d943c310ed25": "0x040000000002000000000000000000000000000000000c53757065724475706f6e740000184073757065726475706f6e743a6d61747269782e6f72671774686f6d617340626966726f73742e66696e616e63650000104054686f6d6173525f537570447570000e73757065726475706f6e74343400", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471402c2da93a5b6fce008754abb6afba51a2f74f0b97bbcdb383f579a02a5e4541fee736710af562c6c": "0x04000000000300000000000000000000000000000000075061726974791d50617269747920546563686e6f6c6f676965732028554b29204c74641368747470733a2f2f7061726974792e696f2f000f696e666f407061726974792e696f00000c4070617269747974656368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471402d1c4ec984b618c46807e1b5ba42007b46e58f24fae00ade4115e1b15680337f99137a5333e0e43": "0x040000000002000000000000000000000000000000001e54686520426164676572204c61622056616c696461746f727320436f2e00000016696e666f407468656261646765726c61622e636f6d00000c406c61625f626164676572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471402df35b98c238fb36c3722bb683f6247d01da39cdc1055f07d24c1c0b5aca199ef3b0ecbfc11f414": "0x08000000000202000000020000000000000000000000000000000021f09f8cb453494c49434f4e2042454143482056414c49444154494f4ef09f8cb400001a4073625f76616c69646174696f6e3a6d61747269782e6f72671d73625f76616c69646174696f6e4070726f746f6e6d61696c2e636f6d00000e40534256616c69646174696f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471402e989611aec18925220f15324663f1bb0bad6212a344c7f4deb40aa6e3f489a56db71d545507e19": "0x0400000000020000000000000000000000000000000008696c347231343100001440696c34723134313a6d61747269782e6f726712696c347231343140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471402fbd3dd4be7ed351c90e3dabd3fd0f6bc648045018f78fcee8fe24122c22d8d2a14e9905073d10f": "0x040000000002000000000000000000000000000000000b6b69616e656e69676d610d4b69616e205061696d616e691668747470733a2f2f6b69616e656e69676d612e6e6c16406b69616e656e69676d613a7061726974792e696f0f6b69616e407061726974792e696f00000c406b69616e656e69676d610b6b69616e656e69676d610000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714030d3f604ca958c6a47c8ebe79ceebec1a2e5dbb3b631e5b80cfe39ac103b3fce2d1a9c8579f510e": "0x040300000002000000000000000000000000000000000a56697274756e6541421256697274756e6520414220285075626c2900001268656c6c6f4076697274756e652e636f6d00000a56697274756e654142000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714031326492a87a9c14631954522a90e4361e6b9bb3876cf6213bac251f99d456ed4703b47f289b95e": "0x08000000000201000000020000000000000000000000000000000008446f746361737400000019646f7473616d61706f646361737440676d61696c2e636f6d00000a40446f74636173745f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140321b5acf1a4323638a88c73e729a0e8a2161f95c844392baa81dc70c8e8d39f76efb0342971591a": "0x0403000000020000000000000000000000000000000007426561636f6e0000001368694077616c6c6574626561636f6e2e696f00000d57616c6c6574426561636f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714032271bc6af67408e20cb98236c8a2d833d8fb6544ce4f5809b14d5e7f5f9ad742f975f787953f61": "0x0400000000020000000000000000000000000000000011f09f918b203739616e766920f09f8d80000013403739616e76693a6d61747269782e6f7267133739616e6476696b40676d61696c2e636f6d000008403739616e7669000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714032bb7554ff00e0c868f95d29b6e5290c6492e6540c3f46d900961f7c8d063dcd299cfcd97462b22": "0x0000000000000000000000000000000000194b494c54202d20506f6c6b61646f7420416c6c69616e63651968747470733a2f2f77336e2e69642f6b696c745f696e676f1068747470733a2f2f6b696c742e696f000000000e404b696c7470726f746f636f6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714033093647d016eaf3860c2799edfaca5866dd49f38c6180806224b1b893e77959a3cc2d4ca1602cf": "0x04000000000200000000000000000000000000000000106b6e696768746f666d616c746131330000001a677569646f2e6d616c61626f63636140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471403456c855e9a00037e878e54c1374b30df335d3a193f3e6b1f84db6c2270ee634cec769d7e33e244": "0x0401000000020000000000000000000000000000000019434f534d49432d474c4f42414c2d434f4e54524f4c4c45521c436f736d696320476c6f62616c204e6574776f726b732c204c4c431668747470733a2f2f636f736d69632e676c6f62616c1840636f736d69635f746f6e793a6d61747269782e6f726717706f6c6b61646f7440636f736d69632e676c6f62616c00000e40636f736d6963676c6f62616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140383e568f18fc74ec66041adc9730fd89001350628c4d92ce2cc734b487604cd9786622591106872": "0x04010000000200000000000000000000000000000000195175696e656e63652f4d6f6465726e46756c6c737461636b135175696e656e6365205074652e204c74642e1d68747470733a2f2f6d6f6465726e66756c6c737461636b2e636f6d2f001c636f6e74616374406d6f6465726e66756c6c737461636b2e636f6d000011406d6f6465726e66756c6c737461636b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140390ba3a7443c05e4eef513781a2a7c94110928e39de53dbe50f9adc5009de3db0e2acff37f0c756": "0x00000000000000000000000000000000001157656233476f2d4d756c74692d736967001368747470733a2f2f77656233676f2e78797a0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140396382deadaa8ee485d0b693f66f1785f35ba1010d7e7528a0116ec424454f58c6e500c3c66a520": "0x0000000000000000000000000000000000144d6574617363686f6f6c204f6666696369616c0e466174696d612052697a77616e1668747470733a2f2f6d6574617363686f6f6c2e736f0015666174696d61406d6574617363686f6f6c2e736f00000e4030786d6574617363686f6f6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714039ea54cb812a324847194325a12bc4f4faacb6aef973eda31658195c26b934318b960aa69050819": "0x000000000000000000000000000000000009646f746875622d3309646f746875622d33000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471403fed7fe7c184ba490bd3d091b8837f2f41c38b6e3bebd28a31ee280f82d15e687f95d798ef41c17": "0x0400000000020000000000000000000000000000000008457a696f5265640000000000000940457a696f526564000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714040dea48ab93d760f034ddb0d301f22e5084439a96ec38e7636544ac137d0514e018fde67f2b03dd": "0x0000000000000000000000000000000000074c454447455200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714040ff78a24cd58c71ebd2c29909eb603331b960308a070b839ee78e80fe12ef05e4639a176ab743e": "0x04010000000200000000000000000000000000000000074c697374656e074c697374656e1268747470733a2f2f6c697374656e2e696f16406c697374656e5f696f3a6d61747269782e6f72671173696c766572406c697374656e2e696f000010404c697374656e3136373831393338000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471404322a3587052539a23809a947f2c06542cbf2fafe17fd7d84c460d51fdd69d01f53a5ca050ee709": "0x040000000002000000000000000000000000000000000b56656761735f6c696665001668747470733a2f2f76656761736c6966652e696f2f1440636372697330323a6d61747269782e6f72671876656761736c6966656d61696e40676d61696c2e636f6d0000094063637269736c76000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140451688eb2d3683ce8b53683b6ce7ef4d1c7bf913580bde6ea10b6fdc790fac42b77955c740d1301": "0x0400000000020000000000000000000000000000000013506f6c6b61646f74204e6f7720496e64696113506f6c6b61646f74204e6f7720496e6469611d68747470733a2f2f506f6c6b61646f746e6f77496e6469612e636f6d000000001040506f6c6b61646f744e6f77496e64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714045d4b9be19df388bc6c08ceb638f3fc5a0fecdfd83e909fd7ae1721794f2925ca0f5094932c3769": "0x000000000000000000000000000000000008616c6c6f6368690a416c6920416e776172000012616c6c6f63686940676d61696c2e636f6d00000008616c6c6f6368690000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471404632aa45f1b73c60a6a339260fce0551ac29fd893232409f6f1182daab8e1021b3861e6a5101332": "0x00000000000000000000000000000000000a6b65697461303932380de6ada6e4ba95e5a58ee5a4aa000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471404d5e25d603189573898b6f62b50749101446132f77fa6dd77a3895674fa8dac87e6c375ea852346": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140501142b6fdb56404e7edd090cdd7a52eb0e50ca77b86a41835bb60755a109e421252fcb6a373624": "0x0000000000000000000000000000000000064b43435f3100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714055dfc6d34f916957640aa86730cd7fbff361db495405a4affecfeeb6581370b07ff5abb023cab06": "0x040300000002000000000000000000000000000000000a506f7765724c61627300001640706f7765726c6162733a6d61747269782e6f7267146d696e7a756b76696b40676d61696c2e636f6d00000940564d696e7a756b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471405b079eb94353bd94adf51a47b72795366d52285e329229c836ea7bbfe139dbe8fa0700c4f86fc56": "0x040100000002000000000000000000000000000000000e536861776e2054616272697a690e536861776e2054616272697a691968747470733a2f2f736861776e74616272697a692e636f6d1940736861776e74616272697a693a6d61747269782e6f726717736861776e74616272697a6940676d61696c2e636f6d00000e40736861776e74616272697a690d736861776e74616272697a690000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471405d79e4283e265f4f422f57b2b12e96bfc2f8e8416bd768da1c4526f803622f7ef7536d4db29e970": "0x000000000000000000000000000000000007686f72696d6900000012686f72696d6137406e617665722e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471405d8bd6067f6ae29c804531378242158a794bd06c1e9ef0e569f60bb32758597af80e5e70c07a64f": "0x040000000002000000000000000000000000000000000e43687269732d5374616b696e67001a68747470733a2f2f63687269732d7374616b696e672e636f6d1240636c616e673a6d61747269782e6f72671863687269734063687269732d7374616b696e672e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471405e989f2a5137a8f22e8d22a7fe2768c944dad8af7829d96eac8644f06643ea8ae68bc3c1e905306": "0x04000000000200000000000000000000000000000000066b6f757469000012406b6f7574693a6d61747269782e6f72670e6b6f757469406a6b76632e6465000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471405fa9b980f99404c1e8cc9421ed7548a68def07a5c4c6d205cd3b84892c4b58c0e35badbae992d6a": "0x00000000000000000000000000000000000a504f4c4b415741444508474d20436f6e671368747470733a2f2f676d636f6e672e636f6d00156576613036313230313740676d61696c2e636f6d00000d40785f636f6e675f77616465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714065d9c0c5a79e8cef73baa66d4746e8447877fe051d6dffa85811dcd14c6dceeb29e011b1514f23e": "0x0800000000020100000002000000000000000000000000000000001654484520534556454e544820434f4e54494e454e54000000113335393637353237344071712e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140666dae771739caea0f7cb4fc2c83488aa67396520178b74e13298b0cc3d89b5e7fcc0be290b406b": "0x000000000000000000000000000000000007436c6f76657207436c6f7665721768747470733a2f2f636c6f7665722e66696e616e63650014696e666f40636c6f7665722e66696e616e636500001040636c6f7665725f66696e616e6365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471406829105dfef3f40a6b0e06e21e9c82af02f3aebb597d0fb4cf6470c1de0278f7a26a301680fca6e": "0x0400000000020000000000000000000000000000000009436861696e326d650000001872697461636861696e746f6d6540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714068d2dd8a39691885e09d262efefa86090446d0cc0fd6cab48b79b667e499beba1e72a0ddf16e523": "0x040000000002000000000000000000000000000000000b4161726f6e323436303100001b40696e6672617374727563747572653a6d61747269782e6f7267186161726f6e40696e6672617374727563747572652e636f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471406a3b4543b0cbdd8b609cda244e45076c572478b1b3b39636a96b7626be093cf39a222e0073cd017": "0x000000000000000000000000000000000005766976730f56697669616e612053696c657373000000000009407673696c65737300087673696c65737300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471406d7541597a81f1b6811dfa0e269a620b63ccbdb616e8e12619d504cb470324ab3ff1aeeeccbff59": "0x0403000000020000000000000000000000000000000008426974446173680000001a6d65726365646573736f72656c313040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471407063321357d092326e1f0717f99bfa5eb959816dd1bd8b79b686ca351fe16c1dfc929d55e49f247": "0x00000000000000000000000000000000000a48756f6269506f6f6c0a48756f6269506f6f6c1468747470733a2f2f7777772e6870742e636f6d001468756f6269706f6f6c4068756f62692e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714071427015841edc7844b0f0b00cfcb99ce376e5f836bac3cd801af422979f32a4bf2d32ac3e5483c": "0x040100000002000000000000000000000000000000001c43696d20546f70616c207c206d697373696e672d6c696e6b2e696f1c43696d20546f70616c207c206d697373696e672d6c696e6b2e696f1968747470733a2f2f6d697373696e672d6c696e6b2e696f2f00136869406d697373696e672d6c696e6b2e696f000011406d697373696e675f6c696e6b5f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471407821119981623015ef2b64a77e076b7f284c1e8c2afa826bf2ada04e58b757e2f9dfb816a250a66": "0x040300000002000000000000000000000000000000000e4a696e73652046696e616e63650000001468616f797565406a696e73652e636f6d2e636e00000e404a696e736546696e616e6365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714078c7addc0fece8f18a5d639662da95bb4924c48441fb432047e77613263cf1438ce8a14fc34c432": "0x040000000002000000000000000000000000000000000d554e4956455253414c444f540000001d696e666f40756e6976657273616c646f742e666f756e646174696f6e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471407b7c5e9987b5a061650c532ed1a8641e8922aa24ade0ff411d03edd9ed1c6b7fe42f1a801cee37c": "0x040000000002000000000000000000000000000000000d446f6b69614361706974616c001c68747470733a2f2f7374616b696e672e646f6b69612e636c6f75641440617772656c6c6c3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471407badfa66414d7abc4e7d5a63d8e887932bb6dc505dd204005c3ecfb6de5f1f0d3ac0a308b2b2915": "0x040300000002000000000000000000000000000000001b436572657320426c6f636b636861696e20536f6c7574696f6e731b436572657320426c6f636b636861696e20536f6c7574696f6e730000216f6666696365406365726573626c6f636b636861696e2e736f6c7574696f6e730000106365726573626c6f636b636861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471407d711054306c2851292a778cf74e0573db07ff3ff3738a4f0c44ffa0f2226e821c4dc3eb7d21300": "0x0400000000020000000000000000000000000000000018f09faa9e612073206820f09fa799e2808de29982efb88f00001c40626c6f636b636861696e637572696f3a6d61747269782e6f72670b314039373130342e646500001140626c6f636b636861696e637572696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471407dad820c63897d8924bccc2bf4d18656da14ad467c161370e43c2bc7ebc83d7f1e6ba4b6acd1010": "0x00000000000000000000000000000000000965746865726e616c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471407eaf323b98489af7febf816c3fee7de2f843afd83a03e4b7138c81f655ad20e31c27ec35bdbcd23": "0x0000000000000000000000000000000000104b6f746f207820466172626b696e64001f68747470733a2f2f7777772e70617472696b2d687565626e65722e636f6d001968656c6c6f4070617472696b2d687565626e65722e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140802b46abd9ac8a9386a4f5a0311a2834e28c84daa299fe14414137807e201a1941e502c7a784467": "0x040300000002000000000000000000000000000000000a646861726a65657a790944616d696c617265000014646861726a65657a7940676d61696c2e636f6d00000a646861726a65657a79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140803dc9d292420d2565c14e67b353eca54a9736c1fb110f72a753c3289399674e011785af19eeb04": "0x00000000000000000000000000000000000474616400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140823dc59ec2f7a204eed7cf3f4f6560d58db4eb78bd24b655bbd1d7a5c6b454e77c8dc5e2721a54d": "0x04010000000200000000000000000000000000000000164d4f4f4e204c414d424f5320f09f8c9520f09f8f8e0c4d6f6f6e204c616d626f731768747470733a2f2f6d6f6f6e6c616d626f732e6f726717406d6f6f6e6c616d626f733a6d61747269782e6f72671976616c696461746f72406d6f6f6e6c616d626f732e6f726700000f404d6f6f6e4c616d626f734f7267000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140874e41bb7db2c8904f9fe095c3f7e02a2ad48e58b7524cd3353a1a09097882259c1cb8b8fbc722e": "0x0000000000000000000000000000000000114672657368437265646974204c616273114672657368437265646974204c6162731968747470733a2f2f66726573686372656469742e636f6d2f001d66697261732e6b61646461684066726573686372656469742e636f6d00000d406672657368637265646974000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471408768e841e1a6e64bc9f6b302d5f299048a1d3aa10d6ea182f3db0d15fb42d0e76c086a13777dd35": "0x040300000002000000000000000000000000000000000854686520546965000000116a6672616e6b407468657469652e696f000009746865746965696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714087a5388d9e5a204ea149bdf5123e8cfade6a4541bc205d1c1bed6c92c876b21731bf4ac7984c67d": "0x04000000000200000000000000000000000000000000095468654775696c64000000197468656775696c64736f7572636540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140890dc820c706f1454824b885099cbba0103d1a671b0aac36c6b8b0e80747f3f111300d41d1cd55c": "0x000000000000000000000000000000000008426c7565446f7408426c7565446f74000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714089372171cde85a1a67f727210edec1922631f1fdd095c40c9b434c864c239968d26755cd982504e": "0x00000000000000000000000000000000000d506f6c6b61646f7453686f740000001b626f6574746765722e7468657265736140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471408a0e5fe9e4b1f842a27dd26f5f3fe4f48fc67cddb54a8cdb0f3c6e4b9c8cf751a59466771dc6144": "0x040300000002000000000000000000000000000000000f5269636861726458636176617465145269636861726420486f756c6473776f7274680000137269636861726440786361766174652e696f00000f7269636861726478636176617465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471408db713c2bbf4320a4731404eb64407b76d75dd815a3267e2dce24d8c2054f3d45d83ea11c8d707a": "0x04000000000200000000000000000000000000000000096d696368616c6973001b68747470733a2f2f6269742e6c792f6d696368616c69732d696e00176d696368616c69732e66724069636c6f75642e636f6d00000d406d696368616c69735f6672000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471408f29307d17340ac7e88d4cdb23702f9bd21d16a968463ac7e1f5272835d72b05e2224612d46222a": "0x040000000002000000000000000000000000000000000749736162656c0000000000000d40737573755f63727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471408f8525d1428358322a7a0d6570fae451f9ecf96564485fbbd451d2d1512e0c3e8b865ad4702091a": "0x0401000000020000000000000000000000000000000005496e676f0b496e676f2052756562652168747470733a2f2f7777772e6b696c742e696f2f7465616d2f696e676f2d7275000d696e676f406b696c742e696f00000b40696e676f7275656265000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140906d8a2ac7d524584a61bd5f070a257326ab2b012a19d36b9ff5b53471a44420687484ad2070828": "0x04030000000200000000000000000000000000000000084c617572656e74104c617572656e74204b6f65686c6572000017616d6972616c6b727970746f40676d61696c2e636f6d00000d616d6972616c6b727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714092e30bbc1252c51b031bd2bb49eab8e971d4734110faca76ae52998450b0f23ef46029277a1e539": "0x04000000000200000000000000000000000000000000054f544152134f746172205368616b617269736876696c690011406f7461723a6d61747269782e6f726700000011407368616b617269736876696c693237000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140932ed16a6ce31dbd08450b51426556a9e61b8e928b97c6075d95cda58b433fdfca36a2b69d9766b": "0x00000000000000000000000000000000000d43485249532043525950544f0000000000000d404348524953435259505430000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714097e95a7fbccc3c012d761ac11e70c35595d382a0c860bb0501ab0690df6c9f96ea7179b206c1d40": "0x00000000000000000000000000000000000a4669676d656e742038001368747470733a2f2f6669676d656e742e696f000100000b4669676d656e745f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714098de700b0bd1b5ca2656a3bbbea71626facc2641a9d9f744c87c393778020354714974894b7b27a": "0x0400000000020000000000000000000000000000000012536f6e6465722056616c69646174696f6e00001d40736f6e64657276616c69646174696f6e3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140998feed74b871672c1a1173d90dfb10b0dce7544381ae4b6e7d46ec1506ec6052eb221a62d1dd18": "0x04030000000200000000000000000000000000000000074f6461696c7900000014636f6e6e6965406f6461696c792e656d61696c00000d404f6461696c794368696e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471409ba869b7efed68f24973457b12e9d08e7dc0b0f255ab508e1829c66f6d2e6c4cb94acda5a00ab5c": "0x04000000000200000000000000000000000000000000094d6f72706865757300000015696e666f40706f6c6b612d626c6f636b2e6f726700000e40636861696e616e646d6f7265000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471409cedc84fed5609d6c1c40574832dee06228c10e43537fe6b3bc4cc78cdb7d34d1586d8904d8fa7b": "0x040000000002000000000000000000000000000000000447696f1147696f76616e6e7920476f6e676f726100124067696f79696b3a7061726974792e696f0e67696f407061726974792e696f0000084067696f79696b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140a2cec7af82c6d22d22f4b3f7a9f0878a49954e7b4491ca841f68831c2e8aeb383cd79dcdc00295b": "0x00000000000000000000000000000000001042494e414e43455f5354414b455f361042494e414e43455f5354414b455f36000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140a4cb53b517606bc609164cfbfa54bc46f2e6421980f9e50a7b21d1e2c4b8a9ecb82e08d94555190": "0x0400000000020000000000000000000000000000000007444f54696e730000000000000b40446f74496e735f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140a6e3cf2b2ed68b7f476394d38a2202be9ac84607ce7fa0a7a53981920999c231210fda7fca36041": "0x040100000002000000000000000000000000000000000a456e636f696e74657216456e636f696e746572204173736f63696174696f6e1668747470733a2f2f656e636f696e7465722e6f72670013696e666f40656e636f696e7465722e6f726700000b40656e636f696e746572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140a7e8087590f806c0ef2cc1000f878a3880a09d698b5375f20c4ab3d8b3a1b783c8150faca3da65a": "0x04030000000200000000000000000000000000000000054c756379194c75637920416e6e204265726e69636520436f756c64656e0000166c756379636f756c64656e40676d61696c2e636f6d00000d406c756379636f756c64656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140a8ec5c60a74c1b9a65626bf6bd3d70916fea48c93358cbf1e97f4f7f5ce8d5a292719e2555de66b": "0x040000000002000000000000000000000000000000000e4c6561726e506f6c6b61646f74001a68747470733a2f2f6c6561726e706f6c6b61646f742e636f6d00146c6561726e706f6c6b61646f7440706d2e6d6500000f404c6561726e506f6c6b61646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140ae0ef8597bfb78fd6ebcc75c7ea9a0c4459162b495e90c7ed5306e3a27f73125d6fbd2a34601323": "0x04030000000200000000000000000000000000000000064a6f7365701c4a6f736570204d20536f627265706572652050726f666974c3b373000019736f627265706572654070726f746f6e6d61696c2e636f6d0000094a6f736570746563000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140b3a777104037709f221049df41595b4296f7cdf47a38b5b7c3187f9cad55c48ad60277ec92ce869": "0x000000000000000000000000000000000009646f746875622d3409646f746875622d34000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140b5c5327ba564a7c86fc56ba95671116870c422992b82a701b9c1c877ec7f6c6adf080ca8be17d7f": "0x0000000000000000000000000000000000085365766572616e0c4ac3a16e204b6f7ac3a16b0000186a616e2e6b6f7a616b3031303740676d61696c2e636f6d00000d536576693532313535353036000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140b70260c8fbe02026c4013c3ada90b00a5c2241cec6165e96958ef1a9884c15a981f86e48b0fc102": "0x0000000000000000000000000000000000094d61787061696e6e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140ba79531536753bb707c94e3ad62ed919cf1eebeffe3381161c4daef849a306d698539931a08ce14": "0x08000000000201000000020000000000000000000000000000000011576f6c6645646765204361706974616c0000001768656c6c6f40776f6c66656467652e6361706974616c00000a406d6f68616b616772000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140bdbcf3faf64bc3f787be6b11ece98c192f5e1fa41c880db0318fe885f614eddf69ffa040b3e9031": "0x04000000000200000000000000000000000000000000044d54430000001b6d696e647468656368617274696e666f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140be961ab1f92f2a95002926543d8b8887044442834d4fd5fe3d6eb257719daefd3f2aed28eeaee69": "0x0400000000020000000000000000000000000000000009506172616d69746f00001540706172616d69746f3a6d61747269782e6f726715737570706f727440706172616d69746f2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140bee7f7b3d6f8bb6dc1bc0568b4f02bc9e8105e9dd9543235232d321b4b46da86eb8f94bb4de8714": "0x040000000002000000000000000000000000000000000d4272696c6c69616e74696e65000000156461726b6d697361343340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c1cc8d36c3db95466f2c9fd9d1c3919443e6d6312f7c281d32ce1978c4a72c0dd6518ccd3cef503": "0x04030000000200000000000000000000000000000000105468696e6b57696c6443727970746f13456c697a61626574682042726f776e696e6700001c6562726f776e696e672e636f6e74656e7440676d61696c2e636f6d0000107468696e6b77696c6463727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c20ce18ec5a3b0022cd6deb3ac44803aeca3cf6543a69eaaab049069eb05231f598c324c2ef0b17": "0x000000000000000000000000000000000016506f6c6b61646f742050616c6c6574204772616e7415524d524b202d2050616c6c657473204772616e741168747470733a2f2f726d726b2e617070000c626440726d726b2e61707000000940726d726b617070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c388ae01faeb42e58be8a938b93a1a251a20a38240e235a5d62c1093c0cb9290e4567fad087606f": "0x04000000000200000000000000000000000000000000064569676572094569676572204f791268747470733a2f2f65696765722e636f2f000f68656c6c6f4065696765722e636f00000a4065696765725f636f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c41e5ffb19e12ae30a11a36a48739b8fa4bee6844af919e22aa50f114f9e395a1caec59cc157102": "0x0000000000000000000000000000000000055365756e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c4559f7a17cb073568191edc1aaf4bea93b17cf53ea49ab78e2d25d83dec8581854be93d3bc9609": "0x040000000002000000000000000000000000000000000f4c6f72656e6120426c6f636b7961000000166c6661627269733139373440676d61696c2e636f6d00000a40424c4f434b59415f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c460df68c43e5ce000356a196f8dfaf9356be2697eaaf5e37f110668bb3caa503a52a223bc0ecd7": "0x00000000000000000000000000000000000c526567656e63792d3030321757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c7c6da4442b90353296c9b3a6546d2319a764e00e1126215b776cb27571db2ef0392bbfbc66d45f": "0x040000000002000000000000000000000000000000000850696f6e656572001568747470733a2f2f70696f6e6565722e6d6f652f144073616368696b303a6d61747269782e6f72671c70696f6e6565722e76616c696461746f7240676d61696c2e636f6d00000e4049686f723037303534383635000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c7d3455667b833b7e5992abc613a36e614c1d17c32342d365f9a66d57adeb96092e94a8cb7ba64a": "0x0800000000020100000002000000000000000000000000000000000b4e6f64616d61746963730f4e6f64616d6174696373204c74641768747470733a2f2f6e6f64616d61746963732e636f6d14406162633a6e6f64616d61746963732e636f6d13616263406e6f64616d61746963732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c9893ff555d916a508e92a4d4441736fba8bf0d9ab8ab258031112be9bb9cd8e91cd11d2f806512": "0x040300000002000000000000000000000000000000000a556e636861696e65640000002173706f6e736f72736869707340756e636861696e656463727970746f2e636f6d00000a6c617572617368696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140cb42537605572168a8bc181a8b2a5e27a7c66051fe9119875f4c5718cc808aaf2258b4b2fa37832": "0x0400000000020000000000000000000000000000000005616c696e0a416c696e2044696d61001040616c696e3a7061726974792e696f0000000009616c696e64696d610000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140cc8f64bbd2e71ea820050e114404eec82932c59bedbfb6c1b58981e8f85af37e5d4f26a34226960": "0x040000000002000000000000000000000000000000000d6d6173746572737061726b7900000014642e6a2e626f6f726440676d61696c2e636f6d00000940646a626f6f7264000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140ce0f91c97c65aae744be50accad162e5162a2499a897f5cfd792e0ebf9ca6ed7d13b5e404b36007": "0x040000000002000000000000000000000000000000000b536e6f7762726964676500001d40776861747265676473666f64726a6b673a6d61747269782e6f726713616964616e40736e6f77666f726b2e636f6d00000e40736e6f77666f726b5f696e63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140cf87334458780db58a47ac1485804eba1da4f4bad5d245535ed92c81aad8a15ce849f7474685604": "0x040300000002000000000000000000000000000000000e4361726c6f7320536177616b69214361726c6f732053c3a97267696f204d6f74612053696c7661204a756e696f720000166361726c6f736177616b6940676d61696c2e636f6d00000c6361726c6f736177616b69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d09678fc53ebff9b6ab520cbb6fe9b6bc5433fa4193074bd1aae212f0dc969d6af584e140a08a5d": "0x00000000000000000000000000000000000d52616d70204e6574776f726b0f52616d70205377617073204c74641568747470733a2f2f72616d702e6e6574776f726b184072616d706e6574776f726b3a6d61747269782e6f726715706172746e65724072616d702e6e6574776f726b00000d4052616d704e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d670abd53527a0c5839fa7a9242c404eaf4128cc218e3ca90ebb90c542994a19c3adcdd0bab4257": "0x040000000002000000000000000000000000000000000a4163616c61204454520000001468656c6c6f406163616c612e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d8e58a290cc0d407460ac178015d2a7c289bb68ef9fdaac071596ab4425c276a0040aaac7055566": "0x0000000000000000000000000000000000087a6a623038303700000000000000087a6a62303830370000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d9954f2f20d04e36495827bfe0b07d16c549eb10d7e45997e95788be44a3f277af6befec99fe62f": "0x0800000000020200000002000000000000000000000000000000001052414449554d424c4f434b2e434f4d001868747470733a2f2f72616469756d626c6f636b2e636f6d0015696e666f4072616469756d626c6f636b2e636f6d00000d4072616469756d626c6f636b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140dbcaadfd532d03b7a0898a186215e4295a37c12f14b3c092ac526e0d3f132112fe33983e11f7a62": "0x0000000000000000000000000000000000066b6974616900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140ded91512786b3a62ccd1ada7e7fc4068a8d69ce621b8355378b362608bdd3f65524c1e401e6433c": "0x040300000002000000000000000000000000000000000b546f6b656e67756172640b546f6b656e67756172641668747470733a2f2f746f6b656e67756172642e696f0016636f6e7461637440746f6b656e67756172642e696f00000f40546f6b656e67756172645f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e032212504d7709ba57da1251d785b2d433ca687c510a82c284826b9b79859b5774a84f7000e928": "0x040100000002000000000000000000000000000000000ef09f8fa2204d49444c2e646576001168747470733a2f2f6d69646c2e64657610406f6b703a6d61747269782e6f72670f68656c6c6f406d69646c2e64657600000a406d69646c5f646576000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e08049fd14356105076e12e0065c3750fbeb83fa35368cbb09af42967eb6a473ff3a357b2b51f5d": "0x00000000000000000000000000000000000c6e616d2073616e676a696b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e21e0ca3b18ddaef4c583b1fe10e634547f909f678b4b8f5a98bea24645127b2eb9fd7b3e6c2f5d": "0x0000000000000000000000000000000000096d6f6c636861696e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e22e33a70eea1beac11e708ac83a57b6e870a4ac9e5b58bd1d247f0183810abacf548469140884e": "0x00000000000000000000000000000000000970617374614d616e164d6f6368616d6d6164204875736e692052697a616c1968747470733a2f2f6963616c31302e6769746875622e696f19406875736e6972697a616c31303a6d61747269782e6f7267156d6f63686875736e697240676d61696c2e636f6d00000d406d6875736e6972697a616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e23dcd64ffcda7f562e0d94ffb8e2492e12fa0f02bc1afa0d2cec3b3309a19337fd653ec4d81e64": "0x040000000002000000000000000000000000000000000e4e65756b696e6420546f6b796f0000001168656c6c6f406e65756b696e642e6a7000000c406e65756b696e64696e63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e6e902c97ee9286b42bde3f29708150bd47382f10fa4eba1c27a068653cfc4e3787b7fe05fe6e7d": "0x04000000000200000000000000000000000000000000064b495a4f53000012406b697a6f733a6d61747269782e6f7267156b697a6f734070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e7a2d3832f0ab5118c044557335d26c3a538ec7a2699ef5665cca1d17755cd6ae53d41f5bf31623": "0x040000000002000000000000000000000000000000000a5a6569746765697374001668747470733a2f2f7a65697467656973742e706d2f001361646d696e407a65697467656973742e706d00000d405a6569746765697374504d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e8195af2fbb9bd3b491f0fd140dfbae6ba14572b9b7e8bea724b9336dea4bde7f0eae9082e2682f": "0x04030000000200000000000000000000000000000000084648455741534d084648455741534d0000177465616d2e6668657761736d40676d61696c2e636f6d00000d4064616f67616e6774616e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e8757f9140fa0d4f4c6e1ea78fa82de3a28d27e20c93b4b8109fd93489d864a73fe7bd4eadf2061": "0x000000000000000000000000000000000010496e73696768742046696e616e6365001368747470733a2f2f676f7374616b652e696f001577656e6a756e6438343940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e9a3c3e586a908f8122315b758fe65626b7d0f7c8f5d0758b235f22df56cbf73610916a88520efc": "0x00000000000000000000000000000000000b43656e74726966756765001668747470733a2f2f63656e747269667567652e696f0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140eb83f2c7db87e68e043d8f7872cd895f8957c9179c4264816be3e649713cb3bdc523f752602cc3a": "0x0000000000000000000000000000000000075374616b6564001268747470733a2f2f7374616b65642e7573001073616c6573407374616b65642e757300000b407374616b65645f7573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140f0643da4d7eac3d003c529dadd597907deb794cab14c863e0cfb1b47af09120efdda16fe432ca54": "0x00000000000000000000000000000000001443594420506f6c6b61646f742057616c6c657400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140f16205ef17fe25d2eeb1a6884bf369c7d1ab3f9ff75b79dd0f6c6a9792834e026a8d2f7ef049e4d": "0x040000000002000000000000000000000000000000000a5354414b4550494c45001a68747470733a2f2f7777772e7374616b6570696c652e636f6d16407374616b6570696c653a6d61747269782e6f7267147374616b65407374616b6570696c652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140f5707a84539a93930e3f26094a2536e02b6879a2a92752493302d84029b80ff449eba8b9dd80d1d": "0x00000000000000000000000000000000001042494e414e43455f5354414b455f381042494e414e43455f5354414b455f38000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140f7af1c09d518a3034d65588960a9500acf14d5d58a4bfff1a29d55e99e3079304028f13fa462a6d": "0x0403000000020000000000000000000000000000000012416c65782044696d697472696a6576696318416c656b73616e6461722044696d697472696a65766963000014636f612e64696d657340676d61696c2e636f6d00000c40616c657864696d657337000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140f848aa6535dc8a065a99d8b861ad966394cfe1fc291e7cbd3a0392b293ebaf2ed64f6bbd7294c4d": "0x000000000000000000000000000000000015506f6c6b61646f7420496e746572204d69616d6900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140fa2c1f54780ff56b08f31c5b83a67cd2b4014b513dd4cfa4ecfd32c22f0cd35a8d0d1639c3a3472": "0x0000000000000000000000000000000000154372797374616c696e202d204d6f6f6e6265616d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140fc514eab423f9a784434de779e5fcbe6da08b123b0d1556c5ded43cccd6a9b1f6efdc9ea4942032": "0x040000000002000000000000000000000000000000000f4b75732056616c69646174696f6e00000016686579407468656b7573616d617269616e2e78797a00000f405468654b7573616d617269616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140fc7663bef7fa5771cd527641e7070529937a78c02fb4de29f1d210908ad654cfc32c1ba930c6d01": "0x000000000000000000000000000000000005636f6c64001768747470733a2f2f6172626973797374656d2e636f6d0017636f6e74616374406172626973797374656d2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140fd49b70acd3290232d4d1b0dcef676d9a72f6abf9aec55e129ef2de135ac172e19c28a9adbcad0b": "0x0400000000020000000000000000000000000000000012506f6c6b61646f7420476f204c756e617200001a4063727970746f676f6c756e61723a6d61747269782e6f7267196e6f74696669636174696f6e7340676f6c756e61722e696f00000f4043727970746f476f4c756e6172000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471410045954da3b77a48c73df5e3b5d0720799fc9d422df981bfcdb7e2daf5fda64098f433317f66481": "0x000000000000000000000000000000000010506f6c6b61646f74204d657869636f00000018646f7473616d616d657869636f40676d61696c2e636f6d00001140506f6c6b61646f744d657869636f5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714102a55fef2f92ecdaa6411ebaa64db799c310fc729b4bbfe823f8e5365370d8905db1782495e630b": "0x040100000002000000000000000000000000000000000750617472696b001468747470733a2f2f6170696c6c6f6e2e696f2f194070617472697a696f5f626e703a6d61747269782e6f726715636f6d6d756e697479406170696c6c6f6e2e696f00000e4070617472697a696f5f626e70000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714103932d4af94b6477a3da336bc10786809ad364ed466f2ac0b224e5979f428cc2d420fb2c1643c45": "0x00000000000000000000000000000000000c506f6c6b61646f7447435600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714103c17ca46c08000ea05f87e141ce5a6f38702929411405799a18e69128fafd24e849444072e5d6d": "0x0000000000000000000000000000000000084176656e7475731c4176656e7475732050726f746f636f6c20466f756e646174696f6e1868747470733a2f2f7777772e6176656e7475732e696f2f0010696e666f406176656e7475732e696f000010404176656e7475734e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714104b7f3de11760cb22f82385aacb628dfcf268ed37fc6d846b03eb3fe766d31de012d888ae4a1265": "0x000000000000000000000000000000000015506f6c6b61646f7420706465782077616c6c657400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141056f8490f45c33c4671360a95c3004648c6a4e52966ed2b097e68847bf729be9f8438f6973ade59": "0x0000000000000000000000000000000000056d62616a0b4d616369656a2042616a0016406d616369656a62616a3a6d61747269782e6f72670000000c404d616369656a5f42616a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714105cd78f2accd77f44899146a600cab633113021d077356a6c362899a4d40ee426fd3ab22d2ab301": "0x040300000002000000000000000000000000000000000777696e746f6e1b456477696e202857796e6e29204c656f2042617565722049494900001477796e6e6f7277696e40676d61696c2e636f6d00000b40426175657257796e6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714106a66f6a055b1e2d0f222915d0e0b32a9137413a0cf64a3fd7676b8b73236f73619147195ca5204": "0x040000000002000000000000000000000000000000000e416c7068612041697264726f700000000000000d40416c706841697264726f70000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471410798f54edbd929bd60281dbd0933b5cbb571fc3177c5803f7b12f9b8193f83787713dfcc9f52a1f": "0x0403000000020000000000000000000000000000000007536f7261696100000016736f726169612e7273723240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471410a0936c3defd2dc4a154ce100d43672e3cab61d2196621d0d69dccbf86d432595f2d0fc4eb5ee61": "0x00000000000000000000000000000000000d50656e64756c756d416c65780000000000000e4050656e64756c756d416c6578000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471410a8fd5f177733e23640b7b7fbbecf967f99ec9516a74f9e255efa5c8529751a383afccfe936175e": "0x04010000000200000000000000000000000000000000114d61737465726e6f64653234f09f94b10d4d61737465726e6f6465323418687474703a2f2f6d61737465726e6f646532342e64652f1540616c65786b6964643a6d61747269782e6f726719706f6c6b61646f74406d61737465726e6f646532342e646500000e406d61737465726e6f64653234000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471410ab4532df9af262e83e7463783cc45e410d91594a73c2ab7daf49c3cc7886c7df454bd948d1f158": "0x0000000000000000000000000000000000076a75616e363200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471410baf040e7f1de1d5a2a286ee3c24f270564b3dfee5bcc553022e4affe2694c62101f00773a7d25d": "0x00000000000000000000000000000000000a73696b616d6564696100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471410bb1f59d0b43521b2dc691fc657bb1b8a732fb6887984ebde8885f652ef6df372b564ea30e4c07f": "0x00000000000000000000000000000000000d4361726c6f7320476f6d657a0d4361726c6f7320476f6d657a0000166361726c6f73406361706974616c782e6d65646961000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471410fbb58c9784f416deca8beea42c6361e77eb489db4e951bb1c63f0eb85afa7827075962fa46537b": "0x0403000000020000000000000000000000000000000015546f6d61732053656e6f76696c6c6120506f6c6f15546f6d61732053656e6f76696c6c6120506f6c6f0000127473707363677340676d61696c2e636f6d0000001e68747470733a2f2f6769746875622e636f6d2f7473656e6f76696c6c6109746f6d6d7939375f00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141108a7f2fbcca12cfc9fd7446ec46d27262587240fe98dbc5855bd390714f3713ef561729052154b": "0x040000000002000000000000000000000000000000000b414a204153544552494f00000016616a2e706f6c6b61646f744070726f746f6e2e6d6500000c40616a5f6173746572696f000a616a2e726563616e6100", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714118564695738fc77fc3f5a249cbc860ba90c0b7322c615b0b47e360e376d85cf366ce6d7f8d9bc75": "0x000000000000000000000000000000000006504f4c4b4100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471411ce0c03039f6a489e4e7009937c56d267338762a60ed004293afd40e7c2081847c12cb63c76a818": "0x040000000002000000000000000000000000000000000744725733524b00000016726164686140776562332e666f756e646174696f6e0000084044725733524b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471411e075ceba8e3f4524112dbb17e6f83bb832ee26149c8b00cefac96a1a668ccf0645898c3c271d04": "0x00000000000000000000000000000000000c54696d204a616e7373656e0c54696d204a616e7373656e19687474703a2f2f74696d6a616e7373656e2e63727970746f00177468776a616e7373656e383940676d61696c2e636f6d00000e407468776a616e7373656e3839000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471411ec48c6e9cf67fb4cf2e774e34c3603b2428a690c058d2ab826b39a2eba4e22b3aae85f9bfa7802": "0x040100000002000000000000000000000000000000000a414354494e4f4c49580a414354494e4f4c49581668747470733a2f2f616374696e6f6c69782e636f6d1640616374696e6f6c69783a6d61747269782e6f726719626c6f636b636861696e40616374696e6f6c69782e636f6d00000b40616374696e6f6c6978000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471411f19977cb6420ff7852bd4de2d3d4207ca8bb3fd9954cfe3c6ca91e1acba438e8a70df5fbbdd91e": "0x00000000000000000000000000000000000c597572694e6f6e6475616c0000000000000d405975726970657475736b6f000c797572696e6f6e6475616c00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471411f91d41b705cb0e442758c71011edc49ef5f9297c81f905dc3e847acdee4edb87b3bda628a02044": "0x000000000000000000000000000000000012456e67656e686569726f2043726970746f0a4775696c6865726d65000020636f6e7461746f2e736f75656e67656e686569726f40676d61696c2e636f6d00000a406762746332303038000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471412060f617a53b90efa99c57636163b80492e7748882c27e82074cc76ae723804e0c8f222aa1c9879": "0x04000000000200000000000000000000000000000000144b726f6d626f70756c6f73204d69636861656c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141211d1890e7a3711586fd1cdd673dec2a5c3dea4f1f2efab11c15c6008698c3adb139a876bc0354e": "0x040300000002000000000000000000000000000000000d404f6e6c79446546694775790e416e64726577204c6966666579000017616e647265776c696666657940676d61696c2e636f6d00000d404f6e6c7944654669477579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471412255c95905b3078f2681118b778f641d6064047cb36d943cbe0761bca515f07d762768bc0205405": "0x0000000000000000000000000000000000044a6564044a6564000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141241731d14d7e2624e438b5a8c79cf1f158bae626b3fcbae0d60e4fe0a783a92a51c7a06c81c1a07": "0x00000000000000000000000000000000000b446f74456e72697175650e456e726971756520527562696f000021656e72697175652e727562696f2e646576656c6f70657240676d61696c2e636f000009406b696b65727562000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141249720e20450dc46645e03be465e70990610e0d6c978da1866dbd9c9828f6e19ef1f0e3b1d02f11": "0x040300000002000000000000000000000000000000000b7969616e6e6973626f7410496f616e6e697320507361727261730000147969616e6e69734070726f62656c61622e696f00000b7969616e6e6973626f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141257e95afd3f3529fabfc151a66d7cbd2cfebbdea1954d13fa4721a568a8086386f445c2cefa261c": "0x04000000000200000000000000000000000000000000114c696768746e696e6720426c6f636b7300001c406c696768746e696e67626c6f636b733a6d61747269782e6f72671b636f6e74616374406c696768746e696e67626c6f636b732e696f000011404c696768746e696e67426c6f636b73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141263f06b8f0929949c665073980c9bdbd5620ef9a860b9f1efbeda8f10e13ef7431f6970d765a257": "0x040100000002000000000000000000000000000000000f526f636b585f506f6c6b61646f7406526f636b581668747470733a2f2f7777772e726f636b782e636f6d0012737570706f727440726f636b782e636f6d00001040726f636b785f6f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471412d4691f7bf1f08098650252aba2203808fa1dca1f57dce2e9927b88d66f193bab53f4910b9e1c59": "0x040300000002000000000000000000000000000000001038426a4c55443366376144473766781457696c6c69616d2043726f6973657474696572000019694d723338675a3754637537786f40676d61696c2e636f6d0000114057696c6c69616d3533363436363531000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714137178bb7584275bc64c6a15649acd3f96cf450ca06d53059b6888d67456f8e7ec31c8504eb3125d": "0x040300000002000000000000000000000000000000000e477520496e73616c75627265730f4775737461766f2050726174657300001a6775737461766f2e7072617465736d40676d61696c2e636f6d00000e696e73616c7562726573627463000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471413c8717f740994a86aa8cd24ade14ce3debcf13ff5d3ce5fcecbfb2acc1c0c9c0c7b25d79d902d22": "0x00000000000000000000000000000000000567686530001268747470733a2f2f6768656f2e746563680000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471413fba91067ee782aaefd2727ec65732fec6ebfc4a824345adb093436abfd5f53e0fe421c6f5cdb0b": "0x0400000000020000000000000000000000000000000006445053544b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714140fdd346d273b4bce5395a6819c6edb4a8679a1f1b9c809de142dd5b84805e4d0a2ad428476d606": "0x040300000002000000000000000000000000000000000868616b6d61726b0d4d6172656b2048616b616c6100001768616b616c612e6d6172656b40676d61696c2e636f6d00000968616b6d61726b5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714143c9b2402368042140be3ffc8865dd47a8d044916b26936a579433599bebca9d3ba1d6eb7722710": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471414754c6ae34414e51eec92559de5be4295be18caa79400d49466b8b06a4c819e766a7b79ad3b846d": "0x040000000002000000000000000000000000000000000b526f73732042756c61740000000f726f7373407061726974792e696f00000b40726f737362756c6174000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714148446d6e27ad179566511e3d396022cf986a5a86d09bf77db45af3ddbae12a8bd78948072505f4a": "0x0403000000020000000000000000000000000000000009546172656b6b4d410b546172656b2041746961000013746172656b6b6d6140676d61696c2e636f6d00000a546172656b6b4d4131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714148771da2618d248c4962b64a7f16b6af320177d041e2229ede9d4efad694b74d02be3f1cbbfdd74": "0x04030000000200000000000000000000000000000000084f6e6c79444f5400000019646f74696679746865776f726c6440676d61696c2e636f6d00000c404f6e6c79446f744e6f77000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714148cd021e35e23e4f0673d30606ee26672707e4fd2bc8b58d3becb7aba2d5f60add64abb5fea4710": "0x04000000000200000000000000000000000000000000044761761544722e20476176696e204a616d657320576f6f641568747470733a2f2f676176776f6f642e636f6d2f0010676176696e407061726974792e696f00000b406761766f66796f726b0a6761766f66796f726b0000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471414b9317a39b5587ca81adb32eb83fa9f6853129997532384eb874facafcf0f717c8eb952df30491a": "0x04030000000200000000000000000000000000000000164d75466920506f6c6b61646f74204163636f756e740a4d75466920496e632e0000117370656e636572406d7566692e61707000000e406d7573696366696e616e6365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471414df282ca6fd7e90be66c34c519a045956620b6c6962fa9440e79b96ee839b93b4a188d961693401": "0x00000000000000000000000000000000000653574b696d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471414f4cb7e8e1dd98fa423f953c39a707184067af6963efe1143a155f57aa003299c45b9be12f02642": "0x0401000000020000000000000000000000000000000006417266616e1c4d6f68616d6d616420417266616e20417367686172204973686171000012417266616e6d6940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714152bf2356a6365ea3ce185c80846549d014ef1b12ab7ce5ad8931c7913208ae3fe5b206cb8d5480b": "0x000000000000000000000000000000000005444d523500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714152cd44728673f349e7c73972c8cf09884b6647f957d945a8c9109ccd4e742e843e89b343a43651c": "0x040300000002000000000000000000000000000000001456656c6f63697479204c616273e29aa1efb88f1156656c6f63697479204c6162732041471e68747470733a2f2f7777772e76656c6f636974796c6162732e6f72672f00196e69636f6c61734076656c6f636974796c6162732e6f726700000840765f6c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714153e9a548981fe578ce2fb4076ef92d3a5cac7689f4bf9c589296b99d5aa899511aff9e2be5c7a40": "0x040300000002000000000000000000000000000000000653616c61640d5361726168204c657374657200001573656c6573746572313240676d61696c2e636f6d00000f74727565736172616873616c6164000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714155306eb29d41fe65cc0cc69582f48b38baa0c7acb297580c4facad35056691f999bf3c53ae08a44": "0x0400000000020000000000000000000000000000000012736e6620646f742076616c696461746f72001c68747470733a2f2f696e666f7365632d636f6e73756c742e636f6d001d69687562616e6f7640696e666f7365632d636f6e73756c742e636f6d00000a40736e696666736b69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141596b645522e66dd2c4f99c0f8272e38f7169e264234dc13a4da815517564a538382e5828f61fc28": "0x000000000000000000000000000000000009706172616c6c656c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471415b4508e0114da171f449a820b2c7718597a61ee2aa3928e53404e89779f8d97f7a3fb341ea68ff1": "0x00000000000000000000000000000000001f506f6c6b61646f7440436f696e6465736b436f6e73656e737573323032331f506f6c6b61646f7440436f696e6465736b436f6e73656e737573323032331968747470733a2f2f776562332e666f756e646174696f6e2f001761646d696e40776562332e666f756e646174696f6e20000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471415d31b7bc7b1054023f71995b4441f187fa21b4020e925b820950705c5e4a602a16c57baf551b3d9": "0x040100000002000000000000000000000000000000001541697264726f702e636f6d206d756c74697369670c41495244524f502e434f4d0000166d61726b6574696e674061697264726f702e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471415dd65723b63fdc2f6d19b31316879ce7470aafdcb908d04dfc5c156f8de974bdd582086d0ff6030": "0x04030000000200000000000000000000000000000000075458536865700d42656e20536865707061726400001962656e736865707061726478797a40676d61696c2e636f6d00000854785f73686570000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471415eee78443792d00346ebc3380be6816f828d1d1df372c51fbe99c95a321d7510403bb98f067695e": "0x040000000002000000000000000000000000000000001c50726f6d6f5465616d207c205765623320557a62656b697374616e0000001c706f6c6b61646f7470726f6d6f7465616d40676d61696c2e636f6d00000d4050726f6d6f5465616d5044000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471415f1d58f2dffcd5d7a23f1a7ce3801006e4c449d66fa97c61b6f45fff10e365e08710c0432930c39": "0x040300000002000000000000000000000000000000000653706963790000001d4d6973686f2e6b616e617269614070726f746f6e6d61696c2e636f6d00000d4d6973686f4b616e61726961000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714161735619834be83b8be96d986897797d117987e4368640ffdf32bc967ba7467d012136c22dca33c": "0x0403000000020000000000000000000000000000000005636c307700001140636c30773a6d61747269782e6f72670b76406c6572792e64657600000740636c307735000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471416214d11e8d53abe10f8035fd1cf87ae493a030edb707fef7c92df6a343489d06c0e242dfe43b35d": "0x040000000002000000000000000000000000000000001b4a4b5242207c20506963636164696c6c7920f09f87acf09f87a7000000196a6f656c406a6b7262696e766573746d656e74732e636f6d00000a404a6f656c4a4b5242000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141627a7ca07c7aef778dc106e241524180b2594b639d2f0eca4d41b1eb7f9e973c253402a7cd2ed4f": "0x0000000000000000000000000000000000076d6179616b610c5a696c69616e67204368650000156368657a696c69616e6740676d61696c2e636f6d00000a4030786d6179616b61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714164c857f81c668cfbc27ad8fa6f2ea276c5657bdd2c6e1c810c96975dabcdc0e4a48fe1b7c6f9900": "0x00000000000000000000000000000000001155736f206465206d756c746973696e671853657267696f205261756c204d6172636865736f74746900001473657267696f4061646c69626e65742e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471416632ac54302ab493a06ba1dcdd93d70630fc8cdb68ac3e69505c4570d43ef1f110c82e0af756678": "0x00000000000000000000000000000000000631574542351757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141666dc35836cd0a48e41df7864847ec31fc0168967dd5b7912c21f4a597438c697f7f4c1a29c4d57": "0x0400000000020000000000000000000000000000000010526f636b585f506f6c6b61646f743406526f636b581268747470733a2f2f726f636b782e636f6d0012737570706f727440726f636b782e636f6d00001040726f636b785f6f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714166a46eb86ae1a6b0f1ae3ffead748e1f440e6d1a76ec495f2f9e1670fd15e737ddc2ab913b8a149": "0x04000000000200000000000000000000000000000000084c4f47414e5447000014406c6f67616e74673a6d61747269782e6f72671a6372697374616c2e726f737369383840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471416709400d558465ddc20836f2e4b88c1858d1e3f918e7358043b4a8abcd2874e74d91d26c52eca2a": "0x040300000002000000000000000000000000000000000547616265184761627269656c20466163636f2064652041727275646100194061727275646167617465733a6d6f7a696c6c612e6f7267186761627269656c40696e76617263682e6e6574776f726b018550a42403112eb7e49d90abe036e1980b988ef01768747470733a2f2f6962622e636f2f66595a5a7959310c4054696e6b6572476162650c61727275646167617465730b74696e6b65726761626500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714169763ff321610ad14fd4519281e3bfda326702a0f55da78d8cff3213553f65d7bdceeff8bb136a1": "0x0400000000020000000000000000000000000000000009434f4c4f53535553001a68747470733a2f2f636f6c6f737375732e6469676974616c2f1d40636f6c6f737375732e6469676974616c3a6d61747269782e6f726716696e666f40636f6c6f737375732e6469676974616c00000f40436f6c6f737375734974616c79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714169ece2ddc0ce13e205addba4075b267f6ab1c5f8308743fe060d0aed47e018bcfbefd0f197ab52d": "0x00000000000000000000000000000000000b4c756d6f73204c616273164d75736875204d65646961205076742e204c74642e1a68747470733a2f2f7777772e6c756d6f736c6162732e636f2f00146b6161767961406c756d6f736c6162732e636f00000b404c6162734c756d6f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471416c2d8d550a452fb203795f6b0bc5cf58ee69bc38f4d82278d7ae40d5c7b7ee7b6d2e8e04e2b4952": "0x04030000000200000000000000000000000000000000047377620d53657268616e20426168617200124073657268616e3a7061726974792e696f1173657268616e407061726974792e696f00000e4073657268616e776261686172000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471416c32812353e2b741090ed109e1c7cdb689467b8b9a48daeb19d21473918cc6fc5632f11a261d80b": "0x04000000000200000000000000000000000000000000054475636b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471416d1d6d8171d77ca767806fa170bbfc9eb86c0b65bb265c85f86e5e0bfb82525c1149a38fc6d613f": "0x0000000000000000000000000000000000054a4f4d490000000000000c406a6f73656d6d6d323337000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471416ed9307fff94f1f0cc0424184702e27c49fb859c93f07d8bb0adf2a0824ada9f01db9bf76b7025f": "0x0400000000020000000000000000000000000000000015f09f8d8120486967682f5374616b6520f09fa5a9184e6578757320496e666f726d6174696b204475727265721768747470733a2f2f686967687374616b652e746563681640686967687374616b653a6d61747269782e6f72671e686967687374616b65406e657875732d696e666f726d6174696b2e6368000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471416f70b3f811d00f5f08cce486eece7d4a7a3d614b7cd85586d657893f2be9df6e8e3c4f7b181bd52": "0x04030000000200000000000000000000000000000000114d696368696b6f20576174616e616265114d696368696b6f20576174616e61626500001b6d696368696b6f34706f6c6b61646f744070726f746f6e2e6d650000104d696368696b6f506f6c6b61646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714173972b961cdea90c49a03d9a47482fda70a5879e99da5159670949018884c6a239ec04c89f9a160": "0x00000000000000000000000000000000001244616e736f6e205477657369676f6d77651244616e736f6e205477657369676f6d776500001764616e74776573696779653440676d61696c2e636f6d00001040706f6c6b61646f74417275736861000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141774ee3fbd2aa269e0cbc3810429380ad335eb242f47acb1f4b609001af240dcbae281594d4ba522": "0x040300000002000000000000000000000000000000000f756269717569746f7573446174610f756269717569746f75734461746100001c756269717569746f7573446174612e636140676d61696c2e636f6d00001140756269717569746f7573446174615f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471417a3c17fe29895d0b4074510d7de2fe2dc843dd1f2eacc53b0c5a54b876e27af0b4eaebae9bc340d": "0x0801000000020300000002000000000000000000000000000000000947656465416e74611c4920476564652050757475205261686d616e2044657379616e7461000015616e7461406d616e64616c61636861696e2e696f00000a40616e74616b657061000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471417ca96d717d13d8f86409335c78332d6a06f712f4d3ded1e7849cb75ec083ee71f23e5477630420c": "0x00000000000000000000000000000000000b537461626c654e6f646510537461626c654e6f6465205074652e1c68747470733a2f2f7777772e737461626c656e6f64652e78797a2f0014696e666f40737461626c656e6f64652e78797a00000c40537461626c654e6f6465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471417dfa67fb23d9e4d093472713dd6fbe16b514cf07d445644396f2881d8237acb70d92055a1aaed77": "0x040000000002000000000000000000000000000000000c56616c69644f72616e6765001c68747470733a2f2f7777772e76616c69646f72616e67652e6e6574184076616c69646f72616e67653a6d61747269782e6f726715696e666f4076616c69646f72616e67652e6e65740000104056616c69644f72616e6765444f54000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471417ea45d57a104fc3f41c1aa075742a552affbe40871e68e62aec936ffae12b497e7b38d32d3eb70d": "0x04030000000200000000000000000000000000000000135a6f6543727970746f4769726c73436c75620e5a6f652046616972636c6f746800000c7a6f65406367632e78797a00000e5a6f65436174686572696e6546000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471417f2428f049676136029b5b2d1d0ff3a0a4aed8721f480386c8c866d79d86386e5780a6454cd7f24": "0x040300000002000000000000000000000000000000000a5f65636172646f356f0a5f65636172646f356f00001a65636172646f356f406b7573616d69676f732e6f6e6c696e6500000a4065636172646f356f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714181900f50b9dad51f855f52621dad2bef24b708644e05d48391ba124f93bb81149ac7f2faac64138": "0x0403000000020000000000000000000000000000000007566963746f72000000136d657461766974694070726f746f6e2e6d6500000a40566974697265756d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714188e91cee61b2febd6f3fc13608eaccd3e3c75789225fbc23963888890d5e7f806b0ccaaf90caf79": "0x040300000002000000000000000000000000000000000b4178656c4265636b65720000001963727970746f6265636b6572313740676d61696c2e636f6d00000e406178656c6265636b65726f6b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471418b47e3024d66dfe628f36dddf8cdb0242104a2531e7d3efd4860a9a4633be69aaf30f63ccb25a5e": "0x040000000002000000000000000000000000000000000b537769737320426f6e640000001c7377697373626f6e64706f6c6b61646f7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471418d26b3f2b895c6dc448b1c0c946fe680dc9d237c6ba6bbcda519c42dfbea7ef74b0b73f7972a666": "0x04000000000200000000000000000000000000000000095f7061636865636b000000176272756e6f2e757073697a6540676d61696c2e636f6d00000e406272756e6f70616368656373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471418e9b69f585d7a7d3c10da0654ed968b149f27cf9db0203337c79b6d86f6741f156598fb7699ab78": "0x04000000000200000000000000000000000000000000074c6179657258000013406c61796572783a6d61747269782e6f726714696e666f406c61796572782e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471418f0062e466404f0976ce4203c844a11164d1b3f8342ad16a4cc5d99ac8eaae5cd74f4b1cc68c764": "0x04010000000200000000000000000000000000000000085355425343414e085355425343414e1868747470733a2f2f7777772e7375627363616e2e696f2f14407375627363616e3a6d61747269782e6f72671168656c6c6f407375627363616e2e696f00000c407375627363616e5f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141908028815102f077027fd39de5dece15c83271c7bed94615b69d3b170a8518b056ec951ef51da46": "0x040300000002000000000000000000000000000000000c446546695f5374616b65720000001d66616b656d61696c666f727370616d6d657240676d61696c2e636f6d00000c446546695f5374616b6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141909140e98d4fcdfd880b45154006c09eb568c69f1febc0dadccaa59723dcd058cdae45c9c13ae68": "0x00000000000000000000000000000000000a4669676d656e742033001368747470733a2f2f6669676d656e742e696f000100000b4669676d656e745f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471419522f0465b284216cb2a6e7b4c6451a1a1fcf05a4545dfbda0215f15ad77851be9f7f7e94171e6c": "0x04030000000200000000000000000000000000000000104775737461766f204a6f707065727400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141954fe85b0e70adcff2ce23cb974ce041c73878aaf0d84454faee2b798569727d81703996c370fc7": "0x040000000002000000000000000000000000000000002057656220332e3020546563686e6f6c6f6769657320466f756e646174696f6e2057656220332e3020546563686e6f6c6f6769657320466f756e646174696f6e1968747470733a2f2f776562332e666f756e646174696f6e2f001661646d696e40776562332e666f756e646174696f6e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714195552a14ebe4e24a6fabeb7a687bcc4705cd5d8cc3ac91adb6460d20d4d65b90ec3ce20be966554": "0x040000000002000000000000000000000000000000000659616f7169000018406a696179616f71696a69613a6d61747269782e6f72670f7940616c747265736561722e636800000a406a696179616f7169000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471419627e3b0a1fe44f466a9934facf9723f7ecc237cf0afaca23a6e832780616e432f3eaf19d8ff949": "0x040000000002000000000000000000000000000000000b5354414b45204c494e4b0b5354414b45204c494e4b1668747470733a2f2f7374616b656c696e6b2e696f2f16407374616b656c696e6b3a6d61747269782e6f7267116f7073407374616b656c696e6b2e696f00000d407374616b656c696e6b5644000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714198703ff0791c2de1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413": "0x04010000000200000000000000000000000000000000094741544f544543480d4741544f54454348204c54441468747470733a2f2f6761746f746563682e756b15406761746f746563683a6d61747269782e6f726711696e666f406761746f746563682e756b00000d406761746f746563685f756b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141998ecfe5c3f796158c941d90f219cf41ce169f540c96936193fbfee601c0e9ae6e415c75a8f80d8": "0x040000000002000000000000000000000000000000000f426c6f636b7365656b65722e696f001768747470733a2f2f626c6f636b7365656b65722e696f1b40626c6f636b7365656b65722e696f3a6d61747269782e6f726718706f6c6b61646f7440626c6f636b7365656b65722e696f00001040626c6f636b7365656b65725f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141a0b756d13ed752dc09033af1dd99c3727bd222c35d9d34e8e4403441792399b08df0d60544fbd48": "0x040000000002000000000000000000000000000000000f4c75636b794672696461792e696f000018406c75636b796672696461793a6d61747269782e6f726714696e666f406c75636b796672696461792e696f000011404c75636b794672696461794c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141a2ca5d095126893b82dc797d2ab47107b7b50397e46dfeb1d962737c349863f8682a86e1fd2630b": "0x00000000000000000000000000000000000e53616c616820506c6b61646f740000001273616c6168313540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141a61ab35fd1e09085e34b19d7230f1ea5da6d4b8fe6ede9d05c2e55b0189f75b967862c1c43d9a1f": "0x040000000002000000000000000000000000000000000b554c5452414e4f44455300001740756c7472616e6f6465733a6d61747269782e6f72671976616c696461746f7240756c7472616e6f6465732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141a870c80f78975df4411ac181d7ec3d63ac2c53bbcc41d8721f9f99f6090c51f463cf91b74eefe57": "0x00000000000000000000000000000000000d79757669616d656e646f7a6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141aa91021c24f2547e098dc986d4fd3a45b360314403a0baadce5da87c260eb1422da793fe623b16a": "0x0000000000000000000000000000000000174665726e616e646f206375717569206d61727175657a00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141acc24036266de3356937386a873382cb01abd0d0b223ae40790ebe0e97d8a06b7236640c865b730": "0x040300000002000000000000000000000000000000000e4372757374204e6574776f726b0e4372757374204e6574776f726b1768747470733a2f2f63727573742e6e6574776f726b2f0016627269616e77754063727573742e6e6574776f726b00000e4043727573744e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141b08960e386dd5cbd55ec415b6703ddf7bec9d5c02a0b642f1f5bd068c6b3c50c2145544046f1491": "0x040300000002000000000000000000000000000000000652304755450d523047554520494f204c54441268747470733a2f2f72306775652e696f2f000000000940676f7230677565000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141b0d7ea318c4d6a0223599480908ad0aa988a0b81a5799a32d32b2e81c79cea35ad07f78397d7b17": "0x00000000000000000000000000000000000b646f746163636f756e7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141b324457916228d02f944a1d1c5688dd06bc0335fb0bb058fa7fb2805a4247047dbbbc6c15121bc9": "0x040000000002000000000000000000000000000000000c506f6c6b616c79746963730000001d746f6d6d692e656e656e6b656c40706f6c6b616c79746963732e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141b4a951e7e2e12e5120f229aaff8334243bbf1867e7ac4f3d7e016ca3af627bd551380f3dd756456": "0x040300000002000000000000000000000000000000000a426974736b77656c6100000014626974736b77656c6140676d61696c2e636f6d00001e68747470733a2f2f747769747465722e636f6d2f626974736b77656c61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141b6b2384d0a5895de2978ce4a089bab55731feb84c485c99b42362de314df66dd9afce844283432e": "0x00000000000000000000000000000000000e504f4c4b41444f5420504c4159000000166e69636b40706f6c6b61646f74706c61792e6f7267000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141c24b3930fc8ca702a93f3f741525a17c26c491b229fac443dc2f185f69923b19d3041955c311056": "0x040300000002000000000000000000000000000000001344656e69732053756b686f7665726b686f761344656e69732053756b686f7665726b686f7600001d64656e69732e73756b686f7665726b686f7640676d61696c2e636f6d0000000007636b636e696b00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141c6684bc5e5975f29a8ead39ce1b44f37d16e98496441be79018e910d5f58c0fa1518d8fd7749550": "0x04010000000200000000000000000000000000000000135354414b494e4720464143494c4954494553185374616b696e6720466163696c697469657320476d62481f68747470733a2f2f7374616b696e67666163696c69746965732e636f6d2f001b696e666f407374616b696e67666163696c69746965732e636f6d00000c405374616b696e67466163000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141cb765d78beead8b7682d70550e153859a2f48dbaac25db251799fcaa8fa084eed3ab73c0ce5273b": "0x000000000000000000000000000000000013444f54205374616b696e672077616c6c657400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141cca28a5e0eadb1e008bf964db02d6018d0f97514170c4418103da670129723ca8547f5e4afa6536": "0x040300000002000000000000000000000000000000000e63727970746f766171756974610b766963656e74206d617300001863727970746f7661717569746140676d61696c2e636f6d00000f4063727970746f76617175697461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141cd490d2ce0d345b5ec41f11b9d98e7422174148cd748dbc7c5eaffb239b0946de4c1bf43db72f23": "0x040100000002000000000000000000000000000000000c61646173747265616d65720f457567656e65204b68617368696e00001b657567656e654063727970746f70726f63657373696e672e696f00000f40657567656e656b68617368696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d035207463779a168272c6f3753f3c797d830406e26815ed5c71ab453d6312d92e53651cf8d2c11": "0x040000000002000000000000000000000000000000000854726162616a6f00000000000011404e6f74696369617354726164696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d1cefdb9f26986204d7b7a1ea1cca728d31978c3822f4ddb7b2deb804107e7e709d6ee451c11633": "0x040300000002000000000000000000000000000000000447756b124765766f7267204e6172696d616e79616e00001e6765766f72672e6e6172696d616e79616e393040676d61696c2e636f6d00000e406e6172696d616e79616e3930000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d3399c309aa965a62bac995e1409297460e9ba42a01bba4c01e2740fcaea01950402ee0a51f8022": "0x00000000000000000000000000000000000b426c6f636b6368617365000f626c6f636b63686173652e636f6d000000000c40626c6f636b6368617365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d458f26330fbe568079c5a78a4d63fea543b4c9feece4cc9fcd4aaa2b94ac5761807ea945bd2d05": "0x00000000000000000000000000000000000d53696d706c652053617261680653617261680000186a61636f62736172616836323640676d61696c2e636f6d000010404a61636f6253617261686a61636f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d4a91a318b45894505a23b381677c7a05a7fe603b023c341b955e2ad03a1398dfd9b85f3c3ef855": "0x0400000000020000000000000000000000000000000009526f73616c696e6400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d7bc19ef441935b0e03cbf394247c7def2b4020688ed95a6eb61c538eefd92963c448e06a50671b": "0x0401000000020000000000000000000000000000000009434f5645524c4554001468747470733a2f2f636f7665726c65742e636313406164653030373a6d61747269782e6f7267136c756369616e40636f7665726c65742e6363000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d8084584a6038ad15a31019bfea7696aa19e004843f73dfd52cd68e9c26a3e29861e55adb900af3": "0x040000000002000000000000000000000000000000001d536f6369616c204d6564696120456469746f7269616c20426f617264001d68747470733a2f2f7777772e706f6c6b61646f742e6e6574776f726b000000000a40706f6c6b61646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d81ee99b6c993e4ca88fe90d5326a97bf01b05083be12b10bd75699ac4107e65c1de1744d209679": "0x04030000000200000000000000000000000000000000155068696c69707065202d205461704e6174696f6e135068696c69707065204c656e6f726d616e640000217068696c697070652e6c656e6f726d616e64407461702d6e6174696f6e2e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d8662dbe62ffc1aae145910fae8147b2d325cdbf3a537a12be32f3874815d076d4820bfe97fc63f": "0x0403000000020000000000000000000000000000000006546f6d6d7900000012746f6d6d7940626173656461662e646576000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141db941c89bca443c40ff75e9f6e5eea6579fd37a8296c58b0ff0f0940ea873e5d26b701163b1b325": "0x0400000000020000000000000000000000000000000017536e6f776272696467652042656e656669636961727900001d40776861747265676473666f64726a6b673a6d61747269782e6f726713616964616e40736e6f77666f726b2e636f6d00000e40736e6f77666f726b5f696e63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141dd4b5b7695b46cd6cd1ffb6ec4677378b3f276ccd6d84e9eb156dc4105eb7e997d9a3604b75420d": "0x040000000002000000000000000000000000000000001259756c696120f09f91a9e2808df09f92bb0000001973746172747365762e79756c696140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141de25a6a6996407006e496c8f09c262953449758d1ac4299ab148c657d2b41eebe82a3c89b576b20": "0x0000000000000000000000000000000000104142524148414d204d554749534841084d55474953484100001c6162726168616d6d75676973686134303140676d61696c2e636f6d000008404162757a7441000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141e1b6c66b87b23257061ec410d336d832362341e983a7e48d0a68898840cf5e94e08aab0fed41010": "0x040000000002000000000000000000000000000000000e4d4f5449462e4e4554574f524b000019406d6f7469666e6574776f726b3a6d61747269782e6f7267124e494b404d4f5449462e4e4554574f524b00000a406172746e61756b61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141e681645b60ebbd6a2b06daf782fa5142e365d1fea0f4a418687f53f201f185bf314c37581677b37": "0x040300000002000000000000000000000000000000000b436967636f6c61496e63074a756261204b0000126472696e6b40636967636f6c612e636f6d00000c40636967636f6c61696e63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141e7f051b9f457ae97cd5336d50ec2652a90f89edaa708f0952cc7b4e95f16d3e632f4488a4e42423": "0x040300000002000000000000000000000000000000001154686520576869746520526162626974054d696b65000018746f7272652e6d696368656c6540676d61696c2e636f6d0000114074686577686974657261626269744d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141e9ee92c6f734ec81a6c1bbf22454cf45f27a51e603ca304242ddac6f1013af1c9611a01a3910115": "0x00000000000000000000000000000000000b446f742077616c6c657400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141ea22a62585a79397e2880bf2b632d5832327b8237a447ed48dca728c2afa80fca610b3477c35abd": "0x0400000000020000000000000000000000000000000013506f6c696d656320466f756e646174696f6e13506f6c696d656320466f756e646174696f6e1968747470733a2f2f7777772e706f6c696d65632e6f72672f0011696e666f40706f6c696d65632e6f726700001140506f6c696d656350726f746f636f6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141f09c884077a085e9277a4f83997f9675c5554349860c719769f71b634a9ecd0bf63dae7cff0ad69": "0x0000000000000000000000000000000000027700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141f111b5054813a93cca76bb38fecfc6a03024af5ae8c655763f9eab8fff50719ac43ff0c59b0db5a": "0x04000000000200000000000000000000000000000000116c696768746e696e672d737472696b6500001440736d6f6b6532363a6d61747269782e6f72671c616c6578616e6465722e6672656562736440676d61696c2e636f6d000011406c6962657274617269616e313937330012616c6578616e64657273686174756e6f7600", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141f4321336da7ceadf4d95d4c5c0131969148d3a16b3d95ab3d051771d971a1955d7e745b0a3a4f16": "0x040000000002000000000000000000000000000000000e5044505f56616c696461746f7200001440706176656c64703a6d61747269782e6f726718706176656c2e627574656e6b6f407961686f6f2e636f6d00000b405061756c4241636944000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141fda62d62fc07febbc1deacfc7e5c6e5f0373560c14fbce156ff2a0ed7e208d049ccd985dec85545": "0x040100000002000000000000000000000000000000000d47656e6572616c2d4265636b0444656e1b68747470733a2f2f63727970746f2d6d61747269782e696e666f194047656e6572616c2d4265636b3a6d61747269782e6f72671767656e6572616c2e6265636b40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141ff990588b6880e4ea9f463588e498f46933a45b834e10273cfbcee3d2e44c8d15072052b669b143": "0x040000000002000000000000000000000000000000000e4a6f656c20f09f87acf09f87a70b4a6f656c204b656e6e791c68747470733a2f2f6a6b7262696e766573746d656e74732e636f6d00196a6f656c406a6b7262696e766573746d656e74732e636f6d00000a404a6f656c4a4b5242000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714203ca9c500dfca7c383d052b70007f5382342d61205c50e75336c57eda16b84db766278420ada25a": "0x00000000000000000000000000000000001144617669642053202d204c6f67696f6e000017406461767363686d69747a3a6d61747269782e6f7267156461766964406c6f67696f6e2e6e6574776f726b0000094062655f64617363000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142057c2e1894e9a819e92823bda563f6821bc3b7af00917608d454dfa89de101414ee0b51ac3ab57f": "0x040000000002000000000000000000000000000000001054755072696d6572426974636f696e0000001a676572617264706c616e656c6c657340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714205f8d2645ea3f1a78dae380bd96b96f6218851036432b300b0fbd65763f51278903922ed7163844": "0x00000000000000000000000000000000001777697a61726420616d69676f73206d756c746973696700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142067c893ca23078d2899477496b6c390ee6a83d1e533d860d1ed9d3093e9f74103185879c65de25b": "0x000000000000000000000000000000000007726f694c656f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142074c595e55b069dda0feab49605a4b3cc1344b4d926d20852341d1796566a524d83781bb3111053": "0x040300000002000000000000000000000000000000000a526f62696e486f646c0000001e726f62696e686f646c36393432304070726f746f6e6d61696c2e636f6d00000c726f62696e686f646c3639000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714208f193ba8c59a98eca90d099f8bbfc41261759f0474d3f613d1d83f0a6cb910e15abe2f95cbab4f": "0x040000000002000000000000000000000000000000000844465f5465616d0000001464617070666f72636540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471420a737060c3110efd67d1cbe5bda2d5975130656f1f799398b018fd40a09a5c86b2026f69fdacb56": "0x040300000002000000000000000000000000000000001043687269732040204772616e746564114368726973746f7068657220576172641668747470733a2f2f6765746772616e7465642e696f00146368726973406765746772616e7465642e696f0000094063616c6d726174000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714210b26b3351f6a65f06a37a8628769bafba50c0ecd085dd7fe574949e013ee737c9d6671e59b8513": "0x04010000000200000000000000000000000000000000084b726177696563000015406b7261776965632e3a6d61747269782e6f72671c6b7261776965632e76616c696461746f7240676d61696c2e636f6d00000f404b7261776965635f7374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142132d2b9d69b1260a8300f53d9cda28b136491a9b18b937eae584f7f08fbb6aac29e0ea38e38f864": "0x04000000000200000000000000000000000000000000104c65747261734372697074696361730000001a6c657472617363726970746963617340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142162588dd88d3a33aa48a9775be7af0521acefce054dc7e9e461814dc167a5cabf52aef8534d8249": "0x04030000000200000000000000000000000000000000194c6520436f6d7465206465204d6f6e74652d43727970746f000000126d6e746372707440676d61696c2e636f6d00000c40506f6c6b614d61726f63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471421a2450da5997cedda95b7b5c463b7d00700c34294c283a21235f8d31377620dcd1a56bf60f3e320": "0x040300000002000000000000000000000000000000000853494d2d444f540000001873696d6f6e6a6f73656c6c40686f746d61696c2e636f6d00000a4073696d6f6e787065000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471421c356d070c125b4b4c0a3bbd567cf9fe5e5ad607debd6e89fb31a294288f94ab2490aebd03ed306": "0x00000000000000000000000000000000000750617265746f0750617265746f1368747470733a2f2f6a6564736164612e696f00157265616c70617265746f40676d61696c2e636f6d00000c407265616c70617265746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471421f2e65cb5d0a0be1c95e1f32ddc271b9161da11a343f31619b38dc9f3d966d2624376549ae1da18": "0x040300000002000000000000000000000000000000000b4f5253454e5f5345414e0d5365616e204f5265696c6c79000012736f7265696c6c79406f7273656e2e636800000a5365616e4f5253454e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714222fa12fb4681a4d0e47ff458bb2f80c4bc89a6a7bd022a555e9c1bc719726f475f8a1841428832f": "0x0000000000000000000000000000000000097261676e61726f6b0f4e6568656d6961204b72616d65721668747470733a2f2f706f6c6b617269636f2e636f6d1e406e6568656d69615f736f72616d697473753a6d61747269782e6f7267186b72616d65726e6568656d696140676d61696c2e636f6d00000f404b72616d65724e6568656d6961000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142230ad1e2bae6213b218a07558705ee2b86d4f2988e708454452b7d2efc237b95e139630e04f6116": "0x0400000000020000000000000000000000000000000009437269735f5061700000000000000b40437269735f50617038000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142231d8f9634359403e2a0c8a13611c5eb6921612ecd1a2d7d6c1525a3723956c1c6193e3e2901f3e": "0x0000000000000000000000000000000000134b657672657620506f6c6b61646f742e4a5300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142237e0f9b0ff0758161378b7c016bd381841b01d1f20e66cc5ba9ead421638045c5ba754dbd5a10c": "0x0403000000020000000000000000000000000000000009636865746861636b1143686574616e7920426861726477616a00001263686574616e7940736974612e6661726d000009425255484457414a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714225b1e95c870e114d86cce0d391087696b6123aae807e8da8ae365eeeebd43f857c6b5c4eee76975": "0x040300000002000000000000000000000000000000001c536c38746520506c6174666f726d2028546f6b656e5472617878290f416c6578616e646572204d6f737300000f616c657840736c3874652e78797a00000c40546f6b656e5472617878000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142264b5df53ebf1f498f37af89509e846463f6874745b6f8c4e02a941d2c9a83b7d60d90ad5b81863": "0x00000000000000000000000000000000000d706570656172617563616e6f0d4a6f73652042656c6f7373690000166a6f736562656c6f73736940676d61696c2e636f6d00000e40706570656172617563616e6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142265233f75ee737e4dcb5e6cb19c4034a66e1f5e10be70f0ac356e9beff459e1b334ce7351a229cf": "0x04000000000200000000000000000000000000000000086c75636173766f104c7563617320566f67656c73616e67000000000009406c75636173766f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471422b354403ceb2cc3ceeefbffd1cab85b87e1469bf23bbd35b83fd508cd41e17b0fd3a81b8ffe4467": "0x04030000000200000000000000000000000000000000105468655375737365785472616465720e5374657665204875626261726400001a74686573757373657874726164657240676d61696c2e636f6d000010746865737573736578747261646572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471422c52d6bb34054bfa8fc69f4bcc2ee09a91d633b59b82ca325027ea9567b1b47fa5912c4edeb9d6a": "0x040300000002000000000000000000000000000000000963617274616769610000001463617274616769613040676d61696c2e636f6d00000a436172746167696130000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471422f8d0d571261afe14d6965cd9bcce81dfe785bd7642bbaf4caa8f203de34459ad12d7a9e501bb6e": "0x040300000002000000000000000000000000000000000c50726f666974206c696e6b0000001b67617263696170726f6475636572393140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471422fa92e09f76627f5a2160296c65f838252b9da9f51b9691950ece465e1a71b444d286d91316dd24": "0x040300000002000000000000000000000000000000000b526f6d616e204d2e4b2e10526f6d616e204d2e204b656d7065721868747470733a2f2f6a6f696e7765627a65726f2e636f6d174072656b746f726d6f6f6e3a6d61747269782e6f726713726b406a6f696e7765627a65726f2e636f6d00000c4072656b746f726d6f6f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471423484ecafdeafb8d3c84767978ada6355ac3719ea8f978244b16d7e8c00552c3a189760b55eeb404": "0x040100000002000000000000000000000000000000000a4d616e74726144414f0a4d616e74726144414f1b68747470733a2f2f7777772e6d616e74726164616f2e636f6d2f0016636f6e74616374406d616e74726164616f2e636f6d00000b404d414e54524144414f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714235333782a45d3df229f2896c2bd6f30162c9cc0f5899432515f2cffed36a4dc6b42d48bd2b2910d": "0x00000000000000000000000000000000001044454144424c41434b434c4f56455200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142383a648795d6d96f093fdd7214faca57e8f0a10e8ea4c03c4602af97676242b933a757824ca8335": "0x04010000000200000000000000000000000000000000054e4f56590000000e7374616b65406e6f76792e707700000f406c6f73745f696e636861696e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142398aeb1ef43f542c44cd5285e160a2184f3f5801cdce8517ebffdb591177acb17cff2db2ffd9371": "0x040000000002000000000000000000000000000000000a4541524e5354415348001a68747470733a2f2f7777772e6561726e73746173682e636f6d16406561726e73746173683a6d61747269782e6f7267146561726e737461736840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471423bd63bc18ca71967478e4ccf706567c80242c11e0c11312b7b8ed3db3af63eebd94167aba9ac1a6": "0x000000000000000000000000000000000010504f4c4b41444f542042524153494c19506f6c6b61646f742042726173696c20f09f87a7f09f87b71e68747470733a2f2f6269742e6c792f706f6c6b61646f7462726173696c000000001140706f6c6b61646f745f62726173696c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471423d0615e8f4e163856b5a7ba509762854581e36acc727a27983e3005731931bc31be21c1df4b401f": "0x0403000000020000000000000000000000000000000010504241205347502057414859554449096f576168797564690000136361726e65677a73407961686f6f2e636f6d0000096361726e65677a73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471423d5be68d79bf6613417721ef067cbae6a29f3ddd4d5df9659d5f007e23152b96c2e5b939af7fc68": "0x04030000000200000000000000000000000000000000094f6e65426c6f636b00000018796178756e6368656e3139393540676d61696c2e636f6d00000b404f6e65426c6f636b5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471423eae731efa0ee7a3aa151f9bdc2bb6f8e27d492446ace702955f1eed20efa5ee31a59dafdf3354e": "0x040300000002000000000000000000000000000000000e686f6676656e736368696f6c640000001c6a6f616368696d2e7269747466656c647440676d61696c2e636f6d00000e686f6676656e736368696f6c64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142411ce5d2c7e203b500427a67b8b8dbf1b569c99d1d0a3662359b5aeaa4cbead3d603857271a3670": "0x040300000002000000000000000000000000000000000841754167656e740000001574775f70726f665f6e654070726f746f6e2e6d65000011404d6134363134333938323637383737000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471424883d27e305ffe5f89d4c543e6cd62e62136614f7b98a423cedb9fd863584a2f4ff887259432437": "0x00000000000000000000000000000000000963796265726e657400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142492dee6806c086baef6619eea08f01aef7e47d460f0730b02c075e446308892e55af56af1572168": "0x040100000002000000000000000000000000000000000b696e74656772697465650e696e74656772697465652041471b68747470733a2f2f696e74656772697465652e6e6574776f726b0018696e666f40696e74656772697465652e6e6574776f726b00000f40696e74656772695f745f655f65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471424ab767106e162e17a9749cfb7256e7e48edca7a6911018861ec6e26d9eb2c81bbf037628fefcf04": "0x040100000002000000000000000000000000000000000e527562792d4e6f6465f09f928e00001240746174616e3a6d61747269782e6f726719527562792d4e6f64654070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471424c51cd1777082130630cade4d018323ce09989df4f43749469506631ec446b3322c5b029283ef03": "0x040300000002000000000000000000000000000000000e43727970746f2042616e7465720e43727970746f2042616e74657200001a706f6c6b61646f744063727970746f62616e7465722e636f6d00000f4063727970746f5f62616e746572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471424ddab62ae2ee0f5da1bdcd2db52642b3be2dd7d474a865c85ef5db7b76d6732b132c80de1750d28": "0x040300000002000000000000000000000000000000000f42726176655f4f6666696369616c0f4361726c6f73204163657665646f00001e69742d736572766963652d706f6c6b61646f744062726176652e636f6d00001040417474656e74696f6e546f6b656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471424df16db48272ad68c085e6bde4ac25702f54f46fa3c1b0a6170bd346103c2c6339911e00306a054": "0x040000000002000000000000000000000000000000000b56414c49444154484f520000001576616c69646174686f7240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142506f1a04a86e00ea2793a1de617bc5ff2e0fc73334fb1792f1e6849352ceeab2cfe0a4f43b77608": "0x00000000000000000000000000000000000b4c75636163727970746f0000000000000e404e4654736172656d796a616d000b6c75636163727970746f00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714251429e29e5bdc418aff8f8e6f78afd4fd4d5c59242373cc0e5ecbd5595578ad042e6cf97d53ea1e": "0x0400000000020000000000000000000000000000000018506f6c6b61646f742045636f20526573656172636865720d506f6c6b61646f742e455249002140706f6c6b61646f742e72657365617263686572733a6d61747269782e6f726715706f6c6b61646f745f657269403136332e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142522dbe7f104bee21ccdf130995bda0c195a1c383532e4704f289b31d3923c18f76ff0ef6626f21c": "0x04000000000200000000000000000000000000000000084d616368616c610000001c6a6f736875617a696f6e666f7274756e6540676d61696c2e636f6d00000e405468654a6f73687561736f6e00096d61636368616c6100", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714252e878992d864fb960d75eab8e58bffcedf1fa51d85e2acb37d107e9bd7009a3473d3809122493c": "0x040000000002000000000000000000000000000000000957444d41535445520000154077646d61737465723a6d61747269782e6f7267136d6f6c7465732e6740676d61696c2e636f6d00000d404d414b53494d3738383736000b6d616b73696d3133343900", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714255d8383c400c461dcc1b944a156b60b0adaa4a2a59dd97804c1ec4fca4751a3efb6bc0434ddf051": "0x040300000002000000000000000000000000000000000e4265616d737761705f5465616d00000011696e666f406265616d737761702e696f00000b4265616d73776170696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471425b20afe8011ef7d040d1324a05bb9a0b86d9eabd01245ffcf277f4611f9750dfe465761481ba053": "0x0400000000020000000000000000000000000000000011416c6979756e2d76616c696461746f7200000012746f6e7473696e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471425d12cd63f2c7151f66dcadc693afcce9876c486304d77941b2084677b0e9b7804935da272dd3625": "0x00000000000000000000000000000000001342617262656ee280997320536c617368203200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471425d728fd5c84d7cd8c5671a38e6cc4175311cdb5280fc86d2ad25d197c14682153a30b406a029e75": "0x040300000002000000000000000000000000000000000c6b616b6f6f7a617669616e0f4b616b6f6f7a61205669616e65790000166b616b737669616e65793140676d61696c2e636f6d000010406b616b6f6f7a617669616e323536000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471425ecccdf058700718b63cf648fa2a43a82671762a02da41dc6abbd1e62a376b3af7c2d09abf5120c": "0x040100000002000000000000000000000000000000000a436861696e5361666517436861696e536166652053797374656d7320496e632e1568747470733a2f2f636861696e736166652e696f0012696e666f40636861696e736166652e696f00000d40636861696e736166657468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714261d16493407cc0ac587192891bca929ce36a9004a6b1beca795e27a0dbf10b14d68cdaa962f15a0": "0x00000000000000000000000000000000001c506f6c6b61646f74204d65786963616e20436f6c6c6563746976650000001163646f746d7840676d61696c2e636f6d00001140506f6c6b61646f744d657869636f5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142622a69ca095df152e33a240cb3adb22310f77b1d8f6e105e325077f4b35ffd8bf35780221fcc1ef": "0x0403000000020000000000000000000000000000000005566c6164001868747470733a2f2f6769746875622e636f6d2f72636e79114072636e793a6d61747269782e6f72670a6d654072636e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471426237f16f577beb4108750788ae77403993574ef05638bfe9cff80729c2ca6ba310f6aa65dd0b901": "0x00000000000000000000000000000000001450617261636861696e732041756374696f6e73114d69636861656c204c6120466c6575720000196d69636861656c406c61666c657572686f6d65732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714264c10224bdb241eee938b6b034193875fa93d617a9543084ef41f40790898fa1eb4118e6361e950": "0x040000000002000000000000000000000000000000000946726f67f09f90b8001968747470733a2f2f66726f677374616b696e672e636f6d2f184066726f677374616b696e673a6d61747269782e6f726715696e666f4066726f677374616b696e672e636f6d00000d4046726f675374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142650651beda2cb6ffc644cc7758af1bf8dd4974d1e920fde4e1cc71b5297571368559b48f180917e": "0x00000000000000000000000000000000000c733066746d616368696e6500001840736f66746d616368696e653a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471426968cb24b23a08fb64a86ea0e91047a3ffbbc68c36ea9ab318ee06c8bb4a354dd3a716956c9eb55": "0x040000000002000000000000000000000000000000000f4155524f5241205354414b494e47000018407374616b656175726f72613a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471426a2abbc21cd770cd88a4b558274e57737ffd3fc9741848596199a29d77fe511804d20810cb76050": "0x040000000002000000000000000000000000000000000d5374616b65506f6f6c323437000019407374616b65706f6f6c3234373a6d61747269782e6f726716696e666f407374616b65706f6f6c3234372e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471426e7f4ebcd01d4dae6dd0a94c6dc8091d357cf0092af2f8e108daf432d02d27dcb7ffd019d98a509": "0x0403000000020000000000000000000000000000000007496e64696b6f00000019696e64696b6f6a6f68616e73656e40676d61696c2e636f6d00001040496e64696b6f4a6f68616e73656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471426f6a2ed87b420011ad2ce70e114cbd2d3611571bb2c5b15b2186460de419ca0c774305b62f5cc33": "0x0000000000000000000000000000000000076461696167690f42617275636820466973686d616e00001164616961676940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714271fca71d49496c2ccab328611b1ace9fc6fa0e67bab07922427c5cf6f0291c5b5235e6868f9f310": "0x0800000000020100000002000000000000000000000000000000000d4c4f43414c43525950544f53164c6f63616c457468657265756d20507479204c74641968747470733a2f2f6c6f63616c63727970746f732e636f6d0019636f6e74616374406c6f63616c63727970746f732e636f6d000010406c6f63616c63727970746f73656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142730809323ff3aebc29ac3c17a8bb1145487c9f80bc86e6982b95bfb522b6e191ab95ad8f248f07c": "0x000000000000000000000000000000000005486f6f6e09486f6f6e204b696d0000106d61696c40686f6f6e6b696d2e6d6500000b40686f6f6e737562696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142777a559c125897fb8897a746ceaa53376946a3da353c1c987df8c0caa4395ac0eaf0e6c74874054": "0x00000000000000000000000000000000000b4a656c6c6965644f776c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471427c5cc778df57308e8bfaeea37b4d2f39cafa194a0758805af9a1b9253dc27dc2b7880d06f312d32": "0x00000000000000000000000000000000000f4b696d7320436172204e6f74657300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471427ce23d8a102db2306e6e94eaa021535d3632154bb1c00bbc511d692a33bd5816d518367421932f0": "0x00000000000000000000000000000000000c526567656e63792d3030381757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471427d82cb3e937516ba0aa6672877b1924e7a86c9ec99bf1cb93797123b14ec80c0effe2a8685e1002": "0x0403000000020000000000000000000000000000000009444f54414d494e4100000016646f74616d696e6134323040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471428047368e108b3b06ef40ac7b3e092d0eca77ad072cd317683ab9d24aca4025788421d4276527d57": "0x040000000002000000000000000000000000000000001ff09f90b05f2e2de3809020435259505449445320e380912d2e5ff09f90b00000154063727970746964733a6d61747269782e6f72671468656c6c6f4063727970746964732e6c69666500000b40637279707469647338000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714285588f89e26dc6c2ab6a0d5885b1debcb5f089ce73d3abe16792cd01d63d788609f8d859fc1fe01": "0x000000000000000000000000000000000017f09f8cb74b494e4420535452414e47455220f09f8cb700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142895ffb6b45282d85a093ae9a82c3b93551017c2f3e6eb796a3cc532da826a9f30cc51d28cc8a601": "0x040300000002000000000000000000000000000000000a476572616c726f636b1f4765726172646f2052616661656c20c3816c766172657a2052616d61796f00001c6765726172646f2e616c766172657a313840676d61696c2e636f6d00000b40676572616c726f636b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714289ca7552a5b54db20af269d7bab673454a2f802bff3917cb7e693fb9857affc0be384560cd5a2b1": "0x04000000000200000000000000000000000000000000085a65726f44414f0000000f6c6565406d656c6f646f742e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471428a876cad533fcb536677e8e5d84c1a25bdac951e9055abff3df4c7a656abd841197a8726ff29a3f": "0x04000000000200000000000000000000000000000000094c656e677569746f0000001530786c656e677569746f40676d61696c2e636f6d0000094030786c656e676f000c4c656e676f37233236363400", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471428cc3c2610e32eb246d9719d59eedbef886f837bc68f5afe35eb594ed7546c9507c5d55992c9f035": "0x000000000000000000000000000000000009506f6c6b61726f620e526f62657274204d2048656964000013726865696430373740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471428d20381664d55c37099f4d19d4f37dea1e2ad9be9f4948f837fc391cf9e9af0b458e960dd102a76": "0x00000000000000000000000000000000000762616e6b343513416c656b73616e6472204e6967616d616576000016636f746d6f744070726f746f6e6d61696c2e636f6d0000084041524e5f3838000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471428db6c1e91cbc43002385caf9a08b92ca458a0b817a8cc303cefd5a0c6e108cb939e04242b9e007d": "0x0400000000020000000000000000000000000000000014537562517565727920436f6e74726f6c6c65720000001d6a616d65732e6261796c794073756271756572792e6e6574776f726b0000114053756251756572794e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714293cf013489f4e2d9afa0d65d7fa0d1b9240ed167102fe95be2b87c6d585917f6c4ee40e45cb6e5a": "0x000000000000000000000000000000000009477265617468697400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142959c4bc29b0128ea4496cb0c04854a6634444b262642d22f70b361cf9e45842bae6e92b42294d19": "0x040300000002000000000000000000000000000000000a43757272656e63797800000014656574696365706f7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714298645876ad18694bee606a879569e5675d379121f832a04d3e378618ee6d12244646d2d00bdf420": "0x040300000002000000000000000000000000000000000a6a6f69655f70696e6b044a6f790000146a6f792e6f7369766540676d61696c2e636f6d00000c405465616d5f46656f6f68000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714298ad014cd66be3404aec61601a366f706a5dda2bdb5987555ebea5347bf32080bdfde6f33849d05": "0x0400000000020000000000000000000000000000000009726f636b6e6f646500001540726f636b6e6f64653a6d61747269782e6f726715726f636b6e6f6465687140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471429a96dcb25143c65cef75691f5bc9f7552778942bc996e7dc0796a3b431d6894e4ee36c168168222": "0x040000000002000000000000000000000000000000000a736f72616d697473750000001974616b656d69796140736f72616d697473752e636f2e6a70000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142a251205d65518b0e6b912626c9dfa3cd9e65b4412b19eb9d123edb1aa22d492a58a88091c483a7a": "0x04000000000200000000000000000000000000000000034d4b0000001b6d69636861656c40636f6c6f7266756c6e6f74696f6e2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142a3ffa5c696e8f33fc5bf1b734c6224841177fb6111b9fc879c86cabd506a7c5b5f84bd66bf1d37a": "0x04000000000200000000000000000000000000000000115468652043656e7465722050617274790000001974686563656e74657270617274794070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142a65c9799fef41adec3d304da58d77a4384fced1c59dd3cbc9618dd1ec92e6feb64293147272a21d": "0x0403000000020000000000000000000000000000000009526f636f536170650f526f636f202f20446f7463617374000017726f636f63727970746f343140676d61696c2e636f6d00000a40526f636f736170650009726f636f7361706500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142a679b6bc1ea7234ccb38aa8821510b7cc609cd55fd19c0f9c3594d49fe8db355bb2e7fb2324c948": "0x04010000000200000000000000000000000000000000096c7578382e6e65740d496e66696e697465204c75781168747470733a2f2f6c7578382e6e65741540616d6133313333373a6d61747269782e6f72670e696e666f406c7578382e6e6574000009406c7578386e6574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142a6803733e06edd5682740b90bc8be47e739a0b66b3bd84eac0962a708078b238c8c08945fb2024b": "0x0000000000000000000000000000000000044d2d4f094b656e6e79204e670000146e6f7665783839303840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142aa976bb8726f15e2e5157fa386365bb2a60fc6f415bf070acdae47078be1396e3dc47ccb837d459": "0x040300000002000000000000000000000000000000001d4e696b6f6c61204d616e646963207c204d565020576f726b73686f700e4e696b6f6c61204d616e64696300001d6e696b6f6c612e6d616e646963406d7670776f726b73686f702e636f00000a6d616e5f6461613231000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142ab0d54695f8d579c6515b55efbd99301b103862a649266e6f4a08ed9f2f9e653faa4629710dd6d2": "0x00000000000000000000000000000000000d746f646f646563726970746f0d746f646f646563726970746f00000000000e40746f646f646563726970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142b031c075ea343ce443c76dcde19df9387486ded7845c6d85ec2a4c17f38f8b1e7a0a14de7968d7d": "0x04000000000200000000000000000000000000000000064b414d454c0d6b616d656c7374616b696e671968747470733a2f2f6b616d656c7374616b696e672e636f6d19406b616d656c7374616b696e673a6d61747269782e6f726719636f6e74616374406b616d656c7374616b696e672e636f6d00000e406b616d656c7374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142b2d37123329b9ba08bf2f84a9f268c10adb63f3446fa65d680c7574d794c4115b605ad40d26cc42": "0x040100000002000000000000000000000000000000000e4252494748544c595354414b45001b68747470733a2f2f6272696768746c797374616b652e636f6d2f1a406272696768746c797374616b653a6d61747269782e6f72671a636f6e74616374406272696768746c797374616b652e636f6d00000f406272696768746c797374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142b2d468ee1c0d6cf28ee86c98db79e06b3e25509ad654b002720aad45713da761bae4f0ae813387d": "0x04030000000200000000000000000000000000000000054761626f000000216761627269656c6e69636f6c6173676f6e7a616c657a40676d61696c2e636f6d00000f4063616d62615f6761627269656c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142b2f2f9bc8a6dc303020182b284d6ac805b1382502a771eb140c80303e128cfefa992a62160a7728": "0x000000000000000000000000000000000008426173696c696f0f4d617474686577204261726e65730000186f6e656e6174696f6e3134393140676d61696c2e636f6d00000d40436174616c797374557365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142b53fe0d3b6de98ab40270f026c5a4841078cc77a050c780f88e5dee8436e569972c93fa56d9a020": "0x00000000000000000000000000000000002077616c6c657420706f6c6b61646f7420706172612070617261636861696e730a66646e74732e646f74000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142b6e818ad6aaf2194425333101d35f55eccfe16b28f0e65007a0076ca42eecb050405f6e0ac4737e": "0x040000000002000000000000000000000000000000000455414900000018616e6172636879636861696e734070726f746f6e2e6d6500000f40616e6172636879636861696e73000f40616e6172636879636861696e7300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142bac4814c142df16f89d49e97071dfd7f8971ed816c0fc60a34aa6a8d0b1af8f7c6922659dfbd789": "0x00000000000000000000000000000000000d63796265726e6574776f726b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c08340921a3d8d9981e0c8001f0d80ef450c0c0561f9e4b22337af479023b9d79851381ffbe0348": "0x0000000000000000000000000000000000083130313538313400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c09493faa9e924efc5d04e7ff3965c8285a2c23aa573117deeed886bbe5e3be0974f1cf0a2ff216": "0x00000000000000000000000000000000000b536861776e2059616e670b536861776e2059616e671e68747470733a2f2f6769746875622e636f6d2f526f6d65726f59616e670015736861776e40706f6c6b6177616c6c65742e696f00000c40536861776e5859616e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c3ee724586db259eaab0cb55c147ffaf184a4c00513e85f6d5bb6416994fbdd0dd168f3c59a291b": "0x040000000002000000000000000000000000000000000c437970686572204c6162730000001d6379706865726c6162732e636f6e7461637440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c4d0f13e5d38cd42a813834d9532d047dcc1c87a3abde12724abfa8b681edaf89d59dc4d69d3e60": "0x040100000002000000000000000000000000000000000c686f6e65796261646765721144616e69656c2042616572697377796c00002064616e69656c2e62616572697377796c4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c5adc2eb80036fe5e217ee74a4735c3e66dff90cc3ec8dd2185411ded94590173ec8cd773cd1071": "0x0000000000000000000000000000000000114a616661725f436f6d706f7361626c6500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c85c1028c0265f1d0ee5462aa1f69fbb13d1bbba3fe774167ce82a5cd36da733f2f2db0e7e4ad4d": "0x040000000002000000000000000000000000000000000d5542494b204341504954414c00000015636f6e74616374407562696b2e6361706974616c00000d407562696b6361706974616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c9114f608ac39a9a45d1c3020272172fdb2238d4b68c1f8d6178dfbf4a80404dcd01da024dac33d": "0x0400000000020000000000000000000000000000000009476162654b6f696e0000001c6761627269656c5f626f6e75676c6940686f746d61696c2e636f6d00000a40676162656b6f696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c953664c84e500ad4d71d52cefd70e1668f6b908e3196d664e2fd5e541905966c514ab660b86966": "0x040300000002000000000000000000000000000000000757616c7669730000001277616c7669733740676d61696c2e636f6d00000877616c76697337000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142d1be0f377b4cffe7c1207030eebbff1aa8d1d3fb13ef4a44251f81480ff627240d45a0e4547c639": "0x040000000002000000000000000000000000000000000b5354414b4543524146540b5354414b4543524146541768747470733a2f2f7374616b6563726166742e636f6d15406e3174726f67336e3a6d61747269782e6f726717737570706f7274407374616b6563726166742e636f6d00000c407374616b656372616674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142d51e6ba205c01881e8f1a5238c8472f9059d189db0d25ae5bfd6380b2ec5325d302689d96bfb479": "0x040300000002000000000000000000000000000000000e4e6573746f722043616d706f731e4ec3a973746f72204e69636f6cc3a1732043616d706f7320526f6a61730000196e2e63616d706f732e726f6a617340676d61696c2e636f6d00000b6e65735f63616d706f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142d5da20efbc496e3401ddfae657e8222bce22c9787be36b1ae9906840546c992fa4b4b9201be1776": "0x00000000000000000000000000000000000d496e73616e654272612e696e05416c79781568747470733a2f2f696e73616e656272612e696e0012616c797840696e73616e656272612e696e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142d6a11aa67106d2d8ae51d44bfb6e10f175e6e86e829e1013589f4f1049b3a98f648cd1a9d8d3007": "0x040300000002000000000000000000000000000000000b416e67656c696e6138380f416e67656c61204b616b69697a61000019616e67656c612e6b616b69697a6140676d61696c2e636f6d000009616e67656c615f6b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142d70dfa84c8df520b8b3f33a5d67eaa3bd04013795e3f6ab9fa3d6851ab3005ba7cacdde440eb053": "0x0000000000000000000000000000000000066a657375730d6a657375732067617263696100001c6a6573757367617263696167756169646f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142da517d91ffe519dea08e3af45c5a91e4f22bf4e5e6491e5927538296954e4fbb450bd5db3ec543e": "0x000000000000000000000000000000000015486174656d207c20446f7442656c3361726162790000000000000e40446f7442656c336172616279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142de8d0b38098bb8dde607c18f59d4b90b26ee90bb1e7fe10d4ad22c871ea17414ddc9a9d355c255d": "0x00000000000000000000000000000000000a42615f73733335383800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142de96dce1f9cc98a04aae2b4b67be2cfee31d6cdc0f777f4b8e6ba330f93978f9d1aefe9af61374f": "0x00000000000000000000000000000000001d5374617368204163636f756e742031202d206e6f6e206c656467657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142dfcf93c305276e4327f10a5aa41f8e64ca4dc6cb07bf883e19354851979be53c77d1d65a66fa765": "0x040300000002000000000000000000000000000000000f78696e7869616e6764657369676e0978696e7869616e67000013646f6e677831313140676d61696c2e636f6d00000e78696e7869616e675f6d657461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142e0a85ddf8e6a3e3d24f805ca7bafb11cfdb0ace585a9d0e6edf83878dc7b42946c33c2378211464": "0x0401000000020000000000000000000000000000000007414e414d495807414e414d49581468747470733a2f2f616e616d69782e746f702f1440646270617474793a6d61747269782e6f726714616e616d697840706f6c6b61646f742e70726f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142e346820d7be398158598801d9659099c1437f879e3003c0461affdcb378e9462824a1b7e5cd4c65": "0x040000000002000000000000000000000000000000000661626761720000124061626761723a6d61747269782e6f726716616267617262617273656740676d61696c2e636f6d00001040416476697a6f7254727573746564000a676172696b3537313500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142e764a24050b5fa2022be0daf8bcff3056f4e4e1c4296d436184ec10c21a4f9bedc57d2778674e7c": "0x040000000002000000000000000000000000000000000852686f6d6275730000001a72686f6d627573706f6c6b61646f744070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142e7e56460089fc7a54c473bf199d05b878ab34e9a37d17d0a8bf70498edb5c759672e984fa38b432": "0x040000000002000000000000000000000000000000000f4170706c6965644243204c61627300001a406170706c69656462636c6162733a6d61747269782e6f7267186170706c69656462636c616273407961686f6f2e636f6d00000f406170706c69656462636c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142e8429dbeda5cc3f2042cbe5632c5f2d92c0f91144fb9f02541d75f721881337e5ba8d5f13691506": "0x040300000002000000000000000000000000000000000f5472656173757279204775696c640f5472656173757279204775696c6400001874726561737572796775696c6440676d61696c2e636f6d00000f40436174616c797374537761726d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142eb239de2237ff4464c92fbc08d8d3594de7a9eeae4ef24891cf7e8330faf07ed804cd0045e49e6d": "0x040000000002000000000000000000000000000000000a53686f7274795f33350000000000000a407273686f7274656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142eb8e564ba3255aa8ed07ac253ff90568509ab1e98620aab2d27739c088425500b1555c200fc5a6d": "0x0000000000000000000000000000000000085765625a65726f001d68747470733a2f2f7777772e6a6f696e7765627a65726f2e636f6d2f000000000d406a6f696e7765627a65726f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142ec71cb46d9dac8c4061fa23b882bde2f44bbbf50b167a0540bd1f34cdfa015199e099ff610e9a54": "0x04010000000200000000000000000000000000000000094f4e454352595054094f4e4543525950540015406f6e6563727970743a6d61747269782e6f726711726f6f74406f6e6563727970742e696f00000b406f6e65637279707432000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142ef8fef75807c63dc8d6404482643a279bc4a12ccb233ae1be9cc911b65313415ae1f6e99ea6351d": "0x040000000002000000000000000000000000000000000950726f706f736572000012406a6465746f3a6d61747269782e6f72671a6a6f7365706840636f6d706f7361626c652e66696e616e6365000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142f05080e250453cc88609d041e06db09ff8a0bea7122bceb122630591856f71285ff8215cdcaa95c": "0x040300000002000000000000000000000000000000000c45737562616c657720412e0f45737562616c657720416d656e7500001b65737562616c6577627573696e65737340676d61696c2e636f6d00000a65737562616c657761000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142f3b5813e65122054cbd158ed5b37e237e8a790a020d9a67032b56318dd7f674de1e5a002f8b5a52": "0x000000000000000000000000000000000004446f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142f4bb305762822d5d4f47497fa575d0be94b1dc8833b9ffee17058bdcb32e4aaaf5f7d846afdbc11": "0x00000000000000000000000000000000000e4c6972616e50656e64756c756d001b68747470733a2f2f70656e64756c756d636861696e2e6f72672f00146c6972616e407361746f7368697061792e696f000009404c6972616e416c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142fb53ad11aed254b52582c7985dc8002e718841421ee5059a92ed9a4e38c0c33365ee196c96d5e0a": "0x040000000002000000000000000000000000000000000a4972696e615f56455200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142fbc5fa5095a463cfa9fb4eccab4919417e2a6072c77e55b7d1b69a9682629a09953ce699260b564": "0x00000000000000000000000000000000000a4669676d656e742035001368747470733a2f2f6669676d656e742e696f000100000b4669676d656e745f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142fccfd4d73aaadfef8c309d6472fab1a89e619867d57934db759e5d76d63b9e67968e36f02787335": "0x04030000000200000000000000000000000000000000084d72457863656c134672616e636973636f20416c626f726e6f7a0000176672612e616c626f726e6f7a40676d61696c2e636f6d00000f406d6973746572657863656c7733000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714304630d144e59358fe1f35d3b712d9b87e9dce926d8772267bbbaeb776e9b2a8615b29d6594c4621": "0x04000000000200000000000000000000000000000000076b734d6f6f6e000013406b736d6f6f6e3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143046396b7c34c0b3eec4bd650a277342ebba0954ac786df2623bd6a9d6d3e69b484482336c549f79": "0x040000000002000000000000000000000000000000000664617678790f4461766964652047616c617373691468747470733a2f2f64617461776f6b2e6e6574124064617678793a6d61747269782e6f72671264617678794064617461776f6b2e6e6574019484ae9c0de026adf6a15a538f550699515c84cb00000664617678790000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471430731e299628f086987179a4c458ad0333ddf074031278a4e40cbf3d07c3c93bdaf1d4e720e25b70": "0x0400000000020000000000000000000000000000000016506f6c6b61646f74204e657773204368616e6e656c000014406d6172796c65653a6d61747269782e6f7267156d6172796c6565626f7840676d61696c2e636f6d00000e40706f6c6b61646f746e657773000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143081f00d680b8e9f7824673613d28fd0e00381e7a257a670c9fe3caf566f5ea3b4eae0190c3fd06a": "0x040000000002000000000000000000000000000000000a7374616b657468617400001640616e647265697369643a6d61747269782e6f7267167374616b6574686174687140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471430a9041ab751137e14b3cf31ec26dcd596285c2afbdd19579b3634a78bc987dad71d91ecf436847b": "0x04030000000200000000000000000000000000000000114a617669657220456c69205265796573194a617669657220456c6920526579657320436162726572610000176a6176697265796573636d3540676d61696c2e636f6d00000d404a617669426c616b654352000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471430abe05ab6e2104d2e84d8f02b52516e31d4e588ef866a26f721896ea42fb351a63d58a418cf9d42": "0x00000000000000000000000000000000000d43727970746f64696e676f3200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471430d3bc09d2bfcfb50c7f10142a81fedec753f7c556f5b93a400c280805e7fcdff668719637b13434": "0x040000000002000000000000000000000000000000000a47656f7267695f5053000000126a69673737303940676d61696c2e636f6d00000b406a696763727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471430ef5160a1f04948b2e8980baff3a96bacc15e3f314bdfa64112a67afc736beee37f5d2e1b907462": "0x000000000000000000000000000000000006576574657a0014687474703a2f2f7777772e776574657a2e696f0d576574657a2077616c6c657400000006576574657a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431053eabded94fa87600c0c74304812e4928a503408a68c782c69a6af2fca55fcd9e48e095b44863": "0x040000000002000000000000000000000000000000000ff09f90a0205354414b4546495348000013406d34646269373a6d61747269782e6f72670e6869407374616b652e6669736800000b407374616b6566697368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143118317c1a74f34820a72747f8fa2e88160c65260e1dd461e775a75e05fd60c0ee07c929411bf611": "0x0000000000000000000000000000000000094b6574757432353600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143185ee0b1cadbcee56ca8c23e3988aaddd0fe5deac26eef5661547ce8ae71c4fbe07014b7052e71a": "0x04030000000200000000000000000000000000000000064d6174656f0f4d6174656f20436861756368657400001863686175636865746d6174656f40676d61696c2e636f6d000009404a5a656974616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714318ee29c136c23ba24d6d7cd9a0500be768efc7b5508e7861cbde7cfc06819e4dfd9120b97d46d3e": "0x000000000000000000000000000000000012537562736f6369616c204e6574776f726b001a68747470733a2f2f737562736f6369616c2e6e6574776f726b000000001040537562736f6369616c436861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431c949d064ba830cfc60f1dfd95340dfe375e3e49d846e35283e3fdfcce5a83aa09c8a4718d64f7d": "0x040000000002000000000000000000000000000000000b4a6f657267537475647900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431ef141127f82186d45548e42d7f5d5aa35ffc16ff29396c99936f0c1eae84d452f1daac87c3c566": "0x040300000002000000000000000000000000000000000c446973747261637469766510446973747261637469766520496e630000156e6174654064697374726163746976652e78797a00001040646973747261637469766578797a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431fa432a48d8271ecc17542453f0d5e9caa6e8351612ecd3fe895c023eb93cbccf0ab0457728b87c": "0x0000000000000000000000000000000000074d75727068790e476572617264204d757270687900001567736d2e6d757270687940676d61696c2e636f6d00000d4064657370657261646f676d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143203618ac806a5094866c7c5c93a0984394d5279fbbecb07c1e48368b042566ebb632c2055698b02": "0x04000000000200000000000000000000000000000000084e6f646561737900001540637261626265616e3a6d61747269782e6f72671577656e7a686968616f406269746f7069612e636e000009404e6f6465617379000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714320eb468db7ea3c7aeb9fc068a3340edead118ac3cf3decc6743724cd5fb11edebaa98b540a08f07": "0x040300000002000000000000000000000000000000000a59756e6720426565660000001a79756e67626565666269676261677340676d61696c2e636f6d0000104043727970746f436f77626f794f47000c79756e6762656566342e3200", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143229ab61e8335194fcbc52e3cdfb14d85daa469993d85fd39f8f52fd8c89c53afc067e327fd2da5a": "0x040000000002000000000000000000000000000000000f6c6f67696f6e206e6574776f726b000000147465616d406c6f67696f6e2e6e6574776f726b000010406c6f67696f6e5f6e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714324c8ff3d7043f733a47ca4e579b94d1edbf9a82eaf0e5b1d018ef37f84d85bd96e415147378e048": "0x00000000000000000000000000000000000e57616c6c65742048697473636800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471432566a7e7c573a80b2cb9187546fcaa8c721b02805a6ed72fc162c0cba916e4af26e95b624668d47": "0x040000000002000000000000000000000000000000000970756e6b726f636b0000154070756e6b726f636b3a6d61747269782e6f726715706f6c6b61646f744070756e6b726f636b2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714327fdfd66e528b9662d8c4e1c6fbab57ba4df15b8120db4cec5c150371d0755d8ee5312382f47f09": "0x040000000002000000000000000000000000000000000b437269734e677579656e00001740637269736e677579656e3a6d61747269782e6f72671e7472756f6e676e677579656e3139373139393940676d61696c2e636f6d00000e40637269736e677579656e3939000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714329deba10a6ffdb9f64d8174827dde573fbc8bd2d0b184a7e38fae4957d1ba577e98522de9bd8e52": "0x040000000002000000000000000000000000000000000b4d61746a617a20e2a793000014406d61746a617a733a6d61747269782e6f7267126d61746a617a406170696c6c6f6e2e696f000009406d61746a617a73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471432ac541eb6aa1242ac1aee6b509bdaa6aeb4718c2218bd7e78a3d6704bf886375e4c243b77a66b34": "0x040000000002000000000000000000000000000000000d45786f746963205374616b65001968747470733a2f2f65786f7469637374616b652e636f6d2f184065786f7469637374616b653a6d61747269782e6f726718636f6e746163744065786f7469637374616b652e636f6d00000d4045786f7469635374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471432e1c9cc0499e7e2dbcd8d24233cad535726ee1613bc044d6c376af651779deee9721338d12d0458": "0x04000000000200000000000000000000000000000000125350414e49534820424f554e54592056320000001a626f756e7479656e657370616e6f6c40676d61696c2e636f6d00001140426f756e7479656e657370616e6f6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714333ed71ba3fea8299a248664937e01d8e4856eb89c980637b2d88c705fb69307d7925ccc61022b53": "0x04030000000200000000000000000000000000000000074a45455045520000001378636a65657065724070726f746f6e2e6d6500000a4078636a6565706572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143351d9da302db1e80e86d53dbd64cb20f18ca85d0e78ea35331f734bedeeafa0166bf06c7224d100": "0x04000000000200000000000000000000000000000000124b6f67617261736869204e6574776f726b00001a406173685f77686974655f6861743a6d61747269782e6f726711696e666f40696e766572732e74656368000011404b6f6761726173686943727970746f000c417368576869746568617400", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471433c674ddb7d7206854d7aa0bba9a5dbb1bb77973f344625df346f6a65840b8534ee22e93fbad767a": "0x040000000002000000000000000000000000000000001af09f95b5efb88fe2808de29982efb88f70676f6c6f766b696e0000164070676f6c6f766b696e3a6d61747269782e6f726714706176656c406e6f766177616c6c65742e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471433c7d151629670075e7fb7c001173521bcbfdca5b2087290de094c04f9e1ce7491b836cd408c125a": "0x040000000002000000000000000000000000000000000e4c61626164616261646170746100001b406c6162615f6461626164617074613a6d61747269782e6f7267186c61626164616261646170746140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471433e2754f2553aa4e5068e605e8d0653954d518d7b9025d374b2e374731bbe800cfa6ca89743f7053": "0x040000000002000000000000000000000000000000000865736b696d6f72000000000000000865736b696d6f720000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471434089e43cd4989a9dbc5fe127aa5c0a6df694aa2a9dc6c68a1acd76e61f8f238bc8e71fc8d311636": "0x0000000000000000000000000000000000117363616c6577656233202d206a726d7200000000000008406a726d723932000f5363616c6557656233233731323300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714342d10fd36c3ac43cec9484c231e2d686bc8932300191a43fa515f95c02ceebda09ad8d8f5fc5305": "0x000000000000000000000000000000000015496e7641726368205465616d204163636f756e740000000000001040496e76417263684e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143458891c8e3214bfc070c3303fb82d487442202f6a3270f8a19af8691f9b6bb5b23dcf1745f02d1a": "0x040300000002000000000000000000000000000000000e53616368696e204775726a61720e53616368696e204775726a617200001773616368696e686c6f32333240676d61696c2e636f6d00000f73616368696e6775726a61725f34000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143461fb0d1f2c29fe9088b991261091d43c92ce790d4c8fb007b7e8d19c9c619a7d722c6fbdb55f04": "0x00000000000000000000000000000000001142494e414e43455f5354414b455f31331142494e414e43455f5354414b455f3133000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143494187c44a6e4fb8efd9cd4b3a223ff29da836fd6f01ce2fecadafaba8fa460c360239f2b084eb9": "0x0000000000000000000000000000000000124445442054656368204d756c74697369671b446563656e74726174696f6e20547275737420436f6d70616e791968747470733a2f2f646563656e74726174696f6e2e6f72670000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471434c90aef7cd6c087500774a5e6eb480dcabecc949e4c2508d7329ea62a1e68aebf76b819da6b864e": "0x040000000002000000000000000000000000000000001c616d6974726f76696368207c20556e69717565204e6574776f726b14416c6578616e646572204d6974726f76696368000012616d40756e697175652e6e6574776f726b00001140416c656b73616e64614d6974726f31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143510bca3b55859f7b8296995e76034c70f1f703618da7493b946e24b590c53cd7bf5ab0c4cadd35f": "0x00000000000000000000000000000000000d746865626c61636b6861776b074948204b494d000014736f6172696e677373406e617665722e636f6d00000b40736f6172696e677373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714355270ed8e9758bf26283680a763407ce7914d1a67d460d0d1f44d51097783ad17f161678218062f": "0x040300000002000000000000000000000000000000000c436f6e6f7244616c7932320b436f6e6f722044616c79000014636f6e6f7240636f6e6f7264616c792e6e657400000c436f6e6f7244616c793232000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471435668a15706f1b1bb42eda141e4c2c67af7180747b776be512c3fd83e5c359e7ca4cb3fc2d3a545b": "0x000000000000000000000000000000000011506f6c6b61646f74204163636f756e740c4a6573736520426c61636b0000176a657373626c61636b36343440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714357accb7976ec983aa479bfcbf35b48d8e5755c7a34bb367ce63261b6a0a51f24de1978c711f813a": "0x00000000000000000000000000000000000c526f79616c6167656e63790000001e636f6c61626f726163696f6e657340726f79616c6167656e63792e6573000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714359ba2c3f9bfa49015d7109f79f5bbf8a34fe2b2c9e68f0076f2bb900fb3cadff0e3e0239d804a70": "0x000000000000000000000000000000000014426c6f636b636861696e2052696f203230323400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714361d0f16c34b17763817e559bdeb521169c4801d70a1dfefe94175d15666a1ae70719a3594a57c16": "0x000000000000000000000000000000000014736f7665726569676e6e61747572652e636f6d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714363df5d8dc0e8fe77042bfc6e75e1277fdefbea917f6b7ca8c36b3e0ad7286d66974c8f2b4cb9672": "0x040000000002000000000000000000000000000000000d414c474f207c205354414b45000016407368616465776f6c663a6d61747269782e6f726713696e666f40616c676f7374616b652e6e657400000b40416c676f5374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471436614a3e28f4b5c8ca7c4d5563b5f38c3a5d1e7d348ea2dbe06332f55f17dd0150d606bcb8777258": "0x040300000002000000000000000000000000000000000a4e6d61727368616c6c124e6963686f6c6173204d61727368616c6c00001d6e6963686f6c61736d61727368616c6c31406c6976652e636f2e756b00001047616d696e675f6f6e5f436861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471436623b12ed037a52fcbe4bd03bed7dd7ad734f50e0c283d9af0a129e71e78ea6128021f9cbf5af05": "0x00000000000000000000000000000000001e506f6c6b61646f74204272616e6420426f756e74792043757261746f7200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471436d8007439bfb5ce4aa76d977ed253365d18637af3d4159ca3ef710933143d8db9b99faaa48a5a52": "0x00000000000000000000000000000000000e466c6176696f20e29895efb88f0000000000000e40466c6176696f5f6c654d6563000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471436e262e10cb9b3db9f96f2a47d349d32da9e47f6206196b6869fce0e614fdb0fc46bc95fbbb60ecd": "0x000000000000000000000000000000000018506f6c6b61646f7440546f6b656e323034395f3230323318506f6c6b61646f7440546f6b656e323034395f323032331968747470733a2f2f776562332e666f756e646174696f6e2f001761646d696e40776562332e666f756e646174696f6e20000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143721f074825b67fc14e5b21d2eee0865adfb8783ac900540d67f0a89eb6881e77dda91d509398809": "0x040000000002000000000000000000000000000000000b476f6e74616a6f6e657300001740676f6e74616a6f6e65733a6d61747269782e6f7267176172747572676f6e74696a6f40676d61696c2e636f6d00000e406172747572676f6e74696a6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471437626cdc63a152498a0e3784748694717e84559e00e0876f456fa206db3ab70327d512a24730ec37": "0x040000000002000000000000000000000000000000000577696c6c00001d406d6574616b6f736d69613a6d61747269782e7061726974792e696f00000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471437a32ce68f563a4a0a820dd53c6ea693d41a8d11910443a34fdc13a3d54cd111682b39d90ef57c38": "0x040100000002000000000000000000000000000000000e7374616b652d706f6f6c2e6575001a68747470733a2f2f7777772e7374616b652d706f6f6c2e65750013696e666f407374616b652d706f6f6c2e6575000009405374616b654555000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471437cd5a422db43856985be267f05f586da7ab52e4430c2f6d461f396b9d6cf4f1eb5362066f7cd82f": "0x040000000002000000000000000000000000000000000b5350494359205441434f0000164073706963797461636f3a6d61747269782e6f72671a73706963797461636f70657070657240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471437fb611aa391843a0617c14e4ba86d011c84b8a2a5b3f18758bf40915608a130518fa89b0a47e169": "0x040000000002000000000000000000000000000000000e436861696e20736572766963650000001564656e7665727437383440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143831c8a7af466e1a968ed5a157452dab7ddc6950d423e78edc9780da648cf7c009982b6bce956e7a": "0x040300000002000000000000000000000000000000000e43727970746f566972616c6c790000001868656c6c6f4063727970746f766972616c6c792e636f6d00000b4e61737461476c656e6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143844e5cda0e40f06f4f08248be088e83f0fd179f3b32d48c4540adaa119630979292e8b24b12144f": "0x04000000000200000000000000000000000000000000144a6f726d756e67616e64204c616273f09f908d000015406d6f7274677261793a6d61747269782e6f726700000010404a6f726d756e67616e644c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471438533548d44cc8d84056f76b206c306712a75e10ece4cffe091b1a49b0ba4c505f2ae4ee673c576a": "0x00000000000000000000000000000000000c5a4b56616c696461746f7200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471438713841aa089048252a69cb3b782cfc3696fed0fe67bd0c92ca21f2767482af41a902e5a8281145": "0x0400000000020000000000000000000000000000000008566978656c6c6f00001440766978656c6c6f3a6d61747269782e6f72671268656c6c6f40766978656c6c6f2e636f6d00000b403078766978656c6c6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714388926241aaeef7a34dc4d6e6c7520791be90da8875a9a40653b4845ca03811c317cdcb034ce9e3c": "0x040000000002000000000000000000000000000000000d44696f6e79737573f09f8d87001968747470733a2f2f64696f6e797375732e6e6574776f726b1f4064696f6e797375732e76616c696461746f723a6d61747269782e6f72671468694064696f6e797375732e6e6574776f726b00000f4044696f6e7973757356616c6964000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143890df58c23c48913a04ac816fac137bf9ea324fbe8aae47b1169761f94c9dc943ed2e4b80620f4f": "0x040300000002000000000000000000000000000000000c52616a2052616f72616e650000001872616a72616f72616e6535373640676d61696c2e636f6d00000d4072616f72616e655f72616a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471438e49f900e62691ecaafae0aaa6333fcf4dc193146945fe8e4da74aa6c16d481eef0ca35b8279d73": "0x0401000000020000000000000000000000000000000005616b727500001240616b2d72753a6d61747269782e6f72670d6d61696c40616b72752e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714390c74f4052dd71642a8f4af92bc51e83093eeecb73f2aab526a11c41735ff54d9fc7de54ace5c6d": "0x040000000002000000000000000000000000000000000d50617261636861696e626f790000001e6a6f686e72686f64656c626172746f6c6f6d6540676d61696c2e636f6d00000e4070617261636861696e626f7900106a6f686e72686f64656c233831363200", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471439335e2f28a7aaec85a72cf77774526be03a8e0759b18af9c2ca15954050ce4098d48996a8e716cc": "0x0403000000020000000000000000000000000000000013506f6c6b61646f742e456475636174696f6e0000001b636f6e7461637440706f6c6b61646f742e656475636174696f6e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714397f26eed6dc09cdae3abb16e30166db6c77a2f24b6e19cc63bd95fc08529bcb05bc71273a762b29": "0x00000000000000000000000000000000000e746d64765f706f6c6b61646f740f546563686d65646576207361726c1568747470733a2f2f746563686d656465762e65750012696e666f40746563686d656465762e6575000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143984bb08caa099b70cdbc545f7f5439e9eeebcf2ba592a87fe0da381d75a0bc8abf9f3b8ade4884a": "0x04000000000200000000000000000000000000000000044a4a4200000000000008404a4263727970000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714398ac470c132d05746cba586963ce742f0f17d705174df4317e773788ebdd7244df0a0ddedcc645c": "0x0000000000000000000000000000000000144379706861646f63f09f91a8e2808df09f92bb10416264756c617a697a204b616d696c0018406162756a756c61696269623a6d61747269782e6f7267136379706861646f6340676d61696c2e636f6d00000a406379706861646f6300096379706861646f6300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471439ae776eda0085e120f67bb36605f9ed8f7718d0b1c2ae212a5de9560662ba0814ae8ddd3bc9be57": "0x04030000000200000000000000000000000000000000045465301154656f646f72204b72617374616e6f7600001474656f4073637974616c652e6469676974616c00000e4074656f6b72617374616e6f76000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471439c5f2d53febd2c2f8c56648d781e59233b49323a09ee6a8b0410a4049d62549d27240f691893872": "0x04030000000200000000000000000000000000000000135468696261756c742050657272c3a9617264135468696261756c742050657272c3a9617264000018742e70657272656172644070657272656172642e636f6d00000840546974693150000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471439fc7b224a1750e8dcbad707002e3836a201fee988a917a528e2eb37ed99c74cb8a98819a9330406": "0x040300000002000000000000000000000000000000000c57696e7465725374616d70124c656f6e6172646f20437573746f64696f0000156c656f6e6172646f40637573746f64696f2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143a0f07f5bfdc2f192a45a8d99f3141ae7e1c9c636bead309c3bf3ee50d72a948acdd3d0104bb5608": "0x00000000000000000000000000000000001a446f742d437270746f666f6c6c6f776572202d20537461736800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143a183e641b31567800859d2281b19e6650fd9bcc6dee02254ea1590ce4b8b831617dd79336ba4d36": "0x000000000000000000000000000000000007436872696e6300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143a2a13c271740b976af2f79717e1a5b28437221e8b526ec3a23d9b83c45baeba67ae76812ea07636": "0x040300000002000000000000000000000000000000000a4d616e64616c696f6e0c41647269616e204b65657400001c61647269616e2e6b656574406c696768746174776f726b2e6f726700000f4061647269616e6b656574333630000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143a47757951924bf938236315632f2c74a59daeaeb84b2f349771ed1dd9018b421a8ed32f69d0750a": "0x040000000002000000000000000000000000000000001050727565626120506f6c6b61646f7400000013646965676f4070726f746f666972652e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143a4998c1a7d8244c6819b9b3dab3439825f9b076ff1be1f248fe246f6be57b131d7d10e38b08fd00": "0x040300000002000000000000000000000000000000000b4761746f724b6f727073115374c3a97068616e6520466972696f6e0000176669725f70697261746540686f746d61696c2e636f6d00000a40676b31385f646f67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143a5db923b142979614acd07ac36ad489a295216ed144b8b0ed0c46a5f8a74c44b1948793f015297a": "0x04030000000200000000000000000000000000000000084d61745061756c000000146d61747061756c303340676d61696c2e636f6d00000b406d61747061756c3033000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143ab053dc6b6a71e1b4f7f03bebc56ebe96bc52ea5ed3159d45a0ce3a8d7f082983c33ef133274747": "0x040100000002000000000000000000000000000000000f41757265766f69725861766965720b586176696572204c61752168747470733a2f2f6c696e6b74722e65652f61757265766f69727861766965721b4061757265766f69727861766965723a6d61747269782e6f72671078617669657240696e762e636166650000104041757265766f6972586176696572000f41757265766f697258617669657200", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143ae48fb4d4a27b38063f5eee28e6df57ff122966e99dc82b479be3be5be9d627c10c5ea4db744d53": "0x0403000000020000000000000000000000000000000008446176696443431144617669642044616c6c2741676c696f00000c63656f4065766f782e676700000b4461766964456e656144000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143afb6326da17f7c2b27005300822ca95d14188dd385d93db13a6f76c4fc434c192ed476d353fc9df": "0x000000000000000000000000000000000008696e6b2168756200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143b04e47e14f8c9afcc472f8aa3afdab9a0f1abb66088817448690426bacc0af6f509241ae452a65c": "0x00000000000000000000000000000000001142494e414e43455f5354414b455f31351142494e414e43455f5354414b455f3135000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143b1767a9bb0967a7c6b17325907642f63b7e30a9636cb7db2ed22aec146ccad2e0a8991b5568607d": "0x000000000000000000000000000000000005426f7661000000166368656e62616f4063727573742e6e6574776f726b000009406170706f697070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143b484b0dc727b45354825d8d050d0ac046e52f333e820999ac3dacb75f29306eb8233c0caf8ef012": "0x00000000000000000000000000000000000c446f742e616c6572742829001e68747470733a2f2f646f742d616c6572742e676974626f6f6b2e696f2f000000000b40646f745f616c657274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143b4dd5f6332fce89f835522ecf3341305a26c938e8ad09fdf91dca4b9a98b8b0daafccd68ac4a505": "0x040000000002000000000000000000000000000000000ff09f95b454555845444ff09f95b400001a407475785f696e5f74757865646f3a6d61747269782e6f72671774757865646f2d77686974654070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143b8fa2e75a1b9c5bcea3dabe52b2a665b1e19bf8c6913a5d54e06d6413ca3ddbec8f9a22415ec477": "0x040000000002000000000000000000000000000000000644617669640000174064617669643a776562332e666f756e646174696f6e0000000c4064617669646861776967000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143ba0d8c6411833131ac5e7c54f557fcef02102186c742fce89cdda3c1073bb3271d8e91557877c70": "0x000000000000000000000000000000000009627261796f323536124168696d6269736962776520427269616e00001d6168696d62697369627765627269616e393640676d61696c2e636f6d00000e4062726963727970746f323536000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143bba269358278e21860054009a10c600b2d7cb347d672e1b27906a15e26955cc014fe868317a497b": "0x040100000002000000000000000000000000000000000e4669676d656e74204c6561726e0e4669676d656e74204c6561726e1468747470733a2f2f6669676d656e742e696f2f001379616e6e69636b406669676d656e742e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143c0955c5290aa69b8b1cf3b7ea2354781b6355660bd1481fe2e68d5a7a9c7692b54eed3c278e5b73": "0x040100000002000000000000000000000000000000001443727970746f50726f63657373696e672e696f2143727970746f50726f63657373696e672e696fe284a2204f4f4d2e41472049451c68747470733a2f2f63727970746f70726f63657373696e672e696f0019696e666f4063727970746f70726f63657373696e672e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143c096cf3f561e3834026c99cba12d64d1d0e7a7a620bf54374603fcc056e1601e3713f9921671120": "0x04000000000200000000000000000000000000000000114c45505245434841554ee29898efb88f00001c40706f6c6b616c65707265636861756e3a6d61747269782e6f72671b69726973686c65707265636861756e4079616e6465782e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143c29f0e466429f37964df9daa6cae8b790469f83dd63d0650bfc76ae16a67c4cabefdcf25d8d172c": "0x0000000000000000000000000000000000074e6f74696669095061756c204b696d1868747470733a2f2f6e6f746966692e6e6574776f726b2f174070696b616e6f746966693a6d61747269782e6f7267187061756c2e6b696d406e6f746966692e6e6574776f726b00000f404e6f746966694e6574776f726b00174070696b616e6f746966693a6d61747269782e6f726700", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143c790f30d60af3f382ecbf12e0965d08387b8aca42993392dbe5ddd0de48393b96075c641f2c9408": "0x040000000002000000000000000000000000000000000647335251300000124067337271303a6d61747269782e6f726719673372713076616c696461746f7240676d61696c2e636f6d000007404733525130000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143ca7f22618c737cbdedcb9123b5751a728ba18380f2c53b9cfb307cda0a6afdd85a30a3e9205385b": "0x00000000000000000000000000000000000b50617261636861696e7300000018736b6174655f62636e393540686f746d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143cc9562cc3c280496e92f87f2434cffb3afa90a740ede218ffd94189a9a5f216b89de7c74609f047": "0x000000000000000000000000000000000005536f74610e536f746120576174616e6162651768747470733a2f2f61737461722e6e6574776f726b2f0013736f74614061737461722e6e6574776f726b00000e40576174616e616265536f7461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143cca7e3b1fdfe91c74d294ca861109c5f994b079460265f593e736010dff119e1449a2c1519c6186": "0x0000000000000000000000000000000000174d65657475707320426f756e74792043757261746f72001d68747470733a2f2f74696e7975726c2e636f6d2f6b3376366338626d001568656c6c6f40646f746d6565747570732e78797a000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143d38025ab9dda7b272e03b44235444cf15cd1c6f4b028ef714605714a5eb4be2a4013c649bc5c97d": "0x04030000000200000000000000000000000000000000194672657175656e63794e6574776f726b50726f706f73616c0000001d7068696c6970406175746f6e6f6d6f757370726f6a656374732e636f00000e6f6e655f6672657175656e6379000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143d4a76d67fff41d458ea543dfaedae9fe811b7c8cef72335ac41180e0c13d2d9e0bb89c506d44049": "0x00000000000000000000000000000000001061736f6c696d616e2028426f64612914416264656c7261686d616e20536f6c696d616e00174061736f6c696d616e39323a6d61747269782e6f7267000000000b61736f6c696d616e39320000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143d50c330808d23bc48bb96e509af35ac3308a94a3ac2db6e47f0197cae378cd4ca86430bc5dbce8d": "0x00000000000000000000000000000000000631325745421757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143d606081b82ba5aa0851213d7b0d4ef3edf4f62f7b0d3dc92edaad32daddb3c51b4ec205ec9c7779": "0x0000000000000000000000000000000000084f55544b415354001d68747470733a2f2f6c696e6b74722e65652f6f75746b6173746e667400166f75746b617374736e667440676d61696c2e636f6d00000d404f75746b6173744e465473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143d6510d934b941c5feba71d41f307c6b4c59481cfb3a5d732175f7766aca821e98b1ffa8ea9f355b": "0x00000000000000000000000000000000000a4669676d656e742037001368747470733a2f2f6669676d656e742e696f000100000b4669676d656e745f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143d7b57c9bab601df742f10a2b57e5ec3247c0ae6da2a2fdb4a731324dc7a2edfe0f4fc761e1a4d3f": "0x04000000000200000000000000000000000000000000094d696368656c6c65000016406d696368656c6c65783a6d61747269782e6f726700000000001336303833373436343939373331313330313400", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143da7764530213aeaace846bae7cfbaa4ddb3d59d4bbaccd5d0b23bc3fc2cdf2194600bdab81b2972": "0x0000000000000000000000000000000000056e6f776100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143dc70605572f3709b8db36235621ae2f05e3e35e61a8101af409113d06b17417db649dab460c5c2e": "0x000000000000000000000000000000000015506172616c6c656c2046696e616e6365202d2035001568747470733a2f2f706172616c6c656c2e66692f000000001f68747470733a2f2f747769747465722e636f6d2f506172616c6c656c4669000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143e0a61ef993a58f6b099640796b5d19532ac152deb098b161a0b0d23c6b95c5a72f0ea27e696db3c": "0x040300000002000000000000000000000000000000000d4564676172506572616e746f1d45646761722044616e69656c2053616c696e6173204c656465736d6100001865646f67612e73616c696e617340676d61696c2e636f6d00000e67656e746c655f68756d616e6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143e843a37d45e41d726171b3ad75723bf624a27485e51e4c2fe38f4b2d24ee52b86a979fb772c513b": "0x0800000000020100000002000000000000000000000000000000000843686576646f720e57696c6672696564204b6f70701868747470733a2f2f7777772e63686576646f722e636f6d144063686576646f723a6d61747269782e6f72671263686576646f7240676d61696c2e636f6d0000094063686576646f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143e9ff1da508f2a3c7ccb1907030863dd708764cc88a4b4d09dc5bb0f4c9ef5f4e73cfc0aa4bcdf3c": "0x04010000000200000000000000000000000000000000054572696305457269630014406433636b6172643a6d61747269782e6f72670d6572316340747574612e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143ed5ac38541b55b1cf68aca8c6afda0f57323e21f3aee8bc2630736c2a85c6213c79160b4d711283": "0x00000000000000000000000000000000000e414a554e41204e4554574f524b1c426c6f476120546563682041472028537769747a65726c616e64291268747470733a2f2f616a756e612e696f2f162040726f786f6e746f783a6d61747269782e6f72670f68656c6c6f40616a756e612e696f00000f2040416a756e614e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143edfdd48fc779cd5a80ea94af8a39eb7ba8d9afb913147e67eae84f48aad7b9ce6ee05094fe0394e": "0x0400000000020000000000000000000000000000000005416c6b6f00001340616c6b6f38393a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143ee48405c88be7992aa791b10dcfbe7ee482dfc6700da33db52b3ac81fc8822dee527f8aabcad613": "0x040300000002000000000000000000000000000000000b536972576f6c636f74740e506574657220576f6c636f747400001a736972776f6c636f74744070726f746f6e6d61696c2e636f6d00000b736972776f6c636f7474000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143ef4b38f8ce032ce06b8e579e2c0a3a3b87f1070181254ea66f8e083c00220215b111d117565334a": "0x040300000002000000000000000000000000000000000d446f74204c696e6520446f74164a61696d65204665726e616e64657a205065c3b16116687474703a2f2f646f746c696e65646f742e78797a001a646f746c696e65646f742e706f6f6c40676d61696c2e636f6d00001140446f744c696e65446f745f706f6f6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143f340ae0b8ad2cdc2017a0afa42b831ea0c10e34b8b208eeccfe324169a8d6776921510cb42a897c": "0x040000000002000000000000000000000000000000000e4173746172204e6574776f726b000016406173746172323030363a6d61747269782e6f726713696e666f4061737461722e6e6574776f726b00000e4041737461724e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143f4e772ad45522ecaea3ca653928298cd4d1d64cf916aacf72e4e2ca435453941a73327a8dd0a00b": "0x040000000002000000000000000000000000000000001056696b6b202d20476f7620f09f8f9b0000164076696b746f722e762e3a6d61747269782e6f72672176696b746f722e616d6261737361646f724070726f746f6e6d61696c2e636f6d00000b40786356696b746f725f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143f542ae0e8a4948cf48ad80b7cac41b7805a33923cd8357e7d179c16db083494bddab65845707b6f": "0x00000000000000000000000000000000001b444f54204a445020506f6c6b61646f742e6a732057616c6c657400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143f632b1c99a04492568b83865c932b2538214e98c5b8e4fc4779b9f0dd63788c8911d933b3b53f63": "0x00000000000000000000000000000000000b566963206375656e746100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143f6dc540984e16754c1383fd768ee83c1cd53eee57d10f21bb61eb6d37360fd34565ce35e5c5241f": "0x000000000000000000000000000000000008427574614d4d5300000018736f6d6564617967726f77757040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143fa0b657ef7bbd841e5db30d360532b3bb6a9c0eb447f439bd16fa7be3002bdac10d2a6ce6e03567": "0x00000000000000000000000000000000001141726a756e207c2050656e64756c756d001b68747470733a2f2f70656e64756c756d636861696e2e6f72672f000000000a4050656e41726a756e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143fb71bbdb75b9a868cd54ac24629880ed1f3e6c8d5858ea08b5a7fbaa2c210c79e04223f3f05f35a": "0x040000000002000000000000000000000000000000000a526f62696e686f6f6400001740726f62696e2e686f6f643a6d61747269782e6f72671f726f62696e2e686f6f642e76616c696461746f7240676d61696c2e636f6d000000000c726f62696e2e686f6f6f6400", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143fd48a75c1748c9c8e1ad9a11d5366e823c79dfb0b4416853734464245fb93d9ba62e818cbffe516": "0x040300000002000000000000000000000000000000001143726970746f204578706c6f736976611c46656c69706520416c62757175657271756520646120526f63686100001e6d657461766572736f64617363726970746f7340676d61696c2e636f6d00000f66656c697065726f636861747631000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471440211a7f8ab7a9a03c757ba7f937e877ce2171c04b729b5fcdf7bb4d9f11c46dfc50212664e5cd08": "0x040100000002000000000000000000000000000000000f5a6869786920496e7465726c61790c5a68697869205a68616e670000127a6869786940696e7465726c61792e696f00000e406e696b6b695f73756e73657400175a68697869f09f8f96496e7465726c6179233730333500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471440935ff2a98db16d44cb8281a79f264f66e42069baa12cb82c312afc38e4c09258b246cfc5752f4f": "0x00000000000000000000000000000000000a44616d6a616e444f541344616d6a616e204b727a69736e696b204d2e00001a64616d6a616e2e6b727a69736e696b40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471440a080abf9c0d1738465abd5a02f5b42b23e323b73e52416514460b9a3e7c34c94ed8d9f986c3d6e": "0x00000000000000000000000000000000000c536b616c6d616ef09f90a200001440736b616c6d616e3a6d61747269782e6f726713736b616c6d616e407269736575702e6e65740000000a6472736b616c6d616e0000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471440b2bd2f7def6a3b80be87a5561edbd79c1ac4606901d84d1b4e185c26ac139cfc4ac12413d26d6c": "0x00000000000000000000000000000000002042494e444d494e543a20616e792d77616c6c657420616e792d62696e646572000016406e6f7474696573746f3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714410472dcbca97371353b66bebdd4061939ffb1a79127e46d4c262bb8548e4a052f2087706cd4cc62": "0x00000000000000000000000000000000000c436f6c6c61746f7273696f0c436f6c6c61746f7273696f1568747470733a2f2f636f6c6c61746f72732e696f0015636f6e7461637440636f6c6c61746f72732e696f00000d40436f6c6c61746f7273696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144137b87771b2fd4e981bc48f19eab52de7f8c981822cc15f26990d5e90faba03e15894c0daf39759": "0x000000000000000000000000000000000015506172616c6c656c2046696e616e6365202d2034001568747470733a2f2f706172616c6c656c2e66692f000000001f68747470733a2f2f747769747465722e636f6d2f506172616c6c656c4669000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714415c4423d7d007052511a0306373926c509df110cda6e83fe525b6cc5564a9cf397ecefeeb57413e": "0x00000000000000000000000000000000000c526567656e63792d3031301757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714417aa25e24e3a895b46b21246e25a4882615af17b38863ad0b757ec4242f7fa58ce70462c0c4b246": "0x00000000000000000000000000000000000e4d7920444f542077616c6c657400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471441c47496ae1126564a8646cd9813bde9f62216e463129227292ac57963a50e3f4184220ef8163052": "0x040300000002000000000000000000000000000000000b506f6c6b614d6172696f104d6172696f2053636872616570656e0000136d6172696f4073636872616570656e2e657500000f6d6172696f73636872616570656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471441e29c1629f394e1e4a77c09a5e7cca4340cd6ce8dd3cf6dfffacadaab7bd6581b7ca50959834271": "0x040300000002000000000000000000000000000000001553696d6f6e2040204b65792050696374757265730e53696d6f6e204869706b696e7300001673696d6f6e406b657970696374757265732e6f726700000d404b65795069637475726573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471442322010c0d1a89d36f6612bdd0a99e13fc4b24f30fb4522c13e2c2dfc3cd3fdcb44a2eb8d94c972": "0x040300000002000000000000000000000000000000000a4d722043727970746f0743727970746f00001969736161636d636d616e7573313040676d61696c2e636f6d00001140497361616363727970743433393534000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471442817abe7768122ad62aa3f00ef7f4e99f6dc2b160ed54d22142d890e4589effd93159596db40a5d": "0x0403000000020000000000000000000000000000000005416e6e610d416e6e61205275626c6f76610000167a756576612e616e6e6e6e40676d61696c2e636f6d000011406d6f6f6e7072696e63657373616e6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471442e8554be4de706545f4c317ada07d49eba49a3c0efaaa1e59283fbb081aca1c62b1826031ab68b8": "0x00000000000000000000000000000000000e42616e642050726f746f636f6c17576f726c64204461746120436f72706f726174696f6e1e68747470733a2f2f7777772e62616e6470726f746f636f6c2e636f6d2f001462644062616e6470726f746f636f6c2e636f6d00000e4042616e6450726f746f636f6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471442f5d87995df46aba849437f5f8b602fc9a4210d6a9834af4adc6ce7492861bd0f5b88d11919cd7b": "0x040100000002000000000000000000000000000000000d43525950544f20504c415a410d43525950544f20504c415a411868747470733a2f2f63727970746f706c617a612e65732f00177374616b696e674063727970746f706c617a612e65730000104063727970746f706c617a615f6573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144316433e1f50b4c3a66e0f4e1a121cc83fddf3096e8ec8c9e9c85989f276e39e951fb0e4a5398763": "0x00000000000000000000000000000000000a67696c6573636f70650b47696c657320436f70651968747470733a2f2f67696c6573636f70652e6e696e6a612f000000000b4067696c6573636f70650a67696c6573636f70650000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714431c4c64db68d8bc2211d6fce26d7140904357fce2aca5d1e63b362f1789bb6d7dbd848d3df79c65": "0x04000000000200000000000000000000000000000000084d6172636f526f000000196d6172636f726f6d616e6f77656240676d61696c2e636f6d000009404d61726330526f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714431d3bd5ffac15fd908006776baddcbd6ee1037b124dce04923c13176eca8a467612a1bfe471184c": "0x000000000000000000000000000000000006757262616e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144346ad63c2bfe5464174ed6a137e6df4c9dbbc1ef6fd102a67295edb937fe7446b0a38930927bf16": "0x0000000000000000000000000000000000084d75726977616900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471443496d81af6ed7735855f6f9634a68990a917f22cda160e53f14a0bab251926d946650b4df53412f": "0x04000000000200000000000000000000000000000000217370617a636f696e5f4368616f7344414f5f496e74724b696e745661756c7473000000137370617a636f696e40676d61696c2e636f6d000008407370617a7674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714434ad746326c40551646bd1c80f91d01409be58ff6e426f857aff02f544540e2b5c7b54c6d4a3e16": "0x040300000002000000000000000000000000000000000753756d6565740c53756d656574204e61696b00001568656c6c6f4073756d6565746e61696b2e636f6d00000a73756d656574776562000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714439f39607719f9fb7026f145d6eb23143d729bc300e35203a831fb08b315235032e2527a659f6c29": "0x00000000000000000000000000000000001a506f6c6b61646f7420526567697374726172233120546573740000001d63686576646f722b72656774657374646f7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471443c450490ea5a0dfaa1e41806e32999e0754be06b02cf2cd7397d7449111cd16757b6a846b9cdc54": "0x00000000000000000000000000000000000e636f696e766572736174696f6e057061756c19687474703a2f2f636f696e766572736174696f6e2e696f2f000000001040436f696e766572736174696f6e5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471443d4cb05677396f618812f78e7c7d0769e2050a07e54d7d26ef922f2ab3e45d66f0289d5dd1deb08": "0x040300000002000000000000000000000000000000000754696767616800000014746967676168406d6f6f6e73616d612e636f6d00000f407469676765727363727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471444000dd1889b03b1be415da93670251b3c219aff9d1069ef99d27a453620c20d9b4dde4739caa55d": "0x0400000000020000000000000000000000000000000009706965726f20672e000000000000000a706966726167696c650000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714444f277f5dcf70d79848dbbf16e1a48ac57884a4d2a3d64ed6784969927e04129066877ad098a009": "0x0400000000020000000000000000000000000000000015526f737320616e64204a6f656c207c204a4b5242001068747470733a2f2f6a6b72622e696f0010636f6e74616374406a6b72622e696f000009406a6b72625f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471444646f06f20d51883c017930b46ab5a4413bf3153b001287ed5ff7fdbd2734cf69abc843f4ee0447": "0x0400000000020000000000000000000000000000000017f09f909f59656c6c6f7746696e2054756e61f09f909f00001940626c756566696e5f74756e613a6d61747269782e6f726713616e74756e40747574616e6f74612e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144473d1741e91e5149a137cacb7c5e216b12fda7a62c853c15ff93d8f0bd0c8b19520c3ec689df366": "0x04000000000200000000000000000000000000000000084d696c647a73750000000e6d696c647a737540706d2e6d6500000000084d696c647a737500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714447e1613a9d973af08d48a00b01356b80f40e50f281c2cda9e858f45a1bc8e989b3eedfb27dfe044": "0x04010000000200000000000000000000000000000000094252415f31362d4400000016637074636f7272656f6f6640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471444807460d777b1493446e1bf0c0eb4682d4b7269c0b0459685dd3cdb024467ec4f01f6e878df113a": "0x0401000000020000000000000000000000000000000013546f626961732041697264726f702e636f6d0e546f62696173204b75737465721568747470733a2f2f61697264726f702e636f6d2f1440746f626961736b3a6961627369732e636f6d15746f626961732e6b4061697264726f702e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144497480ac18f14a6cc267824fecaa355e8b540102fc0386dc902d068e1099f5d64f9bdfad8e6b936": "0x00000000000000000000000000000000000b53756775616e677275690000001773756e62696e674070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144499fd1a049d4b87923e75ccccb33e471161db9558583ef4668de361bdf471e674256e8fe0748706": "0x040000000002000000000000000000000000000000001d50726f6d6f5465616d207c20416374697661746f72207c2052756279000000166f70656e676f7662726f7340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471444ae3a94bfb51fab3e5ec4b057a0f4b697e048bb02918c5c07998f08ade9e7b6a31ca6ddf3956442": "0x040300000002000000000000000000000000000000000b416974696a696127657200000019616974696a696165722e696e666f40676d61696c2e636f6d00000b40616974696a69616572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144567817f570fd2a7d4780b9e5750a1a1772e61c81d02fb63c88815de6c2f5e1123a2915a4dfa1143": "0x00000000000000000000000000000000000873616e6368657a0e46617a65656c2055736d616e6900001966617a65656c75736d616e69313840676d61696c2e636f6d00000e4066617a65656c75736d616e69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471445710aad85286ba2f61e1319acc0189207ad27455845c7d7b60ded1be7c50279c04cea4d89835759": "0x040300000002000000000000000000000000000000000d4976616e206f6e2054656368104976616e204c696c6a6571766973740000126976616e40696c686f6c64696e672e736500000b6976616e6f6e74656368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471445a26c6e9f4fbc9e1a93333836f4c417e6a25d826a06d994d688a791f31a2ffe77eb6f0b11074575": "0x00000000000000000000000000000000000c57616e677368692e65746807e78e8be58d8100001677616e677368692e65746840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471445b8ad3d042acdd1361d8fe50e87561a6623c67f9ad530973749b54f8015c29ce0b234de9f942e45": "0x00000000000000000000000000000000001044617669642059696c696e67204c691877656368617440446176696474686550616e6777616572000014646176696440666f757269657270722e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471445d43cb8401e3564f40cd7a2181289e32776625b9f3a193f749e33ce1bdeb76cfaabece606c7324c": "0x040000000002000000000000000000000000000000001768656c69787374726565742e666f756e646174696f6e00001b4068656c69787374726565742e696f3a6d61747269782e6f726711744068656c69787374726565742e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471445ec95bcb8dd897248d5f568124b09fefe504a22bbce2ccee0fcae9262c639b6b2ebaf95b5c8fe77": "0x04000000000200000000000000000000000000000000175368616e6b6172207c2045646765776172652044414f0f5368616e6b617220576172616e67001a407368616e6b6172776172616e673a6d61747269782e6f72671b7368616e6b61724065646765776172652e636f6d6d756e69747900000f40576172616e675368616e6b6172000a7368616e6b61722e7700", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714464cfe5f5087e90778875e66122277dc5609bad6a10ec246d89c1bd30c549ef3d839d2bc2f78af1a": "0x0000000000000000000000000000000000094a6179506f6c6b6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714465cbd752cabb7fa409b7555f513abf3af9740d09b7a47d7c2ce84dd3b146a791dfd28d8e0abae75": "0x000000000000000000000000000000000010706f6c6b61646f742e676976696e67001868747470733a2f2f706f6c6b61646f742e676976696e670015696e666f40706f6c6b61646f742e676976696e67000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714466588a6e1073ed4aaa806fd8ff8e363c4f3139c07bd115f3879de52f9961fd61f58eb1610ef6836": "0x0000000000000000000000000000000000074c5020444f5400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446720693a520effa96f8ff6a5803682aa883aebdb426940851c7de4cc302e540a4822d63e1216c71": "0x000000000000000000000000000000000014476d656973746572207c2045646765776172650e432e20476167616e2042616275000019676167616e4065646765776172652e636f6d6d756e69747900000e40687573746c65346c69666537000a676d6569737465723700", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144672db3439b14d041e5d733c17f21e33af639896e0e959ed44cdd05f44d67f60e8311022dc90d51a": "0x040100000002000000000000000000000000000000000f51494e57454e2e3136384e6f6465001468747470733a2f2f3136386e6f64652e636f6d001771696e77656e40776562332e666f756e646174696f6e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144692967bd2332c08b22f88d05ca6fdb70235b599b99c69f927ed71163c2ebc11c9649d678a8ba84e": "0x04010000000200000000000000000000000000000000094c6974656e747279094c6974656e747279000012696e666f406c6974656e7472792e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446955dc79999f928ddd3e0632b74f5e8d57de6814a16b6451366eb903a7943ed00051e7cca5d24d2": "0x040300000002000000000000000000000000000000001050617269747920536563757269747910506172697479205365637572697479000014627567626f756e7479407061726974792e696f00000f706172697479746563685f736563000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714469f989f6ca51c58f3b15e49aede08aa29d7400da8d3b4fdbd284b5bb1f1af1a53a8c47398f1f093": "0x040000000002000000000000000000000000000000000b424545465920f09f90820000134062756c726f673a6d61747269782e6f72671f73766562697261642e7072697469736b6f76696340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446a18621916cf2627efce294aceebeb808ff4ab99930030a5182be918fff1261ca5c5b41acbf6f11": "0x00000000000000000000000000000000000c526567656e63792d3030331757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446a8b45a25e83bcdea16fb2015c85c938d41f946c5fcf6c310872e30ec541c81fd2108e7d1b89813": "0x040300000002000000000000000000000000000000000f4d65726b6c6520536369656e636521537461636b7365657220546563686e6f6c6f67696573205074652e204c74642e0000196e69726d616c406d65726b6c65736369656e63652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446b9cd597eba686fe4a48b16cd6a6c6c44e4c9542e923726dc861077b6a4ff3df1969b13a6868b2f": "0x040300000002000000000000000000000000000000000d5061756c6b61646f74746572000013407061756c6b613a6d61747269782e6f7267177061756c6b61646f747465724070726f746f6e2e6d6500000e407061756c6b61646f74746572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446cfb8d6f019ac35a002a7d2c93a1e4c5f3ed5e95b06862f91cc8f914c64ba3fe844b35ce36ce151": "0x00000000000000000000000000000000000c4369746164656c2e6f6e65104369746164656c2e4f6e65204c54441568747470733a2f2f6369746164656c2e6f6e652f0014737570706f7274406369746164656c2e6f6e6500000c404369746164656c44414f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446d4ef367550b68d2a0783588d2ec76c02517d1465e08cc3e5964ae9b3b3215bb598489989f62119": "0x04030000000200000000000000000000000000000000075a454e495448195072616e6176204368616e6472616b616e742050617761720000197072616e6176637061776172406f75746c6f6f6b2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446da05f48ba08b97e60b065719963027baac7cb4d68145539a0b428aa74048ec1c32b6b255530646": "0x04000000000200000000000000000000000000000000084e45574445414c000015407061726964655f663a6d61747269782e6f72671c6e65776465616c2e76616c696461746f7240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446eb4c71c2ad15c3f85bd4ec9a558cde3f05e33b0b74f9e732cc41f904894873247d4c435a3b8b63": "0x040000000002000000000000000000000000000000001d4d4554415350414e2028616c736f2074727920504f4f4c20233138290d6d6574617370616e206c74641568747470733a2f2f6d6574617370616e2e636f6d000000000d406d6574617370616e5f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446f3d1d0510badd5763735fed6d0ce2b2909c3365eccafaeb1ffcc2a10af6060a637b1dacff01616": "0x04010000000200000000000000000000000000000000184c697361277320506f6c6b61646f74206163636f756e740000000f6c697361407061726974792e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446f59e6d908bc0ec8488bea263878e7e16be0a8c4705f9729a5f25462bff7dc7f2d8346370c8ef65": "0x040100000002000000000000000000000000000000000e53504143455f494e564144455200001a4073706163655f696e76616465723a6d61747269782e6f72671b7370616365696e76616465722e646f7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446fca39721ec26e31ee933d8dc66947b2826fa57de49b62e7d9201326cd9cc01abcd8bc06c35c02b": "0x04030000000200000000000000000000000000000000084269744c696f6e000000196269746c696f6e32314070726f746f6e6d61696c2e636f6d00000a404269744c696f6e33000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144702815fa4f5b7fd02251a6e0194f2ee97f988a8f2e779a06a73b2ee3e1a54f413a3b9f6f8d04f6c": "0x040100000002000000000000000000000000000000000e6d75737465726d6569737a657217467265646572696b2047617274656e6d6569737465722168747470733a2f2f6769746875622e636f6d2f6d75737465726d6569737a65721a406d75737465726d6569737a65723a6d61747269782e6f7267186d75737465726d6569737a657240706f7374656f2e6465000010406d75737465726d6569737a657232000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714470f8592fcae215df03039aaa27dbd35081f359f8a6aa39ab5dc098c19937617389dd8cd05e4dc3a": "0x00000000000000000000000000000000000b6b736d7365616e6e657700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144719a17064a7613bb9f26de7808ffcf087492fc04a2c00178c3bf9ae512d1fc817f8430f60093801": "0x0401000000020000000000000000000000000000000008434f534d4f4f4e00001540677265676f7273743a6d61747269782e6f726715636f736d6f6f6e40677265676f7273742e6f7267000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471447207f7f4037875fca91a41c974862cae390d507621b3cd9d96c2d8624fde2481d518a61c6b4cf3b": "0x040000000002000000000000000000000000000000000b53796e61707469636f6e0000174073796e61707469636f6e3a6d61747269782e6f72671a73796e61707469636f6e4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714472c11c45d19e722cfc5e71e4781885c9ee4420c55496b1a1b2d95b5cc0eeeaf4459c4ebc5bb8fe9": "0x00000000000000000000000000000000000c526567656e63792d3031331757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714472da44c2d8c63974ebdc7b636074ac97be407593236b00bd410c19fe56ab1b6d1c5db782f0bc17e": "0x0000000000000000000000000000000000044b6f5400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714476ed96b663d19f9d20ee72ee9744e1669971043d3ff9fe7a7223fc3334c87de6b1c6c0b36555c4e": "0x04030000000200000000000000000000000000000000084d6573736172690b4a6f686e2050757264790000106a61636b406d6573736172692e696f000009406a707572643137000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144822d22761cb98521237b750e00e3d48fe0b1629f2a4cf0630971cbf489dfca33e75235347196474": "0x0403000000020000000000000000000000000000000008476b697269746f08476b697269746f00001467756a6b697269746f40676d61696c2e636f6d00000a4047756b697269746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144825a3675ceeb1c2561077519794c195b22f5058bd1195f6847aa6b5a749053d44468ba5db872d64": "0x040100000002000000000000000000000000000000000f506f6c79636861696e204c616273001e68747470733a2f2f7777772e706f6c79636861696e6c6162732e636f6d001664657640706f6c79636861696e6c6162732e636f6d00000f40706f6c79636861696e6c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714484069a0f1cb9062b8d71afc98c6256dfcb316ff7ef0665270537c85ff081db98255159abb5fe017": "0x04000000000200000000000000000000000000000000124e65774f6d65676156616c696461746f720000154063656c726973656e3a6d61747269782e6f72671363656c726973656e40676d61696c2e636f6d00000e40506c61794e65774f6d656761000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144874818619a271dd4725fa85860f87917edff507310721c0cb930595fe16c829f536fb1289e4a852": "0x040100000002000000000000000000000000000000001177656233726479206d756c746973696700001440776562337264793a6d61747269782e6f7267136d6973636137303240676d61696c2e636f6d00000a406d69736361373635000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714487b7409ae4dd68d8e706d0bd734b0cf21ccbfc5ca90cd9dc03ef4d0be9b932bd23727869445105d": "0x000000000000000000000000000000000004414a4d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714488adbd6698f281d1eeb54e0e7e13080dc9dfeb2cf5de7170fc7c84f4fb70cf5c2ca0a5c93b25735": "0x00000000000000000000000000000000000c7433726e2d6576656e74730d7433726e204c696d697465641568747470733a2f2f7777772e7433726e2e696f2f000c6f7073407433726e2e696f000009407433726e5f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714489667186afa0e91ca5bc1915da74aba3aadd7ce7b809045d5eb5b73559259755fdcd85a40a5dc6e": "0x00000000000000000000000000000000000f4a414d20e298a0efb88ff09f908d000013406a616d31306f3a6d61747269782e6f72671768656c6c6f4073686f6b756e696e2e6e6574776f726b000008404a616d31306f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714489b5689523a93fdf4f5911143092b1788c3a91f96d192b35e4fb201f05658f47b677e7dc9a1fd5d": "0x00000000000000000000000000000000000c52484545207c20415041431053414e472d4859554e2c2052484545001140726865653a6d61747269782e6f72671472686565756e696f6e40676d61696c2e636f6d00000840786352484545000a72686565756e696f6e00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471448b1dce0478b5f30daf47069cecf5c31da9a1cfde3732d2b701bf9f94c77ba7e99335d6b30ad080a": "0x040000000002000000000000000000000000000000001856462056616c6964696572756e6720f09f87a9f09f87aa001b68747470733a2f2f7777772e76616c6964696572756e672e63630017636f6e746163744076616c6964696572756e672e6363000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471448c106532e2fbcf5ec05f950e080aa04f8ef335280637c8c80fa6b8bf54d5a3bbfa746b9f9da5860": "0x0400000000020000000000000000000000000000000006506c7573560000000f706c75737640706c7573762e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471448cdedeb02681e28ac891d5a6e2f56c923dcff8c05d0a535c6695a118bf3de7ed3bab92ff7db641f": "0x0000000000000000000000000000000000144a6f6e617468616e202854616c69736d616e29000016406a6f6e7064756e6e653a6d61747269782e6f7267166a6f6e617468616e4074616c69736d616e2e78797a00000b404a6f6e5044756e6e65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471448fd29f3f7e12961b4ddcbdb50b550740253810978125ded4acafacccfdbf9e2cb3bd031c9291388": "0x000000000000000000000000000000000013636f736d6f76657273656d756c746973696715636f6d706f7361626c6566696e616e63656c74641f68747470733a2f2f7777772e636f6d706f7361626c652e66696e616e63650018696e666f40636f6d706f7361626c652e66696e616e636500000f40636f6d706f7361626c6566696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714490130ac826416f286f68361d0a346a62be267558e72dfb9e3b5a04adcc2c9e46fb7b9482f7c876f": "0x04010000000200000000000000000000000000000000094b6565704e6f6465001968747470733a2f2f7777772e6b6565706e6f64652e78797a11404472756e3a6d61747269782e6f7267156472756e2e6d6167696340676d61696c2e636f6d00000a404b6565704e6f6465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714496b2311f8412ae280a4a5a4e8e8c8ce6b19bd926a83efa02d70a6137d9896c627eea987e10d3655": "0x0400000000020000000000000000000000000000000007444f546f6d6900000019617374696b61696e656e746f6d6940676d61696c2e636f6d00001040546f6d69417374696b61696e656e0014546f6d69417374696b61696e656e233632343900", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714498085158358a41ed824263a2ba0b39e43b2a1fb591c68743ca504c2ce6c3c2aa96e58b6269d3115": "0x0400000000020000000000000000000000000000000016f09f9a82205a756769616e204475636b20f09fa68600001840726f626572743a776562332e666f756e646174696f6e17726f6265727440776562332e666f756e646174696f6e00001140526f626572745f48616d62726f636b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144980dd5ac2100210047e68bf811eb225dae8c88461df5edfc581c80c460a31672c36d53ca0164b0b": "0x000000000000000000000000000000000008617234766f6c6b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471449834f6d0d98c2caf4f7e8c9dcf45daa322fa14585d8f14a37aceca839106ed3414bb04778696145": "0x0400000000020000000000000000000000000000000009636c616e67656e6200001240636c616e673a6d61747269782e6f72670000000009636c616e67656e620000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714498684a38db4f62054c56b5010033b3c17a5677cd9bc45b2d6c5d24b7590b7681bceac60b0f3833f": "0x0403000000020000000000000000000000000000000019546578617320426c6f636b636861696e20436f756e63696c19546578617320426c6f636b636861696e20436f756e63696c00001f6c6565407465786173626c6f636b636861696e636f756e63696c2e6f726700000e7478626c6f636b636861696e5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471449891bd977a475d4fa150742c53997a227cb5648c21029d8a6a087ea1c27c502903aa60ef7701823": "0x040000000002000000000000000000000000000000000d45524e2056454e54555245530000001c65726e63727970746f76656e747572657340676d61696c2e636f6d00000d4065726e76656e7475726573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144990ff033d5343d5a85e37331d7b706f90745bd7e4ad7ae82a83beacf5a585f69fb4afd10704a71d": "0x0000000000000000000000000000000000085261626173736f0f4a6f73652046205261626173736f0000146a667261626173736f40676d61696c2e636f6d000009407261626173736f00156a6f73655f67656e65726963636861696e2e696f00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471449aa36a5cacb5456d4539a7dceeeba9999b6387e9431e83c53f4b884edf5cf049623110eae570125": "0x040000000002000000000000000000000000000000001f45617420507261792056616c696461746520f09f8db4f09f998ff09f96a5000013407978313178793a6d61747269782e6f72670c4f5456406570762e6c6f6c000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144a3ab523f50a954b22d05d25884419493436b157e4f7ca725b885d6e328f7c09849c7c12395aec50": "0x040000000002000000000000000000000000000000000650524956490000144070726976695f6a3a6d61747269782e6f7267186a756c69616e40707269766970726f746f636f6c2e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144a46ea11348a56200a66532a23c418cca12183fee5f6afece770a0bb8725f459d7d1b1b598f91c49": "0x00000000000000000000000000000000000d44617277696e69612044657600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144a4e353d6c92b4f6fc5f90e8fb39b1656b5a018d5fa169f80a4ab3fcd03b3d46e2acdb3ae3fc8174": "0x00000000000000000000000000000000000f4a65676f72207c2050617269747900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144a69dd5ac19d5ad6743037278f95ee81a2cf5a59518d3dd440611989cf8dd826811accf784a9ff2e": "0x0000000000000000000000000000000000044a7572001068747470733a2f2f6a75722e696f2f000d68656c6c6f406a75722e696f00000c406a757270726f6a656374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144a7360f6b774d3fda84ef8c0efdd519e001cb3f5b6351725178283edf1b122a464f0a0f425699759": "0x00000000000000000000000000000000000b4c75636b79205465616d0000000000000b404c75636b7944617070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144a7a8224146595f932ab6289334629c2011e3bbcd7742c9aaa5501d440a5ab5d76b42704ff2baf6f": "0x0000000000000000000000000000000000074d6175726969114d6175726963696f20417274696761731768747470733a2f2f7777772e6d61757269692e636f6d0010696e666f406d61757269692e636f6d00000b404c6c634d6175726969000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144a894c423d88cda06cc6b537b36e5f7347ad0daaebd9f5fa22be1e4b8bc68a58c8ee57d43b4d2e70": "0x04030000000200000000000000000000000000000000116d6968616a6c6f5f7061766c6f766963114d6968616a6c6f205061766c6f76696300001c6d6968616a6c6f7061766c6f766963343040676d61696c2e636f6d000009404d70636f6e6e30000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144af14bc1b4b0280418d30040a8245c5ff17afc9a8169d7d0771fe7ab4135a64a022c254117340720": "0x040300000002000000000000000000000000000000000c456477617264204d61636b0c456477617264204d61636b0000126564406564776172646d61636b2e636f6d00000f406564776172646a6d61636b6a72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144afaabe16b988c8244f1bc09ae85c878c320783337f5991e4a172d3daded474eaf772069ac48b811": "0x000000000000000000000000000000000013414d4920426f756e74792043757261746f72001b68747470733a2f2f6772696c6c6170702e6e65742f3132313731000000000d40616d69706f6c6b61646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144b0852ee2d8116607454e2120a4f7b4eddc39c681fea50a8366b39c176e7393913bbfaca5649a450": "0x0400000000020000000000000000000000000000000016506f6c6b61646f742041504920446576205465616d0000001c706f6c6b61646f742d6170694070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144b11703c47136f3474b0c404b20bac28ded8d662e2eae7ddc52988cd5a22d5de09259258395dc45d": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144b33ce1e975a619404d3773ac89f099d5cd7257a72a53b7877935fe84065dff6ae95c0ed1ce17e63": "0x04030000000200000000000000000000000000000000104845524f49435f6f6666696369616c0a4865726f696320415300000f68617267406865726f69632e67670000096865726f69636767000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144b688debd0defa3c60c02d8df757b0af6de882ebc51bf2bba0cdeb949e6ad76331628768fccbd743": "0x00000000000000000000000000000000000b506f6c6b61646f74203200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144b6b6385bf015c077a31de6245e807c4398025994cefc7ceb4bdbe252c4590e732c99698691b666f": "0x00000000000000000000000000000000000f426c61636b626561726420444f5400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144bc239eae76c6ad1fe5cd339cdd38f39283d20c2352716e68153deb3267c7a5d543c394814e88e04": "0x04030000000200000000000000000000000000000000044a61790a4a617920506f70617400001b636f6e746163742e6a6179706f70617440676d61696c2e636f6d00000b406a6179706f70617430000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144bd6e2ebc6fe2e047b72f47f4a630d6a3c03d7499a70092a183cd5a2541afc72ab8301ba640f4821": "0x040000000002000000000000000000000000000000000645617379410a4561737941204c74641268747470733a2f2f65617379612e696f2f000f68656c6c6f4065617379612e696f00000b4065617379615f617070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144bed375fad94bd6b2ccc353342d8ed955553be5ae666a0b2f05db798bb6a213ded13f25b7af7bf54": "0x0000000000000000000000000000000000054841534800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ca0ff14934456cd32cd9b54bb73288503c7969f219ab74a83cb5b8bc2672ef472b7b7c43d866533": "0x0000000000000000000000000000000000124f6e2d636861696e204964656e74697479064a45524144000017627573696e6573736a33383640676d61696c2e636f6d00000e40627573696e6573736a333836000b4a65726164233130363500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144d2dafa5e265f20094ecf114c292f2a24ff6dbc3dbf8311be37ef53f7e78c9d1a59d0c5762cac672": "0x040000000002000000000000000000000000000000000a66696e616c6269747300001240617269666b3a6d61747269782e6f726717696e666f4066696e616c626974732e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144d35c327c115f99b08745476e8a2fb16504c77a75b2dd20b6f56cfb71c87125f1707a702753af24e": "0x00000000000000000000000000000000000642726561640000001762726574746b6f6c6f646e7940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144d466d1a5e9c13dfc483215a3e72d171dd71c55d3885dfa73a40385682f9fe4ced1e811320265714": "0x0800000000020100000002000000000000000000000000000000000c56616c696461747269756d0c56616c696461747269756d00001656616c696461747269756d40676d61696c2e636f6d00000d4076616c696461747269756d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144d4d81d0048d154f680529ad3b92e92ee8955e6a50109c5f12c1b50be62fa4eb82f66ef62400ccd9": "0x040300000002000000000000000000000000000000000f547261636520416c6c69616e6365002168747470733a2f2f616c6c69616e63652e6f726967696e747261696c2e696f2f001a616c6c69616e6365406f726967696e2d747261696c2e636f6d0000104074726163655f616c6c69616e6365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144d51d2cbac595fa87056ac3306e0fca5ef9784e7d34b1f72af8e2650a29f0b3ce50f86df501ce858": "0x040000000002000000000000000000000000000000000c7777772e6973672e64657619496e666f726d2053797374656d732047726f7570204c4c431d68747470733a2f2f7777772e6973672e6465762f706f6c6b61646f74144069676e617465763a6d61747269782e6f72670d696e666f406973672e64657600000d40696e6673797367726f7570000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144d538289bdc31db0d05099da3d810eceb0001840b3ebbeac4b8b8b230ecbc4988a5b2f131aef4835": "0x0000000000000000000000000000000000135354414d207c2054454143484d454445464900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144dabfd58e995e46fa4a7835edb8c6b0d10b32c76ddd9560feb4894fcfb61593accd8c7451e96562e": "0x0800000000020100000002000000000000000000000000000000000c45726e7374204b696e74730c45726e7374204b696e7473000012706c61736d616a61636b406d652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144dd03705d9d21ba9efbb245a877c2ee64cf822cf8ce58907ceec0d4481746da50d533a386a8c4cde": "0x00000000000000000000000000000000000c526567656e63792d3030391757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144df55d839183b50360b5acfd88341f7df867518c44929c114775a3457f3496d29dd231cca9499143": "0x00000000000000000000000000000000000f43727970746f2e536865696e69780000001963727970746f2e736865696e697840676d61696c2e636f6d00000940736865696e6978000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144dfaf303c80f7947c618838a7cda0fba033eac4b3df3e2b31e1b304765bf98004eb72690fc117f09": "0x00000000000000000000000000000000001142494e414e43455f5354414b455f31341142494e414e43455f5354414b455f3134000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144e4f1bf6b4d19f047a3f515334d24cd37b65d4b1c5838cc7c34951a67f3ae2da041a6e2385d8da05": "0x040300000002000000000000000000000000000000000d427261766542726f7773657213427261766520536f66747761726520496e6300002069742d736572766963652d706f6c6b61646f742d334062726176652e636f6d000007406272617665000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144e5666c0de8b6c84ac2752e0009c6ffc103fd1a723726affbd91d6b8e65ddabbeff28fe14a93b678": "0x0400000000020000000000000000000000000000000012646563656e74657265642e6a656f7269630000001a6a656f2e72696340646563656e74657265642e73747564696f00000000086a656f2e72696300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144e5736534181ad78b690df84dc61bb1b04bb3e5483678390a44eca9ee4a748e98f526e126c19c702": "0x04000000000200000000000000000000000000000000064c65676f73000012406c65676f733a6d61747269782e6f726711706f6c6b616c65676f7340706d2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144e5ef662a865543dea9196cd611c7e79bbca036076b2ffd2f684421ba82134c29e84a1e40479b309": "0x0000000000000000000000000000000000146e6963686f6c6173207c20646f7420706c61790000001c6e6963686f6c61732e646f757a696e617340676d61696c2e636f6d00000a406e69636b646f757a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144e6885d639fed568e0d1e848ba9cf7ec704b12a0f1e2381e42c8a4a4d55f40625de6d60c39ebc032": "0x040000000002000000000000000000000000000000000978634b7265736e61000013407368613838383a6d61747269782e6f7267196b7265736e61737563616e64726140676d61696c2e636f6d00000b406b735f736861383838000c4b7265736e61233333333300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144e883ef525616aa09096cbeb77c7810fd11cdaf9e53f64d20e43e41a437ecf8db2c5a7ad98c89c24": "0x040000000002000000000000000000000000000000000e546563686e6f4172746f726961000000186172746f7269616d617374657240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ebb87c523e02c41a87f7dc3c8fd5d0b2d229e4fcb9aacda9427025218f69627ba1a2b82a07bb451": "0x04010000000200000000000000000000000000000000104f6d61646f7965204162726168616d104f6d61646f7965204162726168616d0000196f6d61646f79656162726168616d40676d61696c2e636f6d000010406f6d61646f79656162726168616d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ebc48c63a5dc09fa4ac69b3ea42acebe4f70767ee894eeef5eef1f011f0dca45097a2e6c40c5366": "0x04000000000200000000000000000000000000000000036635000017406b7573616d61323233333a6d61747269782e6f72671e6b7573616d616b6f736d6f73696c613232333340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ec6dcb09516ac9cae463a6613cae63a77d1c391bb1e00a974ccd178ebd91e00268608f3a570f84f": "0x040100000002000000000000000000000000000000000d5061736861426f7563686572000000177061736861626f756368657240676d61696c2e636f6d00000e407061736861626f7563686572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ed12f7f95496d053674aa73951219dbd27b3e3fc5847b806c68c1de38fd4f22f9493a461c80e903": "0x040000000002000000000000000000000000000000000b472d444f542e54454348001368747470733a2f2f672d646f742e746563681740672d646f742e746563683a6d61747269782e6f72671467646f742d746563684070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144f50c6bb1b68e3b5944f4742584f6194f1ca08a3dd92d00d059439abb46629f6ea6bc0f6202dbb58": "0x040300000002000000000000000000000000000000000e44616d69616e20416d616d6f6f0e44616d69616e20416d616d6f6f00001464616d69616e40646f78642e6361706974616c00000e4044616d69616e416d616d6f6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144fcc35394dbbfdb0eac8ab5909257a63ef3726ca5824a68902205beb1e58d578ceaba30ab3dfed65": "0x00000000000000000000000000000000000a464c5546464833414400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ff1355416158dcf7c4e85307ba0bb29b098e2f405c673f39b76d77fb012ed5f5c61fc68e1cbff80": "0x040000000002000000000000000000000000000000000f466f726b6c6573734e6174696f6e0000001868656c6c6f40666f726b6c6573736e6174696f6e2e696f00001040466f726b6c6573734e6174696f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145010d8218a994822c290e73cd4a89b696210d9f712410463c89368b6fc4d22ce10207d8f31e5e739": "0x0000000000000000000000000000000000054c58333800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714503214bf4f8e7195eec846c98971c15deb2504433f2946dfa0c01f310d1e7b777b79fe0a1a279054": "0x000000000000000000000000000000000015506172616c6c656c2046696e616e6365202d2036001568747470733a2f2f706172616c6c656c2e66692f000000001f68747470733a2f2f747769747465722e636f6d2f506172616c6c656c4669000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714504497b5432c58213aa53e50cea84e455aaf2f9172db100c8068658ee1234f9bcbde84e5bfe52e54": "0x0403000000020000000000000000000000000000000007446f6c70686100000013636f6e7461637440646f6c7068612e636f6d00000a546865446f6c706861000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471450532746b82002af1ecfb64d5f40dbe9c02df58a8570cd2335acd41a107fe5fce9b3fb4f8d537d58": "0x00000000000000000000000000000000000773757975656500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471450541acb5b3adfcb783677be3528d7c562df11a31317f6138279cd39ef96abba3dd1f38e9896a37f": "0x0000000000000000000000000000000000127733662d7374616b696e672d6d696e657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714505d0ff0b2ffbc1700004bcdcc7d30d597e19c7f87652b69736066b729f7e8543231a10760f8157a": "0x040000000002000000000000000000000000000000000a5354414b452d4f5053000011406876616c3a6d61747269782e6f7267147374616b65726f707340676d61696c2e636f6d00000a407374616b656f7073000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714505e4ce25c0327113230fd173f1cbd58c493f4f6488a8bd7d8594e167a45052ce8eb51f697e9e914": "0x00000000000000000000000000000000000b4d617961204163616c6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714506b81d74d617d923ce9d3e9979b7600344c225b00d470e268d6c38616bafea38027a373ae3c3f3c": "0x040300000002000000000000000000000000000000000b61644c49425f4d5f4d531353657267696f204d6172636865736f7474690000146d6172696e614061646c69626e65742e636f6d000011406d6172696e616d6172636865736f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471450848286e4980cc86ef58fbe5043add10a359ead21248eb5575bd560ec489382cea3a7e360aecb71": "0x000000000000000000000000000000000005482d4d4100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471450aff8b6edbd559bf2529946850f8dd66c794a795a6b01a911f25df007e4cf5f97f38a037380f250": "0x040100000002000000000000000000000000000000000d446563656e74726174696f6e1b446563656e74726174696f6e20547275737420436f6d70616e791968747470733a2f2f646563656e74726174696f6e2e6f7267001872616d73657940646563656e74726174696f6e2e6f726700000f40646563656e74726174696f6e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471450e0223a7f06f4edee2804a63951212e1342a2c01ea12f20153f27b6a5a649ef2e6c7b20d7859f68": "0x0403000000020000000000000000000000000000000015696b68616c65643238207c205761674d6564696100000014696b68616c6564323840676d61696c2e636f6d00000b40696b68616c65643238000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145126d11d32941450dc41188d0dcd6722402508e1eb7601ac5d225c923114ff63aa085f20756fc371": "0x040000000002000000000000000000000000000000000f566c61647950726f6d6f5465616d00001740766c6164796c696d65733a6d61747269782e6f726715766c6164796c696d657340676d61696c2e636f6d00000c40766c6164796c696d6573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714512ee0fca2d67ab7d573535a40bb01903e616a383deed22b5e3ff30e552017d2395e3e75a8e78613": "0x0401000000020000000000000000000000000000000010f09fa49620506f6c6b6153746174730b506f6c6b6153746174731668747470733a2f2f706f6c6b6173746174732e696f16406d6172696f70696e6f3a6d61747269782e6f72671a706f6c6b6173746174734070726f746f6e6d61696c2e636f6d00000c40506f6c6b615374617473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471451affb7adda940b6380329063444b0d709fe60a6bd0ee966c85ee1da8d62faf0bf33c58d8a15f93a": "0x0403000000020000000000000000000000000000000005544f4e491c4a75616e20416e746f6e696f20496e66616e74652043617361646f00001d746f6e692e696e66616e746563617361646f40676d61696c2e636f6d00000e40546f6e695f426974636f696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471451b04076756292749ea8a333af594a76a48fd053a4ac0c48a87cdc5908f5099cdfb053d05cbddc3e": "0x04030000000200000000000000000000000000000000104a61636b2048616c646f7273736f6e104a61636b2048616c646f7273736f6e0000176a61636b406c756e617273747261746567792e636f6d00000f6a61636b68616c646f7273736f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471451b7261dd3a3db7140d9be44e5bbd9bb656741d05142d47c08ffbfd1f0157b5e79626dd51fc5270b": "0x0400000000020000000000000000000000000000000010416c6f6861426c6f636b636861696e00001c40616c6f6861626c6f636b636861696e3a6d61747269782e6f72671a616c6f6861626c6f636b636861696e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471451dd6eaed401198dc44209e13e42fd156130e708866c28b0ac7cbd5b650011411b8979e5670f3a7a": "0x0000000000000000000000000000000000074b534d204c5700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471451fe2259dc584cad041148d9102c91506d9e3e75297536084c9e3c3259ff78e4651ef4c464a04377": "0x04000000000200000000000000000000000000000000064e6f646c650000000000000e404e6f646c654e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714522288fcb9f80cd6c81b22d9b1c398a968215a07a4d62af23b6db994b0c6d6e7b8cf8bdd8c57e82a": "0x000000000000000000000000000000000004444f5400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145268dc052973ededba3ecfd7483cdcdad1132af7d1e8067816009cbd77fc0bc30eafe8d2218a1971": "0x04030000000200000000000000000000000000000000066e696b6f73124e696b6f6c616f73204b6f6e74616b697300164077697265646e6b6f643a6d61747269782e6f72671477697265646e6b6f6440676d61696c2e636f6d00000b4077697265646e6b6f640a77697265646e6b6f640000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714527efcd187a9fe40aa71da79c896004229d1592df63c4091b31356787a87c960e7a58ade7021cd77": "0x040300000002000000000000000000000000000000000a437574655f576973700d43686f726f6e67204a616e670000187377656174706f7461746f313340676d61696c2e636f6d00000b40437574655f57697370000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471452c8ca65b329df6b02f87ce6d066323c92f56d284faaa856ce083f9ba81635464f04fabec453c822": "0x040000000002000000000000000000000000000000001a4368616f7344414f5f4e6f6d696e6174696f6e5f506f6f6c730000000000000a404368616f7344414f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714531481d95ba52af5b2a75e17655fc2753328a8fe1ae22a20c8bb0ae8b7a7c809e8d84289571bcd1e": "0x00000000000000000000000000000000000b4a6f68616e44726f69641a4a6f68616e20416c6578697320447571756520436164656e611768747470733a2f2f6a6f68616e64726f69642e636f6d17406a6f68616e64726f69643a6d61747269782e6f7267000000000b6a6f68616e64726f69640000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145322942d92e4b0ac628524da485cdb93551dab991b7569b96ec32ea8dfab885c0ff21d76f781cf7a": "0x00000000000000000000000000000000000b44415955e88a82e782b9054441595510687474703a2f2f646f7465722e696f14406a6f69656375693a6d61747269782e6f72670d6a6f6965634071712e636f6d00000a40646f7465725f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471453839e0f2882afca84b58d6f589a104d2f4bdd8b76317d55c1576464e22dda803dd94162ba40c398": "0x00000000000000000000000000000000000f4c414f53464f554e444154494f4e164c414f5320436861696e20466f756e646174696f6e1e68747470733a2f2f7777772e6c616f73666f756e646174696f6e2e696f0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471453a80b1cc8a5fa031212f18a064433a237a56022beffd0ca0f0baef317b34c7f6f12b19968f10233": "0x040000000002000000000000000000000000000000000a7464696d6974726f760000154074737665746f6d69723a7061726974792e696f000000000a7464696d6974726f760000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471453c13c992a5e1d2c9a201b14e4207ebacf5b729ff166ffa224bb4b5cfca02bdf9f3823a0e2979064": "0x04000000000200000000000000000000000000000000114c656168404f414b204e6574776f726b0000000e6c656168406f616b2e74656368000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471453ea4f8fb6ccab21e6f540b5dd5f15bf2d3f0eabd392a35bfe76c58cbb36227fb4c29785714e085b": "0x040300000002000000000000000000000000000000000e466c6f7269646157454253454f0d486f706520476f6f646d616e000015486f70652e436c61727940676d61696c2e636f6d00000a486f7065436c617279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714541213aceb4fb60c1859cdd686b9d08a9fb3bc6b4c20b794339e028aa7300454deaaff5b5860200f": "0x0000000000000000000000000000000000084b4a646f74343400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471454259ba3fa998087a0d16c9a998cb8884bb937cc6192b7e962151cc0c19529d7aac7491f0617457c": "0x040000000002000000000000000000000000000000000a53746173526f766572000016406b61346f6b313333313a6d61747269782e6f72671873746173726f7665723133333140676d61696c2e636f6d000000001373746173726f76657231333331233632363300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145482a19c5b8df37d1e727755b4af4ed6b10e91b550ed5e30bfcd1d3eedec76e159e137ddf5fe9223": "0x040000000002000000000000000000000000000000000e42616d42616d2057616c6c65740000001662626d6f6e65796261677340676d61696c2e636f6d0000114042616d42616d527567677942616773001542616d42616d4d6f6e657942616773233738303300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471454a7cd8dd3cde7aa5ef0603406fea5cef09155727ee3f76c528d688ea48a5f0183bfb06bce5f7b20": "0x00000000000000000000000000000000000a636861696e796f646100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471454aeea67769129fb946d9ac73a5f11a32e8c8709d631304d2db1ebbbca156fc86b9f438286363814": "0x00000000000000000000000000000000000c426c6f636b6461656d6f6e001868747470733a2f2f626c6f636b6461656d6f6e2e636f6d0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471454d7e633409fc98ca61cffec64bd3d89d7195fd423998178d8a4e6a0593ea5ced602f43d2e5ca346": "0x0403000000020000000000000000000000000000000009437361696e74303200000014637361696e746e303240676d61696c2e636f6d000009637361696e743032000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471455484e82afa6b522260092c95b675be8db8490bc0f55d7357a1cbb066f5198fcb7aa2d7f05377331": "0x00000000000000000000000000000000000c526567656e63792d3030341757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471455538dd590c80f13507c2d0784ffc68240a395784f16cd29f99f974a58876fa9e948fe4ffcb70334": "0x0403000000020000000000000000000000000000000021f09f8d80204c75636b7920467269646179202d204f70656e476f7620f09f8d80001868747470733a2f2f6c75636b796672696461792e696f2f00147279616e406c75636b796672696461792e696f000011404c75636b794672696461794c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145557cf88d37091a7a256aad87b40568d82450352060cb44fd4f22d491cda208f2f7da5b23ff23d01": "0x00000000000000000000000000000000000944594f5244594f52001c68747470733a2f2f6769746875622e636f6d2f64796f7264796f72154064796f7264796f723a6d61747269782e6f72670000000d4064796f7264796f72636f6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714558060fa90d1941f87d108bb4f19a365b10f0ce5a87be412bfc89c359c4e6a34d9ab83532622e949": "0x00000000000000000000000000000000000c526567656e63792d3031321757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471455cbcfc5ff45de9288befc38a0a30b69022eac9e133fb589defc7a8c6b7f0dc601ded9804bd7e114": "0x040300000002000000000000000000000000000000000b4d656c612061644c49420c4d656c612061644c4942210000126d656c614061646c69626e65742e636f6d00000a406d656c6131303030000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471455ebf22a3378f22de4bd04a7052f76425c60648c528535285bc2a23ab28db060db34f7c5e5746aa9": "0x040000000002000000000000000000000000000000000954616c69736d616e0000000000000f40776561726574616c69736d616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714561df2dc51ef7baf3e89f959d4ae263361a6d7d0b87f1be73ad01356f5b982189f19c3be93fbe554": "0x00000000000000000000000000000000000d4f616b205365637572697479124f616b20536563757269747920476d62481c68747470733a2f2f7777772e6f616b73656375726974792e696f2f0014696e666f406f616b73656375726974792e696f00000d4053656375726974794f616b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471456305c2c3bf8f20e465c6be30d314cf647a8fa10212bcb84318394659c46fe75d03640cebb39595e": "0x040100000002000000000000000000000000000000000d416c7a796d6f6c6f6769737410416c7a796d6f6c6f67697374204f791a68747470733a2f2f7777772e7a796d6f6c6f6769612e66692f0015636f6e74616374407a796d6f6c6f6769612e6669000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714563affe7df4a40c094c7373d1e335e281b2a80565b3370c5de9d6b2d87fdf0cddac5641377a24b50": "0x0401000000020000000000000000000000000000000010526f636b585f506f6c6b61646f743306526f636b581668747470733a2f2f7777772e726f636b782e636f6d0012737570706f727440726f636b782e636f6d00001040726f636b785f6f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714564cb6671f34ac580c30d360adcf621ab5e8754a9481cc15c1827574958fdd9fd15c5d4d526c7909": "0x04030000000200000000000000000000000000000000104179657662656f7361204979616d75104179657662656f7361204979616d750000166179657662656f73612e6a40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145680c43f6b36d90ffecaf47bf20372df1eab92aa6781caef84c728ef14a18ebc4c39e35789f8a23b": "0x0000000000000000000000000000000000044a6179044a617900000000000e406a6a65647361646131393937000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471456ae9d419c0660f83235f7d984058bb410c163fc1d7a90e5475c0917aad77deb241093a50b4f683f": "0x0000000000000000000000000000000000064272756e6f0e4272756e6f20c5a06b766f72631768747470733a2f2f6272756e6f2e6574682e6c696d6f0020747261702d706f6c6b61646f746964656e7469747940736b766f72632e6d6500000a4062697466616c6c73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471456b5cfba8996c0c084671f7cec13e5359aad22bffb62ca545c385e1fd68f0f3de08b74c15e58c25f": "0x0000000000000000000000000000000000025000000018676d2e736f646572626572676840676d61696c2e636f6d00000f4042616c6c616e74696e65733837000f62616c6c616e74696e65735f706d00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471456e0891e915252b140975dcdfcd7ecc14eb7f986e0dac66349e19973a66dfa6be7b61cd3fbbe143a": "0x00000000000000000000000000000000000e43494b6f6e746865626c6f636b001f68747470733a2f2f7777772e63696b6f6e746865626c6f636b2e636f6d2f00177465616d4063696b6f6e746865626c6f636b2e636f6d00000f4043494b6f6e746865426c6f636b00084a53233638373600", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457130fa04591b33060283de9f5beb93ac69b24ca8c62f60f39b8c80758d807aa244532c66b67bc3c": "0x0403000000020000000000000000000000000000000012706f6c6b61646f745f636f6c6f6d6269610000001b706f6c6b61646f74636f6c6f6d62696140676d61696c2e636f6d00000c706f6c6b61646f74636f6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145721ebba28d18ffd9c84f75e0b1b92f6b003bde6212a8b2c9b776f3720f942b33fed8709f103a268": "0x000000000000000000000000000000000006616e6472650d416e6472c3a92053696c7661001740616e64726573696c76613a6d61747269782e6f7267000000000b616e64726573696c76610000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714572aae990801cce1043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d": "0x040000000003000000000000000000000000000000000d506172614e6f6465732e696f001568747470733a2f2f506172614e6f6465732e696f164070617261646f7878783a6d61747269782e6f726715737570706f727440706172616e6f6465732e696f00000b40506172614e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145749edf76d87f942544e2e588c90a2e53e051d2f87d40e222e1f034913a30f95a9a2f39114e5be38": "0x040000000002000000000000000000000000000000001c436861696e487562202620546578617320426c6f636b636861696e00001440737269766973683a6d61747269782e6f7267186d654073726972616d7669736877616e6174682e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457707f9d1b18edb4729324ff6798093939a73546e0f3d53a9cd7d4e938d238145c9422ce9f0beb07": "0x0000000000000000000000000000000000205374616b65444f54732e636f6d202d206279204269736f6e20547261696c7300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457903c6184bae82f5a090c88f0438b46b451026597cee760a7bac9d396c9c7b529b68fb78aec5f43": "0x040100000002000000000000000000000000000000000d5365756e204c616e6c656765000018407365756e616c6e6c6567653a6d61747269782e6f7267197365756e40706f6c79746f70652e746563686e6f6c6f677900000d407365756e6c616e6c656765000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457a5cae663c515ca00ecaacb451648a3660fe122ccc2c32cfd9459ca6dac9f10cbf7a0ab60c61318": "0x040000000002000000000000000000000000000000000d4a616d65735f4167656e6461000019406a616d65735f6167656e64613a6d61747269782e6f7267176a616d657340686f6c64706f6c6b61646f742e636f6d00000e406a616d65735f6167656e6461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457f0c0a9a6359c3474e4867b46b4d8ca428315963427c002b2e78d0faf10f6f7ce28a3d963cbc65d": "0x00000000000000000000000000000000000a626c756570616e646100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457fba32d45d674cc3a8ec57f1e3455033d4e4a4d92afbafedade5b15bd8a9569eb77157b8163af4a": "0x00000000000000000000000000000000000577696969000000196a65756468666a74794070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714581f77b10468b1425440f21f8078b780afad2b1f6604939ee2d3d4cdfc2ed48eb1422e76a54e291b": "0x040000000002000000000000000000000000000000000d506572666563742d6e6f646500001940706572666563742d6e6f64653a6d61747269782e6f7267146b6174656b7261737640676d61696c2e636f6d00000f40706572666563745f6e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145833bff9f455466ed63a7eba107bb1e70778603a7c1a10288284b5acf296c15f0b616c19df2b8641": "0x00000000000000000000000000000000001352616d61207c20456467657761726544414f1152616d61205368616e6b6172204a68611568747470733a2f2f72616d61766174732e646576154066726f676d616e783a6d61747269782e6f72671872616d614065646765776172652e636f6d6d756e69747900000b4072616d615f76617473000972616d617661747300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471458397d7e3fd835eec870531deb0be32ec5f13db615776a199622cf2b2a8d5061be0a30d560ac5413": "0x040000000002000000000000000000000000000000000a4162696c657820414700000011722e7a6f6e69406162696c65782e6368000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145839ea98689b2889bc6e12d7ab70abea4c08db7055e84f16bab817b5fb359088ad5190422df9dd1d": "0x040000000002000000000000000000000000000000000e416c657850726f6d6f5465616d00001340616c65782d6d3a6d61747269782e6f72670000001040416c65785f50726f6d6f5465616d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145874725d77d3161042fe55f037d3acfd9073a0110f9a241c7c0b484ee39ebcd77e7952582be5463e": "0x040300000002000000000000000000000000000000000f48656e202d2053706561726269740000001368656e72794073706561726269742e636f6d00000d40537065617262697444414f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714587f0b18f53b18b02aa10e36f0d84091e5850da2564bf99d14d5b9837c1ee2fa8bc068c995994379": "0x040000000002000000000000000000000000000000000a4578747261436f696e0000104079726e3a6d61747269782e6f7267187961726f6e736b694070726f746f6e6d61696c2e636f6d00000c404578747261436f696e5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145901a7d03ac32e8c460411e07f93dc4bc2b3a6cb67dad89ca26e8a54054d13916f74c982595c2e0e": "0x000000000000000000000000000000000006436c61726111436c6172612076616e2053746164656e00000000000f436c61726156616e53746164656e0f636c61726176616e73746164656e0000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145955584d4460250b9d00cdd9010cddfdc119c7ce69b4e122261ee68848e50daaaed117df2a7b6f7b": "0x0000000000000000000000000000000000174f6e72616d7020426f756e74792043757261746f7273002168747470733a2f2f74696e7975726c2e636f6d2f444f542d426f756e74792d320000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714599af3f3a616204088116da7569ffa5b8634742c63b9eaff0d5334e8f68588bef54e28e6ba64d04b": "0x04030000000200000000000000000000000000000000066b617665680000001d6b61766568746865626c61636b736d69746840676d61696c2e636f6d00000d6b6176656874656872616e69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a0dda79fdf58ba93657cdadd375b91ff01e797249907eeaa2d28e7f882f4176d43140767162111f": "0x000000000000000000000000000000000009627962742e6f726709627962742e6f72671168747470733a2f2f627962742e6f72670011737570706f727440627962742e6f726700000a40627962745f6f7267000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a322d41358015c5820e859e96c107c3dc5e0b110d8e5a7fd2bf312b511b00a5a45e59eeec47d741": "0x0403000000020000000000000000000000000000000009436872697342636b00000017646f706579706875636b40686f746d61696c2e636f6d00000a4042636b4368726973000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a53642bcce8d5192055808c210d863dfc372ec85beafa8fd3a8ff497f8eaee401ef05bf27d3065b": "0x04000000000200000000000000000000000000000000214a696d6d7954756465736b69202d20506f6c6b61646f74205265736964656e74000016407374616b656e6f64653a6d61747269782e6f72671b6a696d6d7974756465736b69407374616b656e6f64652e64657600000f407374616b656e6f64655f646576000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a54b00d6ab21bbd58a74372b1f0a88b1df304584326ff69a68e9470d42687e12bf5dfac375d4911": "0x040000000002000000000000000000000000000000000c53454b4f5941204c4142530000154073746577617274763a6d61747269782e6f726713746f6d4073656b6f79616c6162732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a7e0322bf0bc3b7eec3f748ce7ebbe4bd41e991a04eb92b050d5e80667e60938c6a5224d66cd464": "0x0403000000020000000000000000000000000000000011546865204772656174204573636170650000000f676d40706c61797467652e636f6d00000940706c6179544745000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a9ac6c6fb60e3add06b046f9929cd9ec3494f87b7ba1b533f8313c8132896639b110063c81a605b": "0x0403000000020000000000000000000000000000000011506f6c6b61646f7420496e736964657211506f6c6b61646f7420496e736964657200001b706f6c6b61646f742e696e736964657240676d61696c2e636f6d00001140506f6c6b61646f74496e7369646572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145ae3d02694d32b74b4154f12cdef88338edfa85cbdd64b61c410187e4f7971057aef32cdafdfb702": "0x0400000000020000000000000000000000000000000016f09f9bb8205a6f6f70657220436f727020f09f9bb8001868747470733a2f2f636f72702e7a6f6f7065722e6f726717406a6f686e756f70696e693a6d61747269782e6f726710636f7270407a6f6f7065722e6f726700000c407a6f6f706572636f7270000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145ae5cf79085c900374799c49548c591db342eb29f486980d7e28e687f9f88f9f602f050e8e106c64": "0x040000000002000000000000000000000000000000000e544f425553494e4553534c41570000001b746f627573696e6573736c6177406a6b6c65696d616e2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145ae8d02fc1cc6b946e53696350731ed439f8c353b0b69b40b324fcdcb435ba225fbc22a33c9fe154": "0x0000000000000000000000000000000000074f6e656d6169001368747470733a2f2f6f6e656d61692e6e6574000000000c406f6e656d61695f66646e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145af116176166f3dcdc891490870515c71014938641e9b09cfbfadeb502b16d67d2cff9145aaa9a75": "0x0403000000020000000000000000000000000000000009426c6f636b41544c09426c6f636b41544c1a68747470733a2f2f7777772e626c6f636b61746c2e636f6d2f0015636f6e7461637440626c6f636b61746c2e636f6d00000b40426c6f636b5f41544c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145af59607ad06416224714636e0203b3a39bdf5a84df455ee05f6449e2df03fbbc7ed49be08182d7b": "0x0800000000020100000002000000000000000000000000000000001a6e2d667573652056616c696461746f722023312053746173680c6e2d6675736520476d62481668747470733a2f2f7777772e6e2d667573652e636f154076616e74686f6d653a6d61747269782e6f72671563727970746f2d6f7073406e2d667573652e636f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b1cb8848fc74ed707b738ebac4b30c502415704c8a06c9194c3df1f2529855f959b1dbd43377554": "0x00000000000000000000000000000000000631335745421757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b301c74acab4e7e12ccb53338ac0da571d3697548346fb5f0b637ac9412f8abbf6d13588be75632": "0x0800000000020100000003000000000000000000000000000000000d5265676973747261722023310d5265676973747261722023311868747470733a2f2f7777772e63686576646f722e636f6d144063686576646f723a6d61747269782e6f72672063686576646f722b706f6c6b61646f745f7265673140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b37a7061f92e1981e7c14ac9433d4637fecd8b61cfe017b31145aeba9742370c8ac715fe009ff41": "0x00000000000000000000000000000000000b6469707379764d41494e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b4baec7933bf780a85e51387dd437dd83dc7f9c2a7e59bf0590e9dd48758b6abbc463b3e26e5163": "0x040100000002000000000000000000000000000000000c4a6f6e6e792052696e676f124a6f6e204b6f64792057696c6c69616d731f68747470733a2f2f6c696e6b6564696e2e636f6d2f696e2f6a6f6e37313100156a6f6e6e794064616f61636164656d792e6e657400000f406a6f6e6e7972696e676f373131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b4c4e58d29949859a2cb674ea2f4866664769a1663fd6aa321d9cfb89b67c402c881891700c0f57": "0x04000000000200000000000000000000000000000000084c6962657274790000001c6d657461706172616469676d4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b6407bdc635903a666c474e2f859bb39716a333ad449122df3605cf2d272ab876171d0a61cbdd07": "0x0401000000020000000000000000000000000000000008706f732e646f67001068747470733a2f2f706f732e646f6712406d616f79753a6d61747269782e6f726711706f6c6b61646f7440706f732e646f67000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b98628a4ffdb492fc5c731996ade530d0289dd11a6ccf4e246ea5054119d2fe15a2da5c2ef01062": "0x0000000000000000000000000000000000000000000000000012416964656570616b6368617564686172790000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145bab10ce7448709e7c6781a204088ce17d88592c07355af5a72a81a33011ca9c0b8f79329050ee0d": "0x00000000000000000000000000000000000a67696761686965727a0c4c656e6120486965727a690000166c656e61686965727a6940686f746d61696c2e646500000b4047696761486965727a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145bbcb49931f6e14912ec4426bd4c3d506b2322b8817ff42bc670792fd1aa4cfa662548fdb0e60b15": "0x00000000000000000000000000000000001047616c6163746963436f756e63696c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145bd6a3e1e8406faa3c82ab06b794c99f14a161973be7aa6012568b1c491d45ec969ed7420bcfaa59": "0x04000000000200000000000000000000000000000000044a6f650e4a6f6520506574726f77736b6900000f6a6f6540706574726f772e736b690000000d6a6f65706574726f77736b690000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145be461a0929fc6dc1da1e4d7d2a6a1e28f8778ca2d924672d83abcb6c5a2240b8186d4aa5cce2569": "0x00000000000000000000000000000000001c546563682041636164656d7920436f6469676f204272617a75636100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145c2c88f13736061bb6ca4dd8f15039b1550849ac495b65fe2e1e93daf4be62c4c4adf440ae155d68": "0x040000000002000000000000000000000000000000000a57696e6b727970746f00001540736c797577696e6b3a6d61747269782e6f726713626f626f4077696e6b727970746f2e636f6d00000b4077696e6b727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145c66629676bdc5f4766efcb5851054b4aeef694a3ad03d7bf36980a2094c07cb7b7cda28bde5e149": "0x0400000000020000000000000000000000000000000018454c444f5241444f2d544543484e4f4c4f47592e6e6574002068747470733a2f2f656c646f7261646f2d746563686e6f6c6f67792e6e657415407061756c2d6769653a6d61747269782e6f72671d7061756c40656c646f7261646f2d746563686e6f6c6f67792e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145c6942d78c3e288a0842fe19dee2029fe63ae78b250fb0ed99ebcc6a72b36e7f56160150c230f237": "0x0400000000020000000000000000000000000000000008636d616c697a6500001640636d616c697a6530313a6d61747269782e6f7267166d616c697a65636872697340676d61696c2e636f6d00000e4063687269736d616c697a6533000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145c6b1c34b6431f3840b9259dde4ecf577907b60e73ac636e896ac881e1f44c1bab1062fce8edef10": "0x00000000000000000000000000000000000e42414a554e204e4554574f524b1c426c6f476120546563682041472028537769747a65726c616e64291268747470733a2f2f616a756e612e696f2f1540726f786f6e746f783a6d61747269782e6f72670f68656c6c6f40616a756e612e696f00000e40416a756e614e6574776f726b000d6461726b667269656e64373700", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145c74ede8dfd9a44fd833a6cfefacabd9675f88e02953e4341badc949471b18f4e54b07e7383d6fbe": "0x00000000000000000000000000000000000d4f4720436f7265205465616d001768747470733a2f2f6f70656e6775696c642e7774662f00186f70656e6775696c647465616d40676d61696c2e636f6d00000e406f70656e6775696c64777466000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145c9b7dbdbf5f8eeb76446963a70e86cdaccc02ab22bf59bca9b5eb5fdb0353b144fbbddcff8a3a69": "0x04010000000200000000000000000000000000000000124465657020496e6b2056656e7475726573174465657020496e6b2056656e747572657320476d62481a68747470733a2f2f646565702d696e6b2e76656e7475726573174067656e6573697364616f3a6d61747269782e6f72671861646d696e40646565702d696e6b2e76656e74757265730000104047656e6573697344414f5f6f7267000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145cf461f932bdcdbafcfd589d8df6da23f65a51de867fac9490ead3ffbb36ce8d1946cec1789a9a46": "0x040000000002000000000000000000000000000000000d43727970746f4c61622030310000144079616f6873696e3a6d61747269782e6f72671779616f6873696e4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145d2b112c788bfa92d474d9a6e955d7813d04f0fe2b5d35f0986837b7943975699d13ce159067082f": "0x00000000000000000000000000000000001648696e646920456475636174696f6e2047726f75701648696e646920456475636174696f6e2047726f7570002140616d69745f68696e64695f656475636174696f6e5f67726f75703a6d61747219616d6974736861726d616c65616440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145d3dec38e02e37251c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea259385609": "0x0400000000020000000000000000000000000000000007416d666f72630a416d666f72632041471368747470733a2f2f616d666f72632e636f6d00137374616b696e6740616d666f72632e636f6d00000a40616d666f72636167000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145d6b2bca719d97c7ee2019dd45affea8eafaa263f346c25b477cef6858bd732898994e464cb57211": "0x00000000000000000000000000000000000c484f544249545354414b4510484f544249542045786368616e67651668747470733a2f2f7777772e686f746269742e696f0012737570706f727440686f746269742e696f00000d40486f746269745f6e657773000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145da2ed96282667842cf42c1d5eca2e17a00edde3c54ce01a2c1e0c070ebaa11ad9eb85083263b877": "0x000000000000000000000000000000000007444f542e6a7300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145dfe5da7f34068cb40668c14ac6f4e09373373ed8cc2fc6c7e092b10769b571af5c02bf4765ecd53": "0x0403000000020000000000000000000000000000000008416c626572746f0e416c626572746f205061686c65000018616c626572746f2e7061686c6540676d61696c2e636f6d00001140484552435f48414d4d4552444f574e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145e30111214665710be033afa19dd93fa4303e4c72b00b2c4102ff8c9b2fd75292774b56ba44de566": "0x00000000000000000000000000000000000d56726b3364735f537461736800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145e47309d56ee80fcfc1af31cb4678204d2f643f29290d127fc9fc4ad0f148e258ceb48764763e062": "0x0000000000000000000000000000000000044e614e0013687474703a2f2f7777772e6e616e2e78797a000d6c756b65406e616e2e78797a00000a406e616e5f78797a5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145e680ae5b0223aa782a9563f0050686a13dc52d6a266b9cf19325ce9375f6cf13ae4712688011d52": "0x040300000002000000000000000000000000000000001070726f746f636f6c776869737065720b4368726973204d61746100001770726f746f636f6c2e65746840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145e68d454836a65b5902795e8d37421da1234a1a8f330fa910581ef0bfa3204d5bda6840890c6d23c": "0x04030000000200000000000000000000000000000000086c6964616d616f086c6964616d616f0000146c6964616d616f406c6964616d616f2e636f6d00000c426573744c6964616d616f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145e9f43767f234e4e0eb07d0fb791114259b3ae2ff2c186ffeb9f3c0cf05b5008a31994553b544c46": "0x00000000000000000000000000000000000558696e6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145ead34c4d42568f9c0880e0e0918866661f9918d66b53287c95269d24e99121ee80618ca5f253666": "0x040100000002000000000000000000000000000000000c686173687761726c6f636b074a6f736875611868747470733a2f2f686173687761726c6f636b2e6465761840686173687761726c6f636b3a6d61747269782e6f72671a686173687761726c6f636b407068616c612e6e6574776f726b00000d40686173687761726c6f636b000c686173687761726c6f636b00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145eb695b4e8f904c91c2dd1f8db4faa532a9904dcfedc1c53eedf6307b54cbabe0b5b96c52d886c6f": "0x04030000000200000000000000000000000000000000115469676572204d6f6465204d656469610f41647269616e20526f6269736f6e00001a61647269616e4074696765726d6f64656d656469612e636f6d0000104074696765726d6f64656d65646961000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145eb9bc0505da44278aa29a2af6e85eb0bb2d2f00a6894ce0e83ebca01e2830da7678516cb7e84416": "0x00000000000000000000000000000000000b546f6d42726f7468657200000012746f6d676162724079616e6465782e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145ed1cc4a4cfee745c427dd8b136f4c7463ab9a5761b8b4d7b1280e0d14ef070958db8641cb41b417": "0x00000000000000000000000000000000000a574152414f4348414e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145ed4004f0c9e60f942aa0cf9b476762d4948072578e972faa9462a11b5ba17b1db8fcd8cc1d0420c": "0x00000000000000000000000000000000000c4235382046696e616e63650e423538204c61627320496e632e1468747470733a2f2f6235382e66696e616e63650014636f6e74616374406235382e66696e616e636500000c4042353846696e616e6365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145ee8405cff42241194339db8b404ea216d60433f00ed67b0cdcd9e29d21355615d967161db0cb04c": "0x040000000002000000000000000000000000000000001f5354414b454e4f4445207c2056414c494441544f5220414c4c49414e4345000016407374616b656e6f64653a6d61747269782e6f72670000000c407374616b656e6f64655f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145eeade208c2c3d2213aa0eae4c9244da2b6bb58f13febd792db76c932b3bc64d0035df4735c8db02": "0x00000000000000000000000000000000000c526567656e63792d3031371757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145f3b96e8f7e196621cfbfde369c6f58b4df770cc3ba47d6583c0e9603007338779cbad7426767578": "0x00000000000000000000000000000000000b4d5843504f53504f4f4c001468747470733a2f2f7777772e6d78632e61692f0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145f8f8fbe3a4a3e1256ae9b2d74ab4bb07306faf10549792549c52d4d092169530151a2aaeab28a0f": "0x040100000002000000000000000000000000000000000f446f745363616e6e65722e636f6d0f446f745363616e6e65722e636f6d1768747470733a2f2f646f747363616e6e65722e636f6d001561646d696e40646f747363616e6e65722e636f6d00000f40546865446f745363616e6e6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145fc4a5c686ea5a40b346948ec9e4cf84b965ec17a752b3e8eff098934aaad42ec50a347dd7936583": "0x0401000000020000000000000000000000000000000006716472766d0a51756164727669756d1168747470733a2f2f716472766d2e696f14406b616d696c73613a6d61747269782e6f72670b6b40716472766d2e696f00000a40716472766d5f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145fcf6e3e8fa7f7d4544eefa255546c84bf702f6d81c6828033cc49f7043e62043a3e83add44c6209": "0x040300000002000000000000000000000000000000000662727a64730d42726164204472657966757300001462727a64736f6e747640676d61696c2e636f6d00000962727a64735f4744000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714601c869e08b51af7b04b58ffedd058a81a625819d437d7a35485c63cfac9fc9f0907c16b3e3e9d6c": "0x0000000000000000000000000000000000074b68656f707300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146028af9a7bc6edd8d4c9b5341b6040e6f218c5476e5bb87a26fd80e03a0ac65b92d4d3eb917c8f22": "0x00000000000000000000000000000000001042494e414e43455f5354414b455f351042494e414e43455f5354414b455f35000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471460c30e5ee0f16de5405a662b1e68b18eca577e175d2bb0b12a71d7c46bdb9ad0a546ab81686b245a": "0x0000000000000000000000000000000000056a73647700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471460e96a9630dce3d89c7e01287164e51a07f34b17c26c5eff66e1954d347310da015ac23e895a4150": "0x0403000000020000000000000000000000000000000014456c6973615f4576656e74735f426f756e74790d424f544c61627320476d624800000e656c697361406b696c742e696f000010656c69736166726f6d6265726c696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714613c4c21e4ca890ad2e5f1942410cb763e8418f7c2c9afe20141d6ac4f780c4d1ce3dd2205426865": "0x040300000002000000000000000000000000000000000964616e6963756b690e44616e69656c2043756b69657200001364616e6963756b6940676d61696c2e636f6d00000964616e6963756b69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714617869f5844780e5f84795f2f68a2c43453b25ab4814c460f257d9bb05d04596499fd3211821076a": "0x04030000000200000000000000000000000000000000084d616861766972164d6168617669722047616e617061746920446173680000176d6168617669722e732e647240676d61696c2e636f6d00000a32374d616861766972000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714617ca8c9a7bf519bdc156e868d00cf92479a2417ebcdafbf0ce336f4cf3a818be068c49ee0562e79": "0x000000000000000000000000000000000008436c656d656e741e436c656d656e74204f6c69766965722044656e6973204a756d656c696e000018636a756d656c696e4070726f746f6e6d61696c2e636f6d000000000972756d656c696e6500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714617f389a0cb0d26a8659ed6f5a98bf0e1718fcc89e8e55a550e220da0f5de46f356297ea2af72c4f": "0x040100000002000000000000000000000000000000000f426f756e7479204d616e616765721467616c616e6970726f6a6563747320476d62481a68747470733a2f2f67616c616e6970726f6a656374732e6465001a626f756e74794067616c616e6970726f6a656374732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714618fd93a58f35389e2680e2c991a18cf7ba4710a51ba147b6856879a3047a03f8c647c69b953d630": "0x040100000002000000000000000000000000000000000751696e57656e0751696e57656e1a687474703a2f2f7777772e71696e77656e77616e672e636f6d184071696e77656e3a776562332e666f756e646174696f6e1771696e77656e40776562332e666f756e646174696f6e00000d4071696e77656e5f77616e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146191809a9acac4bb8c529de435a764457d6247ef93b5cc72fd73b922e4903834dfb43dbf64013365": "0x0800000000020100000002000000000000000000000000000000001243525950544f4c41422e4e4554574f524b001f68747470733a2f2f7777772e63727970746f6c61622e6e6574776f726b2f154074616e69735f33373a6d61747269782e6f72671b74616e69732e737461636b4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471461d35c4872d484b694c860705264b96854acc3cb307365132bd131524ef83a7c014378ed79373723": "0x0000000000000000000000000000000000164d65786963616e20436f6c6c65637469766520484100000018646f7473616d616d657869636f40676d61696c2e636f6d00001140506f6c6b61646f744d657869636f5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471461e96b98dbac9ae8cebcf37135a013069cdbafff3cc1074943f5ce992bfa90c58dec50c1440dad12": "0x000000000000000000000000000000000013506865656220506f6c6b61646f7420352e31132f722f506f6c6b61646f745f4d61726b6574000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471462075dba595e3a2898a570ec356d2f77d890fb7643ffbf7a92c442af3f45dbd87a5ca8f17ff5b679": "0x00000000000000000000000000000000000f44657672696d50656e64756c756d0d44657672696d20436574696e1b68747470733a2f2f70656e64756c756d636861696e2e6f72672f001964657672696d4070656e64756c756d636861696e2e6f726700000a4064657672696d6277000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714625e8e7181f526d87a202a62e71ca9d711e66c2e8587d830388f723563b782611849824b42608542": "0x000000000000000000000000000000000009504f4c4b41444f5400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146277dfd6b7b21ca2faf5f68fe828f5af8d69c116efd937d90f1956b0edd94e05d8b5285a8eb2a663": "0x04010000000200000000000000000000000000000000115374616b696e6734416c6c20f09fa5a9001d68747470733a2f2f7777772e7374616b696e6734616c6c2e6f72672f18407374616b696e6734616c6c3a6d61747269782e6f7267167374616b696e6734616c6c40676d61696c2e636f6d00000d407374616b696e6734616c6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146279b764d4a4ad2eaebfc0f0232c4a23c29dba65a33f7611db55e924e4b0a65950694b857e33764b": "0x0400000000020000000000000000000000000000000008636179626163680000000000000d405469656e43797072657373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714627f8fe7f248c866bc19869b7dc67efaa0923dd74b337c57baaedf41a1d002534f70cf4520b9b642": "0x040100000002000000000000000000000000000000000549505345001668747470733a2f2f697066737365617263682e696f000b686940697073652e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146281ccf16900ef3cac00a2740247063b6f890eea8309fa99d0fedeeb27602925e1de7e58b0ec6f6a": "0x00000000000000000000000000000000000d50617261636861696e333538134b415a554e415249e3808049574154414e4900001d776f726c642e6f6e652e696e766573746f7240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146282c39a18dfcab98e5d5f02fdd82b7c0ab38bd6093d17261f4c862f22caededb3a808c12a7904f4": "0x0000000000000000000000000000000000096770657374616e61001568747470733a2f2f6770657374616e612e636f6d000000000a406770657374616e61096770657374616e610000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146293ae906f82830db8a2ad752a280c8f9d461025191b195f8c1f60ea080604c24c1aebe1ebf6415a": "0x0000000000000000000000000000000000075279616e486f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471462a40c29b1fd2c93b204051d55c2c80cdf6e0d3346944e921fc97f0b86a4cc5eb5547982fc475d68": "0x040000000002000000000000000000000000000000000b5374616b6520506c7573000016407374616b65706c75733a6d61747269782e6f726713636f6e74616374407374616b652e706c7573000011405374616b65506c757343727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471462b931cf40e0dd8a4278dc8473c1319b51e5e326374b22f4b290bbf716f1d5a6e6bec98e2ac42c03": "0x00000000000000000000000000000000000967616d613238333000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471462d6ffba2553d09e31e11c530aee0dc228f734335dba8e77607b187c46b1c7c5827df020f94b0400": "0x0403000000020000000000000000000000000000000016446563656e7472616c697a6174696f6e5f6d6178691b416c7661726f204d616e75656c20476f6d657a205a756e69676100001461676f6d657a34323340676d61696c2e636f6d00000c40416c7661726f5f5f677a000b616c7661726f6734323300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471462d8d4af4eadb392cc52156f09978540d3163b798f65a8788bd04d828f366674bf9ea1f88e96f519": "0x040100000002000000000000000000000000000000000b48595045525350454544000012406c6f6b616c3a6d61747269782e6f7267146c6f6b616c40687970657273706565642e6175000009406c6f6b616c7070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471462e3e6769daa8cb66aaa8240cb6f2f8c0a86cf27c3f39f980074e7ec3d000bc0248978936bb9a83c": "0x000000000000000000000000000000000020524146207c20506f6c6b61646f7420416d62207c2050424120416c756d6e690c4a656f6e67536f596f756e1c68747470733a2f2f6769746875622e636f6d2f636f636f796f6f6e184070726f6f666f66796f6f6e3a6d61747269782e6f726714636f696e796f6f6e4069636c6f75642e636f6d00000d4070726f6f666f66796f6f6e000e436f436f596f6f6e233631313100", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471462e49551b36f932cd8d4e647a65738b7ec76c4e59af4b40d167270e55d008acabc172759d51e0e7b": "0x040300000002000000000000000000000000000000000c5468616e6720582e2056750c5468616e6720582e2056751268747470733a2f2f7468616e67782e7675134073696e7a69693a6d61747269782e6f72670d6869407468616e67782e767500000c407265616c73696e7a6969000773696e7a696900", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714631b52e3f40c72ed64a020cd2e215de928d7f9defcd9380a7e2415b8c3e22444ed2219cf95fa2e1c": "0x00000000000000000000000000000000001141204b616e65204d792057616c6c657400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146332adb00a8dc85a427150f6dee04d6e06f06a62a3509ba0b0cfa0ac01a69558616402b7498f1247": "0x00000000000000000000000000000000000d536f7461207c20506c61736d0e536f746120576174616e616265000011736f7461407374616b652e636f2e6a7000000e40576174616e616265536f7461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714633914b3a4ceda021eb38b0d5178bc680c10a204f81164946a25078c6d3b5f6813cef61c3aef4843": "0x040000000002000000000000000000000000000000000e416c69636520756e6420426f6200001a40616c6963655f756e645f626f623a6d61747269782e6f72670000000f40616c6963655f756e645f626f62000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714634b6c2676d6ffce12751adf007e19834923db0f540c0f255901febc74640782cff748e94c65c72d": "0x0000000000000000000000000000000000096461746170756e6b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714637afeda6c31f8ce54857fcb60606080a3ad974ef8d8673f899b3e1983f1c512f2f671c79f2b4a55": "0x0400000000020000000000000000000000000000000006416c696e6100001940616c696e656865727a6d616e3a6d61747269782e6f726714616c696e6140616e74697363616d2e7465616d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471463b1d194ccf414dfa4e5f5b5bfc485119954be727698c6eeb542b909a2d40014822d9dd0ebf91a1f": "0x0000000000000000000000000000000000084d617175655f3100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471463cb40b01c7b706af03a9fd09c8d3f8b134a20a873380efc542f5b85606cf62ffaa7fa302d7e0e23": "0x040300000002000000000000000000000000000000000c456c656374726f636f696e0c456c656374726f636f696e000014696e666f40656c656374726f636f696e2e657500000e456c656374726f636f696e4555000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146419f57ea3f84915121b12be1a2b918b9d01ff05c3d2fe5a28769cb747ff9fd7ecafc320dd5f810b": "0x00000000000000000000000000000000000f446f744c65617020456469746f72001f68747470733a2f2f6e6577736c65747465722e646f746c6561702e636f6d0013656469746f7240646f746c6561702e636f6d00000940646f746c656170000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714647269eb11608c5734a12ea862a1818defeb3fcde0962c89b7e71184e08ebbfddca97b9954b43144": "0x040300000002000000000000000000000000000000000944616e69656c20431344616e69656c2043686d69656c6577736b69000017636f6e74616374406463736f6674776172652e78797a00000964636f6d706f7a65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714647a84ffd21ef58f323e0ef6182a1c24b15bad084d75a03ba5aa787e7af723327287f6df292e6f76": "0x040300000002000000000000000000000000000000000e546865205765616b2048616e64000000197468657765616b68616e64646f7440676d61696c2e636f6d00000f405468655f5765616b5f48616e64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471464c511948fee226142c119baba24ac08d19b6f23bd0752b81f5169c331d39481519795bee26dc350": "0x0403000000020000000000000000000000000000000004536f770d4d6177657961746120536f77000014776579617461736f77407961686f6f2e636f6d00000b40536f774d6177657961000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471464eea8ed6e0c669be2baaa3eda02d880fa4ed98b9de89e16e2a064d649231f53c00c27403fc6ea7c": "0x0401000000020000000000000000000000000000000011546967657250726f204361706974616c001c68747470733a2f2f746967657270726f6361706974616c2e636f6d1540746967657270726f3a6d61747269782e6f72671c636f6e7461637440746967657270726f6361706974616c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714651097b4998394e146d1b7fd733a68d1c3e53d6bfd7134a5803fe5a4033c2dc9eba2e31dc21c4a65": "0x0000000000000000000000000000000000076272656e7a69000013406272656e7a693a6d61747269782e6f726700000009406272656e7a6935076272656e7a690000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471465326f57f6604b32cca044696fc5f11711266f7da0da4d0b94e34420cdcaa9f3e9e06939e551d27d": "0x00000000000000000000000000000000000b646772656174616e64610b416e6461204461766964000015646772656174616e646140676d61696c2e636f6d00000c40646772656174616e6461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714653768733bf980751cb8badbed1198dcece2e14047133b22e64bd06a9cf74ec5c8f94f668d1f2720": "0x04000000000200000000000000000000000000000000164b656e6e7920284d616e7461204e6574776f726b29094b656e6e79204c690000146b656e6e79406d616e74612e6e6574776f726b000011407375706572616e6f6e796d6f75736b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714657bab39f52fddf58e07d43b19d901badf3a7f57155ca84f2f835448e93a141bbbd33eac4b767d15": "0x040100000002000000000000000000000000000000002163727970746f7374616b652e636f6d20f09f87a8f09f87adf09f87baf09f87a60c43727970746f7374616b651868747470733a2f2f63727970746f7374616b652e636f6d001661646d696e4063727970746f7374616b652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714657f579f3442148eea0ab1b08b58a3708b50ba9928c4e25ad71d68efcbb868a2f75b987d0e8e4108": "0x040300000002000000000000000000000000000000001063617473776974686f75746861747300000016736869746c62674070726f746f6e6d61696c2e636800001063617473776974686f757468617473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471465b47ab9f3aec5ec06e3ed1e088da56a1e7ea6b57a856a0ead9e03bfbbd1ec74b33153e35015f10a": "0x0400000000020000000000000000000000000000000008546f6d69747a7500001440746f6d69747a753a6d61747269782e6f726712746f6d69747a754070726f746f6e2e6d6500000940546f6d69747a750008746f6d69747a7500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471465ce07032d38638e0453c20a8f8f0b374ec6d08c489e06e74686a2233bcf6422f345dfaab11fda26": "0x040300000002000000000000000000000000000000000b54656e7462616b657273001768747470733a2f2f74656e7462616b6572732e636f6d0017636f6e746163744074656e7462616b6572732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714660e4d7cfca9e1ef4263436c1c3bd22e1a1e09401982bb2df2e6e6c449417a5ad157d07ab2319243": "0x0000000000000000000000000000000000074a61766965720d4a61766965722056696f6c611868747470733a2f2f6a617669657276696f6c612e636f6d12406a61766965723a7061726974792e696f000000000a7065706f76696f6c610000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146619f3097120b33a1bbdfb8e2904d640a26915c57200ac20ee110d6490d5e5129271b09d2ebf2c36": "0x040000000002000000000000000000000000000000000a446f6d694e6f646573001568747470733a2f2f646f6d696e6f6465732e696f001368656c6c6f40646f6d696e6f6465732e696f00000b40646f6d696e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714661f86092c2992fefa8bd5aca42a81a5b5e5d82a75204214606e67517458dfb94363da5cebc42c15": "0x040300000002000000000000000000000000000000000a526563726166746572000000157265637261667465727840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471466331c5b2aefc4da60e469433111edea77c7b0075788c8ce009ad00aeed8529b9c26f26552e81948": "0x0403000000020000000000000000000000000000000007e8b5b5e4ba9107e8b5b5e4ba9100001873746f6e65737461723139383640676d61696c2e636f6d00000f4073746f6e657374617231393836000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471466334165bb2310561082b1a911dd8e9d01ebec53598da502cf118af543db458ce6d0e60b43a5af66": "0x040000000002000000000000000000000000000000000c546974616e204e6f64657300001740746974616e6e6f6465733a6d61747269782e6f726714696e666f40746974616e6e6f6465732e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714665d1a1f97f0cb0ebec5d127b5bc86b320b802f368a9cf427b3682d973b9fe41a9e6f5bff108432b": "0x000000000000000000000000000000000011426c6f636b636861696e20506564726f12506564726f204c75697320526976657261001c40626c6f636b636861696e706564726f3a6d61747269782e6f72671a426c6f636b636861696e706564726f40676d61696c2e636f6d00001140626c6f636b636861696e706564726f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714665d24a2e48cf277dc50817f1905a0dbf31de7065eb1891100f8bb18005786b68082ea625d6f6325": "0x04030000000200000000000000000000000000000000096568696c64656e620000001f657665726574742e68696c64656e6272616e647440676d61696c2e636f6d0000084072765f696e63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714667070096dd1a56f92db463a407b5818299a44b9db0727c16e9cd6b64dde2db70a592421be9f9b29": "0x04030000000200000000000000000000000000000000084d6f72616c6973084d6f72616c697300001168656c6c6f406d6f72616c69732e696f00000c4d6f72616c697357656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714668bbbac68a19cb7a02f7333e25590e4f568ae8a2ddc93a879e92e48fa3cf1666ac56e020c106d55": "0x040000000002000000000000000000000000000000000b436f696e73747564696f0000001a636f696e73747564696f4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471466a0ec80cc3122c082bf733f44a840f0a5c1935a002d4e541d81298fad6d1da8124073485983860e": "0x040000000002000000000000000000000000000000000b53616d20456c616d696e0000164073616d656c616d696e3a6d61747269782e6f72671273616d40696d6275652e6e6574776f726b00000b4073616d656c616d696e0a73616d656c616d696e0000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471466ab20bec2c8842b5c7a60ff74811eee72747ef1f1ae376eda2d3c8aab129f6c2cc76abaf59fb87c": "0x040000000002000000000000000000000000000000000a486563746f723c423e00001840686563746f7265737430363a6d61747269782e6f7267156862756c676172696e6940676d61696c2e636f6d00000d40686563746f726573743036000d486563746f7242233936313500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471466eaee046d4f02542c89cb8652eff8c73266de06baa3760534e7f37fecff971c028c2910efd6a947": "0x040100000002000000000000000000000000000000000a4c6567696f6a757665000000146c6567696f6a75766540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471466ee39ba0cc8fa55f4e0ed785c7c3f9f3efd38a15ac1498383070f1d7154c2ed5769652045609d75": "0x0403000000020000000000000000000000000000000013506f6c696d656320466f756e646174696f6e14506f6c696d656320466f756e646174696f6e2e000011696e666f40706f6c696d65632e6f726700001140706f6c696d656370726f746f636f6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471466f191e02c9f27205e13ed8ae098f9a3cedd297c6a019aff1cd744b56546dec7884c5ddac1090e20": "0x0000000000000000000000000000000000064167796c65000000136167796c654074616c69736d616e2e78797a00000c407374696c6c6167796c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471467065dcde6578a8344eb828e27b43fd3e8cefd90f96aa467bd629dac03603b8355ffe434b865c50c": "0x0000000000000000000000000000000000134b415445207c7c204e4f544946494741544f001b68747470733a2f2f5757572e4e4f544946494741544f2e434f4d15406b6174656761746f3a6d61747269782e6f7267156e6f746966696761746f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146724d23e0f578016d7e81893f6494f953ddc28c0565d5d82c7f57426b59f35a779cef72804b37086": "0x040000000002000000000000000000000000000000000d4f70656e5a4c20436f6d6d2e000000156f70656e7a6c406d616e74612e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714675a4d3970c551d5acd87357aaf3bc58b5499d10d6c03092ef4fa89ac4a9c2fe7a80f6a6cdd7b060": "0x04010000000200000000000000000000000000000000094d494e5477617265174c65726e656e206d697420646572205a756b756e66741468747470733a2f2f6d696e74776172652e63680011696e666f406d696e74776172652e6368000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146773244509d0e7c8d46cd0ae6eeab8ef19bf289712c9f2ae4272c663bfe0786d7c10d4ada5210003": "0x040000000002000000000000000000000000000000000c4859504552535048455245000011406876616c3a6d61747269782e6f72672076616c696461746f72734068797065727370686572652e76656e747572657300000e4068797065727370686572655f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146773f65a3ce78ec9f673019128278eb8e7483c1c8b16506a89d140ad1dedaee28b6589306e98b28a": "0x040100000002000000000000000000000000000000000963656c616461726917436861726c65732d45646f75617264204c41444152491568747470733a2f2f63656c61646172692e636f6d0021636c2e6b79632e646f742e717439386c4073696d706c656c6f67696e2e636f6d00000e4063656c61646172695f646576000963656c616461726900", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471467f3ca507a532ccb2e1884c53071526483b14004e894415f02b55fc2e2aef8e1df8ccf7ce5bd5570": "0x00000000000000000000000000000000000970657079616b696e00087065702e777466000000000a4070657079616b696e0970657079616b696e0000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714682174f20abcb7fdfa5e6f955d973efaca30897c4a3e4fbec88186ae72b8b331408804d73dfc275e": "0x04010000000200000000000000000000000000000000174245535456414c494441544f52207c205a55524943480e4265737476616c696461746f721a68747470733a2f2f6265737476616c696461746f722e636f6d14406d6f736f6e79693a6d61747269782e6f72671868656c6c6f406265737476616c696461746f722e636f6d000010406d6f736f6e79695f7a6f6c74616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146850837ac8d1be3236b8df7482c47933d4409ae2aea62f412be6f2af44173bb32d49e9abf3858445": "0x0400000000020000000000000000000000000000000007676c692e616c00001240676c69616c3a6d61747269782e6f726710706f6c6b61646f7440676c692e616c00000a40676c696f63797465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146857f90ade375e178c1860117351602843d192a9b4eb3b3641da38ab14c7974398761e7b7f3f3a14": "0x04030000000200000000000000000000000000000000054c75646f124c75646f76696320446f6d696e6775657300001e6c75646f7669632e646f6d696e67756573393640676d61696c2e636f6d0000084b726179743738084b7261797437380000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714687ec1d74f1c4464947c43d52db657492fed9368dc326e667d9c7bbf8df33c50974df47d2941ec42": "0x040300000002000000000000000000000000000000000e3078436f70706572736d69746811546962657269752043617a616e67697500000e6f776e61626c6540706d2e6d6500000e3078436f70706572736d697468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714688f2c242370997680f9384b92e09042571a9e5cd43d9656d62acfeb0324ff44698bb2cfe422b36b": "0x00000000000000000000000000000000000e506f6c6b61646f74204c6976650e506f6c6b61646f74204c6976650000106940706f6c6b61646f742e6c69766500000b405a65616c6f745f3078000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714688fa9c16c2592d347051c516138c028eb5de9449fcd8fc9b657540f7592f822359f26b29092029a": "0x040300000002000000000000000000000000000000000a43727970646f756768000000117a6163684067697665706163742e696f0000114063727970646f756768646f74657468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471468b2359cc10fae926295f0214abb5522cf3becf82504ef7c87036236e6b9afd263697a99bc5d5a30": "0x0400000000020000000000000000000000000000000014f09f91a8e2808df09f9a8073706163656d616e0000184073706163656d616e3131363a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714693a853cf5be87fcd81bf7c20643158bc6957827b344bde86cd260676dffa382afe24896634aa16b": "0x00000000000000000000000000000000000844656661756c7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714694ea541e2c22fadd6b8ec23dc68f20b5d315007d9c1a6706f9bd5c883319181129e76a89e978155": "0x040300000002000000000000000000000000000000000f446f7420506c617920416e6769650e416e67656c612044616c746f6e000020616e67656c61407369676e756d67726f77746861647669736f72732e636f6d00000a4064616c746f6e616e000d616e67656c6164616c746f6e00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471469576573c28ce38722e2d9f05aef8aa9965e0798d0789cb16f21ae1610b5695d20340a0e61bb4fad": "0x04030000000200000000000000000000000000000000125761674d65646961206d756c746973696700000017746861746d6564696177616740676d61696c2e636f6d00000e40746861744d65646961576167000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714697ead568e820ccfd2eb07f02043788e254d9e2df57be11566d241c56302b91199b4647947af3020": "0x040000000002000000000000000000000000000000000846415241444159001968747470733a2f2f666172616461796e6f6465732e636f6d1940666172616461796e6f6465733a6d61747269782e6f72671768656c6c6f40666172616461796e6f6465732e636f6d00000e40466172616461794e6f646573000d666172616461796e6f64657300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146988e63c3f5238944c1391e430e3bff9da68fb549a8c47881bd0fc7ed745031f57fa02495cbdbc7a": "0x040300000002000000000000000000000000000000000672616661630772616661656c00001672616661636162696c6c6140676d61696c2e636f6d00000f4072616661656c636162696c6c61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146996157961e3bb9397722aac08a16eefd9a6d17b5d69874b7d84ae30eb523c09054f677e976cc8c5": "0x000000000000000000000000000000000014496e746572204643207c20506f6c6b61646f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146997b214126ecad17e45841538166aa927c3e1c2bdaa3c0d1aa1938b1ea21710eb3a2c9e6431b93b": "0x0403000000020000000000000000000000000000000017526f636b585f506f6c6b61646f745f4469616d6f6e6406526f636b581668747470733a2f2f7777772e726f636b782e636f6d0012737570706f727440726f636b782e636f6d00001040726f636b785f6f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471469a5e82dfb57babbb40b08703caaacd889ed6521b6cd76db8c017652dda03f7239484e10e49ebd1d": "0x040000000002000000000000000000000000000000001d4a4b5242207c20546f7765722042726964676520f09f87acf09f87a7000000196a6f656c406a6b7262696e766573746d656e74732e636f6d00000a404a6f656c4a4b5242000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471469c81f40482c7fe2ac561538f2f61fdee2e15d44a6df7b310fcb0428da93ea0d5373a4ba14408d52": "0x040100000005000000000000000000000000000000000f4e696e6f202d204170696c6c6f6e001368747470733a2f2f6170696c6c6f6e2e696f00106e696e6f406170696c6c6f6e2e696f00000940676f7375313238000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471469d27efc78020c0bb2e2af76c0926af438cb5c3a2c0f534da4c25ab3bed006df4eca319ad3bf8874": "0x00000000000000000000000000000000000d576562332d446f7446616e7300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471469e34466005457c2c48d1c4fc44dbbc10b86e40db24f95f8924efba2b31eecc6a7c32bf2b8a4481a": "0x04000000000200000000000000000000000000000000064c65776973145368696e672059696e204c65776973204c41550000156c657769736c737940686f746d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146a205861e5fd90b2ae3a9e0c24a161ca065e6af741e35dcfa1cb3c0c00d820f9445e1dcd1b36ef09": "0x00000000000000000000000000000000000450345500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146a2d4f462a713142b45f7d4b6bd58cb550270c1ba3d9d97b6766787966b0b5c52c79b4d3b51d9a43": "0x0403000000020000000000000000000000000000000017f09fa681204c454f5354414b452e434f4d20f09fa6810000001974656368737570706f7274406c656f7374616b652e636f6d00000c6c656f7374616b65636f6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146a4f96f9cd70bd9472e7ccd983b92c5ae60481a636eab0fe42269c9f43c302a74f9dc65e0fbe202b": "0x04000000000200000000000000000000000000000000175375627371756964204c616273204f6666696369616c135375627371756964204c61627320476d62481568747470733a2f2f73756273717569642e696f2f0013736f6369616c4073756273717569642e696f00000a407375627371756964000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146a6c65861cbfd4f690ebd94a58a07211dcf05c4164ebab8c3abaca45f16f793fbe34072ae7b9ba08": "0x040000000002000000000000000000000000000000000a4d61726b205279616e0a4d61726b205279616e0017406d61726b2e656d6265723a6d61747269782e6f726700000011406d61726b5f656d6265725f7279616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146a89e104b2a237cd50192a1801fb73df626b690ff6e92a6f502ab5289437d799927cf486cef84319": "0x040300000002000000000000000000000000000000000b4245454659204d454d450000001377656e626565667940676d61696c2e636f6d00000f4062656566796d656d65636f696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146aa8b880a0c4b9171275627409e1eca0f9aa7e08fe1f1a26988cb462283067fdd30c13fcd7981424": "0x0000000000000000000000000000000000134d44726f75676874202d205374616b696e67000000166d64726f75676874406d64726f756768742e64726f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146b14621db5a14421ee995f41ea8d34445ee36e73b1f44437ea7f758bbb1f1e89c9894066b013ca3d": "0x00000000000000000000000000000000000761736c696e6b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146b1f8277766d740bc622132c1da0a0c45d91cb970fb5332e5c592a45f6c7e223767fd8c7fb849c58": "0x04030000000200000000000000000000000000000000125348412d74776f666966747963687269730b436872697320436f63611868747470733a2f2f7777772e646f7469736465642e696f001a6368726973746f70686572636f636140676d61696c2e636f6d00000b406263315f6368726973000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146b9baafd26f9d78929f107a6abccb303dcdd5d05569389f87a411d192e8463829a9c84a95a5b3ed1": "0x040300000002000000000000000000000000000000000c4d69737465725f436f6c650000001e6d6973746572636f6f6f6f6f6f6f6f6f6f6c6540676d61696c2e636f6d00000c4031393238333734367a71000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146ba30fff03a1847c98acccca7675aa832373fa4dfee14c0c237c1e547ae91981b63b4a0a9810d270": "0x040300000002000000000000000000000000000000000b5265616c566973696f6e175265616c20566973696f6e2047726f75702053455a431c68747470733a2f2f7777772e7265616c766973696f6e2e636f6d2f00186163636f756e7473407265616c766973696f6e2e636f6d00000c405265616c566973696f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146bf602d4ccb0664d3c235e80e35082b668682531b9b062fda39a46edb94f884d9122d86885fd5f1b": "0x00000000000000000000000000000000000000000000000000097270686d656965720000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146c4d2026575763437cdc1a6a5a7f23437b6528edcdf553d0685f940a4e6e85579727ef3dc574563a": "0x04000000000200000000000000000000000000000000114365727448756d204d61785374616b65000018406365727468756d2d6a696d3a6d61747269782e6f726715706f6c6b61646f74406365727468756d2e636f6d000009404365727448756d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146c5088428455187bcc95d7d061fc6a655b795794b9b1614d0a240e13e81de9dce3f2b184f653da7c": "0x04000000000200000000000000000000000000000000097279616e686967730000000000000a407279616e68696773000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146c617259271d955c48b2a90dced600b59871b53ba285b33b16ad830ea6877ffea3ea7469a996b054": "0x04000000000200000000000000000000000000000000074655545552450000124031667574753a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146c7206770c39d9295a5f7eb7050fb96d8d7895d9afce428a064ce66e3b094805bcad9a8e68cb9934": "0x0401000000020000000000000000000000000000000013426966726f737420466f756e646174696f6e13424946524f535420464f554e444154494f4e1868747470733a2f2f626966726f73742e66696e616e6365001668656c6c6f40626966726f73742e66696e616e636500001040426966726f737446696e616e6365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146cbe0677de752662eebc7887720ec1ce8b759629cb425df5f15011f0d455bfe1a22ad4cfb36d1a3b": "0x00000000000000000000000000000000001142494e414e43455f5354414b455f31321142494e414e43455f5354414b455f3132000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146d1925fb53c401a7aa926dd1d0ac5fd7a08808a687e8ab73137ea8355c32c397b4b8b1c2db7cd752": "0x00000000000000000000000000000000000a4a61736f6e20547365064a61736f6e00001576616c76656368696e6140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146d2ec78ce0df90db282babe83a600ea252085b952e5df448a09e3b859d510d21900a77549f39b66c": "0x000000000000000000000000000000000008656b697463686f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146d3350ee036daad1f21779c6e9e861c7af89d8edf7077a73c54d16ee419d8080e3539937bf565e4f": "0x0000000000000000000000000000000000114d79436f696e7461696e65722e636f6d001968747470733a2f2f6d79636f696e7461696e65722e636f6d001761646d696e406d79636f696e7461696e65722e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146d34ca1ecaaeb6174471abb5438fa95f8c85b8d5a417df0a6a38b4372874f27f30f20645f3263830": "0x040000000002000000000000000000000000000000000b5975647573204c6162730000154064757979756475733a6d61747269782e6f72671579756475732e6c61627340676d61696c2e636f6d00000c4079756475735f6c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146d5ba05b78a2e080daa4917008c6339bc42960ff491ffb03c3a6ddfc2b2b045d1c24112383398252": "0x000000000000000000000000000000000007686f646c337200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146dc100623401ea343e7064033033db59b89b05afc0408800e1c6a900e5ef4465f6493d50e5070031": "0x00000000000000000000000000000000000f4b65697461204d6f726979616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146dc2070d9c7fd08ed88e71e550f7c318065fe4ce9c7d58430af17fa534f87d27195dd93cce667719": "0x00000000000000000000000000000000000a4669676d656e742034001368747470733a2f2f6669676d656e742e696f000100000b4669676d656e745f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146ddcb34ad887603a8283bf2db7f36e834b16ce3b301f978609b2eefd855f01f6c7f16209c0a9147e": "0x00000000000000000000000000000000000d4d6973636861277320446f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146dfdc0beae27efb8ee5b5133284a68de459de2373129497bf4bad758619ebc6b0b6bc77fb1ee2862": "0x0000000000000000000000000000000000085052585920434f001368747470733a2f2f70727879636f2e636f6d0012636f6e6e6f724070727879636f2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146e0bda57536f0f7afe8ed746b2f0fafda336e27346a75f2f03db0f73a3e73e1ca6deb3676e14d139": "0x00000000000000000000000000000000000a4d61747453616e746f124d61746961732053616e74616f6c61796100001b6d617469617373616e74616f6c61796140676d61696c2e636f6d00000c406d61747473616e746f5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146e282abb12705aa32837c15322c7d358dc07ee65dd3ab42a3d70b6c4577a015b2479100bbeacda51": "0x0000000000000000000000000000000000064368696c6c000000166d6f6c6c79646f7430353640676d61696c2e636f6d0000094055534348696c6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146e4e14c3138d789d92f2999a6efaa86285a96c5d0ba78f11ec72b33c6973ec6fd5afb7b8b0e4fb45": "0x04010000000200000000000000000000000000000000085a656e6c696e6b115a656e6c696e6b2050726f746f636f6c1468747470733a2f2f7a656e6c696e6b2e70726f13406c656f67756f3a6d61747269782e6f7267106c656f407a656e6c696e6b2e70726f00000c405a656e6c696e6b50726f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146e586fa9f032427be49ad2f6a7346dca526a39aeea90aa0231717c77eaf257b0733faed3e1953f19": "0x040100000002000000000000000000000000000000000e414a554e41204e4554574f524b1c426c6f476120546563682041472028537769747a65726c616e64291268747470733a2f2f616a756e612e696f2f1540726f786f6e746f783a6d61747269782e6f72670f68656c6c6f40616a756e612e696f00000e40416a756e614e6574776f726b000d6461726b667269656e64373700", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146ec642500076ba25a6c5f0595d6ed85d6260bc682d4a68a4b4e605d43c67d56f2765d19698549772": "0x040000000002000000000000000000000000000000000b5374616b656c792e696f0000124069696363313a6d61747269782e6f72671161646d696e407374616b656c792e696f00000c405374616b656c795f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f4309182c6e307ed4e8bfb1c924dd64e33ecfbb35d90061bb83b2dde667e58588780068f9fc1471": "0x00000000000000000000000000000000000b506f6c6b616469726b730f43687269737469616e204469726b00001843687269737469616e2e6469726b406d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f47cd4490d5c355aeb3b1fa02364f2a474a149c1ce5b80c177857c0cde909e140d8d88036dde539": "0x00000000000000000000000000000000000844414f4e676f6b001868747470733a2f2f646f7261666163746f72792e6f72670016737465766540646f7261666163746f72792e6f72670000094044414f4e676f6b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f73628ca952be18dad0bc6a0aadf06c56416e83bf75e865d41ccb5ffd74eabf9e81d47574b43049": "0x040300000002000000000000000000000000000000000b43756c74757265446f740b43756c74757265446f740000146a7562616b4063756c74757265646f742e696f00000d4063756c74757265646f7431000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f74c55a2ace0819606aa47c4cbf48834774de4e02bed163e76c54e50415f5a0cb103e6a47511c0b": "0x0000000000000000000000000000000000054c616e6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f75ffac66bf6b9f1028da734244eb60a38d63f97c96f89f4f9630bb98376631a4d24c2baf1ccf6f": "0x04000000000200000000000000000000000000000000064d61727461114d61727461204d6f72616e64757a7a6f1968747470733a2f2f776562332e666f756e646174696f6e2f17406d617274613a776562332e666f756e646174696f6e166d6172746140776562332e666f756e646174696f6e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f83ccad3981de4b7e569787b1b323854ac9a8c40914d400b6fc23a2fedd24321f814ce7db7f6563": "0x040000000002000000000000000000000000000000001452656b7420537472656574204361706974616c0000174072656b747374726565743a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f9c17a3ac4a6c898a3b9446cadec292c5064f0572e8752007bd8db06cc58feccaf23dea69da58cb": "0x04000000000200000000000000000000000000000000076765726d616e001468747470733a2f2f6e696b6f6c6973682e696e000000000c40736b796d616e5f6f6e65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471470391fe33aca6dcaf6a7abb3dd0e36f9f77e31e10462ea14b10c909f37cc0db83ee8349dc531d840": "0x00000000000000000000000000000000000b4461636164652e6f726711556e697420552b3234363720476d62481a68747470733a2f2f756e6974382e617065756e69742e636f6d0012753234363740617065756e69742e636f6d00000b406461636164654f72670009656d696c2e61706500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147049f2f99a873c94c00f86f5f5421e98f7ba345ccd996c53412f39308ea854053fe650ca7bf44f75": "0x00000000000000000000000000000000001242726967687420496e76656e74696f6e73001d68747470733a2f2f627269676874696e76656e74696f6e732e706c2f0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714704dea62a3fb9e66a471c55caca4be7b4e60c6e94b20f9028883f8c64287d4454130c657383c3442": "0x0400000000020000000000000000000000000000000018f09fa78a2049636562657267204e6f64657320f09fa78a00001940696365626572676e6f6465733a6d61747269782e6f726716696e666f40696365626572676e6f6465732e636f6d00000e40496365626572674e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471470d495db70840cac599742dc389cf9dbb6a67d8cbd22170dabce386c06df1ab4ad8c8285f351f2af": "0x040100000002000000000000000000000000000000000b476c617a657363617065001768747470733a2f2f676c617a6573636170652e636f6d001568656c6c6f40676c617a6573636170652e636f6d00000d40476c617a6573636170655f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471470ea89be94fe51a442cc5215992b80128fbe79ab6b9e9ef599e18a9fd3aabb62973d80e66cb40d0a": "0x040000000002000000000000000000000000000000000667626163690000124067626163693a6d61747269782e6f72671d67696c626572742e73746f7279637261667440676d61696c2e636f6d00000840676261636958000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714710936ab2f44516c185002001ae350c3815b9414a1113f6a6eaefa51a52ad3bfa09183c197c23f6b": "0x00000000000000000000000000000000000c6861727279646f3339373912446f205068616d205472756e67204861750000166861727279646f3339373940676d61696c2e636f6d0000104068617272796265617574795f6f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714712aaca2b02746086883c9953ae0dea90b0b1db721a34e5ab73f948f428c403ca23bfca0f514594d": "0x040300000002000000000000000000000000000000001cf09fa6bef09fa4962049766f72794e6f646520f09fa496f09fa6be0000001769766f72792e626c616e63614070726f746f6e2e6d6500000e4049426c616e63613439353736000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471471352c2eb5ded5f286484f63c9e0ae1f460dec3b53307478f5ce3ffab22a1334d34a52da7527ec64": "0x04000000000200000000000000000000000000000000084d656c616e67650000001a6d656c616e67652e7374616b696e6740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714713faaeb6b134411e9d6e3adda6c3383cb1f5e92d6908f7d792fc1b4a80958341e05f53fee624836": "0x0000000000000000000000000000000000154272617a696c2042697a44657620426f756e747900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471471570c7baf07c52daca9b971305af399221a92e1bf8c58307fb1057f0c8f6c3d226cf7402897b837": "0x00000000000000000000000000000000001048656c656e61202d205075626c69630748656c656e6100001668656c656e616a77616e67407961686f6f2e636f6d00000d4068656c656e616a77616e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147164fea0aaf340daa6075a9968b174ce67edaab5fbdb011bd625e2b4728f953e6444386a36b8722a": "0x040100000002000000000000000000000000000000000b54504b4c2e45617274680c546f6b656e506f636b65741d68747470733a2f2f7777772e746f6b656e706f636b65742e70726f2f1c40746f6b656e706f636b65742e70726f3a6d61747269782e6f726713626440746f6b656e706f636b65742e70726f00001040546f6b656e506f636b65745f5450000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471471807145847ce7520a9e6fb48b9423ae5939f07fe1d7f41a6c1ebe3d2135e94af94b7fd717a47418": "0x04000000000200000000000000000000000000000000094d6161726d617061000015406d6161726d6170613a6d61747269782e6f7267106d6172696f40626f796b6f742e636c00000a406d6161726d617061000e4d6161726d617061233830343800", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147180d79828e0ec897e6a7945c3108fbc35ee60d6f338f4472d4658249d96493086994e02e7dd3a11": "0x04010000000200000000000000000000000000000000055855414e055855414e0013407875616e39333a6d61747269782e6f72671b79616e676a696e677875616e6d61696c40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147181755808f2aabbc83e489ed94fbe1d1b6a71e8393d59583910463dc95bfd00a93ce47cb1465928": "0x0403000000020000000000000000000000000000000014f09f8fb5efb88f20464c4f5745525354414b45001768747470733a2f2f666c6f7765727374616b652e696f1840666c6f7765727374616b653a6d61747269782e6f72671b666c6f7765727374616b654070726f746f6e6d61696c2e636f6d00000f404265466c6f7765725374616b65000c666c6f7765727374616b6500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471471bd36a7be01ed70461b8eab2552590c5860de5271e7dc81fbf3fde9c772509fc4fdf67fcdedef61": "0x040000000002000000000000000000000000000000000c747275737465646e6f6465001768747470733a2f2f747275737465646e6f64652e696f0014696e666f40747275737465646e6f64652e696f00000d40547275737465646e6f6465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471471c3ea80d7b0dfb82a60c7682b7a16f3e6502873a523a3c55703f5df93d297fca9c5fd8779d05a28": "0x0000000000000000000000000000000000086a6572657a5f5100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471471c705b1381272e69efc992685aa35aba0942285fefffe37246b1fc16ee417ce28d1be8ca4e20030": "0x000000000000000000000000000000000006737461736800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714720cd28dcf99c07dac133ebfde441672c055b79ca9a6059850984eead1ae036f48ca1230e7f0556f": "0x04000000000200000000000000000000000000000000094d696c65f09f8c8d000016406d61746865726365673a6d61747269782e6f7267176d6865726365674070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471472111003b96bc266a24fde6343e2bf0aefa296afcedea6f16d37c5e1c0d8b6511e7055cf7282b60c": "0x040000000002000000000000000000000000000000001053756c74616e4f665374616b696e67002168747470733a2f2f7777772e73756c74616e6f667374616b696e672e636f6d2f204073756c74616e6f667374616b696e672e636f6d3a6d61747269782e6f72671f73756c74616e6f667374616b696e674070726f746f6e6d61696c2e636f6d0000114053756c74616e4f665374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471472491867cdbdb72a5071733a41703f6cf3fe43daa2814861b512205451a2f33a60a8b3d739eab20e": "0x04000000000200000000000000000000000000000000084c554935444f540000144077696c64646f743a6d61747269782e6f7267000000084031784c554935001a4c5549352f57696c64446f744170706561726564233230303900", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471472695126ff943f9e38d442452b078203a37f178906e67650b19128ad687051f1aaca4c0c428b3c04": "0x0000000000000000000000000000000000086d75686172656d00000000000000086d75686172656d0000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714726da8e64fe5cc017269960f17b619f90d534da2bfb1506b14ee66307459a066289218d2bbcd2414": "0x040000000002000000000000000000000000000000000a4554205075626c6963000000000000094065743930323636000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714728227c4dd30620ff826273e80a776cf79c96ef33dbde5ae91a843fc3f36401c6f878447f6aa6315": "0x0000000000000000000000000000000000104b4a4320383320446563203230323100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471472f593a2e278eb75522e16fcd83f6d6e08fe2b44d56b5d0bdaf33527b49e8832928d003d8097ca63": "0x04010000000200000000000000000000000000000000094e4f5354524f4d4f11446f6d696e69717565204ac3a4676769000014696e666f4073756e646f776e65722e6165726f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714731ba4e11a7d5feb8c77062e797e4a1bd08a3d9ca4feaa8917d02315dd3ecee23f3649246e7ea84d": "0x04010000000200000000000000000000000000000000054449434f054449434f1068747470733a2f2f6469636f2e696f000b6869406469636f2e696f00000e404449434f3033323739373034000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147331c534ba659f84f47f6c77a0720b820074d7f48abb22ef868ba2ec24159bc850e1423dfa1bd43a": "0x04010000000200000000000000000000000000000000094b534d4348414f53000000136b736d6368616f7340676d61696c2e636f6d00000a406b736d6368616f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471473364b7f8cfc00b812c039004da5e1e846aae808277098c719cef1f4985aed00161a42ac4f0e002f": "0x040000000002000000000000000000000000000000000874696d777532300000144074696d777532303a6d61747269782e6f7267000000000874696d777532300000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714735f4b854a56e790d063d0325df758d4e35a9ba4c07526410fbba664c0b61fe163c4405f5b38dc66": "0x040000000002000000000000000000000000000000001950617269747920546563686e6f6c6f6769657320476d62481950617269747920546563686e6f6c6f6769657320476d62481768747470733a2f2f7777772e7061726974792e696f2f001470726f706f73616c73407061726974792e696f00000c4050617269747954656368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471473b93bc1a743680630ddff6cf0557f5ec5929f4ba1ae54279c028f94251e4f4cce45d72c5a9c58ca": "0x00000000000000000000000000000000000c526567656e63792d3030371757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471473c1f960c73bd4b5a40ccb73fa01d3dff2ed46e235fb2fe8eedac1b4e3dea68c76ac2deecf942022": "0x04030000000200000000000000000000000000000000086d5f73686565700b48616f79616e67204c690000166974616c792e313834323940676d61696c2e636f6d00000d404d61676963533836363433000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471473c700cacfaf7b1e7cc47cd222c6c30c2856e545ff74e6b31ed1725334b0e31cd43a52730e9ad66e": "0x0403000000020000000000000000000000000000000011546865577269676874537563636573730e4173686c6579205772696768741e68747470733a2f2f746865777269676874737563636573732e636f6d2f001a696e666f40746865777269676874737563636573732e636f6d000010407772696768745f73756363657373001674686577726967687473756363657373233531383700", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471473fe9dfb9a1dc2c1c41be0c2c5e5ad66d0d3a1ed02ca8ccf056d3b92a84df2429dc1e957eeb1152a": "0x040000000002000000000000000000000000000000000830786e3030627a0000144030786e3030627a3a6d61747269782e6f72670e30786e3030627a40706d2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714741edd192a56853bd2413cac426040b67e93948afbd069b37ca700049a2f170d05b16418ff8da032": "0x0400000000020000000000000000000000000000000014536d6f6c646f7420646576656c6f706d656e7400001540746f6d616b6131373a6d61747269782e6f72671d7069657272652e6b7269656765723137303840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474782af8e47bfcfc0a4a3233cb4870d9f20b5c55e77f839ce96a26f0fd773d019179197576644765": "0x040000000002000000000000000000000000000000000b45584e4553532e434f4d0000001576616c696461746f724065786e6573732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714748c854ac41713f81ae3a39de384cc366c0c0693e82a9b38397a35b201ffc33e383469df052e4227": "0x040000000002000000000000000000000000000000000c556e6f205374616b696e6700001740756e6f7374616b696e673a6d61747269782e6f7267186f70657261746f7240756e6f7374616b696e672e636f6d00000c40556e6f5374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714748e26e4416abae0ccd87fa65729f7bdaa8305581a7a499aa24c118e83f5714152c0e22617c6fc63": "0x0400000000020000000000000000000000000000000005416c6578000000000000000661746865690000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147499a373d4b2f70f8419a4ac409fa4e7bec032c696c526fac10ff9114d928df56ca0bf9e9ae29149": "0x04000000000200000000000000000000000000000000104d41415254454e207c204153544152000013406669657865723a6d61747269782e6f7267166d61617274656e4061737461722e6e6574776f726b00000b4068656e736b656e736d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474b0c239e26aca84a6c70805946002d87f9a6a2c5ec0900cd31ae4e27fd375e71dd6d75c0c264b68": "0x040300000002000000000000000000000000000000000864656669677579084775737461766f00001461737461726465666940676d61696c2e636f6d00000b40646566696775793232000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474c3ae49c1416014a0afbe96d21f06c21f01a6e501750fe36c0e4697b8431fab6f94a558541b6446": "0x0403000000020000000000000000000000000000000005323037350000000e6d6172636f407a65726f2e696f00000a6d6172636f6261686e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474c5981ba60102c7e82d3b7fbff7f5ff1010b279435012e0ce3b68dc387eb2827fc2e9d5001ada7c": "0x00000000000000000000000000000000001062696e616e63655f7374616b655f321062696e616e63655f7374616b655f32000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474d6aadd494e266842a510b82f5075233945c7d705a187bdd4d36745a3ca90f36b860f8b3247a27d": "0x04030000000200000000000000000000000000000000084b6c617374657200000011696e666f40706f6c79636f64652e736800000b6b6c61737465725f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474f1e1edd85aece4106a53bc7d39e4116f4bac46cac7c172269fe76e7757be1094c32d1243ab920a": "0x0403000000020000000000000000000000000000000009436872616c7439380000001b636872616c742e646576656c6f70657240676d61696c2e636f6d00000a40436872616c743938000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474fcea92fd9411873eaf71e6279d9b9666930f468b7204050c448bfe4593762f44e5f04ffc00f968": "0x04030000000200000000000000000000000000000000184d61727320456e7465727461696e6d656e74204c4c432e0c53696b646572205161697300001d6d617273656e7465727461696e6d656e747840676d61696c2e636f6d00000c4053696b64657251616973000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714750f6a824e75e9801a1bae27765f9be012e6d1a2307afac2b32c82dde3027c9d2b4978029f0c5171": "0x000000000000000000000000000000000007417679446f741541726368616e612056616964656573776172616e00001761726368616e61763139323940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714753931c0b2ecf25f803166343a21e65218ead92135f73df970ed63e5aa18b329d9542b47ba9fa219": "0x040000000002000000000000000000000000000000000747757374617600000013677573746176406477656c6c69722e636f6d00000c406775737461766e697065000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714754cb56cf6c9489ed016feaa68e25739dbc4035faf2577d17ec9d7ec2125a99a6770b5be093f6e32": "0x0400000000020000000000000000000000000000000009446f74536b756c6c00001540646f74736b756c6c3a6d61747269782e6f72671268656c7040646f74736b756c6c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714754cdcbcd79de061288197fe1d9f6b12ee7f9656663791366fd5ea4ec01999d7a7f8b84e22a0591b": "0x00000000000000000000000000000000001062696e616e63655f7374616b655f311062696e616e63655f7374616b655f31000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714754f0164b9ddbc7048a94c9ca2c21cb5f258f5873bbb5beceb4c64df4662d43c3c289b4d67a56f06": "0x00000000000000000000000000000000000531304b4100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714757a8da264c88695a6b1c75426a3170fdd0b13bd2ba35e0f80cf2d1010973a8cea518ea78995bb54": "0x00000000000000000000000000000000000c444f54203120284578742900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475846ad69bb139bac2828538511e926bcfe09150d03638cff3f4243d1d74b9fe0cc150567802b45e": "0x040100000002000000000000000000000000000000000a4254434d494e455253084c7563696c6c611668747470733a2f2f6274636d696e6572732e66722f001a6274636d696e6572735f70617269734070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475867a568daa1785baedf2e50d3732045c8b24d42ad3167b994e318707f4ae4cabb7ef212f5e3860": "0x00000000000000000000000000000000000f547269706c4569676874f09f8dba0e44656e697320506973617265761e68747470733a2f2f6769746875622e636f6d2f747269706c65696768741a4064656e69735f703a6d61747269782e7061726974792e696f1e7069736172657664656e2b706f6c6b61646f7440676d61696c2e636f6d00001e68747470733a2f2f747769747465722e636f6d2f44656e69735f507374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475aaed01d33aff0f6a276c8c59606dbc8515f3bbde2bbf30956ae793689cf5c003d7e595d1ecee64": "0x040100000002000000000000000000000000000000000c506f6c6b6177616c6c65740c506f6c6b6177616c6c65741768747470733a2f2f706f6c6b6177616c6c65742e696f184030787468726565626f64793a6d61747269782e6f72671568656c6c6f40706f6c6b6177616c6c65742e696f00000d40706f6c6b6177616c6c6574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475bc7afdeb88fc9d0aa041bf62d5b52adee07e7cbc0687ace86e77308a982c07db871ef2dab63901": "0x00000000000000000000000000000000001042494e414e43455f5354414b455f371042494e414e43455f5354414b455f37000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475ccfb98243b897452cadfbd70405e7a8fe22235a0d0eeaf7cffc9644b3a3ccd8b5177cbb56c3c57": "0x0400000000020000000000000000000000000000000009616e64657273656e00001940616e64657273656e303730373a6d61747269782e6f726718616e647265693037303730313140676d61696c2e636f6d00001040416e6472656930333334333837380010416e6472656930373037233131353900", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475d112c2582d6bc3922bc16cff1acfc4a08cb5bfcebadaa9eb182cd47a51b8b047a0202ae9624a1c": "0x04000000000300000000000000000000000000000000045733461e576562203320546563686e6f6c6f6769657320466f756e646174696f6e1868747470733a2f2f776562332e666f756e646174696f6e0015696e666f40776562332e666f756e646174696f6e0000104077656233666f756e646174696f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475fe22e7da8bab122ee58d589be14b8d4fdf4dea986983733c837b6af4b99a8a550da9fbb1aefc77": "0x0000000000000000000000000000000000054e31626f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147601c8c0075205c282f81b71f17b13f87e58ca1444fc00604907342aed7dbfc828872a8db645032a": "0x0000000000000000000000000000000000063231446f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714760aecf664bf053f863ba022a0315ac70e6881db2f4906ca51d2864c43800cc5601acddc05b0d903": "0x0400000000020000000000000000000000000000000005426c617316426c617320526f6472696775657a204972697a617200000000000b40626c6173726f647269000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147629d0fa8c9ac2292c81fc1faa024d3d1a727d953187860b45bcb185d046631ab98261eb6f2b8d54": "0x00000000000000000000000000000000000e41626c652057616e646572657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147642074451d24466b2e07be4d6d82f546ec91d6009ee215bb736be5b4362e66e7b466ec72d47624f": "0x040100000002000000000000000000000000000000000a534158454d42455247001768747470733a2f2f736178656d626572672e636f6d2f1840735f736178656d626572673a6d61747269782e6f72671468656c6c6f40736178656d626572672e636f6d00000b40736178656d62657267000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471476593933a2785b22f0cd49d0588323d08bdcb1c1e4b71539b8998471df15f41584f98cb9f5008c23": "0x0000000000000000000000000000000000074a617273656e074a617273656e0000126a617273656e406a617273656e2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714768c2c58b90681dfce28672fa749577e198bfe03ec3972b22b47dbbfa9996dca0be76ff05851012c": "0x04030000000200000000000000000000000000000000104d69786f5f5374656c6c6153776170000000136d6562407374656c6c61737761702e636f6d00000b5374656c6c6153776170000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147691ee6d858f48473eb7ee31abeb77dc61aac4a18390bfbe97131da7426583e9df30b3b4e5f5ed71": "0x04000000000200000000000000000000000000000000086d6172316465760000000f68656c6c6f406d6172312e64657600000000086d61723164657600", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471476c0068d9d7b7dea7081fe1fe013c00fbe52543ccd437d45fc26b0d49b7df5c117de02c4193c7d12": "0x040000000002000000000000000000000000000000000b6672616e6b7977696c64000017406672616e6b7977696c643a6d61747269782e6f726700000000000b6672616e6b7977696c6400", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471476d10d82508ddae096e24e9b5ab82dc275b82318a52cebed1cae3e25be096d5f288229b256359e43": "0x040000000002000000000000000000000000000000000b537769737320506f6f6c0000000000000c4073776973735f706f6f6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471476f5243ff4ce86095604806a738c7e4d516625d47db7a4ac3197142b84203c1495b6689b066d9d44": "0x0000000000000000000000000000000000094772697a7a3337350000000000000a404772697a7a333735000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147724a5ea734f20f7bad6db470dcfd5ee86f6e3abc0e5351fa654cbb5528f4daf2f0d393f4a46b421": "0x00000000000000000000000000000000000749555244414f0749555244414f0000176975722e70726f4070726f746f6e6d61696c2e636f6d0000084049555244414f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471477300f589b9251ff6c695c4e546c6889ca591b582eee8b49ba68d8485a3732e08d232b2f28f2342e": "0x040100000002000000000000000000000000000000000852796162696e61001468747470733a2f2f72796162696e612e696f2f144072796162696e613a6d61747269782e6f726710696e666f4072796162696e612e696f00000b4072796162696e61696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471477364a8cd584fbff7ed6682224da03023f194d53bbd806050575d0794e73f6cf8b99be9ae1bbb230": "0x0403000000020000000000000000000000000000000007696c617269610e496c6172696120456e616368651b68747470733a2f2f6769746875622e636f6d2f696c61726961650017656e61636865696c6172696140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714777b3c12eea4a22494b1ee887c35565f8d72777b3e5d8a7ccfda76b370dcdaa105df7bd6e49b8841": "0x0403000000020000000000000000000000000000000007536572686969115365726869692050726f736b7572696e00001a706f6c736b612e7374726f6e6b406f75746c6f6f6b2e636f6d00000b6d6f6d735f6d696e6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714779e501e142783af7caa3fa184254cc0cd46a0a4fc1be30b87afc70d2b290b9545dd4f7af46dd70e": "0x04030000000200000000000000000000000000000000087765623364657608574542334445560000176163636f756e7473407733642e636f6d6d756e697479000009776562336465765f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471477a0350acc7abcb9f66311b1720ee0da02af2b95c703f1db4e2db091296b598b466ae15c9ea29344": "0x0401000000020000000000000000000000000000000009536e6f776361706500001540736e6f77636170653a6d61747269782e6f726716736e6f77636170652e696f40676d61696c2e636f6d00000c40736e6f7763617065696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471477a8f518e90d0d2cbe1c8831d018fed582688b5e75be3c9983ac1761fb24a916451c6999c0c66f5e": "0x000000000000000000000000000000000009646f746875622d3209646f746875622d32000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471477c114f494effd6f109914286fe2fa65a85cfcdbcd4562010745b1fa12e9f02b62795b740000e541": "0x04000000000200000000000000000000000000000000057074716100000011676f6431373540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714780625038e82798d9410c1acc9de3fc8a2c36e5b1116f435b745ce96335ce5d2e133dc3d27268152": "0x0400000000020000000000000000000000000000000011456173794120476f7665726e616e63650000000f68656c6c6f4065617379612e696f00000b4065617379615f617070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714783efdad4741c0a9a1e99029c8d8deca2c762dc353047586d9a46e523bdf3b4ddbd9fed1ceef71fd": "0x0401000000020000000000000000000000000000000011475241424249545920e29ca8f09f9087001568747470733a2f2f67726162626974792e6e6574154067726162626974793a6d61747269782e6f72671368656c6c6f4067726162626974792e6e657400000d4067726162626974796e6574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147854d7d5ed8a10ef807561257b836e4a4367cd5fb433621781f882de92a97eb03977e092f64af57c": "0x040100000002000000000000000000000000000000000c50444d204361706974616c1c506f6c6b61646f74204d6178696d616c697374204361706974616c00001370646d6361706974616c403136332e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471478a2b18d6db0a15e0bb5e12d2f6ada25c3b64171730f1c9efcf76d3bbccff01abd9f92a9aaac10a7": "0x0400000000020000000000000000000000000000000004474d5a00000012676d7a40636f6465616666656e2e6f726700000940676d7a61626f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471478a4b4280c25b8bdee540d3a73580cf5e0ae2d80ac9d98dc27847f5518d62b652a6561d46c16b553": "0x040100000002000000000000000000000000000000000af09f838f205368616400001340736861646f763a6d61747269782e6f726715736861646f767365726740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471478acd82014dac4867a24e507ab6be3b521af33bebbece8f57f9b8c20ae23a87986ec0518c1ac1d2d": "0x04030000000200000000000000000000000000000000104869726f50726f7461676f6e697374001868747470733a2f2f6c696e6b74722e65652f74796d61741440616564696769783a6d61747269782e6f72670e74796d617440707269732e696d00000840636861307465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471478caef8fe8bb73f2a4d813e676d81d97479f9f15572d9eadcaf4503b654c0f6e7baeb49e84510e69": "0x0400000000020000000000000000000000000000000011566972657320696e204e756d657269730000194076697265736e756d657269733a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471478db440095822ae679ad7966c6eafe858c375d0ec2d0717c59c973ccd7c7c82131d48a76dbc22d85": "0x0000000000000000000000000000000000076775706e696b0d4e696b68696c2047757074610012406775706e696b3a7061726974792e696f00000000076775706e696b0000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471478e05e6ced85f9d7180364775e32443f308fc34a8917ec40227726c736c2817ae56c5b982a17165a": "0x0000000000000000000000000000000000086d6364616e393310416e64726577204d6344616e69656c0000126d6463616e393340676d61696c2e636f6d000009406d6364616e3933000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471478fa03421f9ba61e726ef17b500f436cf596935acac782c71a423d35a959f3e6831f13c34db9d71d": "0x040300000002000000000000000000000000000000000a58594c4f44524f4e450000001978796c6f64726f6e654070726f746f6e6d61696c2e636f6d00000a58796c6f44726f6e65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714790543fc3e74b681e0f527663883fadc99963738cc81dd244d866241b296cb6d54596c296170534b": "0x00000000000000000000000000000000000f4573706163696f2043726970746f0f4573706163696f2043726970746f00000000000f406573706163696f63726970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714794c7db721956af68a56b1da8dc3f4bd58630c15f5754ee634528a007ab510c86a7e1fe6e62f4166": "0x040000000002000000000000000000000000000000000a414c46415354414b4500000010616c66617374616b6540706d2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471479f659a7c9788777c4181e01fbb27d6e4792397efe9becf4a3e4c535be6112f60b5ece445a76552e": "0x0000000000000000000000000000000000157061726974792d7374616b696e672d6d696e657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471479fa24e506fa3936321d847f8a53927fe1132754a7708c61049b2d4816ab6ce7195a8308e97c3d41": "0x0400000000020000000000000000000000000000000015f09f8d8041524953544f5048414e4553f09f8d80135079746861676f726173204361706974616c1f68747470733a2f2f7079746861676f7261732d6361706974616c2e6e65741b407079746861676f7261732e632e693a6d61747269782e6f7267207079746861676f7261732e6361706974616c40747574616e6f74612e636f6d00000e405079746861676f7261734349000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147a03e16a44321a127421cac8b6fb5e37a318f997074319584b2be9ca7f9ded1f7c999e27f7eeef02": "0x00000000000000000000000000000000000753504143455f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147a246b025078730ed4fa8184e7ea69dbb3cbee71cfd7490803d457140d5d57d0e53a49a887bc4a06": "0x00000000000000000000000000000000000c6578706563746368616f730000001a65787063746368616f734070726f746f6e6d61696c2e636f6d00000c4065787063746368616f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147a2939f6c5b0bc2542a463a7a8813a1272eb8605af0c83660ce65b57d3d5f85ffa5eeff31793ad21": "0x0400000000020000000000000000000000000000000013416374697661746f72207c2053657262696100001a40616374697661746f726e6f64653a6d61747269782e6f726718416374697661746f726e6f646540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147a390aecbef66d7830ef2d9cf069b213123b970d5b3f1cbba939a6a5f4af7424e0672751b8a2ae1f": "0x00000000000000000000000000000000000f73696c69636f6e7072616972696500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147a4ea65f46c7d37580919233b08e12a121b170ef3622bd400ca60df99cd7a4cac5eae6f06025380b": "0x00000000000000000000000000000000000d6f6e64617869616f2d646f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147a8b32f16affc46690c0525e98b52472f3330771f76feda69ddd01aeec5995085b96df4a0d6abce5": "0x0400000000020000000000000000000000000000000012424420426f756e74792043757261746f7200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147a92dffceaab6643ede4ad3403c21a44fff398a158e058f9212e92444bdcbc699ef01962578ba4f5": "0x00000000000000000000000000000000000750414e4b414a1150414e4b414a2043484155444841525900001d70616e6b616a63686175646861727931373240676d61696c2e636f6d0000000b506f6c6b6176657273650000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147a98c3963c233c3248d3348d85e6e65def6ce7fdf16f9a8e7c7e3290ee2fe99ffb568a1ad86e1676": "0x040000000002000000000000000000000000000000000553696465000000177376657a3038334070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147a9fdf3a1eeb5b7d52fad643426e11575fa0a9069bf4d383b04fd311150ad974af8f5d4b3a6e5b1f": "0x000000000000000000000000000000000010537461726c61792046696e616e6365001968747470733a2f2f737461726c61792e66696e616e63652f000000000c40737461726c61795f6669000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147abb02eb1d54cf5dd5b89078eed9b9dfec5c7d8413bac0b720bad3bd4078c4d8c894325713192502": "0x000000000000000000000000000000000008427261646c657914427261646c657920416c6c656e204f6c736f6e000019627261642e6f6c736f6e2e35383740676d61696c2e636f6d00000c4062726f6c736f6e3130310f427261646c65794f6c736f6e36340000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147abc5f242c0220a7ec9579e168a1b2200cc3447f5e3c29f74883683ab134cac6372f378dee048745": "0x040300000002000000000000000000000000000000000b4561676c6520f09fa6850c4b656c6c7920496c6d6572000017636f6e74616374406561676c652d6e6f64652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147b1b6d2a1ef31b0a3e8c72ac1b710bbce4e7c190568bf560d89416696ac2a4700406487cde98df04": "0x040000000002000000000000000000000000000000000a4d454e47204c4f4e47000000176c6c6835393132323138323440676d61696c2e636f6d00000e40444f545f6d656e676c6f6e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147b232746110617a52cbc67180b8230618e420c16395099c9f44fb825b8c3c649d670e6aa409f5539": "0x00000000000000000000000000000000000d4a616d657320576f2044464700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147b5162449d2d3491bc5db9edb63d7b17fabfab232318e1b087066c0f23b06553f9080fb61a523616": "0x04030000000200000000000000000000000000000000104144494f532041205455204a45464518486563746f72204a6573757320536f736120476f6d657a000016686563746f72736f73616740676d61696c2e636f6d00000c686563746f72736f736167000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147ba825eccf7c1a59b66fc334c7c76cef9cc5ceac0f4b0837d845453a2e0e84703b280edf202c8f76": "0x04000000000200000000000000000000000000000000055554584f00001340766f6a7463683a6d61747269782e6f72671b766f6a74613135392e73747564656e7940676d61696c2e636f6d00000a403078566f6a746368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147bbbfadb8086c23baeb6173b1b6d5933c79992954d1469e845a89a5c754f91a9cb2f7589d78b9970": "0x04030000000200000000000000000000000000000000084d61785f4849430a4d6178205265626f6c00001a6d617840686172626f7572696e647573747269616c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147c44d632272a194b12b8bb5de35aa1722e1996065bb42a0fca24449625d4f72cdc483e682b22832c": "0x0403000000020000000000000000000000000000000005444f544117444f54417c444f543230206f6e20506f6c6b61646f7400001367656e697573756e40636861696e2e70726f00000b646f7432305f646f7461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147c4a65539d0e9a75fc8163c92cac3dd1d5c2c0a049c3652a8b3b8b6cb8a0867a5e494c650b4de371": "0x040000000002000000000000000000000000000000000d504f5354434841494e2e494f00000011646f7440706f7374636861696e2e696f00001040706f7374636861696e646f74696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147c90c43e925f2226fea885b4e897d4fe908db6abeb39365ccc4689c2b6437dba675a4a0a0c0a6610": "0x04010000000200000000000000000000000000000000073330383072611f33303830205265736561726368202620416e616c7974696373204c74642e1468747470733a2f2f3330383072612e6c74642f13403330383072613a6d61747269782e6f7267107465616d403330383072612e6c7464000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d28858f34005cc8b6761e35250c1155f4bd6eef565b7d28f7ccca539fd8f678ec0563427c9d9d46": "0x000000000000000000000000000000000009534147494954415200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d2e715ea1e6005feacf33e37aff83d33c7472ff69683a322ab320d9de25586311e75b6ac8270f5c": "0x040300000002000000000000000000000000000000000b4361726c6f2053616c61124361726c6f2053616c612047616e63686f0016406361726c6f73616c613a6d61747269782e6f72671a6361726c6f73616c61674070726f746f6e6d61696c2e636f6d00000d406361726c6f73616c613232000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d37f03ec99fdcbb1caf1e15eeb0d3a899f1c3e1aa7d5178d4b3e4f29c89667e7c4560172371660f": "0x000000000000000000000000000000000009506f6c6b61646f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d3c2944c766ee6eaa328d54b650d207564ecb9d0267e1bc52c18e22abe6366af6014ca53d06cb33": "0x000000000000000000000000000000000009706f6c6b6164616e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d652feaf863f69f94546ff56643b8c0fed386347d7a8cd0b995383125a0fc0f0e45f0e33a6c5827": "0x04010000000200000000000000000000000000000000196365647269632e414141f09fa68a7c20616a756e612e696f001268747470733a2f2f616a756e612e696f2f1540726f786f6e746f783a6d61747269782e6f72671063656472696340616a756e612e696f00000a40526f784f6e546f78000d6461726b667269656e64373700", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d6d64049c8aa12d29cf01efa70d0f6f4758a5b5374469b0b4d1cd239ce2e5ee2d38fb4b70efdd1b": "0x00000000000000000000000000000000001847696f74746f20427261696e20476f7665726e616e636500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147da0ec7e951876bb62b8fd03e30e4f98b0da0e2a99caa7efff8b951990ead650ae3bb9ae36982651": "0x040300000002000000000000000000000000000000000756614b614e6f0d41726c6579204c6f7a616e6f00001661726c65796c6f7a616e6f40676d61696c2e636f6d00001e68747470733a2f2f747769747465722e636f6d2f56614b614e6f425443000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147da931f7536ac4ab484d62a228121a1800e26e8b0139995703309a81ca4467308d734b4678da3d40": "0x00000000000000000000000000000000000a4669676d656e742032001368747470733a2f2f6669676d656e742e696f000100000b4669676d656e745f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147e5babdd52e35979dc308c3ff0d8cecba66c3198e955d6986b577f2778da300964daa5c05f31310d": "0x040000000002000000000000000000000000000000000a56616c6c65746563680d56616c6c65746563682041421568747470733a2f2f76616c6c65746563682e65750012696e666f4076616c6c65746563682e6575000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147e8c7a3ed6096e376c38ee38bd0943c66fbec7b8222ce117c0feeccdb9c5cd9ccddaafe82bab4c40": "0x000000000000000000000000000000000009506f6c6b61646f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147e954ecfd56b24afeea0ee586e9b430c8b3f0fb625bd8ef5f9f6447e72d8c7e84a24c1a34abe9753": "0x00000000000000000000000000000000000c5375706572636f6c6f6e79125355504552434f4c4f4e5920434f52502e1968747470733a2f2f7375706572636f6c6f6e792e6e65742f17407468656d61726b69616e3a6d61747269782e6f7267186d61726b69616e407375706572636f6c6f6e792e6e6574000011407375706572636f6c6f6e795f6e6574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147ea9886926039761182fe099d0c1787bb1b88de855537dcce095204028736ecfde09dd115c498f2a": "0x040000000002000000000000000000000000000000000c503250205354414b494e47001868747470733a2f2f7032707374616b696e672e6f72672f001a7032707374616b696e674070726f746f6e6d61696c2e636f6d00000c405032705374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147eaf54d33fb6eaa0e45255703a954986602a77b7103cd062576f33811e5b5b853de2ec1d120ea609": "0x000000000000000000000000000000000009616e64793230343609416e647950656e67000017616e647970656e673230313540676d61696c2e636f6d0000000009616e64793230343600", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147ed96b7d3f8a3e92083857fb5e068b7253110088fdc0431964252a7d2f46622d6b3cfc66be587c30": "0x0000000000000000000000000000000000087361746f73686900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147f1f1924b3cbcec77a2b3317472cfc9a20318bf0054952052ef8df169438af1b188eeaedb2bc030e": "0x04030000000200000000000000000000000000000000084145436861696e0b4164616d204576616e7300001b6164616d2e6576616e7340636861696e616c797369732e636f6d00000a406164616d65766e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147f38100bed09f866b0b000e408509bb033443af0bc700ec11894f81c090d58d7dc2ae3174c54902b": "0x04000000000200000000000000000000000000000000074c4547454e4400001a406c6567656e64373334313231363a6d61747269782e6f7267156b7572746f736973407961686c6f6d692e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147f6122436697b141faff1c4b5a94649e0338783122b93a469eb9e2e375bb71c92028a8fe9b6e2f46": "0x08000000000201000000020000000000000000000000000000000016546f74656d204c697665204163636f756e74696e6711546f74656d204163636f756e74696e671c68747470733a2f2f746f74656d6163636f756e74696e672e636f6d0019696e666f40746f74656d6163636f756e74696e672e636f6d00000d40546f74656d5f4c6976655f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147f659dc8b63c4bfa16bf09f62054218ff31e36e042d5c0e56aea26366bfd8c75cff2835ced5afb41": "0x000000000000000000000000000000000012f09f9890207c20f09faaac2067686f7374000016407265706c67686f73743a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147f746099fc9e6cff3cba3cb96173c2dfff3f2bb0cf5e3c70784cffadbf02b1b2be4fcdd1f78e4374": "0x040000000002000000000000000000000000000000000c42697420436174f09f90b1000013406e69756e69753a6d61747269782e6f7267186269746361743336352e636f6d40676d61696c2e636f6d00000b40426974436174333635000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147f88ca6ada2372bc1a0eb7fdecee073651f1a21b9779b7bf5670493a0e35a53ab83b3cabab814a77": "0x0400000000020000000000000000000000000000000008316b766e6f6465000013406461766534343a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147f9e55d7623ce6876ae93e7162785a77d3a2c0413a9ee04af1b948ba5df9ac191552b72e1dd49b71": "0x04000000000200000000000000000000000000000000064372616e65000000000000094030786372616e65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147fa9548e769cc523a237fa87e569e6b5aed61aefe41eacafe0fd7000ca90f888e8517e77be1f3c78": "0x040100000002000000000000000000000000000000000c457175696c69627269756d001b68747470733a2f2f7777772e657175696c69627269756d2e696f001568656c6c6f40657175696c69627269756d2e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147fc4f80a616861525e9ec2d24e959cb9053751ac65b19ef3bc380ed2c24fa23a6bfa44c36b58d928": "0x040000000002000000000000000000000000000000000d4c4155524f20e298aeefb88f000000156c6175726f677269706140676d61696c2e636f6d00000c406c6175726f6772697061000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147fd837e50e26922d265013803cbe5f9f3ef7b38ad278b6d097d3be3ed79248030f460ba93d164a60": "0x040000000002000000000000000000000000000000000b5354414b452e5a4f4e45000016407374616b657a6f6e653a6d61747269782e6f726710696e666f407374616b652e7a6f6e65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147fe9c3b575119fc9bea849c82dc0da19b799de164e15d83352559a2a6ca5fee6bf3f35056a997a21": "0x040000000002000000000000000000000000000000000f506f6c6b61646f7420496e64696100001540616d69742e776f773a6d61747269782e6f726717616d697440706f6c6b61646f74696e6469612e6f7267000010405f506f6c6b61646f74496e646961000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148015f9c9dfb7b49a281a723802b50fb25a874e19d4f643168f4016aa759bad298940eb455cc87249": "0x040300000002000000000000000000000000000000000e506f6c6b6157617272696f72730f53616e6720486f6e67205472616e00001868656c6c6f40706f6c6b6177617272696f72732e636f6d00001040506f6c6b6157617272696f72735f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714801d924a92a5fc1918bd4fb6b90f5088bdc825c3d674bd72e705c6f1163e86f960eeb7969ab4833a": "0x040000000002000000000000000000000000000000000857315a53505233000016407265706c67686f73743a6d61747269782e6f72670000000b407265706c67686f7374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148031c0fb42aa475ed26298f9adfd81b0194a572bd49c0a8469acdcb585586dfc22bd1deef8a8e705": "0x00000000000000000000000000000000001b496e7465726c6179204c7464204576656e747320426f756e747900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714803d5aecf59783b17628a5be63c4d3c8dbb96c2904b1a9682e02831a1af836c7efc808020b92fa63": "0x0400000000020000000000000000000000000000000006626b63687200001140626b6368723a7061726974792e696f0000000740626b63687206626b6368720000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714804e9334b8d21cf9c26ccc67ae0f9051eb2f2b1795b8f166f46536a29b6651fe7f6bb1f8b550047f": "0x040000000002000000000000000000000000000000000c5368616b7572686172756e000000167368616b7572686172756e40676d61696c2e636f6d00000e40416761736869486172756e6100115368616b7572486172756e233837393000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148078a26b9e8719c946e2508c379dc61858e00b9fbf1424b12b64d5120d2f16c525822f94acc0f435": "0x040000000002000000000000000000000000000000000a4d61676963205461620000001679736e61796e6e3230303240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471480815510d147d8979a0b9cef028c95b4635cd22fefd9001a544d17eae85fbaf1857fda4d9f4ba75f": "0x040000000002000000000000000000000000000000000c6d616c697a652066726564000017406d616c697a65667265643a6d61747269782e6f72671663667265646d616c697a6540676d61696c2e636f6d00000e4066726564636872697374757300106d616c697a6566726564233234373200", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471480903a9113fc7d1e24be4391bcf17d95b0ccf03c2c1374f0e20c7a886eccfb3a77b373f3ff97166d": "0x040300000002000000000000000000000000000000000d44697667756e2053696e67681344697667756e2053696e676820536574686900001764697667756e2e736574686940676d61696c2e636f6d00000874656b76797979000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471481032745bb8fa3a2ae2d99c29e603ff76a9705ac23371d47b7245bc3bf953ca7906347b952390d78": "0x040300000002000000000000000000000000000000000b416c657820486f75647a0000000f616c657840686f75647a2e636f6d00000b40686f75647a5f6b656b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714810532057fdf6829669618142822c01d88debd960eaa1d3dbfcb243ad965b8a5ded1c7b7c15b2226": "0x040300000002000000000000000000000000000000000c504241202d206d72617374134d69636861656c205261737461646d6568720000196d69636861656c2e72617374616440676d61696c2e636f6d00000a404d72617374313131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714816c2a63e3c205f4981c728cb2461814ec4e6cb50906eded0e4f51e5513018e28753337cfb971d70": "0x0401000000050000000000000000000000000000000006546164656a00000011746164656a406170696c6c6f6e2e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714816f363193f343a643fa61b298e82f9f207ddea327900cee26b554756c4a533f36cd875e3e7bcf06": "0x04010000000200000000000000000000000000000000114163616c6120466f756e646174696f6e001668747470733a2f2f6163616c612e6e6574776f726b001468656c6c6f406163616c612e6e6574776f726b00000e404163616c614e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148179afc2191e064c0ecd029fdf9259e900f08996fc9862ebfe100d49c439f19bef7084b258175a1e": "0x040000000002000000000000000000000000000000000f507265737362757267204c6162730f507265737362757267204c6162731a68747470733a2f2f7072657373627572676c6162732e636f6d001d7072657373627572676c6162734070726f746f6e6d61696c2e636f6d00000f405072657373627572674c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471481bac95793d75f5ac6d1e9633ce74e1a09f9ca37470de256f8d1cd977ba4e4eb994258dc078f4429": "0x040000000002000000000000000000000000000000000e4265696e67205361746f73686900000017616e616e74406265696e677361746f7368692e636f6d00000e404265696e675361746f736869000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471482a2945d18dc6de7685dc052a755ac3cecc0b0bd0d1405ade433d8463a3cabc1e5b7eedb13c08871": "0x040300000002000000000000000000000000000000000552656d791752c3a96d79204269656e2042616f20506572657474690000126c65696d69303640676d61696c2e636f6d00000a40736578796465666900086c65696d69303600", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471482b81636ee5910ca452de33977b421766e2191acd0b79dd6760fb5e56aee0b00a02422df3f35b26b": "0x0400000000020000000000000000000000000000000010466f7274756e654e6f6465732e696f000015406769736c656d6f6e3a6d61747269782e6f72671668656c6c6f40666f7274756e656e6f6465732e696f00000f40466f7274756e655f4e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471482b8bce0892920f9ca3d904d81a1b1ba11bd6e391daa897b907ff89c5c5aebfe6f2da23292b8500f": "0x040300000002000000000000000000000000000000000d5765796c616e645f46756e640000001a79616e6777616f406d6574617072696d652e6e6574776f726b0000086b6f6461646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471482d187c7f127ad6e6c49e0b3f2b674374ad5d80a75f1e60cdd012e6e8e3739a10cdae9cb76ef857c": "0x00000000000000000000000000000000000c453230205374616b696e6700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471483253a02c1f77c53a0c4d9864d312099740db16ed243615447e5ca42aa689fee0109c195c65fa91e": "0x040300000002000000000000000000000000000000000a43687269737469616e1143687269737469616e20436173696e6900001e63687269737469616e636173696e693139393340676d61696c2e636f6d00000c4043687269735f4e696674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148328836b7b67fa4fdab8f87f6dfc47a03ebf8901b36039ebfce8707a2c5d3f4ff099d788ca6a02fe": "0x040000000002000000000000000000000000000000000555545341000018406c65736e696b5f757473613a6d61747269782e6f7267176c65736e696b3133757473614079616e6465782e727500000e406c65736e696b313375747361000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148348313aaefc25eca801051533332369ef5a24d9d7d13709896d3e170297851c63123b26a4034137": "0x040300000002000000000000000000000000000000000d53657262616e20496f7267611253657262616e2d496f616e20496f72676100001473657262616e33303040676d61696c2e636f6d00000a73657262616e333030000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714839f1a74e283a0e1b26cea7b8424d659bd6ee2dc3176d96dc7d646ebff25fa7004c88c68770d584f": "0x040000000002000000000000000000000000000000001b50617472696365202d2054656e64616e6365732043727970746f0000001a74656e64616e63657363727970746f40676d61696c2e636f6d0000114054656e64616e63657343727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471483c5f86634d0a9e146190509288f1d1dabe6de4917e2a5765eda06bbaa156d19d55e2b7f813dd416": "0x040000000002000000000000000000000000000000000c4d697373426974636f696e00000014646f74406d697373626974636f696e2e636f6d000011406d697373626974636f696e5f6d6169000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471483ce59511097e6b62add0af948eba3b1fcd5cacde1f6fcc70f11ef75056f88ca4d11dcc5b080220e": "0x0400000000020000000000000000000000000000000017416c62657274202d2049204c6f76652043726970746f00001840696c6f766563726970746f3a6d61747269782e6f72671e616c62657274706f6c6b61646f74737061696e40676d61696c2e636f6d00000f40495f4c6f76655f43726970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471483da9cc355d0681680d8a3f4317249a895e4b49badcfa7293cfbd215d6e552d1c07024d36acfbd5d": "0x0800000000020100000002000000000000000000000000000000000f53696d706c79205374616b696e67000000197374616b696e674073696d706c792d76632e636f6d2e6d7400000b4053696d706c795f5643000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471483dcba70a0b190a2a2d23b8643531f6e7ae2dd88ff990de4edec8ec0c655002caca002756d1b2704": "0x00000000000000000000000000000000000d4461766964204172636865720d4461766964204172636865720000156461726368657237383640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148407ca5b0d3d9daf59a32cbcf20e6fd03a2044525bf4b0676c4d0f1fa5f6f15699c607aa705f1fec": "0x04000000000200000000000000000000000000000000056c616461000000136c6164612d6b6d764079616e6465782e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714842f41c0d4632e2e769ab3ef0ff669144d7046a0d9f11b76ec2efa8aa76bdbb0fedb69e8126b897b": "0x0400000000020000000000000000000000000000000019f09f939c20486f6c7920436f6e73656e73757320f09f939c000015406d6f67696f6d616e3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148461b8e5b35b37172450c3f4fb88d8cf3e0a4f044b4ad1d327ecd3e6b1d7dfbb999713f04ee1e87d": "0x0400000000020000000000000000000000000000000011e5a4a7e59684206461697a656e2e696f000013406461697a656e3a6d61747269782e6f72670f696e666f406461697a656e2e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714846cf02493758816a4cd4dd151f0106d8157bdf02bfac75f9abe8e635ecc6498b8a8f6acc1f5e674": "0x0401000000020000000000000000000000000000000014f09f908b696d546f6b656e205374616b696e67001168747470733a2f2f746f6b656e2e696d000c626440746f6b656e2e696d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471484738c96361adf35624b8f2e5a08aa4e0dc556fa9745a1509c91a8c17dae991bcfdf89133ffc5b00": "0x0403000000020000000000000000000000000000000012506f6c6b61646f7420536176616e6e6168002068747470733a2f2f6c696e6b74722e65652f776562335f736176616e6e61680015696e666f4077656233736176616e6e61682e696f00000f40776562335f736176616e6e6168000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471484d3812801bbbf15b1725c0de514e0df808b19dbfca26672019ea5f9e2eb69c0055c7f1d01b4f18a": "0x0400000000020000000000000000000000000000000021416e74692d5363616d20426f756e74792047656e6572616c2043757261746f720000001a616e74697363616d40706f6c6b61646f742e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148510852a75250a28040a61ca8223dcb3c203b27167fdee611801375fff6c6f25c71c3e3ca86cea65": "0x040300000002000000000000000000000000000000000d566963746f72204f6c6976611456c3ad63746f72204f6c69766120566964616c000012762e6f6c6976614070726f746f6e2e6d6500000a40766f6c6976615f76000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148532f472372d0e04e83a05a23704fc96cae39473196633a53d1820656f8b81f7bf30637ce41bd965": "0x0403000000020000000000000000000000000000000004414a501b41697a61204a6f7963652050726164617320536865707061726400001661697a6131376a6f79636540676d61696c2e636f6d00000a40616a637073686570000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148549b7fd2bfcfdd9bc0525c374a8198f3288a0733918321dfc26532e253d94da3a6a27a4c3e31760": "0x040000000002000000000000000000000000000000000b506f6c6b612048617573001c68747470733a2f2f7777772e706f6c6b61686175732e636c75622f0014696e666f40706f6c6b61686175732e636c756200000b40706f6c6b6168617573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714854f02c37bb0a17d4653f0d351f8bca69b7be83c41b90fcee17c7ac2b285bb01a95b3755a6101a3c": "0x040100000002000000000000000000000000000000000b52616469616e63655f3905416c657800124061636964783a6d61747269782e6f72672172616469616e6365395f7374616b696e674070726f746f6e6d61696c2e636f6d00000c4052616469616e63655f39000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471485776350491a535bcea1d92de6550af9c490706f76cb9e12458c4632ad594cd66784630ad2e1ef34": "0x040300000002000000000000000000000000000000000a54686520424c4f4b431254686520426c6f636b6c61627320496e630000127465616d40746865626c6f6b632e636f6d00000f40746865626c6f6b6367726f7570000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714858c0d6078e97ec2863010a4400694804bb594ed57a7d55e6149ce2e8abe2657b601fe2a7fabed00": "0x04000000000200000000000000000000000000000000145061766c61207c205061726974792044617461000011407061766c613a7061726974792e696f0000000a406461656d69613130000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471485a31ae8c4d5be8eea99c22436f5014c366a3e94a05c3410b997e436a414f7697af3f8206fa87e5a": "0x04010000000200000000000000000000000000000000114175726f726120506f70707973656564114175726f726120506f707079736565640000196175726f72612e6d616b6f76616340676d61696c2e636f6d00000e40706f70707973656564446576000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471485a3d2fc56fa42403616337a83344f0849510571f384a48a55563b6618304e4da6162c4b7cc48e53": "0x0000000000000000000000000000000000186f7869786f20706f6c6b61646f74204e585f424c41434b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471485c4e925378eb4916c42f37017f31d6c9ba5dca62626e6fb434d6edc31bfc9aa49f001a6ced27876": "0x040000000002000000000000000000000000000000001df09f8fa2204d696e6973747279204f6620426c6f636b7320f09f8fa20000001778406d696e69737472796f66626c6f636b732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148613e243ad5accda52a6c52dc82940a36fefd1474cc0778517bb1a56b7bda0e308b6c19152dd7510": "0x040000000002000000000000000000000000000000000b4f70656e537175617265001f68747470733a2f2f7777772e6f70656e7371756172652e6e6574776f726b1840776c69796f6e6766656e673a6d61747269782e6f7267166869406f70656e7371756172652e6e6574776f726b00000d404f70656e7371756172654e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148621671899b86161726ac63a0a6a700ad7e1178fef89a87620bbc152a19f74708defc7f08bbc6556": "0x040000000002000000000000000000000000000000000a426c6f636b4374726c00000019626c6f636b6374726c4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148640e8e247a0e20f30cfdb48ff7f33b08499dfc618a8ef9699b8345fa65f0b1339eb8eec3c0e4555": "0x08000000000201000000020000000000000000000000000000000018f09f949273746174656c6573735f6d6f6e6579f09f9492001d68747470733a2f2f7777772e73746174656c6573732e6d6f6e65792f19406161726f6e7363687761727a3a6d61747269782e6f7267194161726f6e2e416e746f6e6f706f756c6f7340706d2e6d65000010404d6f6e657953746174656c657373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714864262e04bb1d055588b5b3b691acdcdcbbc78158f60b97398185efb643eed0bba3e8ad6ac24b545": "0x040300000002000000000000000000000000000000000f4c756e6172205374726174656779134c756e6172205374726174656779204c444100001a696e766f696365406c756e617273747261746567792e636f6d00000f404c756e61725374726174656779000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148665682395484a7f5e5e31bfd996593554b54016676af00cc0ac2015b12c8824e5a50315f1bfe05a": "0x000000000000000000000000000000000012426c6f636b737061636544657672656c730000194073616368612d6c616e736b793a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471486a03b31f22c207f6607dc83a7fc1f33c13e978ee3527fdb2c908ae6b5c0d2dee81bf30a01808263": "0x040000000002000000000000000000000000000000000c426f747469636577736b69001968747470733a2f2f626f747469636577736b692e6172742f001b626f747469636577736b694070726f746f6e6d61696c2e636f6d00000d40626f747469636577736b69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471486e69567b2fc7d85a44fe0211e518d4a7e0d647cb66979cafcf322d3427972abf875d29c7c76d501": "0x000000000000000000000000000000000013776f73732d303031407375627374726174650f44616e69656c204d6172696369631068747470733a2f2f776f73732e696f1140776f73733a6d61747269782e6f72670f64616e69656c40776f73732e696f00000940776f73735f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714870976f0672085c5f8ff75032359f0de13264a134c3e88089cf6a2a31e5cf3cdfe405a4e272f0508": "0x040000000002000000000000000000000000000000000d547963686f204d61736975730000000000000e40547963686f5f4d6173697573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714870de10fb6114007fed7d1cc37fe7a63ac7e5882194d3684e12a17df4d2848a4f4b7e5abefed92c9": "0x04000000000200000000000000000000000000000000125969656c64426179205472656173757279000019406e6967687477696e672d79623a6d61747269782e6f7267166e6967687477696e67407969656c646261792e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471487116eaed0a9a16e7e29f9518827a1bfb2e3b6a8a153cb136f9405f68c728f9c8a38c7971897b77b": "0x040000000002000000000000000000000000000000000f434f494e205245464552454e43451b4a75616e204d616e75656c2053616e63686f20506974617263681968747470733a2f2f636f696e7265666572656e63652e6d6516406a6d636f696e7265663a6d61747269782e6f7267166a6d66696e616e6765737440676d61696c2e636f6d00000c40436f696e5265665f636f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471487149495530dd8d3f81550f147455d286246994dbf4bfa37961d235b96ed8d1189b7445c18680f50": "0x000000000000000000000000000000000006646f796c6500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714871588d7f6c0fdd3002f931bb0cf405212de02243756d8ff665710af7fb234bfb1a50bb78ae1327b": "0x040300000002000000000000000000000000000000000b52617669204b756d61720b52617669204b756d6172000015697473796f757261766940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714871c07918bd122cae4a15453d67f7353ee3d4eca8f465b2337e675b5efdebebe8209b6179af0bb43": "0x00000000000000000000000000000000000f5a6565205072696d65204c6162730f5a6565205072696d65204c6162731368747470733a2f2f7a706c6162732e696f2f0012636f6e74616374407a706c6162732e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471487258a23c1cc74c20c618307d00b3354999ae280858c01fceddd77a25b5bc665fbd4634bf86a4178": "0x04030000000200000000000000000000000000000000057469656e115469656e204e677579656e204b6861631268747470733a2f2f7469656e2e7a6f6e6513407469656e6e6b3a6d61747269782e6f72671b7469656e2e6e677579656e6b6861634069636c6f75642e636f6d00000d405469656e4e677579656e4b00087469656e2e6e6b00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471487537aeb7813f75e5efbe83a561d19b1d21126af5f1608ed28e56f4f70251cf965fe3dcb4901a26b": "0x04000000000200000000000000000000000000000000084b686173746f72000014406b686173746f723a6d61747269782e6f7267127374616b65406b686173746f722e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148756caab39a157be040f4dbfe9b3333f7faf9304bf2ba9af0b4f850bab4e716759e0ebc8c4703c8c": "0x040100000002000000000000000000000000000000000a434f534d4f54524f4e00001740636f736d6f74726f6e763a6d61747269782e6f72671d636f736d6f74726f6e76616c696461746f7240676d61696c2e636f6d00000c40436f736d6f74726f6e56000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714878042bdd9d96dd3f07260abfd43d442e54357c409f75680478b2e97f348126e199537eaf964b342": "0x0403000000020000000000000000000000000000000007536f757261760e536f75726176204d6973687261000016736f757261762e6d2e627440676d61696c2e636f6d00000a3078736f757261766d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148795674870556252585e982d74da4f4290d20a73800cfd705cf59e1f5880aaee5506b5eaaf544f49": "0x040000000002000000000000000000000000000000000c446f6f7264617368636f6e0000000000002068747470733a2f2f747769747465722e636f6d2f446f6f7264617368636f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471487ac7128ed93fd445e50e6e8499b921414360c3da7de7ca78544e38412bb6dc313383aaceb7c2068": "0x040100000002000000000000000000000000000000000a5072656d6975726c790e5072656d6975726c79204fc39c1668747470733a2f2f7072656d6975726c792e696e2f0015636f6e74616374407072656d6975726c792e696e00000b407072656d6975726c79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471487b8d0a4f87b32a47c3f190f0abecf2b39643a21a67df302a024487d84128d5bc68fcc445ac23a06": "0x00000000000000000000000000000000001142494e414e43455f5354414b455f31301142494e414e43455f5354414b455f3130000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471487c09bd19ab0b74df0802c5c92cc72abd8e7b849f32513f21d05bea7f60ec3f92a20854def08f247": "0x040300000002000000000000000000000000000000000b43727970746f5769736500000015636f696e6765656b323240676d61696c2e636f6d0000104063727970746f7769736567757973000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471487c5eb005741995b4a729cc2bb0da0787bfa545a498c261969623c3042b3099ffe331c5728f94125": "0x04030000000200000000000000000000000000000000084261727265746f0f4d617274696e204261727265746f0000166d746e2e6261727265746f40676d61696c2e636f6d00000b6d746e4261727265746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471487d2f749afa8b991984e16482c99cfad1436111e321a86d87d0fac203bf64538f888e45d793b5413": "0x0402000000030000000000000000000000000000000004576569095765692054616e671268747470733a2f2f7061636e612e6f7267000e776569407061636e612e6f726701bfa78a598c9343be661a1ee6e175faa5093a30680000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148827ff7e5656ef4ab1dca1726b672e75cdbdf56f990fc4170e44d460821e91a89d846f2359b45fb3": "0x0400000000020000000000000000000000000000000010467265736843726564697420496e6310467265736843726564697420496e631868747470733a2f2f66726573686372656469742e636f6d001e6465766f6e2e73686967616b694066726573686372656469742e636f6d00000d406672657368637265646974000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714885fb110161cbc6f4227279d29a93cb842f44a0bc9c29f4041d903011031bf155e7cb64814e37a6c": "0x00000000000000000000000000000000001f436f72706f7261746520506f6c6b617373656d626c79204163636f756e74001e68747470733a2f2f7777772e70656e64756c756d636861696e2e6f7267001c636f6d6d756e6974794070656e64756c756d636861696e2e6f72670000104070656e64756c756d5f636861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714886cf5449f57c7b92488bc636ae2d90c355a53620f8c6dc36c8f30837f805ea399710bc2a43d6d18": "0x000000000000000000000000000000000006535441534800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148873265c60b23b3ce47c0672b1389c3456de496556d40ad8f2923595d54eb1f69b617febb8292501": "0x0000000000000000000000000000000000094b6f6c6b61646f74000000156b6f6c6b61646f74383640676d61696c2e636f6d00000e6b6f6c6b61646f745f6d656d65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471488a1a127cd77d12b806fc8e477a0cab0bd93e76f7e9f73fdee31ffe7dcd7d052037c39554f212e04": "0x000000000000000000000000000000000006532d646f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471488ffc163fa9907f076f9c831b885b8f1a216a27064fa793733b162ee06afb502a8cdbc2ccd6cc536": "0x0400000000020000000000000000000000000000000009594a52656e6175640000001c796f76616e6e7972656e6175643634363140676d61696c2e636f6d00000e4052656e617564466562726573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714894c10549d53016ad8290537d6e31fe1ff165eaa62b63f6f3556dcc720b0d3a6d7eab96275617304": "0x040300000002000000000000000000000000000000000a4a616e2042756a616b0a4a616e2042756a616b1a68747470733a2f2f6769746875622e636f6d2f6b6f7574652f0f406a616e3a7061726974792e696f0e6a616e407061726974792e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148954d9b6c7704b5c0a912cf4f0c7894598d81d26f2c24f6e5c2541f312462bb576593e9dc549146d": "0x040000000002000000000000000000000000000000001051757069642076616c696461746f7200001b40717570696476616c696461746f723a6d61747269782e6f726719717570696476616c696461746f7240676d61696c2e636f6d00001040717570696476616c696461746f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714895c460a54a2e543ea803ae6f4cabebc87af9678cfecfa3c302244b138e0d691947bdae74b4a8c6e": "0x00000000000000000000000000000000000c50696e6b446f6c7068696e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714897931e60764d4ea8e602e63afb364ac583747b0a8bab092d5b20ee98f0495ce7562a8c992ac9f17": "0x040000000002000000000000000000000000000000001070617468726f636b6e6574776f726b0000154070617468726f636b3a6d61747269782e6f72671f70617468726f636b6e6574776f726b4070726f746f6e6d61696c2e636f6d00000b4070617468726f636b32000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148980acab3e7bb9bb1035801fd00144e10a3933ed859f8236bbffb93a7ac515bab9f1ca53cbb3f776": "0x040100000002000000000000000000000000000000000b4a7573745f4c75757575000000166c75752e6b6f6461646f7440676d61696c2e636f6d00000c404a7573745f4c75757575000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471489b10dfbde827732504ee3d36525d0ab821bef5161d7dc32eab7015fcf6f9c913d8b7178f9a5d261": "0x040000000002000000000000000000000000000000000b57617465726d656c6f6e00001b4077617465726d656c6f6e6e6f64653a6d61747269782e6f72671a77617465726d656c6f6e2e6e6f646540676d61696c2e636f6d0000104057617465726d656c6f6e4e6f6465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471489b9a5bd12ebd0af56220569726127d988e0eb1dd10defd87548de2579edcb6490af1214e568232d": "0x00000000000000000000000000000000000f4d65726b6c6520536369656e636521537461636b7365657220546563686e6f6c6f67696573205074652e204c74642e1f68747470733a2f2f7777772e6d65726b6c65736369656e63652e636f6d2f00196e69726d616c406d65726b6c65736369656e63652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471489d14e177f11397c9b62bcf47bb081dc8ecdf2d205b84d7c37261d3b5713b8e303b43537ca3a18ac": "0x04000000000200000000000000000000000000000000194d61726b6574696e6720426f756e74792043757261746f7200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471489f6ea03f6581d565675d0d624354179fa260c34540ac9284cded48d4c2951ff17265c4517a2a747": "0x000000000000000000000000000000000009426974677265656e1c426974677265656e20537769747a65726c616e642056657265696e1f68747470733a2f2f7777772e626974677265656e73776973732e6f72672f0017696e666f40626974677265656e73776973732e6f7267000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148a0b7cb67b16efc758ca37c5cd96fe3b250d9cdbabf28b891a93fd9ae9296e0e66732bfb57206918": "0x04030000000200000000000000000000000000000000084c696d696e616c0000001e6d696c65736272656e74706174746572736f6e4070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148a3ab59566c3860f1ecec4f3062f61988b13e9dab318860bd0fffe5b7b37880d50a614a0a20c2502": "0x040000000002000000000000000000000000000000000a2a2a2a2a2a202a2a2a000000196c756e61722e706f6c6b61646f7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148a452b72d725a7f78a676bf14fbdb4da5cd987dde8b7bfada8064a24aba2775bb573c20e5479e06b": "0x00000000000000000000000000000000000a4344524156454e523200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148a8347ca23548ddc8afa8cba08ebd8a15eec2017ee6c73292be36384ac5666d4a6680ac0bf53e97e": "0x04030000000200000000000000000000000000000000094d61726b65646f7400000015636f6e74616374406d61726b65646f742e636f6d00000b406d61726b65646f7474000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148b0889a31b9f57b3e287c7494655d636a846f5c3347ad2cb3c462a8d46e0832be70fcc0ab54ee62d": "0x0400000000020000000000000000000000000000000008736b756e6572741153656261737469616e204b756e65727400154073656261737469616e3a7061726974792e696f12736b756e6572744070726f746f6e2e6d6500000008736b756e6572740000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148b204d64b79dca3e8a449fac4875a24774175651ffcacc851939eff231fcd2e270e1e29429902059": "0x000000000000000000000000000000000012436f696e46756e642f47726173736665640000000000000d40636f696e66756e645f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148b299234c2604004face99d3401cb9b45ee1bc0ec52f4cb35914dc5ad27806230534230eedb8413d": "0x040000000002000000000000000000000000000000000542494c4c0000164062696c6c3a776562332e666f756e646174696f6e0000000c4042696c6c4c61626f6f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148b5245b925036264bf6429fc1003a7db6b560bcd9a9a5942e05c0d2193190d5739c17eabbf6b61c9": "0x04030000000200000000000000000000000000000000184a5553542042657465696c6967756e67656e20476d6248184a5553542042657465696c6967756e67656e20476d624800154061726e6f6c645f623a6d61747269782e6f72671861646d696e406a7573746f70656e736f757263652e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148b64e7386b807a4c244a3fafb7a625ae311e31f2f83f470228a573ae21e011031a8c0721f86fe844": "0x0403000000020000000000000000000000000000000015f09f90bc50616e646157617272696f72f09f90bc00001a4070616e64615f77617272696f723a6d61747269782e6f72671970616e64612e77617272696f72444070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148b6d998b612fe91d80c622c5213c9ff2cc3ffc7872409b6678e1dae72f63405698e8acfa2db2f06c": "0x040300000002000000000000000000000000000000000c6e69636f5f63616c63696f0c4e69636f6c6f205a696e690000166e69636f2e7a696e69313440676d61696c2e636f6d0000095a696e694e69636f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148b886522779ff3151d426e21be4fd135a6d4a02d9c0adbc43b24a428738c2bad59d722ea6f3e2f11": "0x04000000000200000000000000000000000000000000075a6f6e6461780a5a6f6e6461782041471268747470733a2f2f7a6f6e6461782e636813407a6f6e6461783a6d61747269782e6f72671068656c6c6f407a6f6e6461782e636800000a405f7a6f6e6461785f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148b93860429ecf0c99c1d315cb41447f88f1da0f976f9ebca8970536df07af241ace21b5757383c6c": "0x040300000002000000000000000000000000000000001149204c6f76652043726970746f2042440000001e616c62657274627572676f7340706f6c6b61646f74737061696e2e6573000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148b9d575479a1dea6000e1c0ffb6a29c80083a8b1c4dc4d70fb2fbbd9c1319b8e9c0173aaafbd2963": "0x040300000002000000000000000000000000000000000767616e676f760f4b616c6f79616e2047616e676f7600001267616e676f763140676d61696c2e636f6d0000076767657a7472000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ba29f0652612f2cc4494455e738c0a47b5690708ab81dc9264395046089cd8aa613bae176c4880d": "0x040000000002000000000000000000000000000000000f44535347202865782d44414f5f290000114064616f5f3a6d61747269782e6f72671964616f7465726d696e616c636f6d40676d61696c2e636f6d00000d4064616f5465726d696e616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148bd90fa5b38a5d2d74340c22162ba8ddd49d836d01b693aa4cdc07eced946b0701173e0cd6bc7d69": "0x0000000000000000000000000000000000134e6f6e46756e6769626c654a6f75726e6579134f73636172204672616e6b6c696e2054616e2168747470733a2f2f7777772e6c696e6b6564696e2e636f6d2f696e2f6f736361001c6f736361726672616e6b6c696e2e74616e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148bdc67657419bbeb22ce51e9b096db10638d2889c4a847781e0360f6fd3adffa6280107ef7260f62": "0x0400000000020000000000000000000000000000000018506f6c6b61646f742048756220696e205370616e69736800000016706f6c6b61646f7468756240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148bed542ce020de9fd40d213230a9218267b54e293b86a4c6954d4e89ad60f9553ef9a63ac45dbaaf": "0x0000000000000000000000000000000000094d6f6f6e6265616d001a68747470733a2f2f6d6f6f6e6265616d2e6e6574776f726b2f0000000011404d6f6f6e6265616d4e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148bf84080a1ebdf7ca6f56e262666adfbbd80486024bb3255e8a5e31cf474ba64ea31a7c698833461": "0x0000000000000000000000000000000000084765726dc3a16e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148c508a69b80c90ec54b3e6a7a51343d32931c6f6820a84d8c0a8231906c4171d03e1dba0f0b50746": "0x04030000000200000000000000000000000000000000184d43207c204d43536572766963652e696f207cf09f92a50c4d61726b204372696e636500001a6d63626f7577656e7365727669636540676d61696c2e636f6d00000c404372696e63654d61726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148c56ef07b1e70c6e9227d3657bf3452543e8fcc6861134deffaed05ce3dff0ac63059aa0997c32cc": "0x040300000002000000000000000000000000000000000c434841494e414c595349530c434841494e414c595349531d68747470733a2f2f7777772e636861696e616c797369732e636f6d2f002063687269737469616e2e6d656e646140636861696e616c797369732e636f6d00000d40636861696e616c79736973000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148c7ff1340164f7757d1c361b50b0963e2a3d9533bf324bd7898729d41c82f483117f02af181d8fd6": "0x0400000000020000000000000000000000000000000014496e7641726368204173736f63696174696f6e0000000000001040496e76417263684e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148cb4556b548f669b787d4175bfe47411f2c567fbff326dba11aa94216c2fe904ab2c56b567b6220d": "0x04010000000200000000000000000000000000000000094861727269736f6e0000001b686d63676c6f62616c2e63727970746f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148cc04fabfccee3139a92efbf31781a4ef54d55d10220a3025f65bed342c53c2b8fc3061f3d09c041": "0x040000000002000000000000000000000000000000000c4d794d6574617665727365001768747470733a2f2f6d796d65746176657273652e696f00147465616d406d796d65746176657273652e696f00000d404d794d6574617665727365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148d1ba1cf54c412597876aa7c5c9e71fd79444ae3af051244cd66e2700b875faeb1c280d3026b3d2d": "0x00000000000000000000000000000000000e54656b6f6e7978207a65616c7900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148d211992716663e682635369d20e36ccce82c98283410bfa4a4153e31bedb52b33cbce5543cba21b": "0x00000000000000000000000000000000001042494e414e43455f5354414b455f341042494e414e43455f5354414b455f34000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148d23d124156802cc9e25b58a4b93c0c51a65333999fc9f857deb2eace23e3c83ed79b2c08287343d": "0x00000000000000000000000000000000000a5374616b6542616279001668747470733a2f2f7374616b65626162792e636f6d0016636f6e74616374407374616b65626162792e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148d2b0ff93d409b20b9f14d73888b5029adb7dedd443f88d2d56088a315626a1d79507deb24a41d42": "0x00000000000000000000000000000000000f4b6f6461446f74204d696e746572001468747470733a2f2f6b6f6461646f742e78797a0000000009406b6f6461646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148d47493ee3a600117269f7eab2e5f91f9efe10d0dba0e7256d9433230a8f9fdc1c4af10981853476": "0x04000000000200000000000000000000000000000000066a6f6e6173000017406a6f6e61733a776562332e666f756e646174696f6e19676568726c65696e2e6a6f6e617340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148d60cac4e5cdd86746ce78ca56ca1114d6abf7cb86879839ec6bf9c0c027ef318af3a77ac661401e": "0x040300000002000000000000000000000000000000000e416e6479207c20426561636f6e00000015612e676173736d616e6e407061706572732e6368000010616e6472656173676173736d616e6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ddffc86aaebc2d41e5c61cb6941b247d22fa14392fb8710a23493db5857c2904a76b3bcfda7d217": "0x040100000002000000000000000000000000000000001e5765623320456475636174696f6e20616e6420496e766573746d656e740844722e2043616f00001261686a7863727a40676d61696c2e636f6d0000094063616f5f6c6162000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148df58d11b9c4504b7a748920fbf8b122f81c3b7d63f1bd116c75c3741f4aeb3b3d89c7bbdefb2339": "0x0403000000020000000000000000000000000000000018506f6c6b617373656d626c7920476f7665726e616e63650000001668656c6c6f40706f6c6b617373656d626c792e696f000009706f6c6b5f676f76000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148e1506cd6e1c1ab8103da75e835e84c21fd864cdea4484538e7394cdf81d607ae496168e587e1b47": "0x0000000000000000000000000000000000064861726973001668747470733a2f2f6861726973626f73732e636f6d00184861726973626f737340686f746d61696c2e636f2e756b00000c40696861726973626f7373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148e28ba2eeb3d7c40f4168b94d0932bd7f917c00abb58c08e9d951e2718484d1e43ecabc506bd7c3d": "0x0400000000020000000000000000000000000000000019436f6e74726f6c6c657220446f7420436172626f6e7974650a436172626f6e7974651568747470733a2f2f636172626f6e7974652e696f0018446576656c6f7065724079656c6c6f77737475642e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148e46b19352a48af22483ec13c881ea5921623c6bc3b792559dd59df31eb5d42163dc1bb6505d453e": "0x040300000002000000000000000000000000000000000c626964696269646962756d00000012626964696269646962756d40706d2e6d6500000f40626964696269646962756d5f78000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148e534b2433a5f1501096e62e5bef031b7189ac027fcc3eaba9e1743c314e5fa2e7357b45636d7d41": "0x040300000002000000000000000000000000000000000d53657267696f61644c49424d1353657267696f204d6172636865736f74746900001473657267696f4061646c69626e65742e636f6d00000b405365725f61646c6962000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148e7257b4702ef819d2982658654fb6785977f89a5b1aab885021365dbb4b006b0ff550c219d98d33": "0x0403000000020000000000000000000000000000000009446547616d696e6709446547616d696e6700001268656c6c6f40646567616d696e672e696f00000c646567616d696e675f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148e7879bd31890686c879bc272c2afef97bc36cb48543598dd460776f082e51d5239efda3ab7fff15": "0x04030000000200000000000000000000000000000000074875626e65740000001f776f6f6c7374656e68756c6d65616c6472656e6140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148e92984083d101c32c8feeab5bd9a317375e01adb6cb959f1fea78c751936d556fa2e36ede425a47": "0x0403000000020000000000000000000000000000000010436f6c6f7266756c204e6f74696f6e0000001b736f757261626840636f6c6f7266756c6e6f74696f6e2e636f6d00000f636f6c6f7266756c6e6f74696f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148eaabd6d5a651ac5f45684f68ec654742c29fc6782be9921004192a1851c51154cf7b1cce2c6b518": "0x00000000000000000000000000000000000547656172184765617220546563686e6f6c6f676965732c20496e632e1568747470733a2f2f676561722d746563682e696f001368656c6c6f40676561722d746563682e696f00000c40676561725f7465636873000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148eb4ba0034502556f87dc01c2e647a407ec091e8ba718d691562d85ba49a97d55b9f7a7b56e81023": "0x000000000000000000000000000000000009536f7261746f676100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148eb8c14e9575686dc6201c7b373207514df98b17daa489a8d206b474cdcad455201b8b6efa936b0d": "0x040300000002000000000000000000000000000000000a506f6c6b61736166650a506f6c6b61736166651768747470733a2f2f706f6c6b61736166652e78797a2f001468656c6c6f40706f6c6b61736166652e78797a00000b40506f6c6b6153616665000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ec37554e12de10ab08b555a5a3b2725e01ba15eb40aa32dc5b781532854b797808ed45e752b047c": "0x040300000002000000000000000000000000000000000742656e64616b0000001862656e64616b7374616b696e6740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148eccee83ae40fd3db6167d010df1931f8440f02a199bb30d7d00440db494ead7a66c9d564202aa35": "0x00000000000000000000000000000000000f526f636b58204f6666696369616c1d416c747374616b6520546563686e6f6c6f6779205074652e204c74641768747470733a2f2f7777772e726f636b782e636f6d2f0012696e717569727940726f636b782e636f6d00001040726f636b785f6f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ed3cdd8f85271b0a215a54a9ad2ae7acb7ce71d6bf95e950bb20323b4d8153ba0059e20b5fd2923": "0x0400000000020000000000000000000000000000000016456e646572627920456e7465727461696e6d656e7416456e646572627920456e7465727461696e6d656e742168747470733a2f2f656e6465726279656e7465727461696e6d656e742e636f6d001f7269636b6440656e6465726279656e7465727461696e6d656e742e636f6d00000c40456e6465726279456e74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ee7853e903b944aec9da8307266c9d21b5c5abb97429930acd24d53fd2f8212c40822322248406c": "0x040300000002000000000000000000000000000000001250617363616c207cc2a0416375726173740000001370617363616c40616375726173742e636f6d00000b49416d50617363616c42000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148f3e547c92a9f976e48cf28184fede6322720d00b8cdd7f8505499460dc19dc36280b430cc160a1c": "0x00000000000000000000000000000000000544475f3100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148fcb6335f1a565451cd6b5692fb62af477d385a940bf36ccb9dd085a20f5e01bfd4904fef461f5e3": "0x0000000000000000000000000000000000046f72650e4f6c6976657220456e6369736f0000196f6c69766572656e6369736f303740676d61696c2e636f6d00001140656e6369736f5f6f6c693136383630000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148fedd41107e5eb65720f2a91be2692cee676ba11405101ec67422a5dbc749c501c607dbfc585c27e": "0x040300000002000000000000000000000000000000000c6368726973676c6f62616c000000166d616c697a65636872697340676d61696c2e636f6d00000e4063687269736d616c697a6533000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ff4d63ea65c2c7cfe6e0141f1f9c11b8ff9298df8ba96169aee6dfeb3b2e57d27c9ae2b029d6f11": "0x04030000000200000000000000000000000000000000076672616e6a730000001b6672616e6a732e6672616e636973636f40676d61696c2e636f6d00000a406672616e6a733237000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ff6163e3cfc08ee04e8b8b6a5c974f15c784fcabd18a4bf8fba4c5ade55210aa159c106009dfd3a": "0x00000000000000000000000000000000000953686f6b656e6e7900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714900a0b9f77ddf8434c108ee4a7fc5ad38e5af9d408486d66055a9a7893c644789d081040cfecff61": "0x04010000000200000000000000000000000000000000104465766f7073204d6167617a696e65184465766f7073204d6167617a696e6520507479204c74641c68747470733a2f2f6465766f70732d6d6167617a696e652e636f6d1c406465766f70732d6d6167617a696e653a6d61747269782e6f72671a6465766f70732e6d6167617a696e6540676d61696c2e636f6d000011406465766f70735f6d6167617a696e65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714908ee65340aa835e9e1389d5ddfa43eddcc269e5b95bc69e72be36c43882da45cde097dd7703a217": "0x04030000000200000000000000000000000000000000114e61636869746f204167656e742331340331340000196e61636869746f2e63727970746f40676d61696c2e636f6d00000c406e61636869746f657468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149098a1473c99bf7e9a5e3760bdedaa34c256e0b28279d358b68a28cfd5967bd0f8cd5555496fa655": "0x00000000000000000000000000000000000c726567656e65737475726b1b456e6573204d61686d7574204fc49f757a68616e2054c3bc726b00000e656d6f7440676e7379732e696f00000d40726567656e65737475726b000e656e65737475726b233030313300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471490b7f1fb67016ea9caaeb20361e77d9114bdd85dc196c33e15da72f4c28699085c388a3ecaa17f1e": "0x04030000000200000000000000000000000000000000034c56000000124c56406461626c6f636b64616f2e636f6d00000b404b7573616d614e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471490dd85b65e5cd020a40c551ab8f3bd70b9afc4bdc348f71e3403deb9b7dafe384ad536a5b42e7107": "0x0400000000020000000000000000000000000000000007726f64696f6e00001a40726f64696f6e706170613030373a6d61747269782e6f726718726f64696f6e7061706130303740676d61696c2e636f6d00001040526f64696f6e3034373039393331000f726f64696f6e303037233535353300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471490f81dd1ff30118bc44ee45000531bbf1aa4c23540940eb10599e14b4fbed5267c42a0ebf5d09f66": "0x04000000000200000000000000000000000000000000055245504500001140726570653a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149103dcfe925d4e52b2e6d8f0b56e1d493dc573448b702fed2b4318dcc46896527099cf5fc9e0d247": "0x00000000000000000000000000000000000e4c6974656e7472792f7465737400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714912655d634b54e9a086de7162fbfa0b91a67eee94b697646028edcf484ae78fdc0627e7eef1b2247": "0x040300000002000000000000000000000000000000000a53756257616c6c6574000000146167656e744073756277616c6c65742e61707000000e4073756277616c6c6574617070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714913e194223487e6ad60cfbed680a5afbf2888ea18911a5d10abbc7398f19d4507cced58c8fc0d575": "0x00000000000000000000000000000000000c4865726d65735374617368074865726d6573000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714913e6dae982908ac300192a29bd4659b0f05b2263af3d602ea7960160d9e864228dd2f1697809b67": "0x00000000000000000000000000000000000c526567656e63792d3032301757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149187e9b68a6b4d794ef86b506a3a8023b78b27e079f19ad8d15a31924879678fd610bc2639b2bd81": "0x0403000000020000000000000000000000000000000006566965742e0d416e6856696574205472616e0000187472616e616e6876696574786440676d61696c2e636f6d00000940767472616e3037000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471491d20a44a8276c2a3241222d562ffe7f7a5fd8a4b13bdd035647cce34c6eeaf4ab43e431a3268349": "0x040000000002000000000000000000000000000000001d5061726176657273652054616c69736d616e2050726f706f73616c73000016407265706c67686f73743a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149244fde1a07e17b6ec6fb19f22456336dbcaf2ce4d8da72a8d092f60cd123cc9cb972cc1e42e97dd": "0x00000000000000000000000000000000000a616e6465726d61747400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149253b68a74ca5ffce225f681546f6e540ebb18c2b217652e13abb443aaf5dfc8496ec2b0cb883200": "0x00000000000000000000000000000000000c6f7363617274657275656c196f736361722074657275656c2069207065726164616c74610000156f73636172747031304069636c6f75642e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471492595c8ed770133ebc500ab02f6e42ccd4300f6e68a0eaa60a88a5caf900ef6be81d8ab559e7b939": "0x0403000000020000000000000000000000000000000005416c65730e416c6573204a75726b6f766963000018616c65732e6a75726b6f76696340676d61696c2e636f6d00000e40416c65734a75726b6f766963000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471492856427f3f5a77c7c649a13f87c0d5b9b2b934e867a10304249752e96eebd4fe5ec6ff9fb82c078": "0x00000000000000000000000000000000000b616c6172636f6e736a631b4a75616e204361726c6f7320416c6172636f6e2053616e746f73000017616c6172636f6e2e732e6a6340676d61696c2e636f6d000009406a616c61726332000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149285fa22c885aa248e29df67564eddc299a2aa1cdacbec3c1ae061cf0835c87e5b46b920f7573a77": "0x04000000000300000000000000000000000000000000124a7574746120f09f91a9e2808df09f8ea40e4a7574746120537465696e65720018406a757474613a6d61747269782e7061726974792e696f106a75747461407061726974792e696f00000f406a757474615f737465696e6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471492a9b8874561dc036464f15335eee136dd7c216b994ea6ac3394eb723590e9e065fd9061e05d0035": "0x0400000000030000000000000000000000000000000004524f4212526f626572742048616265726d65696572001b407270686d656965723a6d61747269782e7061726974792e696f0000000a407270686d65696572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471492c85c6e1d4ad1da20426d3ac752d4b9c92c4c9090fb1115c379982fa665ab6f6914552adedd1a10": "0x04030000000200000000000000000000000000000000064b75646f73000000176b75646f732e706f7274616c40676d61696c2e636f6d00000c4b75646f73506f7274616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471492da06c1a6bb3bdaa0e1c76edd8151d4841665925d01a029fe176eecc24297bf931d594502293159": "0x040300000002000000000000000000000000000000000e537472696e64626572676d616e0e537472696e64626572676d616e000019737472696e64626572676d616e4076656e616c6c2e636f6d00001040737472696e64626572676d616e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471492f879f180f6a02408b712a589f5cb71cd7094809785ab0a924358d3cb52b27efd4933b6efc14963": "0x000000000000000000000000000000000010446f6e446965676f53616e6368657a0000001c676176696e776f6f6469736d796775727540676d61696c2e636f6d00000f4053616e6368657a43727970746f001140646f6e646965676f73616e6368657a00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471493b1caaf799dd1859bddc94acc7518e753f3ca6710e2777a0dbfc5dd06a67b02a5f731c9621fb36f": "0x000000000000000000000000000000000014456467657472696275746f722053756244414f00001a40456467657472696275746f72733a6d61747269782e6f726721656467657472696275746f72734065646765776172652e636f6d6d756e69747900000f40456467657472696275746f7273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471493c499446dff130948b985dae79adcb9becca19ca2eba2aada6416020dc01abd59f8b4419cd8a002": "0x040300000002000000000000000000000000000000000b4d41442043524950544f000000136163736579696e6340676d61696c2e636f6d00000b406d617474756e636869000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471493d0e54cd18f21273eabb0f32cb0695fedb8d25f6299fe51f90b1e26ed858c1064aeeea0977c1e67": "0x040100000002000000000000000000000000000000000b4e6f727468776f6f6473001768747470733a2f2f6e6f727468776f6f64732e636f2f0016737570706f7274406e6f727468776f6f64732e636f00000d404e6f6178656e6565646564000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149405477f74a11219ba1c4070dc40c8c4f8619ad619382655a6f9764f454954457406f10a87ae164e": "0x040000000003000000000000000000000000000000000850617261646f78001568747470733a2f2f706172616e6f6465732e696f164070617261646f7878783a6d61747269782e6f72671470617261646f78787840676d61696c2e636f6d00000b40506172614e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714943fc2ac54f4c37ccc10dd1946b0fc65c8993ff7f47052713e9aa4b1cb72c913bd397c34adf4f949": "0x0400000000020000000000000000000000000000000009416264756c62656500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149446885b0b18680ae8e0ac0aa68a0c138a3aa84813f0accae4ed7d6ae4b4905495026f16eda4e069": "0x04000000000200000000000000000000000000000000097370617a636f696e000000137370617a636f696e40676d61696c2e636f6d000008407370617a7674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471494770065de5e75f5d0e903b51697fa10a7f8c7e5c750fb3c2f90424b749be8b6c0f0b120f5d7277c": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714949975f6dd9018661c9855eb44b83e5916954e5dc4801b8e7333bffb9f5788a1f7245811421b600b": "0x04030000000200000000000000000000000000000000094744617661737369124769616e6c7569676920446176617373690000186769616e6c75696769406b796c69782e66696e616e636500000f6578717569736974757339343134000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471494af0873e9a60a1b025b4abda214f95f673f89f6d7139894f0b9486cb3f28e5c56956288b4876c69": "0x04000000000200000000000000000000000000000000066a756c696f0000001868694077686f69736a756c696f73616e746f732e636f6d00000d406a756c696f73616e746f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471494bfb37d43938cba9cdbb4a6e2756511dfe6028fe26c3ca3fb6123753e7e222978b5183581cc0c75": "0x0000000000000000000000000000000000174765726172646f2050697a6172726f2047656f7267650f6765726172646f2067656f72676500001f6765726172646f70697a6172726f67656f72676540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471494db11932c4b24d4224eba2123974db88ab28f55b7dd4f8f330013cb431d5a9c121b3384bea81020": "0x040300000002000000000000000000000000000000000646656c69780646656c697800001666656c697834737761726d40676d61696c2e636f6d00000f40436174616c797374537761726d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471494ed5c295f9bfa2588f28e17671ba1808d7b02cd3caaf80113066a467127666f4d80afc50bfbc127": "0x04000000000200000000000000000000000000000000067a6f656d63000012407a6f656d633a6d61747269782e6f72670000000a407a6f656d63666f78000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471495034dce89216a0306a7f8d0b05138414746c1fd2c03695ada9d503e888977e0763fc427f50f7156": "0x0400000000020000000000000000000000000000000013457567656e696f2047696f76616e617264690000001d657567656e696f2e67696f76616e61726469406d6f6f6e69612e6974000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149508d34e1b2941b94a4081d3f77f3ae9304f78983183b8f015dacb620ce7eb0444e733b85422d931": "0x040000000002000000000000000000000000000000000a70616e6472657339351d5061626c6f20416e6472c3a97320446f7261646f205375c3a172657a1868747470733a2f2f7061626c6f646f7261646f2e636f6d174070616e6472657339353a626c6f7175652e7465616d15686f6c61407061626c6f646f7261646f2e636f6d00000b4070616e6472657339350a70616e6472657339350a70616e64726573393500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714953150ed314b45c2b2b3d7f25a51033a9fd84198e78c72fac4e9f23fc149d82200e0b423f1418671": "0x00000000000000000000000000000000000b507572706c65546f616400000017707572706c65746f6164303940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714955ba6c28b709d2f7a0a276b0053aa5d6291575d123aceb4efbc34b98102b967590c008b4cf54872": "0x0403000000020000000000000000000000000000000008427261696c6c650f427261696c6c65204167656e63791568747470733a2f2f627261696c6c652e7774662f0014636f6e7461637440627261696c6c652e77746600000d40627261696c6c655f777466000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471495b0575164a947673676eca79c8b6ff6a5b544274fc7d1e38b38ca8211ae59fd73b8c1073f64fa27": "0x0400000000020000000000000000000000000000000016f09f97bb20416c70696e654e6f64657320f09f97bb000016406b72697368313636323a6d61747269782e6f726716616c70696e656e6f6465734070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471495e5354b81f0f460da9f7fd3d9612a68d2ead69dde53297b172b7db514d0d261e7c5be987df7f32a": "0x040000000002000000000000000000000000000000001453696b207c2063726966666572656e742e646500001540646576305f73696b3a6d61747269782e6f72671a73696d6f6e2e6b726175734063726966666572656e742e646500000a40646576305f73696b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471495ffe83b7e4e53745ac11043321b5292fe5c644feaf53ff448ca444a527d51f380c799ed16565c89": "0x040100000002000000000000000000000000000000000b58656e6f70686f6269610000001f77656c746c6963682d696e6e696e67732e30684069636c6f75642e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471496841c11a7beb5d5c2fe15c1d94dc26f396102556264826f7a197ba897ae75aa5e52d220153cb679": "0x0403000000020000000000000000000000000000000012736f6d656b696e646f6667616d656465760000001c736f6d656b696e646f6667616d6564657640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471496dad83abc32ee034c260b3a7196660071ca1b27e79bf234cb7efaa125300a696a0a42ee686b1734": "0x040100000002000000000000000000000000000000000664616b6b6b0000124064616b6b6b3a6d61747269782e6f72671464616b2e6c696e757840676d61696c2e636f6d00000840646167696465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714972228f5d624edf372e9d0af25b9e826acc65a8d4233ca1149d57eff4a7d78e620889cd37174c57d": "0x00000000000000000000000000000000001c313335204361706974616c20496e636f72706f726174656420303210416e74686f6e7920457566656d696f0f68747470733a2f2f3133352e696f000b616365403133352e696f00000f407265616c4143457566656d696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149730aaa91834c4fe403e9da23891aeb29efc4ba2785edc0ea8f4bc67f0f1942dfb5295191373a47b": "0x040300000002000000000000000000000000000000000c546f726f734167656e637900000012696e666f40746f726f732e6167656e637900000d40746f726f736167656e6379000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471497389e32ef925ccd6c0197856b35c7f631f5aa8d9cfd83f7e75202b0d821e67d2f344e4e4b5fc10f": "0x0801000000020300000002000000000000000000000000000000000d506f6c6b617373656d626c790d506f6c6b617373656d626c791968747470733a2f2f706f6c6b617373656d626c792e696f2f001668656c6c6f40706f6c6b617373656d626c792e696f00000a40706f6c6b5f676f76000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471497caee6b287aa129f6cb33068e0f82887ed35a5e17e77021cd796902e5e2939c325b4f92d4f3957c": "0x0000000000000000000000000000000000114a4f49452028657874656e73696f6e290de68891e698afe9b8ade593a51068747470733a2f2f6a6f69652e696f14406a6f69656375693a6d61747269782e6f72670d6a6f6965634071712e636f6d000009406a6f6965637569000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471497f3d4c5777373935275676a7d8983923233084beb6faac0ea3773730c8abe70eed4795ee2815441": "0x04030000000200000000000000000000000000000000165279616e2044696e68207c2053756257616c6c65740a5279616e2044696e680000137279616e4073756277616c6c65742e61707000000b405279616e44696e6838000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471498426f2bcd57c422f4c8bc5da2f0d0e2f6e040005f783c023b85a8cb21df5c1f509c144fe1887202": "0x040000000002000000000000000000000000000000000858616c616d75730000144078616c616d75733a6d61747269782e6f726715706f6c6b61646f744078616c616d75732e78797a000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714986ea6df1fdbb2a51c20046a7e79f6a36c1f8f74a8caf1e573c448f7f2ca4d7e75928579ddbc134b": "0x040300000002000000000000000000000000000000000a6c74667363686f656e1d4c756b652054686f6d617320467269656472696368205363686f656e1d68747470733a2f2f706f6c6b6176657273652e636f6d2f406c756b6516406c74667363686f656e3a6d61747269782e6f7267146c74667363686f656e40676d61696c2e636f6d002168747470733a2f2f6769746875622e636f6d2f6c74667363686f656e2e706e670a6c74667363686f656e000a6c74667363686f656e00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714989747ec8e57b3315e7b86bae8d18cd7470cc4c03d47875d002cee651566030fea5312bf0e69562a": "0x0400000000020000000000000000000000000000000010477572755374616b696e67f09f91b3001868747470733a2f2f677572757374616b696e672e636f6d1840677572757374616b696e673a6d61747269782e6f7267167374616b6540677572757374616b696e672e636f6d00000d40477572755374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471498a44c6de372836c145d6c503d0cf97f4c7725ca773741bd02e1760bfb52e021af5a9f2de283012c": "0x0400000000020000000000000000000000000000000008546869626175740000124074626175743a6d61747269782e6f726700000007407462617574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471498d18fa62c6f4741589e41f29ab08f2d0e4e4bdf3d1c8a868162c720f9c31e22733f8d633fba901e": "0x04030000000200000000000000000000000000000000064d6f6869740b4d6f68697420426861741968747470733a2f2f6769746875622e636f6d2f6d6263736500126d62637365353040676d61696c2e636f6d000009406d626373653530000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471499004306bcbce5e41a4642fac1519da8a909bba8a1cc4ba6c6d096fac4da4e9a0f5dbe7eae16360a": "0x00000000000000000000000000000000000e6c616e64617320676c6f776e6500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714995d906364498e519ab4ee81530865538477c5f9fa76f57f2058f4d97476d028ccbb4bfe44a0f626": "0x00000000000000000000000000000000001a70686f656e69782d63727970746f2d636f6e74726f6c6c657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714996b1fd9ab500b524ab52bb8245e545fc6b7861df6cf6a2db175f95c99f6b4b27e8f3bb3e9d10c4b": "0x040000000002000000000000000000000000000000000344460000001464617070666f72636540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714998cd9a07d23d28d50ef3cbba6eefa5127e662a1286c69c3f8cd10aa328d394df9e69919af449b45": "0x000000000000000000000000000000000012496e73696768742046696e616e63652031001368747470733a2f2f676f7374616b652e696f001577656e6a756e6438343940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471499c40e700afa99fd3e9303650f53c8624593711265f153cea49411b1966da5d31142b6b88e721c38": "0x040000000002000000000000000000000000000000000a506f6c6b616e65787400001640706f6c6b616e6578743a6d61747269782e6f72671570726f6772616d40706f6c6b616e6578742e696f00000b40706f6c6b616e657874000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471499d7e43eb6d40f70b6ad8860b2acbb26cf3caaedc7deb8c5d7146ac5bbe77bf34a592a97e377a046": "0x00000000000000000000000000000000000644722e20540e54686f6d61732048616d6d65720000187468656469736375736d616e40776f682e72722e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471499eef26ba196a8a8b089dedc24a15308874dc862b035d74f2f7b45cad475d6121a2d944921bbe237": "0x04000000000200000000000000000000000000000000135448454d414e574954484f5554414e414d4500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149a449d74fb4e4f6f80cac1fb723163fc032ac4db84fec2102f6897afa7dac42e379a7d41ad586b5e": "0x04030000000200000000000000000000000000000000094f74746f546f6f740000001e6f746f72696e6f6c6172696e676f6c6f67363640676d61696c2e636f6d00000c404f74746f546f6f743939000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149a8e7db7192318209e634dd70cbdbd492c6874c5613bcb06f1d8dc85eed3051f884c5458e7205655": "0x0403000000020000000000000000000000000000000008416e61746f6c7908416e61746f6c790000176e617a6172616e61746f6c7940676d61696c2e636f6d00000c40373737416e61746f6c79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149aadb0de0e3acc6ad0e409282db1aea4d91486a122492e7a130f681b7daa71cfd4db3db086ea7d65": "0x040300000002000000000000000000000000000000000a4475636b446567656e0f4461766964204c656f6e617264690000136461766964406a6f6273746173682e78797a00000a6475636b646567656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149acc963ace4fd466a228a70c2496ae500d79de266f9c759918256444c352d76bcc4a0c32e2dff716": "0x040300000002000000000000000000000000000000000b43727970746f52616e6b0e43727970746f52616e6b2e696f000011666d4063727970746f72616e6b2e696f00000e43727970746f52616e6b5f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149b2f4bfc1eecbbb29003fe9042a2c3433ecbddf6b360c3f17993544f830dc75f73d9a13a8757bf26": "0x0403000000020000000000000000000000000000000006736875766f06536875766f0000166a616d62646b776c73333340676d61696c2e636f6d00000a40536875766f427463000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149bc7b64471beb6caa4a902266727d6859bbd3cd585e9f64460ed6289f95bd851bd441ff57573ab64": "0x00000000000000000000000000000000000b4461793163686565727a00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149bd6b99bd8180aace8c7ad65c15fa3ba64424a61b177382a0c5468135aecca9ca454f5e7ce4d305b": "0x040100000002000000000000000000000000000000001043503238372d434c4f554457414c4b001168747470733a2f2f637030782e636f6d1640696c6c6c65667234753a6d61747269782e6f726714696c6c6c656672347540676d61696c2e636f6d00000c406b61706c616e736b7931000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149bfeb795391ff04e92126d23f40d0707321f495a7ca4b97a86f2282cdf5229a4b315793e51dea246": "0x040300000002000000000000000000000000000000001643687269737469616e20436861696e616c797369731e43687269737469616e204d656e6461202d20436861696e616c7973697300002063687269737469616e2e6d656e646140636861696e616c797369732e636f6d00000840636d656e6461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149c1d0530fd26bd0a347bf57a51b4924e76624612bcd7bbd269b3079fbcc4a2f72a2fcac55056286c": "0x04030000000200000000000000000000000000000000054e6f6f72104e6f6f72204d6f68616d6d6564204200001d6e6f6f726d6f68616d6d6564624070726f746f6e6d61696c2e636f6d0000114030786e6f6f726d6f68616d6d656462000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149c21b6ab44c00eb3127a30e486492921e58f2564b36ab1ca21ff630672f0e76920edd601f8f2b89a": "0x0401000000020000000000000000000000000000000017506f6c6b61646f742e70726f202d205265616c676172001568747470733a2f2f706f6c6b61646f742e70726f14407265616c6761723a6d61747269782e6f72671368656c6c6f40706f6c6b61646f742e70726f00000d4070726f706f6c6b61646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149c2d3779d2f3e4d20ae756ebc2b9527cb5634924b518af5a0edbedcf16e7d581648d770e4cb27844": "0x00000000000000000000000000000000000e54726962652f537461636b55700f54726962657820507465204c74641568747470733a2f2f737461636b75702e6465762f00136e6963686f6c6173407472696265782e636f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149c54b3d06134b2da7c2754f11fe0d5e6b3c2174eacd1fe36d2738bfbefb541fb4f56eb298dc1491a": "0x04000000000200000000000000000000000000000000064f4e44494e000012406f6e64696e3a6d61747269782e6f7267136f6e64696e37373740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149c6b526cb73c7a0f38e4240801ab3b93aa2312497116b9ced3dfaea754a6e18c45f4605ee3af490d": "0x0000000000000000000000000000000000075374617269740c4a616d6965204368656e671368747470733a2f2f7374617269742e6d652f18406a616d69652e6368656e673a6d61747269782e6f7267157374617269743139393240676d61696c2e636f6d00000c4073746172697431393932000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149c74feb394678e854ae840a749725558ddb56d21b296ea057d8295ba7c7ded83fa0285afa24cc600": "0x00000000000000000000000000000000000f506f6c6b61646f74204a6170616e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149c7aff229a5b7073468ae00d6e49251a2c0809df7e3283dd05fe8232e010734b0de316c5ab07431f": "0x040000000002000000000000000000000000000000001c4b6172696d207c2050617269747920496e66726120262044617461000011406b6172696d3a7061726974792e696f0000000b404b6172696d4a444441000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149c9cab497b19e1dad837b7a3a768b47b1210fc36f3157793bd95820092148f973e5f297a05412e5a": "0x04030000000200000000000000000000000000000000076b756d6173690f45766572677265656e20207961770000126f6c696337343740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149cafa1da45543da296c952e57d77a6acc899f39e7f043839309cc8527b089c5ca76d24c2b63ebb4b": "0x04030000000200000000000000000000000000000000096a736c7573736572154a616d65732043616c76696e20536c75737365721868747470733a2f2f7777772e6b75726b756d612e636f2f15406a736c75737365723a6d61747269782e6f7267146a736c7573736572406b75726b756d612e636f00000a406a736c757373657200096a736c757373657200", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149cdf78c3a20b94bb2a86561dc118ec7d56488f5615de6b325f6dd97e6801aa8b3aa10aa687e8347a": "0x04010000000200000000000000000000000000000000064b6f74616c001168747470733a2f2f6b6f74616c2e636f0011737570706f7274406b6f74616c2e636f000009406b6f74616c636f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d04e8142e8ca463bc94245f476d6d2f02c5c8c12a5914444a4b22fa38f2107025b1a092b376fd79": "0x0403000000020000000000000000000000000000000008416e6e79306e6e1c4672616e636973636f2056616c656e74696d2043617374696c686f00001a6672616e636973636f616e6e796f6e40676d61696c2e636f6d000008416e6e79306e6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d18dbe99b9ed7df4f4097d2ee14bfbac178efc25e50fda49b96b18d6f48958f179041a00c126ec8": "0x00000000000000000000000000000000000c526567656e63792d3030311757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d263a3ca965563a56b8d05d9dd7fef64c1cac6d69a674c5bea54c270a48170c6abebef698337221": "0x040300000002000000000000000000000000000000000b4e69636fe29aa1efb88f104e69636f6c61732041726576616c6f0000196e69636f6c61734076656c6f636974796c6162732e6f726700000d406e69636f6c617265733238000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d3d32c9a2a70e509a6d8b9ce3536600ca5e3235162058682c565f1b7c071d00bff49acfc7489e3f": "0x000000000000000000000000000000000015506172616c6c656c2046696e616e6365202d2033001568747470733a2f2f706172616c6c656c2e66692f000000001f68747470733a2f2f747769747465722e636f6d2f506172616c6c656c4669000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d3e6d4e7e999db42ecef72bcacac7b6f05920ea3593b27d3a8ae8ec55f4925eaf1caccdb57e5225": "0x040100000002000000000000000000000000000000000f4d584320466f756e646174696f6e154d584320466f756e646174696f6e2067476d62481468747470733a2f2f7777772e6d78632e6f7267000e68656c6c6f406d78632e6f726700000f404d5843666f756e646174696f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d417fe5c3fd7281028b2fce5e73610790f841442376a9bfd38c2494cc7831c5481db451be550d5c": "0x040300000002000000000000000000000000000000000e4e494b48494c2052414e4a414e0e4e494b48494c2052414e4a414e0000176e696b6c6162683831312b3640676d61696c2e636f6d0000086e696b6c616268000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d430d0bdbcfdbc6f0de782e8bad3c663be60812f0a2ac63464f5da3ec448c73334c07d71ef27f2c": "0x040100000002000000000000000000000000000000000d5374616b6572205370616365001568747470733a2f2f7374616b65722e73706163651740676e6f737369656e6c693a6d61747269782e6f72671368656c6c6f407374616b65722e737061636500000d405374616b65725370616365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d5c0a5ff6bacb086ebe9137ac7ac32374b6459c8633314440b21be4356a718a408b10c9ab520e70": "0x040000000002000000000000000000000000000000000b636c6f636b636861696e00001740636c6f636b636861696e3a6d61747269782e6f726717636c6f636b636861696e687140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d8014dd68872e0de21727312b2b7ce579dc0f82f129d4edecbcf00abca607d73ccf16e8352cc777": "0x040000000002000000000000000000000000000000000e444f5a454e4f4445532e434f4d00001240646f7a656e3a6d61747269782e6f726716636f6e7461637440646f7a656e6f6465732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d87ee52b783a152bed497470a04ca4c13caccd69c7827e3ddc64473fd2d7c5d496c71061f452b05": "0x040100000002000000000000000000000000000000000b72656470656e6775696e0000174072656470656e6775696e3a6d61747269782e6f72671a72336470336e6775696e4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d967298cdbfa73f664a2b3e8bd3b4ab1878c278d5b10482bd2b590ffeef1552e3c78fe045045a7f": "0x0403000000020000000000000000000000000000000010526f68697420536172706f7464617210526f68697420536172706f7464617200001b726f6869376e732b706f6c6b61646f7440676d61696c2e636f6d00000f726f686974736172706f74646172000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149da3e68b063e9e3fee046115156933810cf762fcb5928e5a750b25eb9cd7932f425972b94f17960a": "0x04010000000200000000000000000000000000000000076b6c65766572001268747470733a2f2f6b6c657665722e696f00106c6f756973406b6c657665722e696f00000b406b6c657665725f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149da48123ab54b499c6477bfd57c12587b1075a80d944c7829784eed61a5c8b8255817e1d62d1070e": "0x040100000002000000000000000000000000000000000d4b495241205374616b696e670e4b69726120436f7265204a534314687474703a2f2f6b697261636f72652e636f6d15406b697261636f72653a6d61747269782e6f726716706172746e657273406b697261636f72652e636f6d00000b406b6972615f636f7265000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149db5c1943eccca8bc422b6d1cc9c0e9ad3e29b03134c8f1e45210f3f404ec3daa05f3aefe8257205": "0x040300000002000000000000000000000000000000000e5468652044617070204c69737400000018636f6e6e65637440746865646170706c6973742e636f6d00000c746865646170706c697374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149dcc277753735b96e04ca25cf1cbc516ed1c138492a7f2e606f60c5a9ac96cb405eaa3914fd12973": "0x040000000002000000000000000000000000000000000b626c6f636b736361706500000013626c6f636b7363617065406d7761792e696f00000f40426c6f636b73636170654c6162000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149def61665adc4306fec2c5ffb46bfe1dbc7935f493a5c9323520878aad74b5a32276a7a268abdb32": "0x04000000000200000000000000000000000000000000076e616667363900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149e21ce449387a9e130d6f231bc79dc0b10d4b09c38f9deada991ddf9234054b5bf8791a576c18a50": "0x00000000000000000000000000000000000d6320f09fa59e206c2065202100000013637874726f6e636f40676d61696c2e636f6d00000c40636f6c65735f5f626167000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149e5b705cbdcc776ab4410d33f13c053dca87be657a0ae3cc87655baf43f7efdd454ff74e3a9d8a2f": "0x0400000000020000000000000000000000000000000014f09f98bb205374616b65204b617420f09f98bb00001340666d6f6e7a613a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149e6f51a51fd3dacb6a7d56a801015edae2ebdeafb80bd4191554965942141024a2014ea2a11c8477": "0x0400000000020000000000000000000000000000000007416e647265690d416e647265692053616e6475000018616e647265692d6d696861696c407061726974792e696f0000000973616e647265696d0000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149e8bb46f23ea823584c5a40e2f5f6e6740ad9656099af2946938802c6f42d42dd6d40d7930a20e2b": "0x00000000000000000000000000000000000c7371756972726531646f74000000127777617264363640676d61696c2e636f6d00000f407371756972726531726164696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149ea70d098f006161264319ed6a0895c04112917fc9bdc0771f4a4773aae014a99d25bbe06fa1057a": "0x0401000000020000000000000000000000000000000014f09f909120484f444c2e4641524d20f09f9091001268747470733a2f2f686f646c2e6661726d1640686f646c5f6661726d3a6d61747269782e6f72671068656c6c6f40686f646c2e6661726d00000b40686f646c5f6661726d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149eb58bb1718cc7793e44001b8695199fa100fff9057e6e086eaf496a15bd82b71d2a66ac148fc46a": "0x04030000000200000000000000000000000000000000064a6f6e48510e4a6f6e20486f6c6d71756973740000186a6f6e68716175646974696e6740676d61696c2e636f6d0000076a6f6e5f6871000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149ebab134ded1549916a96314a4b60b23596683eebea29988aec9fae81a7b8d44887fd4c07a70981e": "0x040300000002000000000000000000000000000000000d57696e746572737072696e670000001477696e7465726b736d4070726f746f6e2e6d6500000b4077696e7465726b736d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149ed60c0f92e374f686e4a0805aa9cd02bf99cfe96bb9b84d1727949eca4b740bca8c1701ae931406": "0x0800000000020100000002000000000000000000000000000000000d537469722d4a502d426c75650d537469722d4a502d426c75651568747470733a2f2f737469722e6e6574776f726b0012696e666f40737469722e6e6574776f726b00000e40737469725f6e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149ef4be7403d4d6000c20e1797f6f0e239f7784c6a63a6c319836d9ecb89e1f32d05f0827bb1c7f64": "0x00000000000000000000000000000000001d5a756d69746f7720285370616e697368204e6577736c657474657229001568747470733a2f2f7a756d69746f772e636f6d2f0013686563746f72407a756d69746f772e636f6d000009407a756d69746f77000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149f053c2746e722456610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38": "0x040000000002000000000000000000000000000000000e5374616b65776f726c642e696f001668747470733a2f2f7374616b65776f726c642e696f17407374616b65776f726c643a6d61747269782e6f726713696e666f407374616b65776f726c642e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149f1252e4c39b7f7710a3bcbb259f08e2f9bfd79197e1a63ea44f47c7790139dcdc1faa9567130f30": "0x04030000000200000000000000000000000000000000055649585900000017736175726162686772696e6440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149f1d97820c576865f25418311f6f3b70b3ebe74fc714aba44e177d104b6c2defb27f9b9936da17b9": "0x040300000002000000000000000000000000000000000d4d6f7361696320436861696e001768747470733a2f2f6d6f73616963636861696e2e696f000000000d406d6f73616963636861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149f1f101b199c8938e69cc993ca5061e9991dfa141144902af69c09a63077294edbff30f6876acadf": "0x040000000002000000000000000000000000000000001b506f6c6b61646f742048756e6761727920436f6d6d756e697479001568747470733a2f2f72622e67792f3736796f7865001a706f6c6b61646f7468756e676172794070726f746f6e2e6d6500001140506f6c6b61646f7448756e67617279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149f29f67769840c143eeaa160b12b6e319d7f6b2bc34cc2a402dc845cea0bf7b959b6917ef1568078": "0x08000000000201000000020000000000000000000000000000000011646f742e7374616b6572732e7a6f6e6500000011646f74407374616b6572732e7a6f6e65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149f3937cb0047bfe065de063644e59d7eb67ac8954c00df696957f7422bd64e57ffe08eff305f4e2b": "0x040300000002000000000000000000000000000000000e43727970746f706f6c6974616e1243727970746f706f6c6974616e204c4c431a68747470733a2f2f63727970746f706f6c6974616e2e636f6d001a636f6e746163744063727970746f706f6c6974616e2e636f6d00000e4043504f6666696369616c7478000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149f749b777c55719970584fa4834e2a822dbfeda69c24bbe1ffce611be40ec0fb13dac0ccca6bd077": "0x04000000000200000000000000000000000000000000107461736b6f6f682028506c61736d29000017407461736b5f706c61736d3a6d61747269782e6f7267167461736b6f6f682e757a6940676d61696c2e636f6d000009407461736b6f6f68000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149f8acf5eb9cf86b918bed2613c80d8905c60c4f1b55d262ae0fcebbafbb2b9f60068d26db6801206": "0x00000000000000000000000000000000001c313335204341504954414c20494e434f52504f524154454420303410416e74686f6e7920457566656d696f0f68747470733a2f2f3133352e696f000b616365403133352e696f00000f407265616c4143457566656d696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149fdd3c97960b9cbce12bea7fcd0ef144e784045ab007184e56f1dbea9dde0f496086946206911be9": "0x040300000002000000000000000000000000000000000e4d616e64616c6120436861696e00000015696e666f406d616e64616c61636861696e2e696f00000e404d616e64616c61436861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149fe12e720a82efc1fcdafa5a5ede1d56189d95430ba0125029978fea782a3f5480606ab1a2b1466f": "0x00000000000000000000000000000000000b6c65697465725f534e490e416e64726561204c65697465721c68747470733a2f2f736f7665726569676e6e61747572652e636f6d001b616e6472656140736f7665726569676e6e61747572652e636f6d00000f40616e647265615f6c6569746572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149fef0c4e3ed2df62246fd50494a2ad83cc5a5c8dee9db659ffb78a5b04d271de44f0a86f334adf2f": "0x04030000000200000000000000000000000000000000144c69666520776974686f7574207374726573730e4d617274696e6120476c69626f0000186d617274696e612e676c69626f407961686f6f2e636f6d00000e40476c69626f4d617274696e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149ffb07437f7fb055b4351de5a0c28c5d9183126191dfbe2a0a9a709988e37727ec5d41594c17ab59": "0x00000000000000000000000000000000000850617274796679001768747470733a2f2f7777772e706172747966792e65750010696e666f40706172747966792e6575000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a026c6eb8dc072361858ef0a9f0778513333b5d761cd65e3e3e8fcc58c980fa2c4efe9ed03382c7b": "0x00000000000000000000000000000000000b5468656f20444f542031001d68747470733a2f2f7777772e7468656f6a616d696c6c65722e636f6d000000000e407468656f6a616d696c6c6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a02eb03d19a027d89608a774c479dd1908bb33e1f18529418c3b6d5e19f956887f892ca2c0902237": "0x040300000002000000000000000000000000000000000b4f4720547261636b65720000001763687269735f7061703840686f746d61696c2e636f6d00000c406f675f747261636b6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a0425165102d0e25091bb84ac5b08adf128e855e1cb079ed594be42af19d09d680dae982ac209ffb": "0x040000000002000000000000000000000000000000000c48616e647943727970746f001768747470733a2f2f68616e647963727970746f2e696f184068616e647963727970746f3a6d61747269782e6f726714696e666f4068616e647963727970746f2e696f00000d4048616e647963727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a04f3d43f3e99aad8c00226393a2a05d5d65bf7590e3c091feb897f8303a7de52cd637106dee2b37": "0x040300000002000000000000000000000000000000000b7068696c6f6e6961726513547567756c6475722042616967616c6d616100001474676c64723035313140676d61696c2e636f6d000010456c696f74426c6f636b466f726765000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a06e6b0fa55b7aa4d00e1d7c3523a41757d5698f367496356c8c7c3613f3ca796feb3491899a7b16": "0x040300000002000000000000000000000000000000000c446f7420416d706c6966790e416b65657261204d634361696e0000166b657261646d636361696e407961686f6f2e636f6d00000c40446f74416d706c696679000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a07b7c28fde24902742a3196b00c55823f0923395fc97bbba54268dfb0c04a22eb014dcf7afd2465": "0x0403000000020000000000000000000000000000000019496e66696e6974792057616c6c6574204f6666696369616c0000001a706172746e657240696e66696e69747977616c6c65742e696f00001040496e66696e69747977414c4c4554000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a097d201c62d3578f486ec0728d4c1ce1b6dbca881396f3a3bb9f6e890572a400d3064423f889747": "0x0000000000000000000000000000000000135761726c6f636b456e74657270726973657300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a09af68755800aad94ef44028b5c2649905e23e0abe33d4542688a2ed40bcc0f169f0d535816f43e": "0x0000000000000000000000000000000000094e656f4e756d6973001668747470733a2f2f6e656f6e756d69732e636f6d2f0012696e666f406e656f6e756d69732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a09f49890c6bdef1acbfbc894060d93d772850a601b3f4b69d02c8026b2e7d99433b4067feabeb29": "0x040000000002000000000000000000000000000000000f4a756c69616e6120436162657a610000001b6a756c69616e61636162657a61407961686f6f2e636f6d2e6272000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a0a010fabd2edd968a59a7a725d58dd2a2e3599dd3195c72dba5c8a6f701543eb9aaec7712dc137b": "0x040300000002000000000000000000000000000000000d42697363686f66665f534e491c536f7665726569676e204e617475726520496e69746961746976651d68747470733a2f2f736f7665726569676e6e61747572652e636f6d2f001e636174686572696e6540736f7665726569676e6e61747572652e636f6d00000f406361745f696e5f6265726c696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a0b5a3940af12c68a3483f31027939520c2bf25b1c7b9c495a442dadc10c393336d5a33951af31c8": "0x0400000000020000000000000000000000000000000012646563656e74657265642e73747564696f0000001a6f70656e676f7640646563656e74657265642e73747564696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a0b881b0063a363a02bf32e061073c44300056b416cd66a4fde1e6c120dbc0089bb65134f5693a3b": "0x040000000002000000000000000000000000000000000a6d7564646c6562656500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a107a21bb039f18f3b746c85a1ee00a6b0db9065182d8787c587cf843018c421a095a18b137828e1": "0x00000000000000000000000000000000000e4566696e697479202845464929084566696e6974791468747470733a2f2f6566696e6974792e696f2f000000000740656e6a696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a109a005bbf30981660ee2e14416b8a688b7de8db55c6dd3a2955ade58adf88156156969f584851a": "0x0000000000000000000000000000000000086a61636b6f6f6e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a11241f2be748c8c5a56c4e36507ff2f3efe7796aade67c1e62c5c013d88f7e9f9452ae9d1e7a41e": "0x0000000000000000000000000000000000064f7361617400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a1139026a8f4e1487447aeb48d61f3ecfcd98a44cf81cedafe80db40a95f80671b01e7c0fa531327": "0x040000000002000000000000000000000000000000001df09f8cb2f09f8cb3506c616e7420412054726565f09f8cb3f09f8cb200001940706c616e742d612d747265653a6d61747269782e6f72670f6c6a7564766140747574612e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a11a320b9a8feb01f857311106c8d7b0daf6e096db9a0d759b52403e439ab23fd6559780a8b1c803": "0x04000000000200000000000000000000000000000000095374616d70656465000000197374616d7065646563727970746f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a13589ec6bd328c6beec9afdb165a47264ed88e3fcc907da93142ed4e0578578fa44ab2cbb14170e": "0x040300000002000000000000000000000000000000000e4b796c69782046696e616e63650f4b796c6978204c616273204c4c43000013696e666f406b796c69782e66696e616e636500000d4b796c697846696e616e6365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a16e9742ca98244e0cd1574cf7fc649a8571d82427b42732e83bcd62f0e3192e92f202ca06f0d53c": "0x040100000002000000000000000000000000000000000662656b6b610d41796f6d6964652042616a6f0000196f6c7577617368696e6162616a6f40676d61696c2e636f6d00000e4061796f6d6964655f62616a6f000862656b6b6b616100", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a17e0d5970ac01707fceddeeb78dc1b3c9b8fff33b20fe9f7600edc6eaf21c8aedcd2451301492f3": "0x00000000000000000000000000000000000c526567656e63792d3031361757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a19b37e844707d72307183930b2264c5165f4a210a99520c5f1672b0413d57769fabc19e6866fb25": "0x0400000000020000000000000000000000000000000006537a65676f0d53657267656a2053616b616300001773616b6163737a657267656a40676d61696c2e636f6d00000d4053616b616353657267656a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a19bbfd9c78f6c5fba9db007fd692b3d1aa851ebc27e880f6f5848be07aa84cd16862c4ad3d86e1f": "0x04010000000200000000000000000000000000000000096d696b6562206364000000136d696b654063756c74757265646f742e696f00000e406d696b6562333030306e7963000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a1c377baa224441cfe5d84e3593dcbacb0a489b98a8be3d9e68af5d38dde584c93689e7732c7d40e": "0x0000000000000000000000000000000000084a656473616461084a6564736164611368747470733a2f2f6a6564736164612e696f00176a6564736164612e696f406f75746c6f6f6b2e636f6d00000c406a6564736164612e696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a20a8de9dde43fecb463a68a6b0a2d857dd0b11702d1d6a3b1b07ec76fbabaf807fdb545d62c9cde": "0x04030000000200000000000000000000000000000000054970706f134e677579656e2054686169205068756f6e67000017746861697068756f6e676e3140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a20d0b846e3d907e00555ee596210f641d2d48b9a1e2b258aead3fe8de4e973bcaf5f24674044367": "0x040000000002000000000000000000000000000000000842696754756e610000144074756e616269673a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a215c23d3f30e28acc4fac060bf7e92c94836df38993b1851e3c2a9728335340fff42ded89ea2326": "0x040300000002000000000000000000000000000000001e416e64726561202d2048656164206f662033546563682053747564696f10416e647265612056656e6472616d6500001d6465762e616e6472656176656e6472616d6540676d61696c2e636f6d00000e4076656e6472616d655f616e64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a21fc86d22b382fcc8f54a0dcd5310e3d4d099ab7972a5fb6ca284666651d4302459c92de4efaf2a": "0x040300000002000000000000000000000000000000001441637572617374204173736f63696174696f6e0000000f686940616375726173742e636f6d00000841637572617374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a250353c7dc8311b99f2f82db75c3af6484741f264039ff2e24e4ae7096516dae4ca77efd0da2d13": "0x00000000000000000000000000000000000c526567656e63792d3030361757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a30ff791ba0dd28618c7f5a8530d6aafc1b191156294a9e27bb674128607896f3fd5914282fb196d": "0x04010000000200000000000000000000000000000000046b6d6c104b616d696c2053616c616b686965761168747470733a2f2f716472766d2e696f14406b616d696c73613a6d61747269782e6f72670b6b40716472766d2e696f00000c406b616d696c5f61626979000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a337657934f576d5e2d126c3dffe301385f3d6da21756147d8f58040a9021e4196a89fffa2800a48": "0x0400000000020000000000000000000000000000000003416c00001a40616c6973746169723a776562332e666f756e646174696f6e00000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a3b0c3cd1f399efd62f1e96782eec4d59ff854b9fa623984b80decebea69292fa92659093421e120": "0x04030000000200000000000000000000000000000000084b687564656a610d4b687564656a61204b68616e00001c6b687564656a615f7368616862617a40686f746d61696c2e636f6d00000a404b4b687564656a61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a3e66c1866cb9999f4fa98b7ec05e11f0f3c5cef7a750e22acccd75cefcfa72c00b5af6346e2e47a": "0x04030000000200000000000000000000000000000000086b6f7065626f79124c6f72656e7a6f2047696f76656e616c690000126b6f7065626f7940676d61696c2e636f6d0000086b6f7065626f79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a3f67b4c0527d154dc3aee12519c19be02628b0f808bddda9aed564027ad809cd392c13e9b924b65": "0x040000000002000000000000000000000000000000000d504f4c4b414348552e434f4d001568747470733a2f2f706f6c6b616368752e636f6d1440736f6e676875613a6d61747269782e6f72671368656c6c6f40706f6c6b616368752e636f6d00000b40706f6c6b615f636875000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a3f97862b7d49be68cd2c9b46e07c20f2263540b993c2b25b3cb995ab873314ac10e8d5f1f50a55e": "0x04010000000200000000000000000000000000000000154554484943414c2056414c494441544f52532030134554484943414c2056414c494441544f525321687474703a2f2f7777772e6574686963616c76616c696461746f72732e636f6d17406576616c7561746f72733a6d61747269782e6f72671d6574686963616c2e76616c696461746f727340676d61696c2e636f6d00000d404556616c696461746f7273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a402b003cd008ec5ba38a1142964f0e049d842c9a932ce34f21017dd4e674aeb8a5bd67553f1846c": "0x000000000000000000000000000000000008426966726f737408426966726f73741368747470733a2f2f626966726f73742e696f001168656c6c6f40626966726f73742e696f00000940426966726f7374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a40acfeba897a3054831c976778f05db5b115be6b85ed7ba7099de3ec01b096c8a91d6074daf2746": "0x0400000000020000000000000000000000000000000004414d4200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a42915ffbd1e4d678e156836bd7dc0639ea54540eb6ec55aec2a3793876208bf5d71ff89eb746a07": "0x04030000000200000000000000000000000000000000064d6172696f124d6172696f20416c74656e6275726765720000166d6172696f40616c74656e6275726765722e6e6574000011404d6172696f34416c74656e62757267000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a4298ccda952a9cf843ed05213492579c701c1cbca6f2d9622be202d81f305d01d37fbedbc99046d": "0x00000000000000000000000000000000000856696e63656e740000184076696e63656e746368616e3a6d61747269782e6f72671976696e63656e746368616e2e637640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a47a74229619b37bfa515f4f9d5b9394fe8e5a71db0f44fd1c4dbbb569b6205ec5af981cd3e0794e": "0x00000000000000000000000000000000000e446f745f69735f467574757265064d6178204900001774686563727970746f6d617840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a47a994958e0ce59ae58ba526977ac8c888aaec71da2be93459c2c6ee4a33f0881da7bd585b43a66": "0x040000000002000000000000000000000000000000000f546865204b7573616d617269616e00000016686579407468656b7573616d617269616e2e78797a00000f405468654b7573616d617269616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a490d8d4ffa73e2c52659f398c17705033d14b42950667700d2e50dcbf1cad45881fba6934fe1361": "0x040000000002000000000000000000000000000000000b426972646f20f09f90a50000000f697473626972646f40706d2e6d6500000b40697473626972646f5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a4a63b3ca43f4645fae67a2277ba75c89fff533a2cd9574791255b0dedb578234bca6935a6bc6c2f": "0x040300000002000000000000000000000000000000000e4d616e7461204e6574776f726b00000016636861726c6965406d616e74612e6e6574776f726b00000e404d616e74614e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a4e8003fe2fb58faba58db6c7bfc75aa2b8ec1c9b2624172c81f6d2391180047091dcd0cea5ec45c": "0x04010000000200000000000000000000000000000000054a4f49450b52454e4a4945204355491068747470733a2f2f6a6f69652e696f14406a6f69656375693a6d61747269782e6f72670d6a6f6965634071712e636f6d000009404a6f6965437569000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a4ed3b905ddf8085bee2c0254a1998a65fc2787a82cbecdca2c0a675be63ae9c5148e32ae753d01f": "0x0400000000020000000000000000000000000000000015546865204b757320444f542044656c656761746500000016686579407468656b7573616d617269616e2e78797a00000f405468654b7573616d617269616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a53864ffd30a765388d1505492274985d6049cfae833ce8ce11597aca19d0f06a29ddb0a7a5fb97e": "0x040300000002000000000000000000000000000000000756616d7073790000000000000c4076616d70737966656172000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a551a248cffb7fab926d3318e308ddc7abc0757edbe7661e6aa17f8e269585ca53556423382b267f": "0x00000000000000000000000000000000000e4e6f74426974636f696e43454f0c5365616e204c6179746f6e001a406e6f74626974636f696e63656f3a6d61747269782e6f7267166c696e6b6c6179746f6e3240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a56d11c227ad244b78e4c82b1882d5cfa1d4b47a04b8906c00110e28b764b92f674b26e02061de7e": "0x04010000000200000000000000000000000000000000114b52414e412e5620f09f9a80f09f8c9900001b406b72616e615f76656e74757265733a6d61747269782e6f726717737570706f7274406b72616e612e76656e7475726573000010406b72616e615f76656e7475726573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a59acabf7cc5c2db3a0b67c6e4b35133a18ff9c3b56d6cd28662f9e47f38afbfc508543087966870": "0x040100000002000000000000000000000000000000000c43525950544f4e495441530000001e63727970746f6e697461732e6365727665726140676d61696c2e636f6d00000e4063727970746f6e697461735f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a5afff021978b2b7b6c683f2280b9cb98172008de3fd6d0ef5e40b746bd2f58424850e48bc33233c": "0x040300000002000000000000000000000000000000000352341244616e69656c20526976617320536f746f00001464346e6e792e736b7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a5e1ae44678815b9744d9a778b5c53b54eb743dd93cc90079261a6e7fdffd8798e6406817d125d7b": "0x040000000002000000000000000000000000000000001144657574736368652054656c656b6f6d1a44657574736368652054656c656b6f6d204d4d5320476d62481968747470733a2f2f7777772e74656c656b6f6d2e636f6d2f001a7374616b696e6740742d73797374656d732d6d6d732e636f6d000010406d6d735f426c6f636b636861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a6391f7854f254e8164c165c3dd34122f5005b617dc4941fed61fdfd1806ac31176c9a28d290ea06": "0x040000000002000000000000000000000000000000000b375f5468756e6465727300001640377468756e646572733a6d61747269782e6f726716375468756e64657273323140676d61696c2e636f6d00000c40375468756e6465727332000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a6433a6dcb5d8737833b5ca84aebe493b7e9bcab4e1b1cfd6d2eca6246dc8ed68fa9a31b87ae7166": "0x000000000000000000000000000000000012446966666572656e7469616c204c616273002068747470733a2f2f646966666572656e7469616c2e746563686e6f6c6f6779002164656c656761746540646966666572656e7469616c2e746563686e6f6c6f6779000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a687dc3f738f7410389373f82baeae3f3cf28a85284180ee443f41220de6901b5df8dc270e635215": "0x0403000000020000000000000000000000000000000008616476657269630f41647665726c6976652053726c73000010696e666f4061647665722e6c69766500000d61647665726c69766573726c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a693de5eabea317ab630005f93d977d7f3e58be6c8027af52620da1b35e7ad4b7c000ff303222f15": "0x040300000002000000000000000000000000000000000a4175646961726d6973114175646961726d6973204761726369610000156175646961726d69736740676d61696c2e636f6d00000a636173695f61756469000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a6eb394e364b8f9c7682e4e399a94b0dfc4a9bc476e0bc69f25413687d2b1c29bb7139dcc8e8714a": "0x0400000000020000000000000000000000000000000012537465616b20e299a8204e6f6f646c657300001e40737465616b5f616e645f6e6f6f646c65733a6d61747269782e6f72671a737465616b616e646e6f6f646c657340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a76c3d2bf5e8dd46d223e97cfb5260aa90a5f3cf5cb993f2658f07202847da92c712623e6c5da31d": "0x040000000002000000000000000000000000000000000a5374617475746f7279000000196d697368616b656c6d616e37373740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a7ad5ea2e1e25da12ab2efc45e91ccb7b8e116388d12dd3be3a57d65bf8c0e6e9f70fd17685d8f14": "0x040000000002000000000000000000000000000000001cf09f87a8f09f87adf09f8f94205377697373204d6f756e7461696e0000001370657465722e63727970746f40706d2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a7b516d797914c7022eac0df731345052fd1e5b11e2b6d7fba33192395c37dc98ecda764fac0a05d": "0x00000000000000000000000000000000000f4b65726e656c4b656e6e657468470000001c7a68656e68616f2e676f6840636f6d702e6e75732e6564752e7367000010404b65726e656c4b656e6e657468470d6461726b61727469737472790000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a7c46d5435a1e2d86ad3c3fdb53ec38b9f865b8e2a836fbac2da234f4e72d660c9935b42a3e4173f": "0x04030000000200000000000000000000000000000000194d6f6565696e76657374207c2054656163684d6544654669001b68747470733a2f2f7777772e74656163686d65646566692e64650014696e666f4074656163686d65646566692e646500000c406d6f6565696e76657374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a88c5f2dbe33d41afa9773cfd85e5d96165adec4ce7cc9265a267a57a241194cc868dbfa7e0c4301": "0x04000000000200000000000000000000000000000000084d61635a616d500000001763726970746f6d61637a616d40676d61696c2e636f6d00000f4043726970746f6d61637a616d31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a8a3ea9a9a3cbf30d21eb80113b2f57759d263c0eb1f02291dbc81a41d5a98029ad55f941eea3153": "0x040000000002000000000000000000000000000000000d77656233616c6572742e696f001668747470733a2f2f77656233616c6572742e696f2f164077656233616c6572743a6d61747269782e6f726712696e666f4077656233616c6572742e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a8aceb78297feebd48c689eebc3c38ac671e2d6604d6490c7ad4261b2c157af30443bc297784795a": "0x040300000002000000000000000000000000000000000b50726f6d65746865757313426f6c7577617469666520506f706f6f6c610000146f6c616f79656a6e7240676d61696c2e636f6d0000114049616d5f5f50726f6d657468657573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a8d8c5df784c714204fb9dcaa194ca3f66a6c695aa7cb84c07bb5706202e5891d46cf6087422e068": "0x00000000000000000000000000000000001d426c6f636b636861696e20547261696e696e6720416c6c69616e636500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a8f0bd6de05e2315fa2847dce28d6741e63a14509aa8aba663935f6d257b49434b202a026c672966": "0x040100000002000000000000000000000000000000000562656172096265726e6172646f1768747470733a2f2f6269742e6c792f334749576265421b406265726e6172646f3a6d61747269782e7061726974792e696f1a6265726e6172646f617261756a6f7240676d61696c2e636f6d00000d406265726e6172727272646f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a91237ad3fc3e223ae0d1db9082bdce75480ee80c3bf3c6496de1ef8171951de2edfe49fdbe30a67": "0x040000000002000000000000000000000000000000000c477233336e4861747433520000001b477233336e4861747433524070726f746f6e6d61696c2e636f6d00000d40477233336e486174743352000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a91aecbe4d3bb95ad3816c3f7974b12327fb40c8ec5dbc5b79ab47f114838fdac54ddc5f7e890a3c": "0x00000000000000000000000000000000001e4d75736963204576656e747320496e6974696174697665204d756c74690000001b68656c6c6f40706f6c6b61646f746d757369632e6576656e747300001040444f544d757369634576656e7473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a93c6e207f351cebc5c184f0565e2192d6aedae584ee736cef875f0e1c558ee3ede26869acd0b4d6": "0x0400000000020000000000000000000000000000000013f09f8c8c204e6f766173616d6120f09f8c8c164e6f766173616d6120546563686e6f6c6f676965731568747470733a2f2f6e6f766173616d612e696f2f1140646179373a6d61747269782e6f726714616e746f6e406e6f766177616c6c65742e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a957c1bfaa0ef8df8692dce19b16ed49226830ab9d2bab753c1118e797bf69fe63e00eceabd91278": "0x040000000002000000000000000000000000000000000a426c6f636b4465657012426c6f636b44656570204c61627320554700174067617574616d646565703a6d61747269782e6f72671467617574616d40626c6f636b646565702e696f00000d403078426c6f636b44656570000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a9b541eb27d45610a4f59749234ff94a7325d0770303f2dd834b6e82fa91a7f7f6afe41bc6ee473f": "0x04000000000200000000000000000000000000000000104d61726b65744163726f73732d424200001c406d61726b65746163726f73735f62623a6d61747269782e6f7267196d61726b65746163726f7373626240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a9d8946d2ec5efc6f618b6cccdab512073431509d2c2d4cc92d188c18b6bb968a0869ad0df4ca05b": "0x040300000002000000000000000000000000000000000844614b616d7065144368726973746f7068204b616d70697473636800001a6368726973746f70684073637974616c652e6469676974616c00000844614b616d7065000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a9d916ee238e56e058e0e1940ab2089ce4f65dc63abad1a6b654561a9a0b09fe5cc679f0ded3fc28": "0x040000000002000000000000000000000000000000000a4e654e6120f09f8cbb000016406e616d6574616b656e3a6d61747269782e6f7267196d796d696e647365746f6e796f7540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a9ef632ace16178262fda88d72053d9381fce1d6fa240c5264be8f884995f6f6dc8fd6b76b41fe19": "0x04030000000200000000000000000000000000000000084465656c616273084465656c61627300001364616e69656c406465656c6162732e78797a00000b6465656c61627378797a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a9f08d3911f890e17a0625bffca33ce094f74f399580b16674ae3e0cc8ef259cde618e60e927ae53": "0x040000000002000000000000000000000000000000000d4b525950544f53434841494e0000000000000e404b727970746f73436861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aa51aec5596c16c9be84f63b9e30f438711f49b4a2f3e251c541f9a6e43b0e9df4f64e8394ba517e": "0x04000000000200000000000000000000000000000000075374616b696e000014406564776172646c3a6d61747269782e6f72671168656c6c6f407374616b696e2e636f6d000010405374616b696e4f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aad0604ad649cd85b6332bfd1e18c86739c3c5e7e76c95e7b0e95339005066cd34d89b842ca57d69": "0x0000000000000000000000000000000000064d617820470000000000000d40477261766974794d617878000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab17ce0890ca2cdce229054651147bc5f6f0ab32ca19ce2c679aa663c212dac43c84ed2c3e494d27": "0x0800000000020300000002000000000000000000000000000000000a416c6578204265616e10416c6578204265616e2043617361731c68747470733a2f2f6769746875622e636f6d2f416c657844313053001d616c656a616e64726f6265616e636173617340676d61696c2e636f6d00000b404265616e5f44313053000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab3f37c5fb7156fd86d918a899c95866c7a826e103307a9eb27318642550a300d56838d08c93e653": "0x00000000000000000000000000000000000c464f5552424c4f434b533300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab53275528e71c4a1fd7775fc942283e61155bb5aa033ebd62e76cdc83a9d4b7dc4c611d7082da80": "0x04000000000200000000000000000000000000000000064f4e595a45001a68747470733a2f2f7777772e6f6e797a652e636f6d2f656e2f0010686f776479406f6e797a652e636f6d000010404f6e797a655f6f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab5eb6225eb473c4c4b00316a66db95fe01dae8970cad009688713c1a4432c2af716ddd364535008": "0x00000000000000000000000000000000000a564c414449534c415600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab6dc514ec367fe662f93efa125cfb7f0ec984625f8fc53cdc2f8aa936fc7d1b846831d132e4f701": "0x04000000000200000000000000000000000000000000105374616b65f09fa7b24d61676e6574001c68747470733a2f2f7777772e7374616b656d61676e65742e636f6d18407374616b656d61676e65743a6d61747269782e6f726715696e666f407374616b656d61676e65742e636f6d00000d407374616b656d61676e6574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab6e86b3ee5baa49d26a9a27ddedcc27b12275126b023f4cd1d0bc3eb533c220a6584a26b18c2774": "0x00000000000000000000000000000000000a446f72614861636b730a446f72614861636b731968747470733a2f2f6861636b65726c696e6b2e696f2f656e0014737465766540646f72616861636b732e636f6d00000b40446f72614861636b73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab7e3e98c718729f7a895955042cb3fe863f3564e7b30e9130e37b6d905be11c0cf91064de1cd83a": "0x040000000002000000000000000000000000000000000853544b442e494f000015406672617a7a6c65643a6d61747269782e6f726700000011406672617a7a6c65645f64617a7a6c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab8afcc57061038068ecba10b973c7673eb761ade1ba23e48d03c35e9f42f80745acfe234565936f": "0x0801000000020300000002000000000000000000000000000000000e4d6f6f6e736f6e67204c616273124d6f6f6e736f6e67204c61627320496e631a68747470733a2f2f6d6f6f6e736f6e676c6162732e636f6d2f0019636f6e74616374406d6f6f6e736f6e676c6162732e636f6d00000f406d6f6f6e736f6e676c6162735f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714abe1d2fca3693953ae931623d3a530f2286c06b91e6f82a09cb757f6cf5b8d3d0f3dcbd60f1ab26b": "0x0400000000020000000000000000000000000000000005626962690000000e74656368406274616e672e636e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714abf0f8ad2f6106869cc09a0521e12de2e2cca2ba86feb5df7506d9f9123e0f2687aadf171a47bc5c": "0x00000000000000000000000000000000000650726f746f1d416c746f726f73204c4c432028206462612050726f746f666972652900001c79756c6979612e6d75726173686b6f40616c746f726f732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ac05ff7688083e8697b2ad8a1a194bf8104462fc283cfe8ea0cc039eee8ca312cd58abf65a2105f6": "0x04000000000200000000000000000000000000000000094242435f42616c6900001c4062616c695f626c6f636b636861696e3a6d61747269782e6f72671c61646d696e4062616c69626c6f636b636861696e2e63656e74657200001040626c6f636b636861696e62616c69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ac220ad36e69b7cec697d17a1916f9313f9894d1db4016b2e1d64384f1e9cb49a735ea6a86328d01": "0x0403000000020000000000000000000000000000000010416c656a616e64726f5f52304755450a416c656a616e64726f000013616c656a616e64726f4072306775652e696f00000a40616c336d6172745f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ac39f36e309d037db40f4abb8698fdab096b0dcbe258ca86e64cd7cdd21633393b54fd74f22b1818": "0x040300000002000000000000000000000000000000000f4b61726f6c204b6f6b6f737a6b610f4b61726f6c204b6f6b6f737a6b610000146b61726f6c2e6b393140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ac6535d22692ff19365a58294c023e466c88ba2dd910a4a3c622c666c6a0c9f523c13feeef02ec21": "0x00000000000000000000000000000000001c313335204361706974616c20496e636f72706f726174656420303110416e74686f6e7920457566656d696f0f68747470733a2f2f3133352e696f000b616365403133352e696f00000f407265616c4143457566656d696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aca973e143819fc644f6dd8841fc39979ef97aedf99a72c873c44d799938c03d96ef1e1fb2624c14": "0x04030000000200000000000000000000000000000000174f70656e20496d7061637420466f756e646174696f6e1b4f70656e20496d7061637420466f756e646174696f6e2050434300001c68656c6c6f406f70656e696d706163742e666f756e646174696f6e00000c7768657265736164646965000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714acdb8f7d99b9b4f82cd49434353de1d51598b44df15fcfed1e26224e055923acc9f9af881dc31d5a": "0x040100000002000000000000000000000000000000000843757272656e741546696e436f2053657276696365732c20496e632e1568747470733a2f2f63757272656e742e636f6d2f1b4063757272656e742d63727970746f3a6d61747269782e6f72671363727970746f4063757272656e742e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ad18028edc6538a02cb70c06950d8d61663a960c7e6664203696390388882bd305600fc1aedf520f": "0x00000000000000000000000000000000000c43727970746f6e617574730000001a636f6e746163744063727970746f6e617574732e73706163650000114043727970746f6e6175747353686f77000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ad2b158f9740a61618e66fcce7649125ff39ccf9f6ab0b1b88d1ec6b7bbd6824d04879a669589026": "0x040300000002000000000000000000000000000000000747617574616d0f47617574616d204468616d656a6100001467617574616d40626c6f636b646565702e696f00000e67617574616d6468616d656a61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ad3e18f67bdae596e8d0e24aa19d8b502a4b778f6172d6ecdc11bd3b9d320c70cec262e291d4a540": "0x0000000000000000000000000000000000055f5f5f5f0000001368656c6c6f4077656274687265652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ad78c5b50e5a1535aad6496e2b96928ca236cb15b3ec0c43305b6edc3418296a4f01812378996a40": "0x0000000000000000000000000000000000054b6f656e0d4b6f656e20437579706572730000156f7074696d6f766540686f746d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ad874555459d7afb60621cb801a995bd99811fb64c3736affcf9ec823badb45c5ee6a812e292ca6d": "0x0000000000000000000000000000000000096a7573746475646500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ada7fdb39f37a1913c8664b0c41d35ec1c68c290d3b2a4e6c323e3c6199a1a3d5a301ae134a20344": "0x00000000000000000000000000000000000b746869636b34726573740a4a696e68616e20496d0000146a696e68616e2e696d40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714adbd010c539216a1b8fecc72fb024b6102c53a3924e8b7e2c163cfe6e5b84299c4481efa0580694c": "0x0401000000020000000000000000000000000000000006696c67696f001468747470733a2f2f706f6f6c67696f2e636f6d1240696c67696f3a6d61747269782e6f726712696c67696f40706f6f6c67696f2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714adc47ca95984db1b2cae6f34fcc3b96db7ffcd6ec5f6a91df93adbe09bcdc2adaf6bb1b8658ed05c": "0x040300000002000000000000000000000000000000000a4173796e63476f6b750000001a7961796f696b7573616d617269616e40676d61696c2e636f6d0000083078676f6b755f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae10508827bed8b3385a3a535bf10808c4d6b1609d36042d9b867bb9446b03f4e6503245dc0c9e40": "0x00000000000000000000000000000000000a5869614d69506f6f6c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae3f2963b6c6f88ad4b61f6445b374d12ae0c94fa138ab0241beb18edb8a270118ad474b42fc062d": "0x040300000002000000000000000000000000000000000a796a686d656c6f6479094a696168616f5965000017796a6834363534303236333440676d61696c2e636f6d00000a796a686d656c6f6479000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae60b338fc29997e986a4fdcd53d0e438f9694c9a6bb76665bc50acf76180049117caf3ca9bbcc6a": "0x040000000002000000000000000000000000000000000f747572626f666c616b65732e696f001768747470733a2f2f747572626f666c616b65732e696f1840747572626f666c616b65733a6d61747269782e6f726717737570706f727440747572626f666c616b65732e696f00000d40747572626f666c616b6573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae6704a5589ed96274b1b6289e6796fc444ca7848a000ff1033fdb8aa867891a3b6a3580d312af58": "0x0000000000000000000000000000000000094d6f6f6e204d616e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae820f0cf7b3fc26522523da8f16bc0b51cfd6e8b113f65f6be19f19681d5d6269cb980f9582c334": "0x0400000000020000000000000000000000000000000007746f6d616b6100001540746f6d616b6131373a6d61747269782e6f72671d7069657272652e6b7269656765723137303840676d61696c2e636f6d00000007746f6d616b610000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae92f7865e89af5b3881c20170b3cfadb60b8455333d313ef17296f86321ef1c7b3a72e10693a00b": "0x040300000002000000000000000000000000000000000a4d61676e6174726f6e13436c696e746f6e204a616d6573205377616e000017636c696e746f6e2e7377616e40676d61696c2e636f6d0000104070697a7a61333134313539323635000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aea3907ec456c507e23cf25bdabd9cf5532e11922e9c4d5b8188ded994a0c5647f16d5e325624158": "0x040300000002000000000000000000000000000000000c426c61636b4d696b4d616b1443687269737469616e204e746f75746f756d6500001e63687269737469616e2e6e746f75746f756d6540676d61696c2e636f6d00000b40546f75746f756d654e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aea617318e829b5f12ae4cc150cef3f9e224d7b6cb10383e91a355a9c9052e21c1c638dbebab9921": "0x00000000000000000000000000000000001457696c6c69616d207c20506172617665727365000016407265706c67686f73743a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aedcaf5c1d328d6a4a5e6693907b2e0647ddb0706e89f7227064060c1de7d10cadee84da22cd8360": "0x04030000000200000000000000000000000000000000086477756c6636390d446f75676c6173204b75686e0000176b75686e2e6f6e2e6b61736840676d61696c2e636f6d00000e406b75686e5f6f6e5f6b617368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aefad5055f10fa735e1d3caa2ac17c3d9376b773bd112e70edbeccef39789d70d41f9dc468181a01": "0x000000000000000000000000000000000021506f6c6b64744d6f6f6e426d506172616368417563437277644c6e474c494d520000001d696e74656e74696f6e323032354070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714af2fd699547c9f4bb4fd1795608e7424be43ddfaa50cf1f80621630df192fd4f9f02fa0e40308a7f": "0x0400000000020000000000000000000000000000000011506f6c6b617374617274657220526561000013407265615f63683a6d61747269782e6f72671472656173636865676740676d61696c2e636f6d000008407265615f6368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714af9ae6e4f434181d9c322cfa42b80ffb1fa0a096ffbbe08ff44423ea7e6626183ba14bfb20c98c53": "0x040100000002000000000000000000000000000000000c456e73526174696f6e6973001c68747470733a2f2f726f626f6e6f6d6963732e6e6574776f726b2f1840656e73726174696f6e69733a6d61747269782e6f7267166c7340726f626f6e6f6d6963732e6e6574776f726b00000d40456e73526174696f6e6973000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714af9bf5521f86ae142ea24923f4561c7393dfee80dbf7d069efda507c76dbc2a160a6f02021ae017f": "0x00000000000000000000000000000000000c54696d204a616e7373656e1f54696d2048656e72696375732057696c68656c6d7573204a616e7373656e2168747470733a2f2f7777772e6c696e6b6564696e2e636f6d2f696e2f74696d6a00177468776a616e7373656e383940676d61696c2e636f6d00000e407468776a616e7373656e3839000f74696d6a616e7373656e3139383900", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714afa63c93073adc978e06bfc989509d6d625c085209adb405867bdbe4f167ded7e61ec126c683165d": "0x04000000000200000000000000000000000000000000135361736861207c2046656c6c6f77736869700000000d68694073617368612e696e6b0000000b4061677279617a6e6f760000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714afb2682abe1821512097f59f6298ee6903bf8b0f183a5a2967fa2d790e94d62aab7ee87247dd346d": "0x0403000000020000000000000000000000000000000017416268696a616e61204167756e672052616d616e646117416268696a616e61204167756e672052616d616e646100001a616268696a616e6172616d616e646140676d61696c2e636f6d0000104072616d616e64616268696a616e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714afc50c1d950a2badd46e3e3ed41155f5f6971639b0fe8fb1afb792f9a7aaf267dc4c61693bbe2645": "0x0403000000020000000000000000000000000000000016426c6f636b636861696e204865616468756e746572000000146d2e73686c6179656e40676d61696c2e636f6d00000d626c6f636b636861696e6868000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714afdda45f48b9d6ccf0a0ba50ffb1d6b6af46b0ae93a21f6943ffe046c9e0423e7c603c46c6696f16": "0x00000000000000000000000000000000000c444f54205374616b696e670000001a6d6174746572686f726e4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b045191cd50fbf997059b7d9ad6e9f5bab40385874989cd04aabbe821094b7e45b5e4de5ecf2bf4a": "0x040100000002000000000000000000000000000000000e416e736f6e202620466162696f16416e736f6e204c61752c20466162696f204c616d611668747470733a2f2f616e736f6e2d6661622e696f2f1d23416e736f6e26466162696f3a776562332e666f756e646174696f6e16616e736f6e40776562332e666f756e646174696f6e00000c40416e736f6e466162696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b07ceda0d965ecfb8233864aaf64f98f44f718a1ea60ebffdd0d4997de67f4b5e7f3b01f1d712d1e": "0x04030000000200000000000000000000000000000000064446472031000000126a616d65732e77406466672e67726f7570000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b09f0dc1cd5bdd13b0a08173d9322251d85475ae44c1325bfbb0254f20318b0aade97b250af5c010": "0x04010000000200000000000000000000000000000000084d6574686f6435001468747470733a2f2f6d6574686f64352e636f6d0011696e666f406d6574686f64352e636f6d000009406d6574686f6435000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b0a07ed5a19f8b6a90fcde4b37a2b8100dd2dc66cc9e195587e3bf396cb376c4589921d1bcd11905": "0x0000000000000000000000000000000000135354414b454241425920444f54205045525300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b0b594ec0cee6911fb9cdfce8071d94d5226bb1746bcafbd3bff4ef7ca9f923f9ba24d6c501002fb": "0x00000000000000000000000000000000000a4672657175656e637900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b0c28bc153cfcb785e71bc8d34c9270330e524544df34af4113a66bf1a300cfd6e67e6bc522cdd1a": "0x04030000000200000000000000000000000000000000064d6174656a0d4d6174656a2053747275636c00001773747275636c2e6d6174656a40676d61696c2e636f6d0000097363687472756c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b0f623591c049c48d238ccb2dae20c1ebb4ce235085255a5d5d0d7bc55bf8b312fdeabac027daf3c": "0x000000000000000000000000000000000009436861696e494445074b75646f77751568747470733a2f2f636861696e6964652e636f6d00146b75646f406d61747269786c6162732e6f7267000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b156c95d777eb874c4d118037ecd231792bbc725102956f2f0488cd30ffd46c2f3dd5b1e17502137": "0x04030000000200000000000000000000000000000000074d626c6f636b074d626c6f636b00001576616c696461746f72406d2d626c6f636b2e696f00000f404d626c6f636b636f6d70616e79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b1580a59c1acfdc54421050207b47ba1bddef66d1e1deee5b27d27d7fc526cfd68e4be18a5b9b146": "0x080000000002010000000200000000000000000000000000000000104555534b4f494e2056697a63617961104575736b6f696e2070726f6a6563741168747470733a2f2f6575736b6f2e696e14406575736b6f696e3a6d61747269782e6f72670f6b6169786f406575736b6f2e696e000011404575736b6f696e4f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b168e3b84020d6822dcd0e9ec909fc8e672d8708223330eac4613042b2c63c8d913fc6a12bd99fd8": "0x0400000000020000000000000000000000000000000004524a5f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b18604d7d7a798faa40aa369106391b44027cbfd19b4e8e475971c90f78717f85bb6a5976299567f": "0x04030000000200000000000000000000000000000000094772696d66616365000000126e6f7461746b6940676d61696c2e636f6d000007403162696e31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b1a455bf3d4031c6b422d3e099417a341702fc9e4dd318da3c2993adcb81a3cf35ba18679724b36e": "0x000000000000000000000000000000000014f09f8c9f20616c6578616e64726120f09f8c9f0000000000000b40616c7868656c6c6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b216fc8c00c1967038406fc5553270a770f2b9afe29ef48028738645f7bc0f221460634d1a7c9a07": "0x040000000002000000000000000000000000000000001f4d6f6465726174696f6e205465616d20426f756e74792043757261746f7200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b237135b4b47977700321713f671d3c1fb706209062ffd05e74bb4a42470156d8103a25d4dc0201a": "0x04000000000200000000000000000000000000000000064b414e4459124b616d616c6120496d6d6163756c61746500001c696d6d6163756c6174656b616d616c686140676d61696c2e636f6d00000d406b616d616c61496d6d6163000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b23d190eeefbfb6f7a9bd53c257e7c227609b012a33e9e17537cadc7740b22be73883942c673b34f": "0x040300000002000000000000000000000000000000001157656233204173736f63696174696f6e1147656f726765204c6f766567726f766500001968656c6c6f40776562336173736f63696174696f6e2e636f00000f4057334173736f63696174696f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b26d5289874157380c300de9970a72be7155e43892cc29b4d4b4c8a571b61cfd5430a52afa1af85e": "0x0403000000020000000000000000000000000000000006637962696f11446f6d696e6971756520536962657564000011637962696f40686f746d61696c2e667200000940446f6d69536962000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b27baa39147ef36e8ae3ad2c81ef018e08ea05d0422b9cf276d6c909936b04105c1686cb3eb2fd0a": "0x0400000000020000000000000000000000000000000014506f6c6b61646f74205068696c6f736f70687900002040706f6c6b61646f745f7068696c6f736f7068793a6d61747269782e6f72671f636f6e7461637440706f6c6b61646f747068696c6f736f7068792e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b2867f14046b21d05a33766207d51925e4b9a2302870bf737305cddd5bb2df2dffa379963e586771": "0x040100000002000000000000000000000000000000000b5374616b656454656368001868747470733a2f2f7777772e7374616b65642e746563681340766564646f6f3a6d61747269782e6f72671b7374616b65642e746563684070726f746f6e6d61696c2e636f6d00000c405374616b656454656368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b2c78530b4a796f2f8f0244b95932b7a67caffd31de91edc5cfb3aa2a13f6199f127ce51c558204a": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b2d135d5db3b036bce4761ea5d8d29dd92a78dc606246d8146320a5e9292de240ab15f60c7802e4a": "0x00000000000000000000000000000000000a534e5a506f6f6c2d3108534e5a506f6f6c1768747470733a2f2f736e7a686f6c64696e672e636f6d0012686940736e7a686f6c64696e672e636f6d00000c40736e7a686f6c64696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b2fb008da08ac54bf6dddfb2f535dd62fdac8b70b241d590e7838c5f553e66cf8bbbafd47fce817b": "0x040300000002000000000000000000000000000000000b4c61726b2044617669730b4c61726b20446176697300001874686563727970746f6c61726b40676d61696c2e636f6d00000f4074686563727970746f6c61726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b340199e34eab193aa612c6fb0748838d721b854a70cb1838cc4fc0814e80d4785dab72125e8a010": "0x0000000000000000000000000000000000086e616e6173736511414e4153534520454c2048414e414e4900001a656c68616e616e692e616e6173736540676d61696c2e636f6d00000000056136653700", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b3b2f5054ad51dabe830cd17659a15933def85ed0afa8f681e5db64551c1ea411b5e9be3e7349e1c": "0x040300000002000000000000000000000000000000000e57414c4c4554434f4e4e4543540e57616c6c6574436f6e6e6563740000176a6573734077616c6c6574636f6e6e6563742e636f6d00000e77616c6c6574636f6e6e656374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b3b4ecc4022f0e1630a3eb5333cc487d3754d4c76346343611dfbfb5eb55c15045daae38282a3939": "0x0403000000020000000000000000000000000000000005526f77690f526f7561726b204c65657264616d000019526f77695f6c65657264616d40686f746d61696c2e636f6d00000c4c65657264616d526f7769000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b3d2b9874fe0df30cc7a6b245f0617fa48c27e56589cd6954c0448ced7c54df2325b007ee5b4ca02": "0x0403000000020000000000000000000000000000000007636f6e7232640b4a6565796f6e6720556d000011636f6e72326440676d61696c2e636f6d000007636f6e723264000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b3dac7c4c99b7c0d8e851ed992228f2268ee8c614fe6075d3800060ae14098e0309413a0a81c4470": "0x040000000002000000000000000000000000000000000b427279616e204368656e00001340786c6368656e3a6d61747269782e6f726714627279616e406163616c612e6e6574776f726b00000d4058696c69616e674368656e04786c630000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b409b598d1b08171e0a38871f4a1941fdd3af5a049c463a4cec1df86f594c61dda778d07b4693c7a": "0x0000000000000000000000000000000000194d4554415350414e2028706f6c6b61646f7420706f6f6c290d6d6574617370616e206c746400000000000d406d6574617370616e5f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b43789f78727cee3c885a011dbc63183416fa77f78a967ad0ffbbbb62e444e9eb490abd2fc67d326": "0x00000000000000000000000000000000001042494e414e43455f5354414b455f331042494e414e43455f5354414b455f33000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b471bc360e5a3e9548020d0712411b7ebf7f757f9f0d3f69f1660d636fb2c9811d81140cf84f561d": "0x0000000000000000000000000000000000074341505045580743617070657800000000000e4043727970746f436170706578000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b49940857135462fa0db8c6cb723c474639931cae07e095e6e8d9b870c90f5b499bd8e6fdf4bd54f": "0x040000000002000000000000000000000000000000000a4c696d65436861696e000000126869406c696d65636861696e2e74656368000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b4a5da87e533f5dff58927b296a23cbf25794b7cbb8fe31c5e68f2bcd2c2483e9c9cd0712216f232": "0x040100000002000000000000000000000000000000000f3125202d2047545354414b494e47001768747470733a2f2f67747374616b696e672e636f6d2f14406761757468387a3a6d61747269782e6f7267166761757468387a4067747374616b696e672e636f6d00000a40475374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b4ab7a3aac34e144a8643e2e7c9f9bec10df82710ba1181b7b07b6cc15674584995f911ebd304661": "0x00000000000000000000000000000000000f4b656b6f7365206f66506865656200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b4c98d3a42ca87e8eadf02d15ffa95f56be8b5d91825988362d5f8918ba3070e258dea7b0c67806d": "0x040000000002000000000000000000000000000000000f506f6c6b61646f74204172656e61002068747470733a2f2f7777772e706f6c6b61646f746172656e612e626c6f672f0018706f6c6b61646f746172656e6140676d61696c2e636f6d00000f40506f6c6b61646f744172656e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b4d353916a9420c20c65d7c1489d18dedea3b4acf5443bd0f088e6062d20f15e774ee860e39e3d2a": "0x0403000000020000000000000000000000000000000008626b6f6e747572124272616e69736c6176204b6f6e74c3ba72001c406272616e69736c61765f6b6f6e7475723a7061726974792e696f12626b6f6e74757240676d61696c2e636f6d000011404272616e69736c61764b6f6e74757208626b6f6e7475720000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b4e729082bc0effa0c691601793de060491dab143dfae19f5f6413d4ce4c363637e5ceacb2836a4e": "0x04000000000200000000000000000000000000000000064c65656d6f000000166c65656d6f407468656368616f7364616f2e636f6d000009404c65656d6f5844000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b508400087c4b7c3a800d94d09f32bd5d031bd76c9a832c34b291c964bbcc63a81ac3589b48f543d": "0x000000000000000000000000000000000013424946524f535420464f554e444154494f4e14424946524f535420474c4f42414c204c54442e1868747470733a2f2f626966726f73742e66696e616e6365001668656c6c6f40626966726f73742e66696e616e636500001140626966726f73745f66696e616e6365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b51eff5e9260eafe64e6db572dcc9e5dc57445ff7c68ce85e42527aa74b2ed5d1e2bceefd308ed05": "0x0400000000020000000000000000000000000000000015434f4c442053544f52414745204341504954414c00001f40636f6c6473746f726167656361706974616c3a6d61747269782e6f7267207262617272617a6140636f6c6473746f726167656361706974616c2e636f6d00001040636f6c6473746f72616765636170000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b5638bc24447b04d3213d525c169d24ac664b8fb61afb7ff9c5c542d0942a9ae620513e2b83e787e": "0x04030000000200000000000000000000000000000000064d756e61790c4f6d6172204672616e636f0000166f6672616e636f6865616440676d61696c2e636f6d0000086d756e61797475000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b575b6cc98247c63f866d0c3a34620c8db7cd658083de421bbbbe597794f2911c1cb53975f5e83a0": "0x040000000002000000000000000000000000000000000ce2a793204170696c6c6f6e0000001168656c6c6f406170696c6c6f6e2e696f000009406170696c6c6f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b5857832389789b78af348b187a2e94f7dfcacc1de5c71b55f6ab8a50e75f0ac1a15baeebfd92e03": "0x040000000002000000000000000000000000000000000b47616975735f73616d6100000015672e756e69743234383140676d61696c2e636f6d00000b4067756e697433313234000b67616975735f73616d6100", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b58ced053a478447f6f6cf81a81b368a0e419b9b6e205f3f9d2927a27e663e6601bad2e7c0df6276": "0x04010000000200000000000000000000000000000000074c7572706973074c75727069730000176c757270697340626966726f73742e66696e616e636500000a4030784c7572706973000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b5c07bdf818842cb2cedffdd95011af0a1c5683f8445a05006f30487f0dd25beac664c54bf55441d": "0x00000000000000000000000000000000000f416e696d6f6361204272616e647300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b622b6f540376f72543919fb30b3e6e49c1e95a77c05b6d87f457e5cc4e7275584bc1021f808ef65": "0x040100000006000000000000000000000000000000001b6e616c756c756c616c615f506f6c6b61646f745f5265706c61790d594f4e47534f4f4e204c45450000156e616c756c756c616c61406e617665722e636f6d00000e406c756c756c616c6131383534000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b67813127799c8e920b456b7a8651f0b81f4517ffc79737cc392230cdd92a5b4bfa09ac728a0b10e": "0x040000000002000000000000000000000000000000000a536166655374616b65001568747470733a2f2f736166657374616b652e696f1640736166657374616b653a6d61747269782e6f726712696e666f40736166657374616b652e696f00000d40536166655374616b65494f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b6d59c328d706cfb061f3d8a0b63df2c81c3a5c1fa616fb3a3695d64249dcbb01d3cf73621fe8e3d": "0x00000000000000000000000000000000000f4675636b5f6368616f735f64616f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b6ecd013f449a75f58f2f7dd26682082ccd78611deeeffb89b38bfe97fe95be7e2047cd8e346ad1d": "0x0401000000020000000000000000000000000000000005474465650c47656f726765732044696200174067656f726765736469623a6d61747269782e6f72671667656f726765732e64696240676d61696c2e636f6d00000d4067656f726765735f646962000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b710ad30347143bdf2e76f70974fa08e941bffc14e3b2c8643a58a35f95bbe411b90ca62acd15a77": "0x0400000000020000000000000000000000000000000008537461747574650000001b73746174757465636f72704070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b7acf702b47d3804de064386a3512bba067ef6bd099e7f3a3e68fe6074a8c1ab872ddd7beb8c9002": "0x0400000000020000000000000000000000000000000007686972697368000013406869726973683a6d61747269782e6f7267166869726973684070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b7b376ac778360f7628da3d78e9d1d4af0ceba193397950ea8da074445f066aabc66c82a50fa4e4a": "0x0403000000020000000000000000000000000000000021506f6c6b61646f74204d75736963204576656e747320496e69746961746976650f6261736820617564696f204c4c4300001b68656c6c6f40706f6c6b61646f746d757369632e6576656e747300000b4062617368617564696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b7e8f2933e177fd140c32e6713cc47364b6998b554957eba420df2ab568e6d8e8c672086dd9d5358": "0x0000000000000000000000000000000000215b4d756c74697369675d4576656e7473426f756e747943757261746f727376320000001a706f6c6b61646f74406576656e7473626f756e74792e636f6d00001140444f544576656e7473426f756e7479000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b7ff6a0c4f676b75103fe40937daa62b317e7c8e87c32b0503f705461ea76fc4babcd0c4e2a30a2c": "0x0401000000020000000000000000000000000000000004726f620d726f62207468696a7373656e1268747470733a2f2f726f622e746e2f6376000a686940726f622e746e000009406772656e616465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b835555e3cf0e1b97645bce397d2046a059a06f0252ce845eef1eae32b9243a054d981ce11245c27": "0x04010000000500000000000000000000000000000000124d7974686f7320466f756e646174696f6e124d7974686f7320466f756e646174696f6e000012636f6e74616374406162696c65782e6368000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b85669beeb21dd0baa6646d5b85790bc0ab869d80385fdc10e1f4befa7f8a4bf31848f73012d2823": "0x040000000002000000000000000000000000000000000946616972204645450017687474703a2f2f666169726665652e62616c702e65750010666169726665654062616c702e6575000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b861b613b2b2cdab7a04046977ce345e873315f47f0a6cf6a3659abaa029d6cbf7135fdd53fb573a": "0x0400000000020000000000000000000000000000000018574f4a444f54202020ca9520e280a2e1b4a5e280a2ca9400000012776f6a646f7440776f6a646f742e636f6d00000840776f6a646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b87e14d1620810750e8ed639d511aae6e8213a795a521b6e088b292e45b9ff1e2dcf31cad748e91b": "0x000000000000000000000000000000000006706f6c6b6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b89d726fb1d2f438faac5c26d98f04b9b842e95e85244977a27fc7c93bc73679728d227172aa814d": "0x00000000000000000000000000000000000c526567656e63792d3031381757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b8a74d4a444db6f1bcf647b00211b2d6c8cdb9e091b95ba03ac8bc6a4dd0124f1f09f8c917d1d270": "0x040100000005000000000000000000000000000000000a44454741204953504f05444547411668747470733a2f2f7777772e646567612e6f72672f0011636f6e7461637440646567612e6f726700000a40444547415f6f7267001868747470733a2f2f646973636f72642e67672f6465676100", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b8bf8f1e86641005011b82ff2f3419c087efdfb9490db431028f2a638d5c6aeee59c4fb3f1a30b81": "0x04030000000200000000000000000000000000000000094b617a756e6f62750f4b617a756e6f6275204e646f6e670000166e646f6e676d6566616e6540676d61696c2e636f6d00000e4b617a756e6f62754e646f6e67076e646b617a750000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b8c65c55ccbce8a00ad902bdbcd4bb2f81f505fa223b63310cd34e5eeb715b0e50ad3b7e0b412e59": "0x0403000000020000000000000000000000000000000009307877617369616e0f416e64726577204c69757469657600001f616e647265774073756d6d657262726f6f6b686f6c64696e67732e636f6d000009307877617369616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b8ebbd021ec2bde2f068505a66e272d987c377f0ae0c0a795edbb4db40be62187205803920118a28": "0x04000000000200000000000000000000000000000000086873696e636875000014406873696e6368753a6d61747269782e6f7267166969656c6974652e6c656540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b8fe9945a99464405661eeafb5d22cc01c4dfe7ddaf4af6210da32aa407b91be8af3f75bc6589871": "0x040000000003000000000000000000000000000000000c4879706572737068657265001d68747470733a2f2f68797065727370686572652e76656e7475726573001d6d616e616765724068797065727370686572652e76656e7475726573000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b902e56a5ec842fbc8018be75da4c5757d622874c1dd478950b27baff9b50ca4c0e7670c237f626d": "0x040300000002000000000000000000000000000000000a77336e3a657269636b0c457269636b2052616d6f7300001577336e657269636b40686f746d61696c2e636f6d00000a4077336e657269636b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b9544e0ad8a886ccfcfb0d15de7d1812d75d043f0bf16879a129a02498b40726280770bd38d3cf46": "0x040300000002000000000000000000000000000000000e4c69616d2050656e64756c756d001b68747470733a2f2f70656e64756c756d636861696e2e6f72672f00136c69616d407361746f7368697061792e696f00000e404c69616d50656e64756c756d000a70656e64756c69616d00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b970ba0a552b2a1b5a1f26de64611bef588e2d98deebffdf026e87b35385c2eb3959c47e4e73c74c": "0x00000000000000000000000000000000000c506f6c6b61646f7420545018416e746f6e696f205061736375616c204a696d656e657a000016747061736375616c6a406f75746c6f6f6b2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b9744a1a4ac9720b28ce403471e5e1dcf0c84eaebeeec6abf5caecb0f65478c5a4e6e40414872e3c": "0x0800000000020100000002000000000000000000000000000000000c3238446179734f66446f74001c68747470733a2f2f7777772e3238646179736f66646f742e636f6d001a6368616c6c656e6765403238646179736f66646f742e636f6d00000d403238646179736f66646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b9a0b6f1289fd337141f9165a69d007a81159ca9efe4b58aed0df50423fcb1bc90cddd9be417697a": "0x00000000000000000000000000000000000b4d757365756d5765656b001868747470733a2f2f6d757365756d2d7765656b2e6f7267002062656e6a616d696e2e62656e697461406d757365756d2d7765656b2e6f7267000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b9aa88162953b359807e371d9df95983e2b9face8efb67f962816f1a0c6681cb1e5455127ab45c09": "0x04000000000200000000000000000000000000000000154150455254555245204d494e494e4720f09f8e820000001d76616c696461746f724061706572747572656d696e696e672e636f6d0000104041706572747572654d696e696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b9cb4016283da91d8686261e411fc4e31d3cb29074978a43851627965b4f4189c7777a83a624b11d": "0x00000000000000000000000000000000001d426c6f636b636861696e20547261696e696e6720416c6c69616e636500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b9f7ccb0a5350c8ee185aadacee7bfae327e2f8104bb96e15d6e026bed15e1290d6f1f88ad681f23": "0x00000000000000000000000000000000000d6672656576657273652e696f0f46726565766572736520532e4c2e1968747470733a2f2f7777772e6672656576657273652e696f0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ba371c7e28307a6d16a1fddb4cd14ff65b25f91ae81ba64df7e6318ed826746ed5298feaa38c6c1d": "0x040300000002000000000000000000000000000000000b506174726963696120410e5061747269636961204172726f00001e706174726963696163616d696c6c656172726f40676d61696c2e636f6d00000b40706f6c6b615f706174000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ba5082da70988302146fae5102954f580c20e67585bbd57aeb722bf29fe02607c8b876270706a901": "0x04000000000200000000000000000000000000000000074d65726c696e000000166d65726c696e6e6f6465734070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ba6da6ae5a6fff014e031ef11ea1fa0b7f1f0c07b0a5d36afeea49a8c094f6959d1c3702c5cd016c": "0x0800000000020100000000000000000000000000000000000000000e5869616f207c20537461726b7300001340787a68616e673a6d61747269782e6f7267127a68616e677840676263746563682e636e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ba7663c3b3aaf51b09cdd094e9a51d26bbc6cbb71d3f7c5b8edde629402e3e5370e7f6904512fc4a": "0x0401000000020000000000000000000000000000000011445241474f4e5354414b4520f09f90b210447261676f6e5374616b652c20534c1768747470733a2f2f647261676f6e7374616b652e696f154064657266726564793a6d61747269782e6f726714696e666f40647261676f6e7374616b652e696f00000d40447261676f6e5374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bac18b8eb37d5be29af7e1fc9dca350922e065a2ae8b3366f554e64c9519c55bf1dd7c8b2f8c2554": "0x00000000000000000000000000000000001054616c69736d616e20506f6f6c2031001568747470733a2f2f74616c69736d616e2e78797a000000000f40776561726574616c69736d616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bac296575a7da3090eb83479fa34dc63024ed44efa464427375a44de486e8d6007c7842b45ce817f": "0x04000000000200000000000000000000000000000000114255454e4f2056414c494441544f524f000017406275656e6f76616c69643a6d61747269782e6f72671a686f6c61406275656e6f2d76616c696461746f726f2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bacc123aba961dfdac7c228c0c2f9f8bd69a79694a21c0aaa11fa0bdffb8a24f8a2b2c7c71dd4464": "0x0400000000020000000000000000000000000000000008616c657867676813416c6578616e647275204768656f7267686500000000000008616c65786767680000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bb6fb2c1a1cf337b7ed3dd1132e1f216cb30c2440b46423faf32c6effd0a2d9a9f24e52f57af6677": "0x040000000002000000000000000000000000000000000b4c415552454e5454524b000000186c617572656e742e747572656b40676d61696c2e636f6d00000c406c617572656e7474726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bb813580522537309ac6f5d9af351a6a087753ae455455f640508159d2455ba20f245403a14a2338": "0x00000000000000000000000000000000000a42697474656e736f720a42697474656e736f721668747470733a2f2f62697474656e736f722e636f6d00196f7065726174696f6e73406f70656e74656e736f722e616900000c4062697474656e736f725f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bb8e58b3f0252518fa04117758ff4b850ed983aa317d44ad71f28a5cc36caca35d4b60cc28c02061": "0x040300000002000000000000000000000000000000000b436f6e6e6563746966790000001c78696f6d6172616268756c6c617235323740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bb99afa281244f547837d6d2430ff5a0e6f8b7aa57f325f01ae204332d4cda591324dc09b5da1268": "0x04030000000200000000000000000000000000000000054d6f726b0000001e676f76406d6f726b6d6f726b6d6f726b2e616e6f6e616464792e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bbcb4a8bc42b334be86b14052f27742916a13482c39afc8d9a8f873d799c9aa070bbd045570baa66": "0x04000000000200000000000000000000000000000000114d69636861656c5f52657075626c696b00001d406d69636861656c5f72657075626c696b3a6d61747269782e6f72671861646d696e40676c6f62616c70617468776179732e696f00000d404750435f4d69636861656c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bbe20aee1ef9d6a1a8955315ec9f709c88644db0bfc9df67e13c44336d15899eae335b2e0b05346e": "0x040000000002000000000000000000000000000000000d43727970746f6772617068790000001963727970746f677261706879766c4070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bbe6cdadc6b5f81166abfdc8c3f01b4913bb09c1690b3ad15179ad20fb3e1f46d90e0104ea90951b": "0x00000000000000000000000000000000000b4e69636b20536d697468174e6963686f6c61732043616d65726f6e20536d6974680000126e69636b4074616c69736d616e2e78797a00000e406e69636b63616d736d697468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bbee26bcd7ecf2ba823ef42d2d68197d69bab7d3cbade923c9ba19206656cfe238336e3df412581b": "0x00000000000000000000000000000000001250616369666963204d65746120496e632c1250616369666963204d65746120496e632c1c68747470733a2f2f706163696669632d6d6574612e636f2e6a702f00186b65697269407061636669632d6d6574612e636f2e6a7000000d40506163696669634d657461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bbef2b0d9d60628cf627e295ecc92fc03a0f47172c8655f8d2a0d23df634fc94ce264807cf5bab23": "0x04000000000200000000000000000000000000000000074f7261636c6500001440616c6d6172696f3a6d61747269782e6f72671c76616c696461746f72706f6c6b61646f7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bbf605712f9a94b89e2dad25d8b2be1adbae19a2063b835fab6a12c15bfb2c027420a5afc7381e7e": "0x04000000000200000000000000000000000000000000084d447564757461000000186475647574612e6d617269757340676d61696c2e636f6d000009404d447564757461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bbfb887412ddd8c82e9bbb2cfebfeb22622c29ba56cd766025f4cf35c7737bdcc6762378b7cb207b": "0x0400000000020000000000000000000000000000000015616e6472656974612d76616c696461746f722d3000001540616e6472656974613a6d61747269782e6f72671b616e64726561662e7370657a69616c6540676d61696c2e636f6d00001140616e64726561667370657a69616c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bc3a76766e184695e0584b8462ed4202de4277676f6b1d2b77115672493e6f6fff429b660a0ab865": "0x0000000000000000000000000000000000164465636f6465642056696577696e672050617274790e44696c6c6f6e2048616e736f6e1868747470733a2f2f7777772e646961646174612e6f7267001a64696c6c6f6e2e68616e736f6e40646961646174612e6f72670000104064696c6c6f6e68616e736f6e3132000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bc7126812bf1df493e1630f099540e76e98b9fb0002c3a5ae3f40b6ec180df68fe5cd9bd2088fa18": "0x040000000002000000000000000000000000000000000a535445414b43484546000017407374616b652d636865663a6d61747269782e6f72671868656c6c6f40737465616b636865662e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bc9fa9104384658136e4b176f4f8c8e93d1f038c4ad53d6ce6308764888af81d0b2acc9903f59a3d": "0x00000000000000000000000000000000001850617261636861696e7a20556e204a6f6262656420544500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bcbd30ffb6d16c690237f4df962d9a15d5d2fa981f6f689fa4add977e746c01a07620a92caea5277": "0x04000000000200000000000000000000000000000000136c616e6465726f73207c205374616b655570000015406c616e6465726f733a6d61747269782e6f7267156c616e6465726f73756140676d61696c2e636f6d00000d406c616e6465726f7375615f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bcfdd67ea673f1f2641768da63aab1ad01b2ffed1a44b41c4475f3efdcb74d1e45cf3c490db0c11b": "0x040300000002000000000000000000000000000000000b7863526f6d312e646f74077863526f6d310000167863526f6d314070726f746f6e6d61696c2e636f6d00000a40726f6d315f646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bcffc29008504fd75ca3d296ca48e252a8029882a8218a8c821bb51d80f4852a4b61e29b3d8d3e79": "0x040100000002000000000000000000000000000000000c426c6f636b636f64657273001868747470733a2f2f626c6f636b636f646572732e696f2f001b656e67696e656572696e6740626c6f636b636f646572732e696f00000e40626c6f636b636f646572735f001e68747470733a2f2f646973636f72642e67672f7a6571466e7755786b5900", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bd0c168620def27bea3a8ff4ae2930c102a7bb34d17374198a33d4250b6c5eb4689efc0035298107": "0x000000000000000000000000000000000016436f6e74726f6c6c6572204a6575206ec2b032202d084d6169734e6f6e000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bd3136476e89f2d1688a4b3d49b7fa3e1587f8a8e3b445c7c3e830d524a6dc0bfd89a0f8627a6f08": "0x00000000000000000000000000000000000741554b4c454e0000000000000c40616e746f6e6961796c79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bd45ee52acd85afa825872f7d324c8d97a9d5f5c94d918eea93ef783f305767b768a76f9fede7b4a": "0x0401000000020000000000000000000000000000000009414c4c4e4f4445530e416c6c6e6f64657320496e632e1968747470733a2f2f7777772e616c6c6e6f6465732e636f6d0015737570706f727440616c6c6e6f6465732e636f6d00000a40616c6c6e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bde7f741d77b7e0ea2e36a2a787a3d59588d756dd54b5d1cf5a464496d7c29d31438f1a8a2a0a80e": "0x040000000002000000000000000000000000000000000a436861696e5361666500000012696e666f40636861696e736166652e696f00000d40636861696e736166657468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714be03b2298e56f6b680118fb6d4f674aebcecccfa0640584af7004d155d17fd88e0b5d1b682460a2a": "0x040000000002000000000000000000000000000000000c646f747374616b652e696f0000001268656c6c6f40646f747374616b652e696f00000d40646f747374616b655f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714be084a2d67f3fe459800cbb128a37eb9e9ce630aebdaa4e3345ac67d75b766524cdf2e21de7b721a": "0x0403000000020000000000000000000000000000000006446f646f77000000156372797074646f74616f40676d61696c2e636f6d0000114066617368696f6e69737461776f6e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714be09d91e809b5850d61b7925b1cfbbd6c618187421191758888a19df2d04f622da9d941c6066b47a": "0x0401000000020000000000000000000000000000000009444f5445522e494f09444f5445522e494f10687474703a2f2f646f7465722e696f14406a6f69656375693a6d61747269782e6f72670d6a6f6965634071712e636f6d00000a40646f7465725f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714be3183951dd1f1d5e626934768e68509f3b657372165e6f98fdefe615cc8e669d5bbe033a6478556": "0x040100000002000000000000000000000000000000000bf09f9491204b656974680d4b6569746820496e6772616d1968747470733a2f2f6b65697468696e6772616d2e696e666f18406b656974683a6d61747269782e7061726974792e696f106b65697468407061726974792e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714be58ca2ba19c9036f8596d3d1bfe4d7b96b76a35bb52078edb437a5e5b932fad5f653bf0080e0d50": "0x0400000000020000000000000000000000000000000008414c455353494f001d6c696e6b6564696e2e636f6d2f696e2f616c657373696f6f6e6f7269134069726f6e6f613a6d61747269782e6f726718616c657373696f2e6f6e6f726940676d61696c2e636f6d0000084069726f6e6f61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714be88be4b51946ab0b45ad6a53e0a688752f3a40f49cf7e666169c787f83bf1c2ff8aa026d99ac177": "0x040100000002000000000000000000000000000000000e5354414b494e4744585f434f4d0e5354414b494e4744585f434f4d1668747470733a2f2f7374616b696e6764782e636f6d16407374616b696e6764783a6d61747269782e6f726713696e666f407374616b696e6764782e636f6d00000b405374616b696e674478000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714be90c353cce89dbc62838e85d6feea406b4544b851f10449c2f2376b9d3805a3b7cdb98ef2573f7d": "0x040100000002000000000000000000000000000000000c41576f726b65722d3030310000114066756e633a6d61747269782e6f7267156c69646977656e63686540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bea99ac32a4539bc724d262fd25c8cc975189c3ae4f0dee1ba2e17080cda69183412d0928b49db0f": "0x040000000002000000000000000000000000000000000b7375626c61622e64657619537562737472617465204c61626f7261746f7279204c4c431368747470733a2f2f7375626c61622e6465761a406f616b6c65792e7375626c61623a6d61747269782e6f7267126f616b6c6579407375626c61622e64657600000b407375626c6162646576000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bed90d4bbefb67eb8485f4b667f18f10d2c523593467680fb28b501f93d053ed08a1eed3c9e5c852": "0x040000000002000000000000000000000000000000000c43524950544f4d454449410000001d63726970746f6d656469616f6e636861696e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bee71c5b95c53e49da92c32ab2b4e1a46bb659cb6fd22fc824611e4c2803fbedd93c246f97c67118": "0x040300000002000000000000000000000000000000000a566976616c646920300e476f6c616e20566976616c6469000018766976616c64692e676f6c616e40676d61696c2e636f6d00000e4042756c6c697368476f6c616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714beea5d629df9274d3ca902971765b01d4fc6e7b9a45d1e3e1f9ed351e5bd8554d3c812457f2579d0": "0x000000000000000000000000000000000012506f6c6b61646f742048656c73696e6b690000001b706f6c6b61646f7468656c73696e6b6940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bef0fe62add82534c03802bc59091c05f317f32a796a720027867fc14e6554a7be0c19d7f107b332": "0x000000000000000000000000000000000009506f6c6b61646f7408686f74206b6579000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bef1561c49f96ee16aff72a0c7b124579def4ebf4515e735b0fe3eea919c682e6d71ed9c0474da7c": "0x00000000000000000000000000000000001a4576656e747320426f756e74792056322043757261746f727321506f6c6b61646f7420436f6d6d756e697479204576656e747320426f756e747900001f706f6c6b61646f746576656e7473626f756e747940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bf00044145d9dee7b6e0dce13b0bd22e17942bfa320877be89092b7e4f482fc68e1099109ca42938": "0x040300000002000000000000000000000000000000000f50494e4b20504f4f4c20233235340e4a757374696e205365656e657900001d6164766572746973696e674063726561747273747564696f732e636100000d4372656174724a757374696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bf0ff86d35aedc7b309145b12c7144a895495d82d6ba5cefc34b841859d6732af2759287266a2b19": "0x04000000000200000000000000000000000000000000084d65726d61696400001a406d65726d6169646f6e6c696e653a6d61747269782e6f7267196d65726d6169642e6f6e6c696e65407961686f6f2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bf1fb55b1ab52a450857c62463c3671fa8ef7253b3380ff662b0963c86dd9d227c10428b2d8c746c": "0x04030000000200000000000000000000000000000000054572696b0d44756f6e6720416e68205475000016747564756f6e672e66747540676d61696c2e636f6d00000c4572696b64756f6e673731000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bf74188b125a3306308b59a947eeb792acf6de27fa47a92ad37d53a15a7b97cd25f11c25455ba253": "0x00000000000000000000000000000000000e4c6f63616c436f696e53776170001a68747470733a2f2f6c6f63616c636f696e737761702e636f6d00177465616d406c6f63616c636f696e737761702e636f6d000010404c6f63616c436f696e537761705f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bf95774f0918328726c943cbc77122d3e8b6a1b92179ee776b972eae6f333697f254f369e150473f": "0x040300000002000000000000000000000000000000000c56616c69644f72616e676500000015646f75674076616c69646f72616e67652e6e657400000f56616c69644f72616e6765444f54000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bf995359aa3940443a8389c4cbbce2c9761722bdcb9a53d1e15023f95af6aecd5deba6377003f919": "0x040300000002000000000000000000000000000000000a4d636f6f6b42616c69134d61747468657720427279616e20436f6f6b0000126d636f6f6b383140676d61696c2e636f6d00000c404d436361746170756c74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bfe2bdce4846e722a0c3719d913e12ae573407a1b2584247c88a292ffbba8cc862211f7defd8f10f": "0x04030000000200000000000000000000000000000000064e696e6a6100000020706f6c6b617373656d626c792e71346d356440706173736d61696c2e6e657400000d4062616c616e6365626f726e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c0095c67a6440edf74db9a1104a31f8b431ece5bcabbe3e508d22fe13670d32875ff6347a88d1388": "0x0400000000020000000000000000000000000000000015506f6c6b617363616e20466f756e646174696f6e14537469636874696e6720506f6c6b617363616e1668747470733a2f2f706f6c6b617363616e2e6f72670013696e666f40706f6c6b617363616e2e6f726700000e40706f6c6b617363616e6f7267000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c00b6c66130a22cc129c10048c90abf494afa1f1d2794d6afdd7e62e46d8bc073114bf42d1d64b3a": "0x0000000000000000000000000000000000084c7563616d657300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c029ee460555e12cb2692080bd814373a7c780dcc62922ba2e770c11a50bb1bb38fd3e69f0192a71": "0x040000000002000000000000000000000000000000001c416e756269204469676974616c204d61696e204964656e7469747900001940616e7562696469676974616c3a6d61747269782e6f726716696e666f40616e7562696469676974616c2e636f6d00000e40416e7562694469676974616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c02a0fb78fe9c0b6e60ae0c90c135ea717c10d2568a2ef847fbd201108f3f8b1a50608e83183574f": "0x040300000002000000000000000000000000000000000a4379706865727475780e4d6178696d65204576726172640000196379706865727475784070726f746f6e6d61696c2e636f6d00000a637970686572747578000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c0357d417cbd92c04e4c31b4c8d28f356b320a3186b82c979647af58b29a1573774e4bc7db1b7b5c": "0x040100000002000000000000000000000000000000001b566f6c74657265204361706974616c204d616e6167656d656e74001368747470733a2f2f766f6c746572652e63681540766f6c74657265353a6d61747269782e6f72671774726164696e67406f6465726d6174742e636c6f7564000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c038a43990a07bb81280a479ee3beca7af1636aca17582f30829782e2c9b1b9c72aaf8060563ab37": "0x040100000002000000000000000000000000000000000e494f53472056656e74757265730e494f53472056656e74757265731068747470733a2f2f696f73672e766311406a6f63793a6d61747269782e6f72670e68656c6c6f40696f73672e766300000840494f53475643000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c053a54bef0f336a9c217bcbcd61459955b47bafddefd16d131156fbb235c55d25f6374f0cd04610": "0x0000000000000000000000000000000000085175696e746f7300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c07690bc374b92f796acfe70c04eae75f56d603fa55ea58adc1a5be6f7780f6bb8b55ca788ad670f": "0x0000000000000000000000000000000000135375706572636f6c6f6e7920d0a16f72702e001968747470733a2f2f7375706572636f6c6f6e792e6e65742f164030786d61726b69616e3a6d61747269782e6f7267186d61726b69616e407375706572636f6c6f6e792e6e6574000010407375706572636f6c6f6e795f7673000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c07bdf560316d32b08ec72cbf62bb66f416f46f988e130585c834a381efdbb0755e30f47a2a0da5a": "0x040000000002000000000000000000000000000000000f50524f4f462e434f4d5055544552134d6f6f7365204c616273204c696d697465641768747470733a2f2f70726f6f662e636f6d7075746572001a76616c696461746f72734070726f6f662e636f6d707574657200000f4070726f6f66636f6d7075746572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c08fd019b5ff673488b8f51942016c72e537611887d58b4e6a44e0f435480472362dfc5244f08038": "0x040100000002000000000000000000000000000000000538425443053842544315687474703a2f2f7777772e386274632e636f6d2f000f77656e647940386274632e636f6d00000c40627463696e6368696e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c0b698fe85dc7f07f46a2cda2040566d6299f92cdb1132a231dc2632ff84b711e3db8634c344f93e": "0x040000000002000000000000000000000000000000000d47696f726765416264616c610000001767696f726765616264616c6140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c14003ed5bc24012503db62affc9c535c960ee60970a8357b7764be446b2dc100a3f77b4370ce165": "0x040000000002000000000000000000000000000000000c506172697479204461746100000014646174612d7465616d407061726974792e696f00000d40646f746c616b655f78797a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1470541a3b4a961448bfb9be2787bb39b122d5b1707e83e535899c58d919a7afeba26968e12382f": "0x0400000000020000000000000000000000000000000004573346105765623320466f756e646174696f6e1968747470733a2f2f776562332e666f756e646174696f6e2f001661646d696e40776562332e666f756e646174696f6e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1587ff616dd25a0560d57708a28e8cbb8794c04d67b66541c191d2effad8596ab63c619f257aa11": "0x040100000002000000000000000000000000000000000d384254432d504f4f4c2f30310d384254432d504f4f4c2f30311568747470733a2f2f7777772e386274632e636f6d000e79757a6240386274632e636f6d00000c40627463696e6368696e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1639ae30e11b073cc003ff85b9d4030c01000f725b0ca03088c45c8e9ab90853c56d1c7b6cbc470": "0x00000000000000000000000000000000000b506f6c6b61446f74203100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c17a5e2df8e467cbba3f7fae8b3156ca2a3b0b84d3b2d922938bc2ab1405aea7813740a02146750b": "0x000000000000000000000000000000000017504f4c4b41444f542d4252415a494c2d4556454e545300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c17b80d313e3c78cce44b6b392394133943e063102b113e0577108fb9cb3000fe04faec3a3ad3934": "0x0400000000020000000000000000000000000000000012f09f8f942048454c494b4f4e20f09f8f940000144068656c696b6f6e3a6d61747269782e6f726710696e666f4068656c696b6f6e2e696f00000d4068656c696b6f6e6c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c19ae875baf61fab3e3a490c516b2a3582e6400e33f3eec42a12589958cbb86c87b23bc94710d21b": "0x04010000000200000000000000000000000000000000134361706974616c5374616b696e672e636f6d001b68747470733a2f2f6361706974616c7374616b696e672e636f6d1c406361706974616c5f7374616b696e673a6d61747269782e6f72671b737570706f7274406361706974616c7374616b696e672e636f6d000010404361706974616c5374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1a0c9593f15c53958c46d422c8c3d1692f51889cf64e2e32cadce1d1d341ca6196a8d4b18a9a354": "0x04000000000200000000000000000000000000000000064d49444153000014406d6964617338393a6d61747269782e6f7267156d69646173676f64383940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1a153b6113c7dfb000b93d72dcc12bd5577438c92a19c4778e12cfb8ada871a17694e5a2f86c374": "0x00000000000000000000000000000000001042494e414e43455f5354414b455f391042494e414e43455f5354414b455f39000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1ab9046e485e6d5466ca78e64f7df8847d8c192f3daddf32426f72a3baa4c3e320082afdb884134": "0x040000000002000000000000000000000000000000001a624c64204e6f646573207c20436861645374616b654b696e6700001340626c643735393a6d61747269782e6f72670000000a40624c644e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1ba3367c853c0b7056fef6e642069325ec72887efa3e22034c6890beebceb935852d776a3d08a30": "0x00000000000000000000000000000000000c506f6c6b617573642e696f0c506f6c6b617573642e696f1468747470733a2f2f706f6c6b617573642e696f0013706f6c6b6175736440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1d50c9830174ca88c232c91ef2a9983ba65c4b75bb86fcbae4d909900ea8aa06c3644ca1161db48": "0x040000000002000000000000000000000000000000000c65636c6573696f6d656c6f0e45636cc3a973696f204d656c6f00184065636c6573696f6d656c6f3a6d61747269782e6f7267000000094065636c3373696f1245636c6573696f4d656c6f4a756e696f720000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1d7648a3e3194dab2bdb0d774986625498e0b5fce860c7d58103bdb6b7b348054d525fddc3f3e7f": "0x000000000000000000000000000000000008576574657a2d3200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1d8ccc3c147543c94575c5627d7661400a3eccacf5440b5f877fa6099f4797a321523e3ade7215d": "0x00000000000000000000000000000000000448616f0948616f2044696e67000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1d9151efd144bc7c6e2ca836b28b68978aa39dc41d5b7ef3a7b8630a3e432d8ca99f24fd86cbd05": "0x040000000002000000000000000000000000000000000764616d736b790000001c63727970746f64616d736b794070726f746f6e6d61696c2e636f6d0000104068656c6c6f69747364616d736b79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1e0ca80539b15c8796b851c8164a129b23282ca4b3bb694364b0bfb504e98b5d2ffc5140d58078e": "0x0400000000020000000000000000000000000000000019416e74692d5363616d205465616d2045786563757469766500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1e288e289580287886286c58d67217bdd854832d5e9f1b218dec6a0ff7e0b7573147ca94a233a0a": "0x04010000000200000000000000000000000000000000204269742e436f756e7472792026204d65746176657273652e4e6574776f726b0014687474703a2f2f6269742e636f756e7472792f000f6869406269742e636f756e74727900000f40626974646f74636f756e747279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c2118a9d986b584ea8a3f426b435bc9415d2bae037d416a81c5b02c8cd6751549b37700c720aab15": "0x040300000002000000000000000000000000000000000e59616e6e204d6f7270686575730f59616e6e20506f696e636c6f7578000014636f6e74616374406f726962696b792e636f6d000009406f726962696b79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c22c37787c57611ecc23ed33549e874ae7c7653fc5d95b3242dc7df5742664b4809e337a13126433": "0x040000000002000000000000000000000000000000001be29ca8f09f918de29ca8204461793720e29ca8f09f918de29ca800001140646179373a6d61747269782e6f726714616e746f6e406e6f766177616c6c65742e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c237c8c9d7bd4904bc267fea33668e3515a7c01f4acca67d73d30574b600a404d2b7210aaac85569": "0x040000000002000000000000000000000000000000000de29d84e29d84e29d84efb88f00001740696365636f6c646e61743a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c2846271fb408595e02d02d96dcacc309d5fb57319b26ca2334ce9d413929bb8ebbfe2ca5e614600": "0x0000000000000000000000000000000000094164696c2d446f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c28f8abd364479314411b54c486afdd65bbe6f482fab68a28443c845c004a1c5d141314577d67d0a": "0x00000000000000000000000000000000000a4669676d656e742031001368747470733a2f2f6669676d656e742e696f000100000b4669676d656e745f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c2910faeab8bbb21aa92898eb263b225b26d5af6d0899f4e628161089ebc308887c48716ba248d5f": "0x00000000000000000000000000000000000d557273756c61207c2057334600001840757273756c613a776562332e666f756e646174696f6e17757273756c6140776562332e666f756e646174696f6e00000a40757273756c616f6b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c2a5b45c043e387bd2a0035cec74b2f90f7e72cab1fb16b6ba8317631976b138f7cced3e00668b0b": "0x04030000000200000000000000000000000000000000074d61676e65740f4d61676e6574204e6574776f726b0000136d6167706f7274406d6167706f72742e696f000010404d61676e65745f6e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c2c055e89a151d2372eecb8803cc4c49b49b0897c51190c9e32f9509e0bb2d7ee174378c7ebf3c46": "0x040000000002000000000000000000000000000000000541636169000016406163616973686962613a6d61747269782e6f72671461636169736869626140676d61696c2e636f6d00000d406c65633238333531303833000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c2ce802d4a097bfe0cd0767b5aaddecbfd90c086a3ae9c5efd0d2ab21b7d574ba605ded74c226125": "0x0000000000000000000000000000000000105361746f79616d6120233120444f54001768747470733a2f2f7361746f79616d612e746563682f00197361746f79616d612e7374616b6540676d61696c2e636f6d000010407361746f79616d615f7374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c2ceac9b196d4a9b7a44e4c663e89e2c161dcf2b0fa46ec92f4017ec832e681ae5ba5f917dc54b58": "0x0401000000050000000000000000000000000000000006746f656e6700000016746f6d6d792e746f656e6740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c31003d453d9cc76b1451f8962f76c9748e3ebeb43d5ba6cc25af020f2eb2316d6237115a3de72dc": "0x040300000002000000000000000000000000000000000762656533343418416c626572746f204e69636f6cc3a1732050656e61796f0012406265653334343a7061726974792e696f15616c626572746f407375676172637562652e6172000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c31738bafd189046ecef3a91c92840fb38e4cd3e20a604c75992cda08df8135416e5f4504e3d681d": "0x0403000000020000000000000000000000000000000003534b000000147477736b6875616e6740676d61696c2e636f6d00000b407477736b6875616e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c32ddea12298867b068f5973c7e1c0739ff08393aeba931748af1156690cd6db3bdccbca7eb82752": "0x040300000002000000000000000000000000000000000642414e584100000017706172746e657273686970734062616e78612e636f6d00000f4042616e78614f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3361cdef8ce970506b2f22dc927017e40cb8834d89a7eeb49a598a965f00fa38ceea3b1c6ed6637": "0x040300000002000000000000000000000000000000000454696e0a54696e204368756e672068747470733a2f2f6769746875622e636f6d2f6368756e677175616e74696e0014637174696e3039303340676d61696c2e636f6d00000e406368756e677175616e74696e000c4063686173656368756e6700", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c34aa17cf274fb0fce72013d22d568d7101bb1ecb5f43bb0d327619eb37337afdf24c5893fdfc06f": "0x00000000000000000000000000000000000c526567656e63792d3031351757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c38be37ff19e3a8a7617b9c6475f887ba801cee49b322a4d888224c8d0791bb0d5c999b6605e251a": "0x000000000000000000000000000000000009646f746875622d3109646f746875622d31000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3a245cb2d2a7e9b56e751974614540cafc9bc363a690d2b4196c79399dd6f9750c202f671125358": "0x00000000000000000000000000000000000b5042412044616e69656c1444616e69656c20506572657a2047617263696100001767617263696164616e79313240676d61696c2e636f6d00000f40446563656e7472616c44616e69000a64616d616e74696e6f00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3aa97983f6ecffc96625a0cbd0931ad831add3bcaa6320950385aec23b3854c6ce987de1c9f8837": "0x04010000000200000000000000000000000000000000085032502e4f5247085032502e4f52471068747470733a2f2f7032702e6f7267000f6c657473676f407032702e6f726700000e4050325076616c696461746f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3b628138bb91f0585ae10011f28f84a7403b3ad52c14fae856077d3be1cb18b88081577a52d1ea7": "0x040100000005000000000000000000000000000000000d446f747479447265616d657200000016646f747479647265616d6572406475636b2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3d4753480e3c1e936f6c360f80a8a9d2674a52440e1b41088663475ee6676796ce14bf3bcb4ae16": "0x040000000002000000000000000000000000000000000f7377656e7468656275696c646572001c687474703a2f2f7777772e7374616b65326275696c642e636f6d2f0000000009407377656e77333100097377656e3737353000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3fdb0ea29d362e6b83d19e4a3ad242102f94a4452381300ace74c5d50fbdd9675a869401d3bff64": "0x040000000002000000000000000000000000000000000645726e69680000001a65726e6968656e656c626f7371756540676d61696c2e636f6d0000094065726e6968626f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c423231fa12d1b91a0606395f5c1ec90f373c26ff05ce375bc584608549d0dca2338dbc7a0fd814e": "0x00000000000000000000000000000000000450534317506f6c6b61646f74536d61727450617261436861696e1d68747470733a2f2f7777772e6f6d6e696274632e66696e616e63652f154069636f64657a6a623a6d61747269782e6f726714676176696e40636861696e6e65742e74656368000009404f6d6e69425443000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c4278e2e719c876ab430a1d38186a28164facec9010e36b1289eb6d3ad0f03f328188fd52bcb333a": "0x0403000000020000000000000000000000000000000005526973680e52697368616e74204b756d617200001a5269736840706f6c6b61646f746e6f77696e6469612e636f6d000011404f6666696369616c6c795f52697368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c43f93ee2474bcdbd0a26ba88664597d50d7a6cc478135d84a261d3efe0338de3a5c71b77b18ed3f": "0x0000000000000000000000000000000000094475627374617264001568747470733a2f2f64756273746172642e636f6d000000000a406475627374617264000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c451757b8ae3669366f108b7fa5e27b25dd980f303f110194181f5725f724db5258f497e3fd7c135": "0x040100000002000000000000000000000000000000000c536572706163727970746f002168747470733a2f2f706f6c6b61646f742e736572706163727970746f2e636f6d124070736572723a6d61747269782e6f726715696e666f40736572706163727970746f2e636f6d00000d40736572706163727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c47e6cc596c775ea049386f24725f9bf05946141f7baab4c1976ff5396ae250af174a04ef54a1962": "0x00000000000000000000000000000000000b4a6f616f2048617a696d0b4a6f616f2048617a696d0000146a6f616f68617a696d40676d61696c2e636f6d00000a6a6f616f68617a696d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c48c8cf649baa1400a8933d3f2164648399cc48cb8bb8c915abb94a2164c40ad6b48cee005f1cb6e": "0x040300000002000000000000000000000000000000000967696f74746f6466000000127665726966794067696f74746f2e78797a00000967696f74746f6466000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c4b4dd7580fa785794b57fffa14cca7b965e2179f8ae5a94a84ba15aabfd0ef3f67f8ebf74e9654d": "0x00000000000000000000000000000000001345726963207e44697374726163746976657e154572696320416c6578616e64657220486f6c7374000015657269632e686f6c737440706f7374656f2e646500000c40686f6c7374626c6f636b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c4dce5c7e5fc1055a4d9ffc123ea0bfd66aad52c6bc6f6740b23bcb36548761c5bbdbf156cd7577e": "0x040300000002000000000000000000000000000000000a4942432047726f7570114942432056656e7475726573204c5444000010626f624069626367726f75702e696f00000d404d6172696f4e617766616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c4f3bb9a6a26a4b7249aca910e224a87c14afb90980ef0db0a6b12c9d6b48c1acae111a1dda36617": "0x040000000002000000000000000000000000000000001050415241434841494e532e494e464f0000174070617261636861696e733a6d61747269782e6f72670000000c4070617261636861696e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c516af68b4b46adaa5c4954040dafae7716b80bc7d5069fcbad863fe020a518d2afa27086f205285": "0x0000000000000000000000000000000000064e696d6974114e696d6974206b756d617220676172670000156e696d6974363139393340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c562a9eed81aa2dadae2b867564f01654946a095e69f0f49df1eb5c0efce5730cc3d1d83da3f4b09": "0x040000000002000000000000000000000000000000001af09f8c9020646563656e747261444f542e636f6d20f09f8c90001868747470733a2f2f646563656e747261646f742e636f6d001661646d696e40646563656e747261646f742e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c587ad64f66fbec7eec4cf006491dfbbfcb46eb5c8adc1a7535d554061f7f01c87a1e80f55598f67": "0x040300000002000000000000000000000000000000001344656e69732053756b686f7665726b686f760000001d64656e69732e73756b686f7665726b686f7640676d61696c2e636f6d0000000007636b636e696b00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c58b75eb4a8be7450236cc1bd6896c2a467da5f74331cc91ad6175f58d67c4fc3f50b2f8aa070490": "0x00000000000000000000000000000000000c526567656e63792d3031391757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c5b2faae0caa0f972c6f57e9289919d242aa985c1963f2b4040ddc57df3682d890657d130c035576": "0x0800000000020100000002000000000000000000000000000000000b43686f727573204f6e650e43686f727573204f6e652041471468747470733a2f2f63686f7275732e6f6e652f001168656c6c6f4063686f7275732e6f6e6500000b4043686f7275734f6e65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c5dad8e8b3b4327c8cc1b91e8946862c2c79915a4bc004926510fcf71c422fde977c0b0e9d9be40e": "0x00000000000000000000000000000000000976696b696976616c0956696b692056616c1068747470733a2f2f76696b2e696e6b144076696b6976616c3a6d61747269782e6f72671576696b696976616c406b6f6461646f742e78797a00000a4076696b696976616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c60c7e71ad50cedcc07b6eec14cd9119097bbf9bad28692a99e1c351e529c04793836183ce20bc45": "0x040300000002000000000000000000000000000000000a50617472696b2045420000001a74686973697370617472696b2e656240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c6b97ff91a535e9758b2c6f6766aab985078011ec8e759a965ab99168f7399f201b375400b9b0175": "0x040300000002000000000000000000000000000000000b576973656164766963650d73756d6974204b61706f6f7200001373756d697433356940676d61696c2e636f6d000011407769736561647669636573756d6974000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c6c19190ae451b5ae25e8c141e674ba58ca7fd0043366f6903488f3c585ff1180c9993eb896a3373": "0x040100000002000000000000000000000000000000000f44656c6567614e6574776f726b730f44656c6567614e6574776f726b731368747470733a2f2f64656c6567612e696f2f1440636f736d6175743a6d61747269782e6f72671664656c6567614070726f746f6e6d61696c2e636f6d0000104044656c6567614e6574776f726b73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c6da84d4d27caae500a8facc16c587e6b038173c4c85bcc36e7f506265012172163c29c9c0d8252d": "0x040300000002000000000000000000000000000000000a757365726d616e653111456476617264204e616674616c69657600001b6d69636861656c6e616674616c69657640676d61696c2e636f6d00001063727970746f5f757365726d616e65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c6ebdb2259f1d7d39ed0c9d18434f72d143cd55ae6d8add183e570d99674e334780029618f59c733": "0x04010000000200000000000000000000000000000000047a636f000000157a636f38394070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c704657f880bd0c07a34c5f475b5018f0d759283ff6a559713e8fe4fe672df009f3c812853b2ea35": "0x040300000002000000000000000000000000000000000f4d61726b6574204d6f62737465720d417368204461766964736f6e000016617368406d61726b65746d6f62737465722e636f6d0000104d61726b65744d6f6273746572554b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c7289bc44ade334e8db5c746c14cf05e182b10576a9ee765265366c3b7fd53c41d43640c97f4a8b8": "0x040100000002000000000000000000000000000000001144617277696e6961204e6574776f726b1144617277696e6961204e6574776f726b1a68747470733a2f2f64617277696e69612e6e6574776f726b2f001768656c6c6f4064617277696e69612e6e6574776f726b0000114044617277696e69614e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c74631fdb69272c020db24b51cc17362ffbaff228d977efd5fcc799ee877b1c6b8f144810555d25d": "0x040300000002000000000000000000000000000000000e436f696e74656c6567726170680000001c61647665727469736540636f696e74656c6567726170682e636f6d00000f40436f696e74656c656772617068000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c78dbbfac53841cd2c0d08e42e58247b57421f3239e0e192b21edaed4bca2458028c981634bdb607": "0x040000000002000000000000000000000000000000000f5354414b452048554c4bf09f91bd00001a407374616b6568756c6b69736d653a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c7a191740d407ab0362e53ccb59d8ef4125dcea1beb4a046797486adb9a7fe7c7496c8e8fe775d50": "0x000000000000000000000000000000000009444c494e4f444553174469737472696275746564204c656467657220496e632168747470733a2f2f64697374726962757465646c6564676572696e632e636f6d001f61646d696e4064697374726962757465646c6564676572696e632e636f6d00000c40646c6564676572696e63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c7b59ed3c46118b33a5e67c5be0b1a151232d17929a6479d7d7187544a40c059664c6315e94c977c": "0x04030000000200000000000000000000000000000000064d696d6972001568747470733a2f2f6d696d69722e676c6f62616c001368656c6c6f406d696d69722e676c6f62616c00000e404d696d69725f676c6f62616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c7bda7f8eb7fbbb7b45897c0b5d286cf13edcac05f1089d8d5427964bd7deefb3e025857880b0d7f": "0x0000000000000000000000000000000000074b6c65766572001268747470733a2f2f6b6c657665722e696f0013666565646261636b406b6c657665722e696f00000b406b6c657665725f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c894982e15d43f07fe8bc73363ddd77dbd0717156237bd0bf9b94036ba003fb6c938495a9002df68": "0x040300000002000000000000000000000000000000000c456e636f646520436c75621e456e636f646520436c756220456475636174696f6e204c696d69746564000014616e74686f6e7940656e636f64652e636c756200000b656e636f6465636c7562000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c89d000515601ae39c82e3f47021dbab243cffebb35e9b44bf2dd301f06778861ce3ab634f607001": "0x00000000000000000000000000000000000a53757065726d614e5a14466572677573204d617274696e20506f77657200001e646f6f646c65722e616972637265772e30664069636c6f75642e636f6d00001140706f776572735f746861696c616e64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c8c057868e022eb34c1bdac31e30cd50156586f5009d576c2efdc103be5ef0649d55d3b53941760e": "0x040100000002000000000000000000000000000000000d4b495241205374616b696e670e4b69726120436f7265204a53431568747470733a2f2f6b697261636f72652e636f6d15406b697261636f72653a6d61747269782e6f726716706172746e657273406b697261636f72652e636f6d00000b406b6972615f636f7265000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c8c34606dfbf7e1d0776a6d2dc585e66545d1538c8d8db9a221e7b67591790941d049992973e360d": "0x040300000002000000000000000000000000000000001250617472697a6961207c20414e414d495800001440646270617474793a6d61747269782e6f72671b70617472697a69612e646562656c6c6140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c90131946f8bd67ffa9d746a03245f55825fbe051be34eb34422bfa23f0b1d9317cdef087182ea5d": "0x040000000002000000000000000000000000000000001b494e46524153545255435455524520434f52504f524154494f4e000014407961796f692d763a6d61747269782e6f726720737570706f727440696e6672617374727563747572652d636f72702e636f6d00000c40494e4652415f434f5250000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c9662fb2af085bcff6225c6c2ffe4074df65d2adc2dcdbc576e33ee43c4089b0c034966426ff4377": "0x040000000002000000000000000000000000000000000d4e69636b205368756c68696e001968747470733a2f2f6e69636b7368756c68696e2e636f6d2f18406e69636b7368756c68696e3a6d61747269782e6f72670000000d406e69636b7368756c68696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c96a6c22d4b03e5980d0f3b4ac7e29a54b4b4c6638d0a865aba5da8d2881ceac549c5e278e62a90d": "0x040300000002000000000000000000000000000000000931676e3072346e64134761626f7220546a6f6e6720412048756e67000019672e762e746a6f6e676168756e6740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c970e8c26c18107fc6a04790e90ef5ac434c22f9b7eaf891738931a7b7ad14d1949303ec79433850": "0x00000000000000000000000000000000000f4752422054726164657220444f5400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c974eec21c6558fc0a6497cc5b43976b51f865da2ed13f750640abd317a44fc0be1d06ba41036732": "0x0403000000020000000000000000000000000000000009636f6465307866660c4a756e67796f6e6720556d00001a69616e2e6a756e67796f6e672e756d40676d61696c2e636f6d000009636f646530786666000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c99fde22c2a91b8042361acf91eb62232ddd85db70e0408d9812869a015e7dfc8cb91f685ff8e64c": "0x040300000002000000000000000000000000000000000f706c617970726f6a6563742e696f0d4e696e61204272657a6e696b0000166e696e616272657a6e696b40676d61696c2e636f6d00000f706c617970726f6a6563745f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c9a3d35454d01d9a63206239ed004343cce85027f05c7fea001f12b65f257f11f53a414a1c1ee9a0": "0x04000000000200000000000000000000000000000000114368616f7344414f204f70656e476f760000000000000a404368616f7344414f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c9a62f8a51ee740a70e4021e1c2df9e68b5d0c0cb0a69668e45601c3dedb732ba64e020f34c96231": "0x00000000000000000000000000000000000753442d444f5400000012646173697a696e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c9ceb72bb306b765f621771ddf37d482210b8c59617952eb1c2b40cfec55df47215231365186a057": "0x040000000002000000000000000000000000000000000f527573742053796e64696361746513527573742053796e646963617465204c4c431668747470733a2f2f7275737473796e64692e6361740013696e666f407275737473796e64692e636174000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c9d264aa4e49a5a7a2e546a96f0a016b5103ca34bfec8fd77988fde0c1f427b2ed97b9af2934a27b": "0x0403000000020000000000000000000000000000000008526963686c796e08526963686c796e00001c636172756c6173616e72696368796e363240676d61696c2e636f6d0000087263766572677a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c9d4715fc01dd3c55e91aeb058d11c897e1f6f510cfcb62b781b19bbcad30eacb81f4976d95e9cff": "0x00000000000000000000000000000000000f45422043555241544f525320505000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ca08516f7be365cf1a21174f3333c2bb416072b2c31d8f1e60f8e4ad3cf9546ab47e5b6fd060d303": "0x04010000000200000000000000000000000000000000054b757a6f0c4b68616c696441686d656400114067757a6f3a6d61747269782e6f7267144261642e39342e697140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ca3402e483e6170efee3129dacd1d1b4820ea6f516d7bfaccc4b64b16730ac6282daf1dc476e0001": "0x04030000000200000000000000000000000000000000054d61726b0c4d61726b204361636869610000186d61726b2e652e63616368696140676d61696c2e636f6d00000e406d61726b5f6361636869615f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ca43fffc2927f1f788d340852d044285b8229e36012b665ca5b75412d5e2e83d66994b784b1f3f73": "0x00000000000000000000000000000000000b44616e20436f6d6963730944616e2047616b680017406765656b5f626c6f636b3a6d61747269782e6f726713646f6d313235646640676d61696c2e636f6d00001040506f6c6b61646f74436f6d696373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ca550b4f7a101e7f344941abe7c5bd2da1688a7abf18b5244d0f524c5e085f5abb2257ca0c038f04": "0x040000000002000000000000000000000000000000000a683478407068616c610948616e672059696e1d68747470733a2f2f6769746875622e636f6d2f68347833726f746162164068347833726f7461623a6d61747269782e6f72671668616e6779696e407068616c612e6e6574776f726b00000a4062676d7368616e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714caa0b0ec39cf59af4e1550920067048086a9f30f799a1749508e222ad1a9d999f586e6f3e782c932": "0x040000000002000000000000000000000000000000000b706f6c6b61776f726c6400001740706f6c6b61776f726c643a6d61747269782e6f7267177869616f6a696540706f6c6b61776f726c642e6f726700001040706f6c6b61776f726c645f6f7267000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714caae41ec132a0861a69de95059adda24b9b38dbe06908378c09ef0d917c7188992ed339e0e530076": "0x00000000000000000000000000000000000647756363690f4d617572697a696f204775636369000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cac1a4bc9a87003e757945316854910d449179fda9aedb37ab23a3dc9f8330ad77fcec3f4b18cc03": "0x040000000002000000000000000000000000000000001d4f524d4c20536563757269747920426f756e74792043757261746f720000001468656c6c6f406163616c612e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714caf961ad1b6e226da072610f1e1ffade38a6d64df55a89e6b07f65ed2be0eb6efffdade4ca576c12": "0x040300000002000000000000000000000000000000000b4b6972696c6c5f6e6577000014406272797a67616c3a6d61747269782e6f72671b6b6972696c6c2e6272797a67616c6f7640676d61696c2e636f6d000011404b6972696c6c4272797a67616c6f76000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb1015e06f27ef398638bcb5e5ae5e04954d7fa2d29ccedf7f323482573198732af0b3fe32f8da03": "0x040300000002000000000000000000000000000000000973656164616e646100001140646f6e616c3a7061726974792e696f14646f6e616c6d4073656164616e64612e64657600000940646f6d756972690973656164616e64610000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb2e515a03279de32c2aabc0d8257e2dc928553a73d8bb18412665692e53505852328d0aa1126714": "0x00000000000000000000000000000000000e5068616c61204e6574776f726b0e5068616c61204e6574776f726b1668747470733a2f2f7068616c612e6e6574776f726b0016737570706f7274407068616c612e6e6574776f726b00000e405068616c614e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb4a358712ffad148aee4e164d5d70ac67308f303c7e063e9156903e42c1087bbc530447487fa47f": "0x040000000002000000000000000000000000000000000b6c6f6c6d637368697a7a0000000000000c406c6f6c6d637368697a7a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb55ee48ce2e7cebb40d3324de0087ed64fa4e91ebd1ea92ad87e12c0903904285d5db76cff97f54": "0x000000000000000000000000000000000009586161535f444f5400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb61c8ed9c1a667e3c672a7ed8c3771e42829418dd6781ed468ea3612fbf0512e847fed2a8995535": "0x00000000000000000000000000000000000a494243204d656469610d456e626c6f63204d6564696100000e617669406962632e6d65646961000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cbb6063367ee9c92e81006772a8947817db9e6676f0d67eae9cff6354f2d6ac9392132de4b2a1034": "0x040100000002000000000000000000000000000000000e4956594e4554574f524b2e494f001668747470733a2f2f6976796e6574776f726b2e696f0013696e666f406976796e6574776f726b2e696f00000e404976794e6574776f726b494f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cbd0c872a0daf479a4848ac04c2ad298cfcbf27ade0ddebb2cc3b37b090dd933a1e988b7a3ead075": "0x040000000002000000000000000000000000000000000d436170742d4861726c6f636b0e4c756361204d6172726f63636f1d68747470733a2f2f7777772e636170742d6861726c6f636b2e636f6d1940636170742d6861726c6f636b3a6d61747269782e6f72671a706f6c6b61646f7440636170742d6861726c6f636b2e636f6d00001040546865436170744861726c6f636b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cc2507f5d267891bbcb50c2942b0d5c8095f4f5ed87d2dba92bbb5c46b78dcdde51fe9fd58c5113c": "0x0403000000020000000000000000000000000000000008526567696f6e5800000015737570706f727440726567696f6e782e7465636800000c526567696f6e584c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cc59dc16328b27565822491aa322469edf3e2fe31839f3daebb226c62fbff8c1d5c0a79d18853e2d": "0x00000000000000000000000000000000000644796c616e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cc6a7f8747bd5de8a3a5b1cbef050a59893598ed0817fcc42c7f4faee9d0bdef4a9325a2ad4d3b8c": "0x0400000000020000000000000000000000000000000019444f542047616d657320426f756e74792043757261746f7200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cc6bdb23395a5660e623a613a8a3fd529aaf39b6041c5dc86cae0a8fed13606d621366d876c37773": "0x040000000002000000000000000000000000000000000f4d696775656c204d617271756573001c68747470733a2f2f7777772e6b696e6572612e6e6574776f726b2f001c6d696775656c40696e76697369626c6568616e646c61622e6f7267000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cc9df1794dc10741c11b9f12fa2747bff85d085211256f60824c4cc1d59459afec8119184fcbba15": "0x00000000000000000000000000000000001b53595354454d20434f4c4c41544f5220505552452050524f585900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ccb59fb10ff3b3c02e05b827a4ba848e1e43ae944fce00c7d0d4c96a38a01eb02cf867bfde7e6b5d": "0x0400000000020000000000000000000000000000000005434354460000124068657866663a6d61747269782e6f726716636f6e746163744063727970746f6374662e6f726700000b4043727970746f437466000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd131804ccfea9ef22efc513587234d063cb685c5b68172893193192942a565b241626b207f27637": "0x000000000000000000000000000000000008476f6e7a616c6f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd50be1c014b9821d220801e6e3f65c962363dd64baefae8b383799b3247b29892b15288c476e336": "0x040100000002000000000000000000000000000000000c574f4f4b5926574f4e4b590000001e6a6f686e736f6e2e66696e616e6369616c393940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd5bc0fba06a116f64cc5984790978efca45099329e5dec0365922e84982e8a277ca4c58756ddb48": "0x00000000000000000000000000000000000b4c616b65727320444f5400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd624b47e3069b393e8faae4c5713c72aea65d52aa1616d3e918dee3819fbbe08cd4c76dbd754a50": "0x040000000002000000000000000000000000000000001450726f5374616b6572732e636f6d20f09f928e001768747470733a2f2f70726f7374616b6572732e636f6d1b4070726f7374616b6572732e636f6d3a6d61747269782e6f726718706f6c6b61646f744070726f7374616b6572732e636f6d00000f4050726f5374616b657273436f6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd936bdf7e1b9fa87ef3b54d0328f6a7928f8536c2dccb07e8796aca7f3d7e126659105d764d4d98": "0x00000000000000000000000000000000000c526567656e63792d3030351757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ce2ddd4fd1d67791dcba36567d6fbd47af19d77054475a0f4c56dbccab4c13dacd22410f8275da08": "0x040300000002000000000000000000000000000000000d4272756e6f2047616c76616f0d4272756e6f2047616c76616f0019406272756e6f7067616c76616f3a6d61747269782e6f7267176272756e6f7067616c76616f40676d61696c2e636f6d00000e406272756e6f7067616c76616f000d6272756e6f7067616c76616f00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ce2ff9c38ccd13f3964e98590170e1cd1b9a476ed5147431261ac43ac0a9931ac9a9593027619612": "0x0000000000000000000000000000000000086a616d6d61727300000013636363697272757340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ce8bead92c07b351cc83588b4681c7aa4e83598809e195fbce7b0bca4321fe09db96dd814de1fd36": "0x04030000000200000000000000000000000000000000084261766f766e61135061756c2053746576656e20436f74746f6e000017616c70656e6c6967687437304070726f746f6e2e6d6500000b40426564666f72643336000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ce9a50917cf77bb19681fe005baa3099a7d9c03a46e539b173d2b3de75b11e86cd5fbb7d4e92993c": "0x0403000000020000000000000000000000000000000009506564726f37373706506564726f1968747470733a2f2f7777772e726d74657272612e6f72672f00196c69676874736f6e656d7573696340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cedae9c81b8ef8ff42be75cb933073a967d8cb8c6c723028208a678c5a58f5e8f49a237eb33e1654": "0x040000000002000000000000000000000000000000000d4a61792043687261776e6e610d4a61792043687261776e6e610000196865796a617963687261776e6e6140676d61696c2e636f6d00000a40476c646e43616c66000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cee83f43ea0dd41a22b7a9ef681c4a3c1743e5c343ff5b6f8aec3dc43bb0d49e29243d79ed406365": "0x04030000000200000000000000000000000000000000054b494c4e054b696c6e1068747470733a2f2f6b696c6e2e66690010636f6e74616374406b696c6e2e666900000e404b696c6e5f66696e616e6365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cf1074d3968196ede68f570f13d4581940602ee3ea8ebb7c3fca3ee8e21ddf90084b3df3a3ae7336": "0x040000000002000000000000000000000000000000000653696f33340000124073696f33343a6d61747269782e6f72670f696e666f4073696f33342e6f72670000084053696f333437000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cf421cf5662793c2d407fda03feb041adbdd1bed331b9c92168c8d21f31ae1639d0332433d5e2b07": "0x00000000000000000000000000000000000847726162626572001d68747470733a2f2f6170702e677261626265722e6e6574776f726b2f00146e696b40677261626265722e6e6574776f726b00001140677261626265726f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cf4ef5c9ad9aa87e3ac8adb41dbcf04f2d67294fa621940d040400987e05cff6326b1318939db159": "0x040100000002000000000000000000000000000000000d466f72626f6c6520f09f8ea00d466f72626f6c6520f09f8ea01468747470733a2f2f666f72626f6c652e636f6d16406b77756e7965756e673a6d61747269782e6f726711696e666f40666f72626f6c652e636f6d00000940666f72626f6c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cf81097fae6d315cba35e9bf428de9355a0e6fd6ef56ab5e0dabad5f5a8eac3af6f5202e84ac6b47": "0x04010000000200000000000000000000000000000000104e4f54415241535042455252595049000015406b736368657965723a6d61747269782e6f72671f6e6f746172617370626572727970694070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cf8a21b0cdae6e2d1e6e3b7ca66e70b75a1841f3ee48553b310484d34321335e55479232449d6f50": "0x040000000002000000000000000000000000000000001064656967656e76656b746f722e696f0000194064656967656e76656b746f723a6d61747269782e6f726715696e666f4064656967656e76656b746f722e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cfa782accd3d75bebe776c10ad0e1fe7f606cfe42448e02cdb640c21214ea6c0c99df36ec0ee3d0d": "0x040100000002000000000000000000000000000000000f436f6d707574652043727970746f001a68747470733a2f2f636f6d7075746563727970746f2e636f6d0018636f6d7075746563727970746f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cfac989e84b5ad935ee1e16ea093ea043d7f67a6f34f440c5fb921b56b54e81c177898d348685b51": "0x04000000000200000000000000000000000000000000095354414b452e5355000016406d722e6f776e6167653a6d61747269782e6f72671d7374616b652e736f766965742e756e696f6e40676d61696c2e636f6d00000a407374616b655f7375000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cfc0cc32c14f6b1b1c2a5f648afea2a94286c17f6c60d16c9ef8511fa4ae88a54ce2748b6c8fa90f": "0x080000000002010000000200000000000000000000000000000000054166726900000f406166723a7463686e63732e6465126166726940636861696e736166652e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cfe3b56da886c4b6e23cf83af2b043696cefcbe2ffe680eba45ccf26d6d9a354d742bafd45aaf2e7": "0x00000000000000000000000000000000000c50414c2043757261746f72001f68747470733a2f2f706f6c6b61646f746173737572616e63652e636f6d2f000000001140506f6c6b61646f7441737375726564000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d094e3cac725c344ac1b1e12bfb60e8225efa102d2f6f74ccfa53d583571363505fb54feeacf8c2e": "0x00000000000000000000000000000000000d504f4c4b41444f54204d4143114d617274696e204d63446f6e6f7567680000196d61636d63646f6e6f75676840686f746d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d09eaf34f53d7c401480bc228ee751c1aca34061c4952efb304aa94beed8e38fd9c5e693f62c3f26": "0x04030000000200000000000000000000000000000000066365736172066365736172000016636573617267653133303240676d61696c2e636f6d00000a43657361725f476573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d0d3d5efedb29953decf71909282816105360e12c52694c8e39f30f82532be18b3e32e3e435dbf08": "0x0000000000000000000000000000000000064b43435f3300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d1067d55a33c02831232508adcaf57c6e78a850f9d715e3694b52000ce537832eb55c7a59f859e13": "0x040000000002000000000000000000000000000000000a524f544b4f2e4e4554001268747470733a2f2f726f746b6f2e6e657418406869746368686f6f6b65723a6d61747269782e6f72670d687140726f746b6f2e6e657400000f40726f746b6f6e6574776f726b73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d113bb3ee11e240450c816dc61aa6fa2afb1d48ab14435942be7296f10b310653c80325af700c166": "0x04000000000200000000000000000000000000000000134b6972696c6c5f5448452047656e6572616c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d16f6c8ce2379b06a375190836f6df983719441a0f32b28a7448ed785bcfdb67c5f6061b9654335f": "0x000000000000000000000000000000000010416c69616e7a612048697370616e6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d183e95ab708f0d6785f4c6690a6c2bde954d46c627698f5730072791cb5485116c678d89974230c": "0x040000000002000000000000000000000000000000000c417263656d204d617269730000000f6e696368406b61786f6e2e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d1eaa7d142bf1e42a200be596abc1fb84833a9440274227b2f9709e573abf14d0c6b2fc58ed3a50f": "0x040000000002000000000000000000000000000000000d47726567205a61697473657600001540677a6169747365763a6d61747269782e6f726712677a40756e697175652e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d1ee388cb4a93ade8c16e2cb1309a3ab9b697e3c80a5cad5dfded90b04e2d8943f2e0835af140a77": "0x040300000002000000000000000000000000000000000856616c65726969125379646f726368756b2056616c6572696900001473766d31393835756140676d61696c2e636f6d000011405369646f726368756b76616c657232000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d1f6cf7981174df67aa5506d9391c78c760cf7490a5f7412a1fea6cb4969119a11f49429818b1d97": "0x00000000000000000000000000000000000631345745421757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d25b2b83caf5ac06d857fcac7bd9bb03551d70b9743895a98b74b06e54bdc34f1b27ab240356857d": "0x04000000000200000000000000000000000000000000065465736c610000001b7465736c612e76616c69646174696f6e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d27b00c2f56f7b336c31b105bf4566e9837d11fc54b523f7b3ec8993f8c880b1e0c283d7bcd0aa53": "0x0401000000020000000000000000000000000000000011e2999e47616d655468656f7279e2999c0000184067616d652e7468656f72793a6d61747269782e6f7267136d61696c4067616d657468656f72792e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d2f4c0196c97de9d14eb0f8e9dd9e3ad05eb774e3158b4c432bdbd5f64f0fb78a25b4d1863c0f468": "0x040100000002000000000000000000000000000000000f4c6f7569736520572e2052656564144c6f75697365205761727769636b20526565641668747470733a2f2f7374617961666c6f61742e696f00156c6f75697365407374617961666c6f61742e696f0000114041666c6f6174546178437265646974000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d2f5f529ff74e1246425fc08d539497b1f466d8528211fd89b2e222eda9d39f7bd1967bf9e6f5f16": "0x000000000000000000000000000000000006486572736800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d343694d94be95e2744405c2356641a0d373433e220c5b03d3ffd2bc3e528574e19068b4c2490614": "0x040300000002000000000000000000000000000000000847c3bc726b616e1347c3bc726b616e2053656e656d6fc49f6c7500001a6775726b616e73656e656d6f676c7540676d61696c2e636f6d000009307863666c6f6b69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d3a269b657e1dfd090a4c78f16c247b4b438a25734d0479b32c196cacb25ecc95a79480dfc6cee7c": "0x04000000000200000000000000000000000000000000077368616d6230000013407368616d62303a6d61747269782e6f726713722e7261616a657940676d61696c2e636f6d00000940307368616d6230000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d40d5206d8ab23bb285de1abe8f2e26bceb56db8969b332803ecfba0d4baf49e1e9c31c80748747a": "0x00000000000000000000000000000000000f55542046696e74656368204c61620f55542046696e74656368204c6162001940757466696e746563686c61623a6d61747269782e6f726712636573617265407574657861732e656475000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d435a9777e7ecc393c5862ed65c524b7bb3564776a81904218f44f3d7c35162a608e39dbadbcda05": "0x0000000000000000000000000000000000084e61742d446f74134e6f7220536166696e617a20417a726169650000166e73612e70796e7574323840676d61696c2e636f6d00000a40316d5f39794e3437000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d43703150f1fcc536a21a0e28cbaa3132b3abfdc4240eaf50bd237467690de245441612261e37571": "0x040000000002000000000000000000000000000000000d456c6f646965207c2057334600001840656c6f6469653a776562332e666f756e646174696f6e17656c6f64696540776562332e666f756e646174696f6e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d44074de089225b9404fb63cfb2153551f4497165a2262d420453628d4c0f790c9b11ca4748bb139": "0x040300000002000000000000000000000000000000001ff09f928e20537061726b6c696e6720426c6f636b636861696e20f09f92bc1a537061726b6c696e6720426c6f636b636861696e20f09f928e00001a7a766167656c736b79657667656e7940676d61696c2e636f6d00000b40457667656e79795f41000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d476d3200736c2bcc42bd98a8029cf3787ee280a8980b4a8d5f152ebc2705cb48b4c7ee6daad0268": "0x000000000000000000000000000000000014506f6c6b61446f742043726f77644c6f616e7300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d4859e78fba22c21ac2091f6d5251183c62941cde5cd3e10ffcb6d418d42e03ebc6f1945a817f76e": "0x040300000002000000000000000000000000000000000a4d6574686f642e67670f53636f7474204d634d696c6c616e1768747470733a2f2f7777772e6d6574686f642e67672f0013706f6c6b61646f74406d6574686f642e6767000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d4a79ae0ef45ec63a455ccc77072570b273044973e0ab6f56d3325421584a479eed68f84603e034f": "0x08010000000203000000020000000000000000000000000000000007417373657458001368747470733a2f2f61737365742d782e696f00107465616d4061737365742d782e696f00000b40444f54417373657458001334313630333438343133393436373537313200", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d4ed4dd340a2cebbbc486ed2f394da6e6b58b130687b48d3d19f756ba6d0655d37bf58ff0f59f974": "0x04000000000200000000000000000000000000000000124164616d5f436c61795f53746565626572124164616d20436c6179205374656562657200154061737465656265723a6d61747269782e6f7267176164616d2e7374656562657240676d61696c2e636f6d00000e406164616d7374656562657231000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d4f4dfc6da461b20aa72c321b20bbd5b78b14f6fd800017bca47190956eb42ada2a4d8f8a8ca994d": "0x040000000002000000000000000000000000000000000df09f97bb4261736563616d7000001840776f6c667374726f6d32373a6d61747269782e6f72671b6261736563616d702e7374616b696e6740676d61696c2e636f6d000011404261736563616d705374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d509c5c59195b1ec5c3739d60301126756a7510e34f9d656d4435cd4fe64bbd001f1f3473bc9c333": "0x04000000000200000000000000000000000000000000055a656b65000017407a656b653a6d61747269782e7061726974792e696f0f7a656b65407061726974792e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d5150021507a071f86420f7843bff8fcee7d1bafae828d0d0c3668bfca8150820be3e774e8aa8c2c": "0x040000000002000000000000000000000000000000000b5472616e736973746f721c5472616e736973746f7220506f6c6b61646f74204e412c204c4c4300001179407472616e736973746f722e777466000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d53a56fa8630064970eb89fbedb6567f5061f23f2da6c73feb710676d618a205a28d643451c48a72": "0x040300000002000000000000000000000000000000000a616476657269636b790f61647665726c6976652073726c73000014696e666f2b646f744061647665722e6c69766500000d61647665726c69766573726c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d5ab2f60e5f823fd07cd066334cc9ed0e17a3a845a9efb144c25c9741d63102d88380c7f20ecd7b9": "0x040000000002000000000000000000000000000000000d44617070466f726365204d530000001464617070666f72636540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d5e66d23eb784c1150fa056fe8636d5041e3a460e63839603087bf789ce60514f00bb2473b728e4b": "0x000000000000000000000000000000000014506f6c6b61646f74202d2050432047616d65721e53c3a97267696f204f74c3a176696f20466f6e736563612053696c76612168747470733a2f2f7777772e796f75747562652e636f6d2f6368616e6e656c2f001973657267696f2e6f746176696f4069636c6f75642e636f6d00000f4061706f6c6c6f74686562756c6c000d63726970746f6d6f6564617300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d5fdc8ab7d97949ee424b2ee4c8a8fb3334248367a7a7e5c2d236205368cd4aee4e8ae274fc45566": "0x040300000002000000000000000000000000000000000c4b616d70655369676e6572144368726973746f7068204b616d70697473636800001a6368726973746f70684073637974616c652e6469676974616c00000844614b616d7065000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d6392158cf43d6cab4358371ed445b0650e6b0a3c749c3a8674db5eeccc75103beb78b0a903bf32b": "0x00000000000000000000000000000000000a4d6574616b6f76616e135669676e6573682053756e6461726573616e1668747470733a2f2f6d6574616b6f76616e2e636f6d000000000b406d6574616b6f76616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d64d4d86c0b29268f2931a66c7207e83365c6425ff0756499e2130ad00b384731c7290c8536c53ed": "0x04030000000200000000000000000000000000000000084445444341505308444544434150531368747470733a2f2f6465642e67616d65732f0013444544434150535840676d61696c2e636f6d0000094044454443415053000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d6ad5303bac6267692286c3c817a7beb00fd0398384e170dcdb5dfcccae635adc3d8426119594a0a": "0x000000000000000000000000000000000008546f706f6c6b6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d6bff5ea3e68b58898185ec550ab27fe12285719dc1bfc83a8dd7d3e77a32c0fb4e12be09b79ad48": "0x040100000005000000000000000000000000000000000e41454d20416c676f726974686d0e41454d20416c676f726974686d1c68747470733a2f2f7777772e61656d616c676f726974686d2e696f0018737570706f72744061656d616c676f726974686d2e696f00000f4041454d5f416c676f726974686d000d6a616b7562736177637a756b00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d70ae159e1aa09aa28863c0c3e58d40a623b4cabef57d2ba807fdb703c4fb481d5fce365858e7224": "0x000000000000000000000000000000000006566974697300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d74bea4c3bf5621814d0ddb81faf43b169f397727a277d7cace318bdfce287d90314e72e4dce490c": "0x00000000000000000000000000000000000c4a61636b7974617572757300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d789194338d34070928263bfc144cfad6e7e62923f27cd0e8df2af4bee9eeb4784dbf7a48b0a296c": "0x00000000000000000000000000000000000a6d61645f616e676c650d53616368696e205465647761000019746564776173616368696e31323340676d61696c2e636f6d000000000a6d61645f616e676c6500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d78e3922994e68f87b1c17d66cb08fdf1d84ccca7767bb71ec36658ff95c522951b103c8cd8623ea": "0x000000000000000000000000000000000009596f6b6575736f6e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d7906ae903234547463a9cd3e7cec50ccc93515557ab58221d20c67a409583428ad67caff9415107": "0x0401000000020000000000000000000000000000000011436f68696261436f6e74726f6c6c65720e4d616179616e204b65736865741468747470733a2f2f6d616179616e6b2e636f6d14406d616179616e6b3a6d61747269782e6f7267136d616179616e406d616179616e6b2e636f6d00000e406d616179616e6b6573686574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d7a036c9790a85a62c0b2cfdc7507c42c88c22c0eadedd30251b090cc8de670c436ecd91186b5136": "0x000000000000000000000000000000000003421900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d7a5e201687ab46302982c3a62acf008c3ac7793286c0f7b93efeac8de80e9ec9733bfd477148707": "0x0403000000020000000000000000000000000000000007616277726c6400000018616268696d616e797540646f75726f6c6162732e78797a000008616277726c645f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d7b596e66afccd2bd89ea70e822e338b7519379e4a4685595da674fd167b7bd12dbfd10c9bc2b50e": "0x040100000002000000000000000000000000000000000d44617265646576696c337837000000134372797970746f7040676d61696c2e636f6d00000e4044617265646576696c337837000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d7efccf788fb1a6528d50241999da5b300f01f3004a67a25a11854608f1f437ab86ed2e115243a43": "0x040300000002000000000000000000000000000000000a4b7261746973743073000000186b72617469737430736e66747340676d61696c2e636f6d00000a6b7261746973743073000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d8462e30b1801504cc3d040787c25df74513d303f228e590e9e0156cc54790d6720d607420e80165": "0x04030000000200000000000000000000000000000000094c6176656e6465720000001c6c6176656e64657265737468657232303240676d61696c2e636f6d000011406c6176656e64657265737468657231000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d84deb4759f2e2e9f6a7fa830da55dde09b411ff877ed0ee8fd1ceb2009067ab5bc0ffdc54af4065": "0x0400000000020000000000000000000000000000000011416e6b616e2028706f6c6b61646f742900001140616e6b616e3a7061726974792e696f10616e6b616e407061726974792e696f00000006616e6b346e0000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d85c06897a6dfc1b8cee324d4a0f2bce600a681a3ba2f4cf507c83012008f01557f2c5e413b76066": "0x040000000002000000000000000000000000000000000e4441524b5f504f4c4b41444f54000019406461726b6c657373323030313a6d61747269782e6f7267196461726b6c65737363726970746f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d883005234a96e92bc64065524532ed9e805fb0d39a5c0199216b52871168e5e4d0ab612f8797d61": "0x040100000002000000000000000000000000000000000741524b5041521141726b61646979205061726f6e79616e00134061726b616469793a7061726974792e696f1261726b61646979407061726974792e696f0000000761726b7061720000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d8e0253a5ce94a9a125858e5bcf61ff597c01f811fe12e66f34e0b2ff135e48a03c51c3234afe97f": "0x04030000000200000000000000000000000000000000084d656e696c696b0f4d656e696c696b204573686574750014406d656e696c696b3a6d61747269782e6f726713737079786d656e6940676d61696c2e636f6d00000f404d656e696c696b457368657475000a406d656e696c696b3300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d8e02c95f42c870728c57701aff086e2d4d00536a35ebb0dea7732d5bd285c63fac7197b6bf3e37e": "0x00000000000000000000000000000000000a4c7567616e6f646573001668747470733a2f2f6c7567616e6f6465732e636f6d0013696e666f406c7567616e6f6465732e636f6d00000b406c7567616e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d90301728ff0374ae4d7ebfe2f9bce87c9b49975fe7de84393c376b29ee297be934ac540d8a6381b": "0x040000000002000000000000000000000000000000000a434f494e53494445520000000000000f406a6f696e636f696e7369646572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d9275dddf1009186a0c8063be933d442a3453e47d22a9d53344c604f71cb0f70c1f67c0129cf6137": "0x040300000002000000000000000000000000000000000a63727970746f6d616b0c446965676f204d6172696e000015646965676f6d616b40686f746d61696c2e636f6d00000e40446965676f6d616b5f6d6564000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d9402b8cd99c1552705e3020123277ead705580b26edbab0e534d5941db23a8216a430962ada9519": "0x00000000000000000000000000000000000a53616e74697468616d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d9cef13374a70e655010efb7049583595fbe3da57dc5db048e590c28f107e5e4fa2bdcc4b1293f6f": "0x040000000002000000000000000000000000000000000b43727970746f6c6f677900000014746563684063727970746f6c6f67792e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d9e0312b39961bc6726a98c27f84bf42fc842794a925418335fc9fe3badb1f535dce9c9d9efcc02d": "0x040000000002000000000000000000000000000000000b5473756b6920f09f8c9500000019636f6e74616374407473756b697374616b696e672e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d9ebec847667f8a9dc028a7c1bfd7e24a64a11564b7384e571e27e33bddbae91f978ac1a6ead7310": "0x00000000000000000000000000000000000a5368756d6f20436875000000107368756d6f2e63687540706d2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714da23f4f6f4d9e6bc96140a201be6f41e63c5b3bf6b02f67da3f232c6715397302494f894f964ac78": "0x040300000002000000000000000000000000000000000d56696e6365436f72736963611856696e63656e74204469204769616d626174746973746100001076696e6365407061726974792e696f0000114056696e63656e7444694769616d6231000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714da40d28d53abbfcf16f9415c34da11ca5a35f3f18627af4ef312d90777ed086ea20e364b11656921": "0x040300000002000000000000000000000000000000000667656e67650d476f6e7a616c6f204574736500001667656e67656b7573616d6140676d61696c2e636f6d00000d4067656e67656b7573616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714da588541e0520af8802a229c888897bfe30ff149788e0dce8e078f2f4ebc0533dc44ca4c9960100b": "0x000000000000000000000000000000000018506f6c6b61646f74404574685461697065695f3230323400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714da6dfa4d6fcbad64768ac003ffdf15238a61c42e781d16331ca3cb2805e06f602469206d6a795734": "0x00000000000000000000000000000000001c62616c73656c6c732f506572646f6d6f2d70617261636861696e731e6672616e636973636f206a6f73652062616c73656c6c73206c6f70657a0000146662616c73656c6c73407961686f6f2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714daa67a441fadf00ca2b09b0a84ba632e3745eacd5cc7dde15c73b61255bd6376177a907b4e830079": "0x00000000000000000000000000000000000c4b6f746f2053747564696f0c4b6f746f2053747564696f1468747470733a2f2f6b6f746f2e73747564696f0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714daa6f458469f7726be386bfcdd57a31913902c8092cbb4e721e9bdcd6babebe0831a4ff52c260431": "0x0400000000020000000000000000000000000000000004737077000018407370656c6c7765617665723a6d61747269782e6f7267147370656c6c77656176657240676d782e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714daadc5f0b3a48319d4f44a50f35f9340aad2b3666011f78afa719f5e80a0c4f3969525729c35e654": "0x0000000000000000000000000000000000174a61636b20506f6c6b61646f74202f204b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714daf5619ede74e518e90ce79e0167f82e66250b1cfab388aa86a2e2b1e893907b19932e6751a08e04": "0x040300000002000000000000000000000000000000000c416c6c696e43727970746f001968747470733a2f2f616c6c696e63727970746f2e636f6d2f0015696e666f40616c6c696e63727970746f2e636f6d000011405265616c416c6c696e43727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714db02485938505b5136bae49de1ebc06355938e2cfe64ae4b27d6741c070bf817042eaeeae226d741": "0x04030000000200000000000000000000000000000000065742526f620e526f6265727420486f6c6d6573000014686f6c6d6573726a406c6976652e636f2e756b00000d40486f6c6d6573726a526f62000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714db20fbbd4ec3b172c1df5c7e8ca56037450c58734326ebe34aec8f7d1928322a12164856365fea73": "0x00000000000000000000000000000000000d44617669642053616c616d690000000000000f64617669645f6f665f6561727468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714db39fbf092d6577f4d5cfb0370c406b3cd3d9db1517bca918bdc96629af87092cfb09989a2d0388a": "0x00000000000000000000000000000000000f63727970746f76656e64696d6961001c68747470733a2f2f63727970746f76656e64696d69612e636f6d2f00000000104063727970746f76656e64696d6961000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714db4e290a8c8e6d7d4c8dfef612efd6af3b857c60a4350f446e795aaef08c419649d7f8f65955eb15": "0x04030000000200000000000000000000000000000000144a756d696e73746f636b20506f6c6b61646f74124361726c6f7320526f6472c3ad6775657a0000156a756d696e73746f636b40676d61696c2e636f6d00000b6a756d696e73746f636b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714db51125ce2e8c4560c2017a4f115c013d899b494c955a7ec4cc9786a3997f1823baacc213896a35a": "0x000000000000000000000000000000000015506172616c6c656c2046696e616e6365202d2031001568747470733a2f2f706172616c6c656c2e66692f000000001f68747470733a2f2f747769747465722e636f6d2f506172616c6c656c4669000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dbc32343b195f2c99256c8dc61df081bf36a5ee0f1bb8c987003aa1ed4fa3dcc93c05dfec013f27b": "0x00000000000000000000000000000000000b416c657068205a65726f001a68747470733a2f2f7777772e616c6570687a65726f2e6f7267001468656c6c6f40616c6570687a65726f2e6f7267000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dbc647e39c873964a0f2dda8e1a5b5f1820545ba2f4d33f1d99e259c9a3e8071329f84c07f40f514": "0x04030000000200000000000000000000000000000000064a616e6b6f114a65616e6d6172636f2052616e6768690000166a65616e6d6172636f696e40676d61696c2e636f6d00000752616e676869000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dbf7430d0eb6bd0486c273a2e537718a8bb986e964a0eb5e5e525ab6ee44e191d7ba645cac2efe05": "0x000000000000000000000000000000000017506f6c6b61646f74206961627369732067696c6c65730747696c6c65731568747470733a2f2f61697264726f702e636f6d2f001567696c6c65732e684061697264726f702e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dbfc69131dbd305c4c2ded7ca2dd19095123de090a46149c2047d0aa4c6ce195490563d881f7491b": "0x04000000000200000000000000000000000000000000085369726a657931000014405369726a6579313a6d61747269782e6f72671b6e69636b6f6c61736a6f73687561303040676d61696c2e636f6d00000b4044725f5369726a6579000d5369726a657931233237313300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dc22c730a7ef5a54488b87e574eee2f9b8e7810eb3567edffc303c4f9c76946da200ce429b444d59": "0x040000000002000000000000000000000000000000000a4d617843726970746f000000166d617863726970746f6f6b40676d61696c2e636f6d00000c404d61785f43726970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dc33802d5bdfa7529ef6dd302c66ad6ee5ee679f6fd7c3ff4b19489daad6680691aa209b719f2139": "0x040000000002000000000000000000000000000000000a6c756e617220646f74000000196c756e61722e706f6c6b61646f7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dc5da19e1472ceec06dd5a888daa57d1bcb763f269e5cf4bfe73b44d106b34ce572dcee124057a6b": "0x040000000002000000000000000000000000000000000a414c454a414e44524f001c68747470733a2f2f6769746875622e636f6d2f616c336d6172742f1440616c336d6172743a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dc60ff49e9f778bbd24bfa7e01cb86e6eab810a04a61d7bc3c32c094afd5b4739194c9583a69d238": "0x000000000000000000000000000000000015506172616c6c656c2046696e616e6365202d2032001568747470733a2f2f706172616c6c656c2e66692f000000001f68747470733a2f2f747769747465722e636f6d2f506172616c6c656c4669000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dc6d83874526905136aff2ede1563784631d6149024982108f661b079b6b79f3d042041a9da11e2a": "0x040100000002000000000000000000000000000000000748616e77656e0d48616e77656e204368656e671d68747470733a2f2f7777772e68616e77656e6368656e672e636f6d2f164068656177656e3131303a6d61747269782e6f72671468616e77656e406c6974656e7472792e636f6d00000a40635f68616e77656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dc79486ab3b689692440bee5d463a2cd234b5d8fb3b6eeb3f91b5fe9e26267846abaf7cbb154524b": "0x040000000002000000000000000000000000000000000b416e64726564796c616e14416e647265204443204472204c616e7a6f6e692168747470733a2f2f7777772e6c696e6b6564696e2e636f6d2f696e2f6164636c11406164636c3a6d61747269782e6f726717616e6472652e64632e6c616e7a6f6e6940706d2e6d6500001040616e64726564636c616e7a6f6e69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dc7d270f233cb625a6ac5af2b37a6bb6d5c9cbb7fa56748fb1c9cf9ad1ef43334efa76a431aa3d22": "0x04010000000200000000000000000000000000000000175375706572636f6d707574696e672053797374656d731a5375706572636f6d707574696e672053797374656d732041471368747470733a2f2f7777772e7363732e6368000c696e666f407363732e6368000008405343535f4147000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dc87dbc53489aff444fd1d056884026869c3a2ca0d5f75455995962bbd5f5676b9aefed98d176c22": "0x0403000000020000000000000000000000000000000005526963680b526963682043617365790000177269636869656a636173657940676d61696c2e636f6d0000097269746368637379000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dc98458dbb1371bf08d31593110e775453dea202d90d97424b66f31b337467ecd5f3bf86329d3b97": "0x040300000002000000000000000000000000000000000a43617270656469656d000012406a6469656d3a6d61747269782e6f7267146a7361766f406d61696c66656e63652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dcb7b0516f93e814720d807d46b941703ffe0278e8b173dc6738c5af8af812ceffc90c69390bbf1f": "0x04000000000200000000000000000000000000000000076f726469616e00000018706f6c6b61407265757361626c652e736f667477617265000000076f726469616e0000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dcded909158c7cfe7cca49e0d4903aeefcfb804fb07b71195a216074f9194f611991ede515e8ba46": "0x0403000000020000000000000000000000000000000006417661746111417661746120486f6c64696e6720425600000e696e666f4061766174612e676700000961766174615f6767000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dd3ab7da34fe2f80d646eb13c8251f905355c49d20ff0fff32f649474a97d040d8b5165e9ec74926": "0x00000000000000000000000000000000000e4a6f6e6174616e20537461736800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dd5ac43b991d5bfdf68fd95ffc9cc02f15e28ce9df041da32f3b564e249fb4a8caa1c5135b1fad4d": "0x0400000000020000000000000000000000000000000005496767790000001869676e6173692e616c6265726f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ddd17007ceeb939fb4d78a8bb35a7b0ff8ae6a7808f9b17c83efd28b8612c2388034d0e35ce51376": "0x040100000002000000000000000000000000000000000c5374616b696e675465616d0c5374616b696e675465616d1968747470733a2f2f7374616b696e677465616d2e636f6d2f18407374616b696e677465616d3a6d61747269782e6f726715696e666f407374616b696e677465616d2e636f6d00000d405374616b696e675465616d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ddee1d127f978b69654acc3f002ced5c8d1fbce6268485fe0a2be3d624d32b6e53132daf8f28a380": "0x0400000000020000000000000000000000000000000018564953494f4e5354414b4520f09f9181e2808df09f97a800001840766973696f6e7374616b653a6d61747269782e6f726715696e666f40766973696f6e7374616b652e636f6d00000d40766973696f6e7374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714de11e082d85cbef160f94710848d9dce161724f257a240494c901728bdf2fa51c138fc5580ee3134": "0x00000000000000000000000000000000000e4a6f6162204e697761676162610e4a6f6162204e6977616761626100001b6e697761676162616a6f61623130303040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714de218ead5d0a168c9228177e3d9e1bfbd17975b3185cc99dc6b235a2bfd42609ab31f3f3059d6e6b": "0x040100000002000000000000000000000000000000000d6469676974616c6d696e747310542e20412e204d696e7a656e6d61791968747470733a2f2f6469676974616c6d696e74732e636f6d0019636f6e74616374406469676974616c6d696e74732e636f6d000011406469676974616c6d696e7473636f6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714de4e384e5c5bcda65ac4bbe840e332da2656c0e760904003fa7a2123a216a33e81b8531400600304": "0x04010000000200000000000000000000000000000000095869616f476f6e67095869616f476f6e6700144072696368656e673a6d61747269782e6f7267113435353433393034344071712e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714de5652b31dd1f614c6aff670231f257996dcabb052286394791d85d4be9d8635cc14df0c11e67864": "0x04030000000200000000000000000000000000000000144a6f686e206f662074686520707269657374730f4a6f686e204d756c6c6f776e657900001b6a6f686e6f667468657072696573747340676d61696c2e636f6d00000f404a30686e4d756c6c30776e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714de570a3f6eb03219824c1f132f117e3bfad5f23d7d68cfbd3022c11214b4154ad0ab329351365547": "0x040300000002000000000000000000000000000000000a56616c656e74696e610000000d73636861696e40706d2e6d6500000d40307876616c656e74696e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714de8c0cc61d322ab8b0a6788e02cfb0b5c9629a2153e9f26b9f1122ea8a03abf85cf8e3aacc76ec2b": "0x04030000000200000000000000000000000000000000076c696b6b65650e4c696b204b65652043686f6e670000196c696b6b65652e63686f6e6740686f746d61696c2e636f6d00000c6d61706c65726963686965000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714deb3e9bfbd8d3c590cf6b6cdababf69c2af37a41a2f360820bb7dff2f61c20bb61a9503a8901ee20": "0x040000000002000000000000000000000000000000000f4861736865642053797374656d73001268747470733a2f2f6861736865642e696f124074656b69743a6d61747269782e6f72671068656c6c6f406861736865642e696f00000f4048617368656453797374656d73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dedb59bd6fbcfbabc75c3b5f909a0c53c58fe9ab06b9cd336e82918b3275d402c2dd8501455f1769": "0x00000000000000000000000000000000001b5765625a65726f204576656e7420426f756e74792050726f787900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714deefe5d90b67b654b66953df31de525fd4c075b30b266f8fca1f29533c9dd7d45128408726d19979": "0x040000000002000000000000000000000000000000000f73656e7365696e6f64652e636f6d001c68747470733a2f2f7777772e73656e7365696e6f64652e636f6d2f0014696e666f4073656e7365696e6f64652e636f6d00000c4053656e7365694e6f6465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714df04aa6913361fbfc6c5094505321fb73284b9882d87d66bd6ba692faf1a4f5254d977dad8934801": "0x000000000000000000000000000000000011496e7465726c6179204e6574776f726b0014687474703a2f2f696e7465726c61792e696f2f000000000c40496e7465726c61794851000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714df081b6eb6159ca822e0586d9ca1db9e8e60a7eaea3fdbbe6fd5238477c91d04e1532b1ed251d251": "0x04030000000200000000000000000000000000000000085042415f54494d0a54696d20446f62696500001574696d40706f6c6b61646f742e61636164656d7900000a4074696d6164616d64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714df3b8158c3a22b52c8660fc9479c8b741d2065985d0b77d00a36a50900438d83ba70ab138f528326": "0x00000000000000000000000000000000001054616c69736d616e20506f6f6c2032001568747470733a2f2f74616c69736d616e2e78797a000000000f40776561726574616c69736d616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714df56e27f047aded67252b4b1f8103acd6ff363c971c7dea21afc0285ad5ad75176dd53947a6aca4b": "0x000000000000000000000000000000000012636172746569726120706f6c6b61646f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714df658b757ba3a7aa702baf94343fc34fc6b80b225c14758484c91816726a7b3951bc0ce1daae9f53": "0x000000000000000000000000000000000005696e6b21001068747470733a2f2f7573652e696e6b000000000a40696e6b5f6c616e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dfdd2a5f61982fba4297a93d2faba768a0be3c2a69bee7a17d73264b9adebae51e28e7b37463f91d": "0x04000000000200000000000000000000000000000000064e3444524f00000000000007404e3444524f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dfe38f3528e245c5c66d295453335e1fac0d88b96160f5643d0bc4ae9eeeb8402f26c866187b9960": "0x040000000002000000000000000000000000000000000d426c6f636b2042726964676500000016626c6f636b6272696467654070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e01ab7ee15ada6e3eeef86dcd6803a23da2d5a8834ce66fe3e9f705bc756dc0e835741d68f200762": "0x04000000000200000000000000000000000000000000056c6163680000000c69616d406c6163682e7077000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e02c902560555f54d44824ac8d1edecca67639ca74d208bd2044a10e67c9677e288080191e3fec13": "0x0000000000000000000000000000000000076f6c616e6f640d44616e69656c204f6c616e6f0018406f6c616e6f643a766972746f2e636f6d6d756e6974791264616e69656c40766972746f2e7465616d000000076f6c616e6f640000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e050fe4b1877288206c7ea7684b6aac6cd63cf88c92b0f05398bc3e13e0b0c5936c3027b8e0c7e2f": "0x04000000000200000000000000000000000000000000105b5279752d4361706974616c5d2031000017407279756361706974616c3a6d61747269782e6f726713727975407279756361706974616c2e636f6d00000c405279754361706974616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e08890d6de27a2900e117eb473a2617377b8ddcab2e411131969c226ba36618ea24514b6f736b77c": "0x0000000000000000000000000000000000094d6f6f6e4e6f6465094d6f6f6e4e6f6465000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e09d6b3fcb94c12410446dd351747cd3a9557e288b706aa824c74440006e9730a806a2b5d16f2e51": "0x040000000002000000000000000000000000000000000e4b494c542050726f746f636f6c0000000d6b696c74406b696c742e696f00000e404b696c7470726f746f636f6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e09e422aff2862656cb9c61a3d59451f446f191f7e41facb800ab8c789255af69fe0d6ca397e1238": "0x040100000002000000000000000000000000000000000b6b616974656e63757261000000156b616974656e637572614070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e15938b3e3caed8b5c0ad5714ebe5c2ff7ba60c09f693cfe2582ba7dd65e1feb74b1c99cccb75079": "0x00000000000000000000000000000000000f4c415945522043414b45202d2031001968747470733a2f2f6c6179657263616b656361702e636f6d000000000e406c6179657263616b65636170000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e16c7dc70b9d971f180f3232cf72cfbc3f350733ec10eb9ba8a135e3831d813259c3c7e3d46fca2c": "0x00000000000000000000000000000000000b43727970746869726f6e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e177989adf0462e92c02b3a008b94bf4a9e846002dba45ed38eb41ef3c8edc223403723b3301a331": "0x04030000000200000000000000000000000000000000065a65657665065a6565766500000e72617669407a656576652e696f00000830785a65657665000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e18d41e2249b70ec4eb32a5fbbccb1d97d31237172fbfd92945caa6822d5f8afb558aa7b89bc5a11": "0x040000000002000000000000000000000000000000000753616b7572610000174073616b757261746563683a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e1b94c49ca35815a7e9b1d7500a5e651f1faf14965e6993c10eddb1bdbcc1ca2e4d0812320c42216": "0x0000000000000000000000000000000000104d656e6e6120416275656c6e616761164d656e6e6174616c6c61682041626f656c6e61676100001b6d656e6e61742e616275656c6e61676140676d61696c2e636f6d00000000106d656e6e6174616275656c6e61676100", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e207ae5a1f676e495a39c793248e0a8cac2ec88172c7d1a3b2f10c6c2455e20c5dbb739cf3e9ea0a": "0x040000000002000000000000000000000000000000000959414f20476d6268000000176c756b6162616c6173686f7640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e21241c1f77eea219c34bbbde6bff80d45a0e9f3500e7aebd52d558fcd919b2e0d788dd8728a047a": "0x0403000000020000000000000000000000000000000018416e61656c6c65204c5444207c2045636f73797374656d00001740616e61656c6c656c74643a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e25361ec814d346808ebc46e11c7f7ba99411e693af6481ceb7cc935cfc5b2344a9831f915f6555e": "0x040100000002000000000000000000000000000000000d444953432d534f46542d31310e4469736320536f6674204c74641a68747470733a2f2f7777772e646973632d736f66742e636f6d154064697363736f66743a6d61747269782e6f72671876616c696461746f7240646973632d736f66742e636f6d00000e4044697363536f667457656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e26d187c65071fe036da1284412c9f435d93ae01474705ea7f0ac3154103a0d08f3efabdbb389345": "0x000000000000000000000000000000000009436f696e62617365002168747470733a2f2f7777772e636f696e626173652e636f6d2f7374616b696e67000000000d40436f696e62617365446576000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e2bc3b02d70c5dd5bab650983063ab81171b9efc65665326b507438d99994d489f07ef16bcc93d6b": "0x040000000002000000000000000000000000000000000f535452415742455252592d444f5400001740737765657462657272793a6d61747269782e6f72671d73776565747374726177626572727933303240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e2de10fd49d4b23394472b8251f87622be5a6c44f9eb3fcd59038eda7f08163511cbe8aeeb584136": "0x00000000000000000000000000000000000b4d494b452d537461736800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e2f69a0dbf9d98314642514ce6e9e7fb66ef4334728307f47be8b2509e6fa870a7685f3e560e3a08": "0x0400000000020000000000000000000000000000000007706569726f6e00001340706569726f6e3a6d61747269782e6f7267177461696368756e673939363140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e31041f839b1c98afe111b571b0ba64cb8365c7e9bba1e412d6fd57634a54bd1996314689e061a68": "0x00000000000000000000000000000000000843727970746f72002168747470733a2f2f7777772e796f75747562652e636f6d2f4043727970746f72000000000c4043727970746f725f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e31192e1956f8f3aa6996ba5fce10b5419b5a9fd55998b5d7fde4922e61f93b021cb2cf6dfd5707e": "0x0400000000030000000000000000000000000000000006426a6f726e0e426ac3b6726e205761676e6572001840626a6f726e3a6d61747269782e7061726974792e696f10626a6f726e407061726974792e696f00000b40626a6f726e77676e72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e333905c7589ca5182526dcb428e7f915dc46c895f155ff1b31a93371b4f7c59aa89569beacd2b03": "0x00000000000000000000000000000000000c506f6c6b6177616c6c657400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e33504e56333a26eec8073c78e4291eadb0184b89afe2f9389c762e6e869329275dde3f729507251": "0x040300000002000000000000000000000000000000000748656e7279500f48656e72792050616c6163696f7300001968656e72796470616c6163696f7340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e35aea91533fa89ffc7995246b1a9c38001bcf09a7338b892dc8ce10cc201c4567ac4c56f4658846": "0x00000000000000000000000000000000000c43727970746f20415049731243727970746f20415049732c20496e632e1668747470733a2f2f63727970746f617069732e696f000000000c4063727970746f61706973000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e35b67b937cc75caa81dfbac142664eb6f7ff61c5c0b2c8a180059b27ccb68ccc6b9c152be120b70": "0x040000000002000000000000000000000000000000000c6669616c6b612e6c697665001468747470733a2f2f6669616c6b612e6c6976650012706f6c6b61406669616c6b612e6c69766500000c406669616c6b61706f6f6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e38e649e5f9f7676b4d599b32c954b0a9e554c96b248f3e66046a82f46ac914fc675938f771f8372": "0x040000000002000000000000000000000000000000000942696762616c6c7a0000154062696762616c6c7a3a6d61747269782e6f726716696e666f4062696762616c6c7a2e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e393f842833927bb48a751e3ab512dda0be14000c63798a628ee5c8bad55e947c356dbf38b0b0210": "0x040300000002000000000000000000000000000000000745737468657215457374686572204a61646520506172746c616e6400001369616d406573746865726a6164652e636f6d00000d404573746865724a61646531000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e3d6c0bdba37bbdc244c335b828809b83644239e5c6df4b01630483c410c6f380cd58aee02f6b830": "0x0401000000020000000000000000000000000000000015576562332056656e74757265204361706974616c15576562332056656e74757265204361706974616c1068747470733a2f2f776562332e76631440776562332e76633a6d61747269782e6f72670b686940776562332e766300000d4056656e7475726557656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e40a8cb9cddb8c20106261d48665f2a3f6f015d725285ae547e9b3e83bfd332a39b1ef8cf1a22a3d": "0x000000000000000000000000000000000007416d666f72630a416d666f72632041471368747470733a2f2f616d666f72632e636f6d0013636f6e7461637440616d666f72632e636f6d00000a40616d666f72636167000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e46168425cb085b326ef1ebd6770b8291ce61d9f3cfee80c6a459b7e564988cd9fe6e4be89c9aabd": "0x040300000002000000000000000000000000000000000f506f6c6b61506f72742045617374001a68747470733a2f2f706f6c6b61706f7274656173742e78797a001a636f6e7461637440706f6c6b61706f7274656173742e78797a000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e4643365f6f183049456976091da2f5b7483d689df155834018d42a99572e4582beda8f879f0a11b": "0x000000000000000000000000000000000008746861646f756b17417468616e6173696f7320446f756b6f7564616b697300001761646f756b6f7564616b697340676d61696c2e636f6d00000b40746861646f756b383408746861646f756b0000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e4b32bdcfe8a21ed50b428a44aee6d7d7971bc278208f295b647bd1cd44985423c3cf405adc2e336": "0x00000000000000000000000000000000000b6d616c696b656c626179001c68747470733a2f2f7777772e6d616c696b656c6261792e636f6d2f0013686579406d616c696b656c6261792e636f6d00000c406d616c696b656c626179000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e4c774b7f47a03509d8c2041692eed6612bae5f84f15d6e5e3943d3ee38dabd26dd2ded79780e6b2": "0x00000000000000000000000000000000000c526567656e63792d3031341757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e4ccf4e65ffa766b5af0f6de364a186904df50d92e02723052cc2187692243e6dbeba9f7fa30e33d": "0x0000000000000000000000000000000000085044204e79747400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e4e4cd2e3863bdd6e4395b60d99030b923a52cd9ef3468a2a7ee4a21cb88a1fc276f763a67656618": "0x040000000002000000000000000000000000000000000f44617669642053656d616b756c6100001a40646176696473656d616b756c613a6d61747269782e6f72671868656c6c6f40646176696473656d616b756c612e636f6d00000f40646176696473656d616b756c61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e5018c1728c62231664513c046d4497ba05c19efac47cb0dbe498e20b089dff25aa08d1a77ec970b": "0x040100000002000000000000000000000000000000000a5374616b65666c6f77002068747470733a2f2f76616c696461746f722e7374616b65666c6f772e696f2f124069373439353a6d61747269782e6f7267127465616d407374616b65666c6f772e696f00000e4073665f76616c696461746f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e557553c94ed289f20e7fc24fdb992bc25566724e1533d7e861fe1a902394cf823a49f1a9c6d6520": "0x00000000000000000000000000000000001a4d616e7461204e6574776f726b206f6e20506f6c6b61646f740e4d616e7461204e6574776f726b1668747470733a2f2f6d616e74612e6e6574776f726b0016636f6e74616374406d616e74612e6e6574776f726b00000e406d616e74616e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e55dfe32a8ec457fb669bdbd25438dcf9a34ab730a518fa6594d888439187042e9607803e9fd756e": "0x04000000000200000000000000000000000000000000085269636172646f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e57b6fff5aa31fc5dc73e84c4d039277ae7819cf959a0092683ea8e6e7e9d2447c918d8aa89d681e": "0x0400000000020000000000000000000000000000000009456c2050696e746f00000015656c70696e746f6d616e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e5a27d3189e99969dad042c036fcd9897945a880458b8e7104b30617a9640eaa22b7e23e675e0a02": "0x0400000000020000000000000000000000000000000014504f5745525354414b4520504f4c4b41444f5400001740706f7765727374616b653a6d61747269782e6f726719706f77657240706f7765727374616b652e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e5ec7a33cbbb8d9e04f3da939fa351c562c7e06e1e3716976b5e14230e83a45995cbad9086f49e17": "0x040000000002000000000000000000000000000000000a506f6c6b61676174650a506f6c6b616761746515687474703a2f2f706f6c6b61676174652e78797a1640706f6c6b61676174653a6d61747269782e6f726716706f6c6b6167617465406f75746c6f6f6b2e636f6d00000b40506f6c6b6147617465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e5efd10bd264dbe62c0adc4df234352b61fd60a32c2890fc64c2c0a3de5e33ee1c5bc9d8f581642d": "0x0400000000020000000000000000000000000000000017f09fa7b12053656974616e20426c6f636b20f09fa7b10000184073656974616e626c6f636b3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e601d44489655af884301af9b7a04d8e8cbc7e13b463fd50bea892b3e7952d62c44cd70815e0567a": "0x040300000002000000000000000000000000000000001d4c414f5320436861696e20466f756e646174696f6e204d656d6265721d4c414f5320436861696e20466f756e646174696f6e204d656d626572000017696e666f406c616f73666f756e646174696f6e2e696f00000c6c616f736e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e60910119cc2ea203e87ac01090985a916808ebe0f45ed24ae099c59d163bc073fef792b1309ec0c": "0x00000000000000000000000000000000000f4f676e6a656e20416c656b7369630f4f676e6a656e20416c656b7369630000216f676e6a656e406365726573626c6f636b636861696e2e736f6c7574696f6e73000000000b6f676e6a656e3038303000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e61549e518cc68adc8a5bf93006b7fd50ffc2abaffd57ef06c67f2171b5097070892fa1a195d920f": "0x04030000000200000000000000000000000000000000184d43207c204d43536572766963652e696f207cf09f92a50c4d61726b204372696e63650000156d61726b6372696e636540676d61696c2e636f6d00000c404372696e63654d61726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e63ab25a74c3ba8458baf0f841ed4154e046e8567bff89dbb50dd8302c248394234a0ab191de0d30": "0x0400000000020000000000000000000000000000000007434543434f4e0000000e646f7440636563636f6e2e6d6500000b40636563636f6e5f6d65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e676ae0036688fbf1cfe7dfca152379d21d1fd8dd18698889590afa4abd3cd05cbf4f6d15cd5454f": "0x040000000002000000000000000000000000000000000c4576657279646f746f72670a45766572792e6f72671668747470733a2f2f7777772e65766572792e6f72670012737570706f72744065766572792e6f726700000d404576657279646f746f7267000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e6d19e9cf5f198f5205b1d0649f02b8d82c090a215995a883e0e4d709c4513e8e9890a110fb5420d": "0x040300000002000000000000000000000000000000000841757468656e61134665726e616e646f2052657920476169646f00001e6665726e616e646f2e7265792e676169646f4061757468656e612e696f00000a66726579676169646f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e768b256ec04939e689582a5e1411cd4bdc5086ec5604dd4dcbe4255339299de13d428335c46902f": "0x00000000000000000000000000000000000a6c61726b6e6574353100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e79ea902982619aa3283cc9f4408df3ccaef653fc163e56509619c1e0e46bb4e677d227fa50bef7f": "0x0403000000020000000000000000000000000000000006436973636f124672616e636973636f2041677569727265001140636973636f3a7061726974792e696f206672616e636973636f61677569727265706572657a40676d61696c2e636f6d00001040636973636f5f6167756972726570116672616e636973636f616775697272650000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e7b5d2aa3f9d8295b8e06dc2e6bb6bd269319ace4cf8f663338f8f285a0564d6a139063c985d2310": "0x040100000002000000000000000000000000000000000a48617368517561726b0a48617368517561726b1568747470733a2f2f68617368717561726b2e696f0015636f6e746163744068617368717561726b2e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e7b7e5fca7ee9bcc9607759a0532ec6ceda78a076d3a63eb7f7b7be9a87ace1f94b2f25df3d0702c": "0x040000000002000000000000000000000000000000000d4f70656e5a657070656c696e175a657070656c696e2047726f7570204c696d697465641e68747470733a2f2f7777772e6f70656e7a657070656c696e2e636f6d2f001966696e616e6365406f70656e7a657070656c696e2e636f6d00000e406f70656e7a657070656c696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e7cb8e1a29da70a064f4c7e6a5f3f25b4d063e5461bf3882569aad883b6db400695ccfd7c6e6ef22": "0x00000000000000000000000000000000000c5843417374726f6e6175740f44616b6f7461204261726e65747400001764616b6f746140696e76617263682e6e6574776f726b00000d405843417374726f6e617574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e7cfb082496967f7ec22eb74dea33d78388ca084d35bb754ab5256d4d606d83818f639d0c63dd541": "0x040300000002000000000000000000000000000000000d4e69786f6e204a6176696572000000196e6969786f6e6a6176696572797440676d61696c2e636f6d00000d6e6969786f6e6a6176696572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e7dfd30137a8f95b6201961514cf5ad87f1c4dd0c392ee28231f805f77975147bf2c33bd671b9822": "0x0000000000000000000000000000000000106b697368616e736167617468697961114b697368616e20536167617468697961001d406b697368616e6d7361676174686979613a6d61747269782e6f726700000000106b697368616e7361676174686979610000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e7fa098460d3db9eb088c46557805c70d888174482b02e258482e5e3f5ae7a20bbdc333c9c046d04": "0x00000000000000000000000000000000000b696e6b21756261746f72001868747470733a2f2f7573652e696e6b2f756261746f722f0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e819164bbb79142da4d26dd19482ab1dfae06825850bc2a3e3c82821977573c80eb9f19747b9215d": "0x00000000000000000000000000000000000c4f6b6f74206a6f736875610c4f6b6f74204a6f736875610000176f6b6f746a6f73687561393340676d61696c2e636f6d00000e404f4b4f544a4f534855413433000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e82757563afd35c4501f6db8fa8f98a21f0a62678bbd5f0f91be1c0a6c7215f2610a782d0d3a2458": "0x0000000000000000000000000000000000094a75616e6f444f5400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e85d0bcdbe07f1da309409e68f563d9e9160bc30f7418cbe5735e3e2dc9922db1826807029b8ba5e": "0x04000000000200000000000000000000000000000000104d61785f43727970746f7a696c6c6100001c406d61785f63727970746f7a696c6c613a6d61747269782e6f72671963727970746f7a696c6c616d617840676d61696c2e636f6d0000104043727970746f7a696c6c615f6d67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e86c54857827324682635b83e254e0ed6438dd7d9bc229658cf164cebf4322cf4932815d4d7ad323": "0x040000000002000000000000000000000000000000000f47656c69746f202d204f6e797a6500000010616e67656c406f6e797a652e636f6d0000084067656c69746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e87135bfa99a9afc6ad7c1595e740abcfe3a9b2cc4243d13341ebdf1ddebfe5184822cbc4fdb6116": "0x00000000000000000000000000000000000f53616e6a656577612053696c76611850205355524553482053414e4a454557412053494c564100001873616e6a656577612e73696c7661406c6976652e636f6d00000b407373616e6a65657761000f7373616e6a65657761233830383500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e876a25b4b1879f1746b2591bb9bf87e8b24cb5e4b265192187471475c775ed7708f7cab9f76617e": "0x040300000002000000000000000000000000000000000a4e334d55534e65616c0c4e65616c2050657465727300000f6e65616c406e336d75732e636f6d00000a406e65616c5f6e7065000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e883951f96e016e628c1641676e9e4f0c271a9b92fb49311bb7cfc00a0478dc92908fd30005a194b": "0x040100000002000000000000000000000000000000001b444f542056616c696461746f7220416c6c69616e63652044414f001b68747470733a2f2f646f7476616c696461746f72732e6f72672f1440706d656e73696b3a6d61747269782e6f72671b646f74616c6c69616e63654070726f746f6e6d61696c2e636f6d00001040444f5456616c416c6c69616e6365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e88d81bf95788cc15a9616ee0f6737de3d1a75ee0c6a2101f70671cc68da4ceda653a18cd751ea3d": "0x00000000000000000000000000000000000a4d6178446f744465760d4d6178204b7261766368756b0000156d636b7261766164657640676d61696c2e636f6d00000f404d61785f5f4b7261766368756b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e8b5663905f9c3c0f861ce44b57a59f1f6953a922920de251b138c3a751b3f9adf075dcd4d2c9851": "0x040100000002000000000000000000000000000000000b506f6c5f43727970746f0b506f6c5f43727970746f0000196d7073686964616c676f3139393040676d61696c2e636f6d00000c40706f6c5f63727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e8c5f28ea575985d2cbf07f54d172d80de65ac3f2707f660dd53f7ead6013a9d47921e881d258e64": "0x040000000002000000000000000000000000000000000f424c4f434b434841494e425241440000000000000d40427261645f4c6175726965000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e8cb1cf7b100db583c343c62a938e255060d46435233ab16bb11168adfa99c770fca459af08b0241": "0x040000000002000000000000000000000000000000001156616e636f757665722043616e6e6f6e1d416476616e636564204461746162617365204e6574776f726b696e6717687474703a2f2f7777772e4144622e4e65742f444f5411406a617a643a6d61747269782e6f72670c444f54404144622e4e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e8edd00301de472cb4e98052ea4e41501850a90d99cd46fe92a91bfe039fff0f4e5c0d5eb69f5813": "0x0000000000000000000000000000000000097968616d61636e75001c68747470733a2f2f6769746875622e636f6d2f7968616d61636e750000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e8f8b7184f9a04c0ca72d01b6c36c383e4ba984681b7b467dafefec8f44dab1ed507ae6ab2704c30": "0x040300000002000000000000000000000000000000000930785461796c6f720930785461796c6f7200001630787461796c6f72406368616f7364616f2e6f726700000a30787461796c6f725f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e91edd91ccfc5f024617b7364d403c2b44cc4ae58ec9f2b3b412d3b9cdf57ec06e3cb878a228a70a": "0x04000000000200000000000000000000000000000000054761626f000013406761626f31383a6d61747269782e6f72671178636761626f4070726f746f6e2e6d65000009405f78636761626f000c4761626f3138233932333800", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e935216ece9e99210a44ceb024e05ccf8c9153a48c24dda24a5eb82db438cdc55b1b234c613eac14": "0x00000000000000000000000000000000000c4765726d616e676c657a61194765726dc3a16e20476f6e7ac3a16c657a204172616e64611b68747470733a2f2f736f6d6f7363727970746f6d782e636f6d2f00176765726d616e676c657a617240676d61696c2e636f6d00000d406765726d616e676c657a61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e940a76f99d2ec9f40e8a79a9a76b954f2e08ffd985d6f6a3bd3fca001baee4e235cb67ed9cda635": "0x040300000002000000000000000000000000000000000b6a6f686e6e796b6177610d43616573617220446974616e0000156a6f686e6e796b617761407961686f6f2e636f6d00000c404a6f686e6e794b617761000b6361657361723030383800", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e9705190c69f75e984a135c14c92b678df586c20c8e3ca3511043f0dc8bfd88017d0bb97bfcff63a": "0x04030000000200000000000000000000000000000000054a617773144a61756d65204d6f72656e6f20526f766972610000136a61756d6540676f6c646a6177732e636f6d00000b40676f6c646a6177735f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e97f51eae0303cf7d07d209d7880ecdc39f636e4390f665c563274bfe9a981c6c31f2995c184b0c2": "0x040000000002000000000000000000000000000000000d4261677069706573204f7267001468747470733a2f2f62616770697065732e696f000000000d4042616770697065734f7267000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e999e16a19189c1f8c8897c6e9a74d582959e1d4273719c9edbd33d5c44815ebe162fe0ee8191863": "0x0000000000000000000000000000000000046d696f096761627269656c65000015672e6c756e676869373140676d61696c2e636f6d000011406761627269656c3037333531393039000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e9ea0dabafbeec8280251f075ec25c5b4fd4272d81fb78eeeeef9819356f102b5e7bde1154a73f2e": "0x00000000000000000000000000000000001d44757463682054756c69706661726d657220436f6c6c656374697665001b68747470733a2f2f6474662d636f6c6c6563746976652e636f6d001961646d696e406474662d636f6c6c6563746976652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e9fdc68bc008f11eaf24540bccc2a2661e0301d4e45b87ab8e961db49e4660ef217619bdcd5fc638": "0x00000000000000000000000000000000000e617263686973696e616c5f696f20417263686973696e616c20546563686e6f6c6f67696573204c696d69746564000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ea0e1b22a44d19352c2a55b5e0d28cc772b47bb9b25981cbb69eca73f7c3388fb6464e7d24be470e": "0x040000000002000000000000000000000000000000000c5a7567204361706974616c001768747470733a2f2f7a75676361706974616c2e636f6d0017636f6e74616374407a75676361706974616c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ea1425c366c9ab900a2831bc1a5cfdfd6aca13c77cf934fdf2a6010d041d4d76a62698cd58c87956": "0x040300000002000000000000000000000000000000001f446563656e7472616c697a656420436c6f756420466f756e646174696f6e1f446563656e7472616c697a656420436c6f756420466f756e646174696f6e1768747470733a2f2f63727573742e6e6574776f726b2f001168694063727573742e6e6574776f726b00000e4043727573744e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ea2794691c218be17657796360e40e5d980d7b7835108a8534538dc530bce1b77c49cde4b7f97b36": "0x040000000002000000000000000000000000000000000641726a616e0000134061726a616e7a3a6d61747269782e6f7267000000114061726a616e7a696a64657276656c64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ea2c0371426ff011ea857aabed70020c0433dfba617fdd3abe9dc3b22b427f884b13f4f4dcb6481b": "0x04030000000200000000000000000000000000000000074261746d616e001a68747470733a2f2f6c696e6b74722e65652f5f6261746d616e1c4030787468657265616c6261746d616e3a6d61747269782e6f72671a30787468657265616c6261746d616e40676d61696c2e636f6d0000114030787468657265616c6261746d616e1469616d6d617374657262727563657761796e650000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ea92920fa526337e0c06466c9aab1dac1ca8bddbf02a3f0913358bf068012a0478d62c7cd076c12c": "0x04000000000200000000000000000000000000000000104672657368437265646974204f7267194672657368437265646974204f7267616e697a6174696f6e1868747470733a2f2f66726573686372656469742e6f7267001f63657361722e74696e616a65726f4066726573686372656469742e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eabad1af85b4f2da751b2f1dc8d7e182eb3615a1894330dfd769ca25e945004b9c28a0309a875757": "0x04030000000200000000000000000000000000000000087375626f7469630d4976616e205375626f74696300000d69407375626f7469632e63680000087375626f746963087375626f7469630000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eabd7ed4ca42f780a8ebd4a61d47391a24659b5762d9ef578229c4fc2186f5f88174f8e728f27f78": "0x0403000000020000000000000000000000000000000013546961676f207c20616464726f70732e696f0e546961676f2054617661726573000015746961676f6d6d74323040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eac493d2c384d548f0f3c639e5a8ee634594037f1f6eaba8a3d06c791615f80fa892deb77c0bf346": "0x04030000000200000000000000000000000000000000094c656f205068616d0f5068616d20486f6e672054686169000016686f6e677468616970726f40676d61696c2e636f6d00000c406c656f7068616d5f6974000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eaf34109655642c20a6d7337f0454acdaf58ff349faf36febd6f9dadddbebd1198919523b91f6b11": "0x00000000000000000000000000000000000c4e6573636166657573657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eb00f7c148179177909f4d84481e5466f7af1143a7193f40bd8c0606d75eb089666c29ca0347606a": "0x040300000002000000000000000000000000000000000a4c75697320f09f8c80000000166c7569736567723331303140676d61696c2e636f6d00000d40456e72697175656b736d5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eb1d5fd73e1080ee944ade7aa7487574933c8394cc8c74d9073c65de1d77534b7effcc6cf34aefac": "0x0400000000020000000000000000000000000000000010496e66696e6974792057616c6c65740000001a706172746e657240696e66696e69747977616c6c65742e696f00001040496e66696e69747957616c6c6574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eb307eab2c6490695ee3b9f948b36e799b4190bd0a025c1cc5132f52b3701c0a0912296120176d30": "0x04010000000200000000000000000000000000000000066450726f70000000176176696461636f6e74726f6c40676d61696c2e636f6d00001040426c6f636b636861696e65723931000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eb374a353870a2b9bac27ccc2a336ec0f7920048d460197d4abde56e977771aec19b3c9c6d110c7a": "0x00000000000000000000000000000000000b53706f6f6e79426172640000001a612e6e746f6c676b6f764070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eba5f322b497160118a5657b88d667ab46d1070d58ecc1f15011f60df20f510ee0aac61754bb9e01": "0x00000000000000000000000000000000001142494e414e43455f5354414b455f31311142494e414e43455f5354414b455f3131000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ebdea675e3bab66142780fa79136b5a383ca1180c911553235f69e97edb9aa09b6f80acd437da754": "0x04030000000200000000000000000000000000000000064265747479000000176d616b65736974626574747940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ebee8c2dc7e37890e84b20a21cd1f35835bb85d8e27d3b6d02bf08300998555443ec4cd3206ec37a": "0x0000000000000000000000000000000000056a75737400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ebf17402f1a0c5314e936e1e0efeeb5090b1f8afdf530d798c7d54a747704755ea03b110144e5150": "0x040300000002000000000000000000000000000000000c6775746f6d617274696e6f0d4775746f204d617274696e6f0000197375706572647570616866756e6b40676d61696c2e636f6d00000c6775746f6d617274696e6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ec14530f7667a130dae5b67f7237a4ecc7daf168ee45d8b9f2fcfa07e7ae255daad9e09912595d4b": "0x040000000002000000000000000000000000000000001e494e20535042202d20f09f8dbef09fa582f09f8db7f09f8db9f09f8db8000015407370626472696e6b3a6d61747269782e6f7267185350424472696e6b4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ec3029bbd85364b1f4792917b47917519e2c05619763a4e7b45b84815f902f62e16f23e9f2b22653": "0x04000000000200000000000000000000000000000000104972696e61204b61726167796175720442513900000d6972696e61406271392e696f000010404972696e614b6172616779617572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ec49f5213562f6f6309c4389039f51c4d308dd49f39c28e4d4f5e51413f123d3f7ebf050c2307877": "0x000000000000000000000000000000000013426c6f636b636861696e656420496e64696113426c6f636b636861696e656420496e64696121687474703a2f2f7777772e626c6f636b636861696e6564696e6469612e636f6d1a406d616e617661696c61776164693a6d61747269782e6f72671c6d616e617640626c6f636b636861696e6564696e6469612e636f6d00001140626c6f636b636861696e6564696e64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ecc49e9888c4723b003be57bf884dd5eb5ea5274429e80980c136324444c5771a4a4c67a5124106b": "0x0000000000000000000000000000000000114172747572204775696d6172c3a36573194172747572204775696d6172c3a36573205065726569726100001761727475724065616363726970746f2e636f6d2e62720000114061727475726775696d617261657370000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ecd1bc9bdcddbb405437eaad7661fc64223db26c26db0c8aa317f5c56e3c640830495b4786d6e635": "0x040000000002000000000000000000000000000000001d4d61726b205279616e202d204576656e7473205369676e61746f72790a4d61726b205279616e0017406d61726b2e656d6265723a6d61747269782e6f726700000011406d61726b5f656d6265725f7279616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ed229b4f9a288d7518790dd7ca07916547aeab9f8155af2cb219bbdc7df93974d04c101bf9f18a1d": "0x0000000000000000000000000000000000066d312e7663066d312e76630e68747470733a2f2f6d312e76630000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ed6de9d282688326da649a9855dbd7872b852ef786c270f57cb1462262ebdb67ee0729a3eef90122": "0x00000000000000000000000000000000000c54454143484d4544454649001b68747470733a2f2f7777772e74656163686d65646566692e64650014696e666f4074656163686d65646566692e646500000d4054454143484d4544454649000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ed7f24e195293ab9d638bd6f76c3b3aa2810fa97ca64a8195d9460c08c8a509b78e9a6ec82c6e920": "0x0000000000000000000000000000000000115a4f454d432d434f4e54524f4c4c4552000012407a6f656d633a6d61747269782e6f72670000000a407a6f656d78666f780007407a6f656d6300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ed90d5a15a85da0268cfeae1986b9acaa08e6d3264672b32f62e784bc8447bb52e3c79c840b79877": "0x0403000000020000000000000000000000000000000008546865204847410000001b48696c6c47726f7774684167656e637940676d61696c2e636f6d00000c4048696c6c47726f777468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ed956e0a56bcce19c5d607c5643cace51ad268171f8b62bc30a1913178c92393f3a7b1ef3283e316": "0x040000000002000000000000000000000000000000001146494e4f50535f5042415f50524f58591c506f6c6b61646f7420426c6f636b636861696e2041636164656d792168747470733a2f2f706f6c6b61646f742e6e6574776f726b2f61636164656d79001961636164656d7940706f6c6b61646f742e6e6574776f726b0000114041636164656d79506f6c6b61646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ed9d129015daefd5b2d89b7dbf920e6cd64997f1b3ee49c4de09327342dbbba971a362062817a24e": "0x000000000000000000000000000000000008677564753136390c4c494a554e205a48414e470000177a68616e673438373733393240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714edcb62732d88d5a1983ac92a9005b595553a62a3522499a38af23ae77e0c71f3b617abf004147e5b": "0x00000000000000000000000000000000000f5041524954592054495020424f5400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee00d20c4599b66920e43fc4c70fa7fd379f66551283b0b39b7d81a8934bc38a0eff954c13211039": "0x040100000002000000000000000000000000000000000449424f0449424f0f68747470733a2f2f69626f2e696f000a68694069626f2e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee1637b31feeb6eb1250f6160df84e6e3a53754e1da799eaf11ab3fb77bf2958b8bcb14829a8a109": "0x04030000000200000000000000000000000000000000096a75737461646576001468747470733a2f2f6a757374616465762e696f00156a75737461646576303940676d61696c2e636f6d00000b406a7573745f61646576000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee1ca131ec7060eeac214900c36399dc45f36261c677a53ea58cce1e5d113deed23227ab523fc53f": "0x0000000000000000000000000000000000125761674d656469612054726561737572790000000000000e40746861744d65646961576167000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee2b9d3d30c267cd2a62706ffa8c0fa1406c5a61ff4759b0b0c450f8cca8e6cb337e5f9d8a7bc21f": "0x040000000002000000000000000000000000000000000853616d737439330f53616d75656c204a2053746f6e6500001773616d73746f6e653933393340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee3695245c82732db5bc42b793f36f2174681d45b224f6e5222d64508a0a28454ffc085bd3d33210": "0x0000000000000000000000000000000000104252455720436f6e666572656e6365104252455720436f6e666572656e63651c68747470733a2f2f7777772e627265776265726c696e2e78797a2f001568656c6c6f40627265776265726c696e2e78797a000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee528ad5e6be0beb7a5e9031237026ed1babffdd92e6ef7c73e3212cdcd62c7559644596c3398175": "0x00000000000000000000000000000000002153796454656b2044414f202620576f6d656e20696e20426c6f636b636861696e001268747470733a2f2f73796474656b2e6169001a6a757374696e2e676f6c6473746f6e4073796474656b2e6169000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee610577caaf8b311cb53a337df19dd608aa3e6bb703e8e2817ee1fbddc7536f097b90f3e1910f66": "0x00000000000000000000000000000000000a4e696768744861776b00000000000011404e696768746861776b506c7567696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee704d3e290801f7c2c7f984de75f10a8ab85a9945e79890b776970fd15e39de1cbaa0816aaab920": "0x00000000000000000000000000000000000c617265636f6e742e70726f14417265636f6e742053657276696365204c4c431568747470733a2f2f617265636f6e742e70726f2f1840617265636f6e742e70726f3a6d61747269782e6f7267117765623340617265636f6e742e70726f00000d40617265636f6e745f70726f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee710f5d44a205f970e6681d2a90ec58ea62e45205b7663bdcebf659aa162fe0b4d31474e5c24914": "0x040000000002000000000000000000000000000000000f637265616d5f667261696368655f0e4b617265656d2046617268616e1c68747470733a2f2f7777772e63616d62726f74686572732e64652f00166b617265656d4063616d62726f74686572732e646500001040637265616d5f667261696368655f000b6b617265656d3437353200", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee977649867b775e26f6ba0b2c596d1a471444945c9fdbdfe25e3f8862096f8f6de11d87da1a7111": "0x040000000002000000000000000000000000000000000f546865205068756e6b79204f6e65000017407468657068756e6b79313a6d61747269782e6f7267147279616e406c75636b796672696461792e696f00000c407468657068756e6b7931000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eec11b5fca7cddef5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c": "0x040000000002000000000000000000000000000000000d506f6c6b61646f747465727300001440706d656e73696b3a6d61747269782e6f72671c706f6c6b61646f74746572734070726f746f6e6d61696c2e636f6d00000f40506f6c6b61646f747465727331000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eed6418d5b4cb40034fee14ee94a7350a0c839cd4a41dd465e77717b257b55265ce7f577188c8257": "0x0403000000020000000000000000000000000000000019506f6c6b61646f74204461707073206f766572204170707314416264756c6b617265656d204f79656e65796500001844617070736f7665726170707340676d61696c2e636f6d00000e64617070736f76657261707073000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eed972f494e31056d64ccc7e84c99634be22610d47abd531d36b7793703c129fa21658f27cf5c42b": "0x0400000000020000000000000000000000000000000011426c6f636b6f7073204e6574776f726b0000001d656e67696e656572696e6740626c6f636b6f70732e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eedee3a95fe6fb672e2a4419244bd15a7af48d6556acfeaccb5f2f54a9892882f243160eac6eef52": "0x040000000002000000000000000000000000000000000c457175696c69627269756d0000000000001040657175696c69627269756d5f636f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ef422814dc3e336a24cf826d945c3cfddd0e76c8b1f093bc5dbcfceef4e30817337887813567fb04": "0x0401000000020000000000000000000000000000000010526f636b585f506f6c6b61646f743206526f636b581668747470733a2f2f7777772e726f636b782e636f6d0012737570706f727440726f636b782e636f6d00001040726f636b785f6f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ef5874a92f7239d9b2312d7e5b7f8209e6b7bcc4535401fbae5dd1098fdf5fe06b5f638620e6351f": "0x040300000002000000000000000000000000000000000844697461766961214469746176696120436f6e73756c746f726961206520547265696e616d656e741968747470733a2f2f7777772e646974617669612e636f6d2f0014636f6e7461637440646974617669612e636f6d00000b40646974617669616272000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ef6d8e4c19a55597bc42516c44e05faa2b4b905fb91fa1652c65e04d376414e39f79bad7dced6c55": "0x00000000000000000000000000000000000c426974636f696e696e757300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ef87b5cbae78ad371c7529b314d9e87a1c241cfe54312668a3159e1063a0aed9f70d3db1f03f8d10": "0x040000000002000000000000000000000000000000000b6c69616d616861726f6e000010406c69616d3a7061726974792e696f186c69616d2e616861726f6e40686f746d61696c2e636f6d00000c406c69616d616861726f6e0b6c69616d616861726f6e0000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f003382b575752d0b88d9d28cd21ec20bf31abadbc04405045fc0781f5c13e63d8a369d371de2e55": "0x0400000000020000000000000000000000000000000020506f6c6b61646f742050696f6e65657273205072697a652043757261746f720000001f70696f6e656572737072697a6563757261746f72407061726974792e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f0291cc04e6365cddca89b135d1a6aee0a498610a70eeaed056727c8a4d220da245842e540a54a74": "0x040000000002000000000000000000000000000000000d66657272656c6c2d636f6465002068747470733a2f2f6769746875622e636f6d2f66657272656c6c2d636f6465194066657272656c6c2d636f64653a6d61747269782e6f72671666657272656c6c3939393940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f0391ee85a4435190fe8ecbba7a1e216bd1c3bb7e749a98fcae77b4185c5522cbad8e826d0d92371": "0x0400000000020000000000000000000000000000000016f09f9ba1204457454c4c495220444f5420f09f9ba1001468747470733a2f2f6477656c6c69722e636f6d14406477656c6c69723a6d61747269782e6f726711696e666f406477656c6c69722e636f6d000011404477656c6c69724f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f065def57c0ed66e2e001e3f827e6eed45a60d131d97df1a5b429ed1d0f89fdedf3eda0a16502d3a": "0x0000000000000000000000000000000000064b616d696c104b616d696c2053616c616b686965761168747470733a2f2f716472766d2e696f14406b616d696c73613a6d61747269782e6f72670b6b40716472766d2e696f00000c406b616d696c5f61626979000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f0970b3f474766050ea760413255de0a565b08a056a1b4100de8df4d5135ae4dbe51ddb6fd23de7b": "0x00000000000000000000000000000000000e4465636f646564556e697175650f556e69717565204e6574776f726b1868747470733a2f2f756e697175652e6e6574776f726b2f0012637340756e697175652e6e6574776f726b00001140556e697175655f4e4654636861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f09b8c6be35500bfea06e81f2bd502063fe57a0447f6c1b4576a2f5a0e3e5794757bb565abce363e": "0x040300000002000000000000000000000000000000000d6c6f6c616c6f766573646f74000000146c6f6c616c7576723140676d61696c2e636f6d0000097734743376726d38000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f0ad4ed5898f2b8c80af4d39c625c32b2b6ea0b94c341ac826c49fa28451768e71afb46bc7afac04": "0x080000000002010000000200000000000000000000000000000000034147001568747470733a2f2f76616c696461746f722e6167154061677831303030303a6d61747269782e6f72671368656c6c6f4076616c696461746f722e61670000084041477831306b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f0ef7d0b30432179d6ee0051f7d4642b88616d632ba4457ca6c1169501cb9c2513c6b168f4df1252": "0x040100000002000000000000000000000000000000000d706f6c6b61646f7420636869096368696469206f6c0000187765616c746830314070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1024f494b9ebee98a1671bda9ae5c92eb8b3697a52b8f112222eeee80994306b8c6b8d817f22351": "0x0403000000020000000000000000000000000000000014f09fa6b420426f6e65205465636820f09fa6b400000013626f6e65746563684070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f13fcfe46ac782db6eb166bebe4af81c4b929fff65b437b18eb9c7a3c668dc6c53f39d895d00943e": "0x000000000000000000000000000000000008686f616e67766d000000167675686f616e673033303740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f141bc71dafe807f7cd5f5ff9b7eefb11b8b32c1bb1e1fc63c08019d81124b3aa85f24ae8c779a31": "0x040300000002000000000000000000000000000000000f74686520686f646c6661746865720f41726d616e646f2043617374726f00001861726d616e646f63617374727040676d61696c2e636f6d00000f40746833686f646c666174686572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f18a58b0fa8cec93dcd35aa554e0ac5db78e83bfc51649fc9b550bec1b162c70509199c1b4c0cc1a": "0x0403000000020000000000000000000000000000000011506f6c6b61646f7420496e736964657211506f6c6b61646f7420496e7369646572000015726973696e676170616340676d61696c2e636f6d00001140506f6c6b61646f74496e7369646572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1c80fdef53d785909cb20eb25e42c2fa106d75ee4d44b9c2bac20323a540529e9f4f40da5337bb3": "0x040000000002000000000000000000000000000000000c4d65726b6c657472696265001768747470733a2f2f6d65726b6c6574726962652e696f18406d65726b6c6574726962653a6d61747269782e6f726714696e666f406d65726b6c6574726962652e696f00000d404d65726b6c657472696265000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1d74521ceb0a868249bf7f403ca14e4d0b0f4ff5c9d447772ce079b9b7c389e86587a2589fd7558": "0x0403000000020000000000000000000000000000000007456e7a6f726f114e617267697a61204b7572616b696e61000015656e7a6f726f2e64657640676d61696c2e636f6d00000d40656e7a6f726f5f7465616d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1f8c71902a2a288729d9e0636390cc1ec43a6f95d06475b0e42017c6726e5f17e8e70e67cf69d56": "0x040300000002000000000000000000000000000000000b5b6167616c6c696e695d10416c626572746f2047616c6c696e6900001a616c626572746f2e67616c6c696e6940676d61696c2e636f6d0000104047616c6c696e69416c626572746f00096167616c6c696e6900", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1fa33e1c88a625cf278bbe8c33fe8fe03c6c684b44dfc26dfb5bcefb3ef511f5446530af859c112": "0x040000000002000000000000000000000000000000000e4d697463682d576172696e657200001a406d697463682d776172696e65723a6d61747269782e6f72671d646f742e6d696e6572732e736369656e636540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f2005476fdc5028fb4ac19c9a723477c0b31ef41dd0cfd9539a3a8d763e6a6c4c96eba6eba5e4d7f": "0x040000000002000000000000000000000000000000000c7072656d61747572617461000018407072656d617475726174613a6d61747269782e6f7267207072656d617475726174612e76616c696461746f7240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f23d01c894e574b19abbbcee9ebaa3a753da127bf308e33cac065110734cc2b689cff009d94ee62a": "0x040300000002000000000000000000000000000000000e426c6f6b42726f6b657261676500000018626c6f6b62726f6b657261676540676d61696c2e636f6d00000e426c6f6b42726f6b6572616765000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f23d30d0a705bc35c69d8c568b24a3108b6f9604f118359c268804e5a0de2b415ce978160dec2359": "0x04000000000200000000000000000000000000000000134261626573506170657328444f5429636f6d0c42616265732050617065731c68747470733a2f2f7777772e626162657370617065732e636f6d2f184062616265735f70617065733a6d61747269782e6f7267166f666669636540626162657370617065732e636f6d00000c406261626573706170657300184062616265735f70617065733a6d61747269782e6f726700", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f2988908eea3feb7586b9f5a2e5fad9175b0a540b7bf2ffcca689f99ee06cbc207b4f15a26b58363": "0x040100000002000000000000000000000000000000000e4147475245474154452e4f5041001b68747470733a2f2f6167677265676174656e6f6465732e636f6d16406167677265676174653a6d61747269782e6f7267206765742d696e2d746f756368406167677265676174656e6f6465732e636f6d000010404167677265676174654e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f2a816b6bd3a924c32a54d822b72d04a74a61509cb66376129556412bfaec8fd8d41f50ed423c957": "0x040000000002000000000000000000000000000000000c564c4144494d495250524f00001a406772617465766c6164696d69723a6d61747269782e6f7267196772617465766c6164696d69724072616d626c65722e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f2ad51c6c76e65c8d0bb4d4b0f530b756f58c53f814710ee17fc79324d6b21c3ae22398c1ed5dc1b": "0x0403000000020000000000000000000000000000000017546f6b656e67756172642042656e65666963696172791b426c6f636b20536f6c7574696f6e732053702e207a206f2e6f2e000016636f6e7461637440746f6b656e67756172642e696f00000e546f6b656e67756172645f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f3194d5c012787bae6edf7a6551c93e9ac1c9bd0daf98b25abefc01eb7afa918d322539b997d462e": "0x00000000000000000000000000000000000b646f63746f726368696e0e7469656e20627569206d696e6800001c6275696d696e687469656e3139383475734067616d696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f33c3d7c430f900954eb2d8672a2aaa09a149fae1d2cca54cda463da043b276e246881a2f4e9e179": "0x00000000000000000000000000000000000b506174696b6120696e630b506174696b6120496e631868747470733a2f2f7777772e706174696b612e6465762f001267756c63616e40706174696b612e64657600000c4072697365696e5f636f6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f3430f9486eebcb28423c2127c4f7199f134cad21d786dc788effc31b9164767bbb4cd8ce740ab29": "0x00000000000000000000000000000000000e43726f7764204163636f756e7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f3a8cb14bfca5d3d82c5c0e26848d49b32a7ae09a67f6822f2a18310b69a3ed9c31ee02144020826": "0x040000000002000000000000000000000000000000000f486173686564204e6574776f726b0000000000000f404861736865644e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f3bb05b647c9705134ba460ddb05a10ff78533182868e683684300888b0029e09123a945f0823020": "0x040300000002000000000000000000000000000000000645796173750e45796173752042697268616e750000156a6f736874656368333940676d61696c2e636f6d00000f40457961737542697268616e7537000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f3d619806458ce0ea8070648f6e43b7d8a8f10418b696130d2046c10645f10085de80e6098b85f09": "0x04000000000200000000000000000000000000000000134875746368202d20436f6e74726f6c6c65720000001d70617072696b615f766f6361626c65306a4069636c6f75642e636f6d00001040746865666c79696e676875746368001040746865666c79696e67687574636800", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f3e3959f84b063bcd6c29a7c39cee45b0e045a94081bc188ef73be2be086d66aefd850fc7eeacc45": "0x040100000002000000000000000000000000000000000e4f6e46696e616c6974792e696f0f4f6e46696e616c697479204c74641a68747470733a2f2f7777772e6f6e66696e616c6974792e696f124069616e68653a6d61747269782e6f726717706f6c6b61646f74406f6e66696e616c6974792e696f00000c404f6e46696e616c697479000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f4137709d90899e9fb2d80eed7a8b28753f70afb95bda3edda074ffd7708116acb919cf484854777": "0x0000000000000000000000000000000000094c6564676572203100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f41c7a3cee29ba2d784c9c917350f814d7b3600e688da3ce67ad920cc321be65addb3e6ae0b51451": "0x040000000002000000000000000000000000000000000e4578696c65642052616365727300000016696e666f406578696c65647261636572732e636f6d00000e406578696c6564726163657273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f41c81026445f16f0ad8516cbee7751114909ea4199c27ec84911bbc85c01449c3b418a754f91e69": "0x04010000000200000000000000000000000000000000075472616e73580a7472616e73782e696f1268747470733a2f2f7472616e73782e696f13407472616e73783a6d61747269782e6f72670d6869407472616e73782e696f00000a405472616e73583131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f428a77ef581364ada86cee6a178b43ac0e605d8dac093106dadcac8f00f0a8a5b8431c4b56a775b": "0x00000000000000000000000000000000000e566963746f72204d657a72696e0e566963746f72204d657a72696e1368747470733a2f2f74726169742e7465636813406d657a72696e3a6d61747269782e6f726719766963746f722e6d657a72696e4074726169742e746563680000000a7472616974746563680000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f43858092a1274370ce14f14486f3fb3513a44a19970a0bbf4da8b642c9837cfa251b33384dec257": "0x040000000002000000000000000000000000000000000c477265656e20436c6f756400001840677265656e2d636c6f75643a6d61747269782e6f72671f677265656e2d636c6f75642d6b7573616d61406f75746c6f6f6b2e636f6d00000f40477265656e436c6f75644b534d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f4f0e33d9ec9b36d224872ad60345d726772361291b4cf7f3e1b8087f2277e2b5cc25a9b309f4727": "0x040000000002000000000000000000000000000000000753656e7365690c53656e736569204e6f64651768747470733a2f2f73656e7365696e6f64652e636f6d14406a6368697474793a6d61747269782e6f726714696e666f4073656e7365696e6f64652e636f6d00000c4053656e7365694e6f6465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f53e59e4baae9e387082636ca5c22aaad30b64c9fb6af0c6b91055d1834f1a5badaeec7091dd8b8b": "0x040000000002000000000000000000000000000000000846696c6970706f1246696c6970706f204672616e6368696e6900194066696c6970706f3a776562332e666f756e646174696f6e1866696c6970706f40776562332e666f756e646174696f6e00000d4066696c6970706f77656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f5485e0e720d2144ed5f93b8f24ce936d3df4faad4c247e1e57503b2be42904520d0018162ebc76c": "0x00000000000000000000000000000000000f42656e736869676572752044414f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f5912d36263b8f7806a2129ac63420996a943d410317bd705dad70b5073f4f8edd63901fe332d56d": "0x00000000000000000000000000000000001357696c6c69616d202854616c69736d616e290d57696c6c69616d204368656e0016407265706c67686f73743a6d61747269782e6f72671577696c6c69616d4074616c69736d616e2e78797a000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f5bcc47f0db2d6a236a561a21a65f5106286c1d983cfaf4da5115a90073d1c9c6e053d4bbf596d27": "0x04000000000200000000000000000000000000000000104865616c74687920506f636b65747300000018696e666f406865616c746879706f636b6574732e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f5d0ba7a9e0e043b545b7958451cd22afb0367d6c99af1360190813571c47b8a94a055d575d38249": "0x040000000002000000000000000000000000000000001443525950544f204a41434b2053504152524f5700001e406a61636b73706172726f7763727970746f3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f5d53ab33cd6333ae62fd2fd91105ee48911b567b815318f9a9c5f1002c88dc3c568aea2e0f8eb34": "0x00000000000000000000000000000000000c546f746f2043727970746f0e546f746f2043727970746f6e791a68747470733a2f2f746f746f63727970746f2e7375622e69641740746f746f63727970746f3a6d61747269782e6f726717746f746f63727970746f373740676d61696c2e636f6d00000e40746f746f63727970746f3737000d746f746f63727970746f373700", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f5e5a1e323e94d19728453ef7429569c384e3e39ffc0f147aabb8a71185dedca4ffab6fe44815500": "0x0000000000000000000000000000000000065452554a4900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f5f2eeffe9c9cf62a22ff027237d3f1f468e46ebaa49f910df2affac228efed30a62ab3daaa99e57": "0x0403000000020000000000000000000000000000000007763064306c3007763064306c30000013736f72616e6f64654070726f746f6e2e6d650000094076696e7364656c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f609c73b2b467ef264c3558888b7bcb721cf6803dac859f125de0afa615c461bd1b2587ad461c81d": "0x040300000002000000000000000000000000000000000b53616c696e61204465760000001773616c696e6164657664657640676d61696c2e636f6d00000b53616c696e615f646576000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f6198f55b54f219a44a65df7135dd3fd5e958140e4800abdb5db615d7f4aefd21d5d746b7e456b34": "0x040000000002000000000000000000000000000000000944616e70756c6c6f0f5341424955204d5548414d4d4144000015736d64616e66696c6c6f40676d61696c2e636f6d00000e40535f4d5f44616e70756c6c6f000f5361686167756d656c233032313200", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f623c11edc7a4858d6c8c22c86dda329b85d76f7f7d68623ddeb1e9649819900e6b715967a0aff36": "0x00000000000000000000000000000000000c526567656e63792d3031311757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f6678cee6fb3557e047d9556653e9335812ba87a2463e04f455a68dd5391e22397d55d89cb8cb116": "0x00000000000000000000000000000000000a525542524f5353414e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f668ff8ab90e05ebf047b090d2e8e2406ccc97a60df3452fc8574333b91009c91e00ce8fe11551f9": "0x00000000000000000000000000000000000c4170696c6c6f6e204d4b54001468747470733a2f2f6170696c6c6f6e2e696f2f0015636f6d6d756e697479406170696c6c6f6e2e696f000009404170696c6c6f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f67278c03253af6c20f057efcf26c451d58366c5906a3468517b624fb5674a547422726ebea3eb16": "0x000000000000000000000000000000000008446f744b696e6700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f685fe8bfef999d22074f20847843acac10a56948a6634e827bcaabb455b9c958d285b2ec9090314": "0x04000000000200000000000000000000000000000000094e5244204c616273000000136572696e7665373740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f69bb097d37ec3ca7e406ae038214b907dfa08e190c4d61bf43d28be997541747e3465ada083d262": "0x04010000000500000000000000000000000000000000064a554c494f0f4a554c494f2043415244454e415300001364697061706f636240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f6a51af30694c2c19a820a93a16c1def7154cdd57c063e1a4630411e076f1e1e1ce93ca953af333e": "0x040300000002000000000000000000000000000000000b41434f42204a61736f6e0f4a61736f6e2046726965646d616e00001b61636861696e6f66626c6f636b73406f75746c6f6f6b2e636f6d00000a41434f424a61736f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f6db4258f530c658ca676edbf98876ab4fd6ad742f7954773a0e234345d6551a8ee9738a8ae33d42": "0x040100000002000000000000000000000000000000000753524c6162731f5352205365637572697479205265736561726368204c61627320476d62481268747470733a2f2f73726c6162732e6465000f6e6f686c4073726c6162732e6465000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f6e7d7d57efb1158faf96a8cf4ac3d4de8b04b607a7a70cc4aeb5ea742ea2c59836057a2678dad64": "0x000000000000000000000000000000000017537061636577616c6b207c20506f6c6b61204861757300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f73159fa6ef16058625b21fc3cfe39c52cf4d753fe8ad5f3b2ace458d9d11d266f080216e5e885e6": "0x040000000002000000000000000000000000000000001d4368616f7344414f204576656e747320426f756e74792050726f78790000000000000a404368616f7344414f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f738bf8232b5657ec2401487a14072ba228693b006c7be226b17b2bf498630b41631f91065e17875": "0x040000000002000000000000000000000000000000001143726f75746f6e4469676974616c2d3100001540746f7861333333333a6d61747269782e6f72671763726f75746f6e6469676974616c40616f6c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f740ceb4be9720dce0f0f94962fc0a8c1a0f0527dc8e592c67939c46c903b6016cc0a8515da0044d": "0x00000000000000000000000000000000000a656c697a6162657468000013406c696c6574683a6d61747269782e6f726700000000056e6f6f740000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f77e7d1a38a5e4b2befe71ab1f2719097a35e93e9114427bcd71e5109c14d82b9b3d9080f16dec2f": "0x04010000000200000000000000000000000000000000045a4b56001968747470733a2f2f7a6b76616c696461746f722e636f6d2f001668656c6c6f407a6b76616c696461746f722e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f78baea38e12315a6c7fdb8b8eaad1af9faaf918493606e1a3e8c20f9d852773ab5ebfbb93bd1948": "0x040000000002000000000000000000000000000000000757656233476f0757656233476f1468747470733a2f2f77656233676f2e78797a2f0010696e666f4077656233676f2e78797a0000084057656233476f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f79f574773cdeb99eacf14f2850c8d4145f07936bad43325bb0d150b1111757e944d62ecd0abcce6": "0x00000000000000000000000000000000001bf09faaac2054616c69736d616e20476f762044656c6567617465001568747470733a2f2f74616c69736d616e2e78797a000000000f40776561726574616c69736d616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f7a35e45eb5c8f006a4e76d530fa715a95388b889ad33c1665062c3dec9bf0aca3a9e4ff45781e48": "0x000000000000000000000000000000000007526f73c5a56113526f737469736c6176204c69746f766b696e0000000000000009726f73746164657600", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f7f56e24024aa32cc0aacd65996d35fa753d12fc099078f0357d5628950585143e953675c7aee712": "0x00000000000000000000000000000000001c313335204341504954414c20494e434f52504f524154454420303310416e74686f6e7920457566656d696f0f68747470733a2f2f3133352e696f000b616365403133352e696f00000f407265616c4143457566656d696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f7f82bb21d26a5d0647201c657cb2ea9a6f15069728a26a9bf195c93adfa947cace0e7df16d7e102": "0x040100000002000000000000000000000000000000001054726962652f416e67656c4861636b12416e67656c4861636b20507465204c74641768747470733a2f2f616e67656c6861636b2e636f6d2f00186a757374696e2e6e6740616e67656c6861636b2e636f6d00000b40416e67656c4861636b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f7f8fa46e9ed81a89ce3de1cd55ad6f4ab351ab212431d94cec798e1727176cca174fa661c8f636e": "0x040300000002000000000000000000000000000000000856696e63656e740f56696e63656e7420476564646573001440766765646465733a6d61747269782e6f72671576696e63656e7440736e6f77666f726b2e636f6d0000094076676564646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f80b38f6992cd55c0e06a7b3013bdbcd4f649d47a82e646be1223be5ceb8d32e8847fb7dbd2ccf57": "0x0401000000020000000000000000000000000000000015535543482046494e54454348205354414b494e4715535543482046494e54454348205354414b494e470018407375636866696e746563683a6d61747269782e6f7267196465766f7073407375636866696e746563682e636f2e6e7a00000d407375636866696e74656368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f81ec86fea69eb9bfb430ce27d4be287efa0c50ef42c36c3ef14e55ecaf40ac53e1df33b0720d176": "0x00000000000000000000000000000000000631574542341757656233204c6567616c20456e67696e656572696e671268747470733a2f2f6f6e656c61772e7573001073636f7474406f6e656c61772e757300000b4074656e66696e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f898daa4756e63c5ca467889146a7467efffe20d97c077cb961d176dfa96f669857d3aaa8485fc0a": "0x0000000000000000000000000000000000114d696368616c40416c6570685a65726f0f4d696368616c205377696574656b1668747470733a2f2f616c6570687a65726f2e6f7267001d6d696368616c2e7377696574656b40616c6570687a65726f2e6f7267000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f98bc77ab23b03eed401f460e0251ed41d7fb32ca463b5233b620cb9569eef5327def27fbd7c7b57": "0x04000000000200000000000000000000000000000000084361626c652d58000012406361626c653a6d61747269782e6f72671e6379636c6f707373756d6d6572734070726f746f6e6d61696c2e636f6d00000f4073756d6d6572735f6361626c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f9a33b675b34b0c00a7cbce722b9e8f16e7c0a9bb209f761cc94e25191e7599cb0d0234d1ad11d66": "0x00000000000000000000000000000000000a4942502050726f787900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f9ace18a7f38e38e94204c6fb288a7302b1ff34b6aafd5edf6de6b895db07f3d6ca1a75d1681f37e": "0x040300000002000000000000000000000000000000000f506564726f204c6f75726569726f1e506564726f2052616661656c204c6f75726569726f204c65616e64726f000019706564726f2e706f6c6b61646f7440676d61696c2e636f6d000011404368656d6963616c4f7074696f6e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f9b0358c010b6eb69ecfdf118a26b3c2926e7ba57cb2c08eac9e981318d88b958c0e06e97e774c1e": "0x040000000002000000000000000000000000000000000f556e69717565204e6574776f726b0000001568656c6c6f40756e697175652e6e6574776f726b00001140556e697175655f4e4654636861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f9e4ceaaa31d1e273ec9398e00987bf25afda5d3f3e3a1a1f1b121d8728d7da7a30dd1b545eb3d49": "0x0403000000020000000000000000000000000000000012436861696e616c79736973204c6567616c0000001b6a616d65732e7061696b40636861696e616c797369732e636f6d00000a6b6f6e657368693133000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fa2d9158713aa2daac18d0d46a223a6576df578a0c7f7e087d7dceb3608cbdf792b279c532631c09": "0x00000000000000000000000000000000001367726568656920706f6c6b61646f74204772000013406772656865693a6d61747269782e6f72671167726568656940676d61696c2e636f6d000009404772655f486569000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fa4279b211bd820ab22c2075548019dd268e74f3aa69c9703b129e989d230f935797975d5ed9247d": "0x04000000000200000000000000000000000000000000125a6574657469632056616c696461746f7200001d407a65746574696376616c696461746f723a6d61747269782e6f72671e6f70657261746f72407a65746574696376616c696461746f722e636f6d000010405a6574696356616c696461746f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fa4c4ebe45297c58e8435412cd8649ed9d5212898af799270589d46d53af6c9b30dc6103b5917454": "0x0000000000000000000000000000000000064b61696f6800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fa701643441fc0cc0a73047c4bca127582fa1541c886915b2a872c95fb538fcea099bab0a47b8f54": "0x040100000002000000000000000000000000000000001153554e5348494e454155544f53444f5400001f4073756e7368696e656175746f736e6f6465733a6d61747269782e6f72671c73756e7368696e656175746f73696e666f40676d61696c2e636f6d0000114053756e7368696e655f4175746f735f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714faa55b79d5b983962aad2d511e0a2ade151b1e3442675156b71aea1f049ce004311cf33c9d70c474": "0x040000000002000000000000000000000000000000000a53656261737469616e00001c4073656261737469616e63726970746f3a6d61747269782e6f72671b73656261737469616e63727970746f3840676d61696c2e636f6d0000114053656261737469616e43726970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fad7d2ce54667f8c1ea80b0dde0e207c8ec57ac05fbec636502cb216bb423642919679fe8f074051": "0x0401000000020000000000000000000000000000000015525454492d353232302028504f4c4b41444f54290f5261756c20526f6d616e75747469001c407261756c2e727474693a6d61747269782e7061726974792e696f177261756c406a7573746f70656e736f757263652e696f00000b406e6163686f72747469000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fadf532a0cd06f2c30bdeebf156313a98c5235fd02e6086502e320acf1791ec4390b8bb4735e5033": "0x04030000000200000000000000000000000000000000064b6f6b6f4c000000186e696b686f6c65636c7563617340676d61696c2e636f6d00000e406e696b686f6c656c75636173000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fae4899c3cb40a9ee6c87f4b9656543d64815b6626ba2ee48c8c54de210dfa98bfe53333fdf26744": "0x040100000002000000000000000000000000000000000d41646472657373204c6162731141646472657373204c61627320496e6300001b6861727269736f6e2e636f6d666f727440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fb0bc5a64f81e0ca7cbb0ed8bf228935241774290753bf282020d73e45f6724b0196c97b3bd53462": "0x040000000002000000000000000000000000000000000b6f70656e6269746c6162000018406f70656e6269746c61625f3a6d61747269782e6f72671c6461766964652e6f70656e6269746c616240676d61696c2e636f6d00000c404f70656e4269744c6162000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fb2ad09a8a07f8da26c3fc13ac393359abbdbec7ad3de6f6dd110169e0ef401b19c693afcfc38f08": "0x040100000002000000000000000000000000000000001e545247207c204469676974616c20496e6e6f766174696f6e2046756e642054524720496e737572616e63652042726f6b657273202850747929204c74641f68747470733a2f2f7777772e726f6265727467726f75702e636f2e7a612f00184b6576696e40726f6265727467726f75702e636f2e7a6100000d40526f6265727447726f7570000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fb7fa862606e0cd75626fb92ce5aacc7ac4dd042dd55308832ba8dde38c557b140ae8740948fe76c": "0x040000000002000000000000000000000000000000000763776368756100000000000000076368756163770000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fb983efc82b2f0f392d5c737ce301d743f39f522a06af54bc5f37c1f9037c22c40722ec16a07364d": "0x00000000000000000000000000000000000b646174646f742e6f72670000000000000b40646174646f746f7267000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fbc4385a1a8a38b114dd7b536252ac1b8294062b9f93fbd0b8c2632010aef94753354a3721def21b": "0x00000000000000000000000000000000000f506f6c6b61204578706c6f726572001168747470733a2f2f706f6c6b612e696f000b6940706f6c6b612e696f00000940706f6c6b61696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fbe4b7926dff6bda8c7b7c1af5f115225fb19bbba44e2b9b68acc26d2dfeff02d948183ffcdc0d0f": "0x000000000000000000000000000000000008484d204d4152530f48616e747573204d6f737465727400001968616e7475736d6f73746572743140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fbeb0670b76a6ac8ea614ce8bc4baa3c39e8019636cc6f8d9a67291f19dabb2d898a308b6b93b72e": "0x000000000000000000000000000000000009616e67657765623312416e67656c696361204772617465726f6c000020616e67656c6963616161677265726f6c2e3037303440676d61696c2e636f6d00000b616e6765696e77656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fbef5ae8c51b799f2a0e4eb85f552a217a9ddd86b965229be3210d010f0f0f78398d8d9a5a5f0537": "0x040000000002000000000000000000000000000000000f395374616b65206279203947414700001840397374616b652e396761673a6d61747269782e6f726719397374616b652e706f6c6b61646f7440396761672e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fc06d1b8b9ab844be64bc946c10a1f75e683f236e72a44d6d61b3bdcf72ffd8c738e488efc6e1567": "0x040000000002000000000000000000000000000000000b4d61746843727970746f001c68747470733a2f2f7777772e6d6174682d63727970746f2e636f6d17406d61746863727970746f3a6d61747269782e6f7267116d61746863727970746f40696b2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fc6a42b3b802fc9518d54ea25ad26acd7094fba6bdb278e769f9ac350cc36b2f631da13fa92bed79": "0x040100000002000000000000000000000000000000000c5374616b652e576f726b730c5374616b652e576f726b731468747470733a2f2f7374616b652e776f726b73154077656264657639393a6d61747269782e6f726711696e666f407374616b652e776f726b7300000c405374616b65576f726b73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fcbacdb7dda02f70504baa1f30e0267703f471e94de948bd9f09caaf3c3a2f4c2dad3685a79ee000": "0x0400000000020000000000000000000000000000000006616e76656c00001240616e76656c3a6d61747269782e6f726717616e647265792e76656c646540676d61696c2e636f6d00000d40416e6472657956656c64650007616e76656c2e00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fcd27506d243061f2edf0fd8948ea642f135b314b1358c77ec6d0a4af83220b6ea18136e5ce36277": "0x04000000000200000000000000000000000000000000124368726973404f414b204e6574776f726b0000000f6368726973406f616b2e7465636800000d4063687269736c6932303436000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fce864e50b620f11ad65f8153459863f71364d90f27265da0084743373e0c75ae69d651efc95b62e": "0x00000000000000000000000000000000000b506f6c6b61205269636f0b506f6c6b61205269636f1668747470733a2f2f706f6c6b617269636f2e636f6d0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd0157da0fed5e2b4805c5f3b7f9abe9da4189cead8a9a8453ab2cfc637a0f9cd93d59661aba9954": "0x04030000000200000000000000000000000000000000074a6179436565164a756c69616e6120506572657a20436172646f7a6f00001d6a756c69616e61636172646f7a6f313740686f746d61696c2e636f6d00000c49616d4a756c69616e6143000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd050f61009683f92e62fe384b5820c81695aa763b54daf138b67b014714c5c6f75d68e4d1b3785b": "0x00000000000000000000000000000000001944617272656c6c202d20506f6c6b61646f74204163616c6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd0ec0420825c1bfce2490656709c33bdd50d72dc0ec562bb72db84945ef7a1be45be14bbc6fc877": "0x04000000000200000000000000000000000000000000047369780000124068657866663a6d61747269782e6f7267127369784063727970746f6374662e6f726700000c4053697854686544617665000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd32583ae5aff69da2d756efc15354d37aafecf3a850808b1276d1cee16f14a14397e81b616e9a4a": "0x040300000002000000000000000000000000000000000a5368696b615f7770771657697061776565204c696d6b6173657473616b756c00001b6b77616e672e6c696d6b40656e746572746f73746172742e636f00000e40456e746572746f5374617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd4f36a10fe246e4e87f578ff46b741dafc7ffd2b6e223f50269ea6b8260b9bde108d6e5870f877c": "0x040300000002000000000000000000000000000000000a64617374616e73616d0000001664617374616e73616d313640676d61696c2e636f6d00000b6b696e676c656172645f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd64180d1412f211888c6e2c05a5db8fb2ce4a31ffc434049fac143401d77e862dea055bf5607073": "0x0000000000000000000000000000000000134d61726375732720446f742077616c6c657400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd71c324186304a590c5d23600de15438062c91c4976d001a14cecf539c2b8db9399c4b56e6b1166": "0x0403000000020000000000000000000000000000000008487970654c6162084a6f65204b696d00001268656c6c6f40687970656c61622e636f6d00000b40676f687970656c6162000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd8929a3a5cb6d462fd09555017774e81bda25510ca97864e9bc350620523fd11508f99b8fdc8b7d": "0x0000000000000000000000000000000000145765625a65726f205632204d756c74697369670000000000000d406a6f696e7765627a65726f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd9785f8772870809eee1e58c17ff7b037f2da5766e9bc78d5568c58d45cf363b9630ef32b2ccd79": "0x040100000002000000000000000000000000000000000a507572655374616b650e507572655374616b65204c74641b68747470733a2f2f7777772e707572657374616b652e636f6d2f0013696e666f40707572657374616b652e636f6d00000d40707572657374616b65636f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fdc037f375e9e4c3961db3fef76ece3b513f6896e19fd09588d62f5c6a99d577275d7db8005e610f": "0x040100000002000000000000000000000000000000000d4175677573746f204c6172611a4365736172204175677573746f204c61726120476176696e6f0000126175677573746f406861736865642e696f00000d404175677573746f4c617261000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fdc296dd3da2e409e472fc53af693baa4199e1edd6a3d86badfc6d2d4aad3331d8a40fd6b18b751a": "0x00000000000000000000000000000000000d6361726c6974726f7374657300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fdf70154c5cd66e448b3ed689e1d1c790052dfea406cff690cbf0354a3598c961c7e8054068a6c9d": "0x040000000002000000000000000000000000000000000a70616e7661645348310000134070616e7661643a6d61747269782e6f72671669616d70616e766164696d40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fe0f1e8f0e428f0ffa859a32665b4dd29d647732d0d8e0b794cb21ae44862153bfca9522c14e9c71": "0x040300000002000000000000000000000000000000000a486f7065436c6172790d486f706520476f6f646d616e000013486f7065696f756d40676d61696c2e636f6d000009486f7065696f756d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fe7066486cbde784e0d0031d0a450dfc4bb16333fe575dfb8452bb0f79c768181478190a5d9a653f": "0x04000000000200000000000000000000000000000000144c6974656e74727920436f6c6c61746f72203100000012696e666f406c6974656e7472792e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fea0c4e647948252eccdb05e3f618a3da74db2ca0a4c635b94c388e3e620c7ef7093ef34f206ca7c": "0x04030000000200000000000000000000000000000000144175746f6e6f6d6f75732050726f6a65637473144175746f6e6f6d6f75732050726f6a6563747300001b7468656f406175746f6e6f6d6f757370726f6a656374732e636f000011406175746f6e6f6d6f75735f77656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fecc695c6a87d6466ecb07b7a8f63febc1c458983d4ec414e4cbb76ec3f128d9cedd5f4c4fd2965b": "0x040000000002000000000000000000000000000000001073306d65306e652d756e6b6e30776e000000000000001073306d65306e652d756e6b6e30776e0000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fedff71a46bae1ee98388d733bfdc1edad482ef118803415e01703eb7e20e7822a3a322f999c3177": "0x0000000000000000000000000000000000084d756375323536104d7563756e67757a69204d6f7365730000126d6f656d75637540676d61696c2e636f6d00000d4063727970746f70726f5567000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ff02177bcafc5807e274c36b3b6efe4d0de454afa853ce1e7a4f789aaa2f3c9613a61fb365f9362b": "0x040000000002000000000000000000000000000000000746696e7369670e53746576656e20426f796e657300134066696e7369673a6d61747269782e6f72671073746576654066696e7369672e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ff643fe3320aabbafcba1bf303b55be82bf6e48504909dfb85be27bcbbb2a330e9f4fc1261d8f02a": "0x040000000002000000000000000000000000000000000e47656e657269632d636861696e00001a4067656e657269632d636861696e3a6d61747269782e6f726716696e666f4067656e657269632d636861696e2e696f00000f4067656e657269635f636861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ff68e68c8f4329adc0fb1e91315aff633f7889e1b32c46b2b33e534d059f29a4fda276ce4e59f83a": "0x04000000000200000000000000000000000000000000084469616d6f6e640000001776616c69646469616d6f6e644070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ffc544aa04d3feb9a69484f2b10ec2f1dea19394423d576f91c6b5ab2315b389f4e108bcf0aa2840": "0x000000000000000000000000000000000005466162690000184066616269616e3a776562332e666f756e646174696f6e0000000d4066616269616e676f6d7066000000" + }, + "childrenDefault": {} + } + } +} diff --git a/cumulus/parachains/chain-specs/people-westend.json b/cumulus/parachains/chain-specs/people-westend.json index 8bfbb33264150f5d28fa80a93128f9708998db53..ac24b2e6435922e67e2cb07d66b90b2bac2fa5b8 100644 --- a/cumulus/parachains/chain-specs/people-westend.json +++ b/cumulus/parachains/chain-specs/people-westend.json @@ -17,8 +17,8 @@ "/dns/boot-node.helikon.io/tcp/9522/wss/p2p/12D3KooWHhZk21Wzvsd3Un1Cp63diXqr6idbG1MEiUWaitUZuX4c", "/dns/boot.metaspan.io/tcp/35068/p2p/12D3KooWAtw8ybFXNmNdTUsvt2gfKwtuea9wDQT2b8FpbVNKYGwc", "/dns/boot.metaspan.io/tcp/35069/wss/p2p/12D3KooWAtw8ybFXNmNdTUsvt2gfKwtuea9wDQT2b8FpbVNKYGwc", - "/dns/boot.stake.plus/tcp/46333/p2p/12D3KooWLNWUF4H5WE3dy2rPB56gVcR48XY2rHwEaZ6pGTK6HYFi", - "/dns/boot.stake.plus/tcp/46334/wss/p2p/12D3KooWLNWUF4H5WE3dy2rPB56gVcR48XY2rHwEaZ6pGTK6HYFi", + "/dns/people-westend.boot.stake.plus/tcp/30332/wss/p2p/12D3KooWD5T1YN8oZUEsRXWod69kYH67jrSXHm6tSvs7RvH4Cb3p", + "/dns/people-westend.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWSByQrekhxx7pyDMTZcnnWBBFdj2LtqN9QtTCBDckc2zi", "/dns/boot.gatotech.network/tcp/33340/p2p/12D3KooWHwURYtEHpexfrZa8k8hVgVi5FTFr4N8HBnn9kPDsWfgA", "/dns/boot.gatotech.network/tcp/35340/wss/p2p/12D3KooWHwURYtEHpexfrZa8k8hVgVi5FTFr4N8HBnn9kPDsWfgA", "/dns/people-westend.bootnode.amforc.com/tcp/29999/wss/p2p/12D3KooWE1btdwDhNpApg8BEe2QwJxdVDtz6a6BRhgTeUh9HMhWs", diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index 2b943b6dca55989a891895b4abb3195970978b06..6d436bdf799a4f7682ced2098f4926ec9bc50379 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -13,42 +13,41 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"], default-features = false } +codec = { features = ["derive"], workspace = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } # Substrate -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -pallet-asset-tx-payment = { path = "../../../substrate/frame/transaction-payment/asset-tx-payment", default-features = false } -pallet-assets = { path = "../../../substrate/frame/assets", default-features = false } -pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } -pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } -pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } -sp-consensus-aura = { path = "../../../substrate/primitives/consensus/aura", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-asset-tx-payment = { workspace = true } +pallet-assets = { workspace = true } +pallet-authorship = { workspace = true } +pallet-balances = { workspace = true } +pallet-message-queue = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } # Polkadot -pallet-xcm = { path = "../../../polkadot/xcm/pallet-xcm", default-features = false } -polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false } -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor", default-features = false } +pallet-xcm = { workspace = true } +polkadot-primitives = { workspace = true } +xcm = { workspace = true } +xcm-executor = { workspace = true } # Cumulus -pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false } -cumulus-primitives-core = { path = "../../primitives/core", default-features = false } -cumulus-primitives-utility = { path = "../../primitives/utility", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../pallets/parachain-info", default-features = false } +pallet-collator-selection = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-utility = { workspace = true } +parachain-info = { workspace = true } [dev-dependencies] -pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } +pallet-authorship = { workspace = true } +sp-io = { workspace = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder" } +substrate-wasm-builder = { workspace = true, default-features = true } [features] default = ["std"] @@ -73,7 +72,6 @@ std = [ "sp-core/std", "sp-io/std", "sp-runtime/std", - "sp-std/std", "xcm-executor/std", "xcm/std", ] diff --git a/cumulus/parachains/common/src/impls.rs b/cumulus/parachains/common/src/impls.rs index 16cda1a4ed83850f4e67765a5e7092dad4a24305..c1797c0a75132d4cd3b64ac3e90791fab4dc516a 100644 --- a/cumulus/parachains/common/src/impls.rs +++ b/cumulus/parachains/common/src/impls.rs @@ -16,6 +16,8 @@ //! Auxiliary struct/enums for parachain runtimes. //! Taken from polkadot/runtime/common (at a21cd64) and adapted for parachains. +use alloc::boxed::Box; +use core::marker::PhantomData; use frame_support::traits::{ fungible, fungibles, tokens::imbalance::ResolveTo, Contains, ContainsPair, Currency, Defensive, Get, Imbalance, OnUnbalanced, OriginTrait, @@ -23,7 +25,6 @@ use frame_support::traits::{ use pallet_asset_tx_payment::HandleCredit; use pallet_collator_selection::StakingPotAccountId; use sp_runtime::traits::Zero; -use sp_std::{marker::PhantomData, prelude::*}; use xcm::latest::{ Asset, AssetId, Fungibility, Fungibility::Fungible, Junction, Junctions::Here, Location, Parent, WeightLimit, @@ -66,7 +67,7 @@ where AccountIdOf: From + Into, ::RuntimeEvent: From>, { - fn on_unbalanceds( + fn on_unbalanceds( mut fees_then_tips: impl Iterator< Item = fungible::Credit>, >, diff --git a/cumulus/parachains/common/src/lib.rs b/cumulus/parachains/common/src/lib.rs index b01d623d2b93da529f37bbfd8cf139ea5b98d9ae..3cffb69daac3fae6d5729a985489433f442bf22c 100644 --- a/cumulus/parachains/common/src/lib.rs +++ b/cumulus/parachains/common/src/lib.rs @@ -15,6 +15,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + pub mod impls; pub mod message_queue; pub mod xcm_config; diff --git a/cumulus/parachains/common/src/message_queue.rs b/cumulus/parachains/common/src/message_queue.rs index 0c9f4b840c9166ba9380f06970ad15bb1cac14c6..511d6243cb8c47a0e137f9eec03bbb1afdf5e644 100644 --- a/cumulus/parachains/common/src/message_queue.rs +++ b/cumulus/parachains/common/src/message_queue.rs @@ -16,10 +16,10 @@ //! Helpers to deal with configuring the message queue in the runtime. +use core::marker::PhantomData; use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::traits::{QueueFootprint, QueuePausedQuery}; use pallet_message_queue::OnQueueChanged; -use sp_std::marker::PhantomData; /// Narrow the scope of the `Inner` query from `AggregateMessageOrigin` to `ParaId`. /// diff --git a/cumulus/parachains/common/src/xcm_config.rs b/cumulus/parachains/common/src/xcm_config.rs index a9756af7aed245ea792d12addbbb2fff529eedaf..7c58a2b2405c73477b0b88b95f99af870fdb5c90 100644 --- a/cumulus/parachains/common/src/xcm_config.rs +++ b/cumulus/parachains/common/src/xcm_config.rs @@ -14,13 +14,13 @@ // limitations under the License. use crate::impls::AccountIdOf; +use core::marker::PhantomData; use cumulus_primitives_core::{IsSystem, ParaId}; use frame_support::{ traits::{fungibles::Inspect, tokens::ConversionToAssetBalance, Contains, ContainsPair}, weights::Weight, }; use sp_runtime::traits::Get; -use sp_std::marker::PhantomData; use xcm::latest::prelude::*; /// A `ChargeFeeInFungibles` implementation that converts the output of diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml index 8100e681348836fb28c9236b9ba20d27f117d71b..7bd91ae6774c61f93b12a91af298e64777980ac1 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml @@ -13,16 +13,16 @@ workspace = true [dependencies] # Substrate -sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } -frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } +sp-core = { workspace = true } +frame-support = { workspace = true } # Cumulus -parachains-common = { path = "../../../../../../common" } -cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } -emulated-integration-tests-common = { path = "../../../../common", default-features = false } -asset-hub-rococo-runtime = { path = "../../../../../../runtimes/assets/asset-hub-rococo" } -rococo-emulated-chain = { path = "../../../relays/rococo" } -testnet-parachains-constants = { path = "../../../../../../runtimes/constants", features = ["rococo"] } +parachains-common = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true } +emulated-integration-tests-common = { workspace = true } +asset-hub-rococo-runtime = { workspace = true, default-features = true } +rococo-emulated-chain = { workspace = true } +testnet-parachains-constants = { features = ["rococo"], workspace = true, default-features = true } # Polkadot -xcm = { package = "staging-xcm", path = "../../../../../../../../polkadot/xcm", default-features = false } +xcm = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs index e5378b35f5e484e10db94c66bc5244099b682604..3a87322664d91edb829b44603122c300602f2978 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs @@ -21,7 +21,7 @@ use sp_core::{sr25519, storage::Storage}; use emulated_integration_tests_common::{ accounts, build_genesis_storage, collators, get_account_id_from_seed, PenpalSiblingSovereignAccount, PenpalTeleportableAssetLocation, RESERVABLE_ASSET_ID, - SAFE_XCM_VERSION, + SAFE_XCM_VERSION, USDT_ID, }; use parachains_common::{AccountId, Balance}; @@ -68,7 +68,10 @@ pub fn genesis() -> Storage { ..Default::default() }, assets: asset_hub_rococo_runtime::AssetsConfig { - assets: vec![(RESERVABLE_ASSET_ID, AssetHubRococoAssetOwner::get(), true, ED)], + assets: vec![ + (RESERVABLE_ASSET_ID, AssetHubRococoAssetOwner::get(), true, ED), + (USDT_ID, AssetHubRococoAssetOwner::get(), true, ED), + ], ..Default::default() }, foreign_assets: asset_hub_rococo_runtime::ForeignAssetsConfig { diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs index 202d02b250bb2e90261a01c13c6aab59c674b511..80d2376c6811d7e8f407330dd3c2b02a5260159b 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs @@ -13,6 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +pub use asset_hub_rococo_runtime; + pub mod genesis; // Substrate diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml index e0abaa66c5cabba445b91c19436f9a4ce3642386..86d4ce3e7ac829e959aa3169adbd22a257cc26a5 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml @@ -13,16 +13,16 @@ workspace = true [dependencies] # Substrate -sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } -frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } +sp-core = { workspace = true } +frame-support = { workspace = true } # Cumulus -parachains-common = { path = "../../../../../../common" } -cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } -emulated-integration-tests-common = { path = "../../../../common", default-features = false } -asset-hub-westend-runtime = { path = "../../../../../../runtimes/assets/asset-hub-westend" } -westend-emulated-chain = { path = "../../../relays/westend" } -testnet-parachains-constants = { path = "../../../../../../runtimes/constants", features = ["westend"] } +parachains-common = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true } +emulated-integration-tests-common = { workspace = true } +asset-hub-westend-runtime = { workspace = true } +westend-emulated-chain = { workspace = true, default-features = true } +testnet-parachains-constants = { features = ["westend"], workspace = true, default-features = true } # Polkadot -xcm = { package = "staging-xcm", path = "../../../../../../../../polkadot/xcm", default-features = false } +xcm = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs index 6043a6aeda48f1e1ec010ac42e98a50feaae3a30..608690218d2f4c439511e508e261fe3e74d37465 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs @@ -13,6 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +pub use asset_hub_westend_runtime; + pub mod genesis; // Substrate diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml index 789f10a35f268c62e0cc9fa153c99e7e5282ee8d..f3c0799ad0f6acf14b3e99d4e27e46921c4e9cb9 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml @@ -13,12 +13,12 @@ workspace = true [dependencies] # Substrate -sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } -frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } +sp-core = { workspace = true } +frame-support = { workspace = true } # Cumulus -parachains-common = { path = "../../../../../../common" } -emulated-integration-tests-common = { path = "../../../../common", default-features = false } -bridge-hub-rococo-runtime = { path = "../../../../../../runtimes/bridge-hubs/bridge-hub-rococo" } -bridge-hub-common = { path = "../../../../../../runtimes/bridge-hubs/common", default-features = false } -testnet-parachains-constants = { path = "../../../../../../runtimes/constants", features = ["rococo"] } +parachains-common = { workspace = true, default-features = true } +emulated-integration-tests-common = { workspace = true } +bridge-hub-rococo-runtime = { workspace = true, default-features = true } +bridge-hub-common = { workspace = true } +testnet-parachains-constants = { features = ["rococo"], workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs index 8c18d112bc12fb4883d313106fa66841dcad8d2e..5ef0993f70a1ce33daa68ec23b474716e6bee956 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs @@ -15,6 +15,12 @@ pub mod genesis; +pub use bridge_hub_rococo_runtime::{ + xcm_config::XcmConfig as BridgeHubRococoXcmConfig, EthereumBeaconClient, EthereumInboundQueue, + ExistentialDeposit as BridgeHubRococoExistentialDeposit, + RuntimeOrigin as BridgeHubRococoRuntimeOrigin, +}; + // Substrate use frame_support::traits::OnInitialize; diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml index d82971cf55aeddf20032be952b8a980014434f6b..ebcec9641e7d9f122f5b6737769bc140d9c877a5 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml @@ -13,12 +13,12 @@ workspace = true [dependencies] # Substrate -sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } -frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } +sp-core = { workspace = true } +frame-support = { workspace = true } # Cumulus -parachains-common = { path = "../../../../../../common" } -emulated-integration-tests-common = { path = "../../../../common", default-features = false } -bridge-hub-westend-runtime = { path = "../../../../../../runtimes/bridge-hubs/bridge-hub-westend" } -bridge-hub-common = { path = "../../../../../../runtimes/bridge-hubs/common", default-features = false } -testnet-parachains-constants = { path = "../../../../../../runtimes/constants", features = ["westend"] } +parachains-common = { workspace = true, default-features = true } +emulated-integration-tests-common = { workspace = true } +bridge-hub-westend-runtime = { workspace = true, default-features = true } +bridge-hub-common = { workspace = true } +testnet-parachains-constants = { features = ["westend"], workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs index b0dddc9dbf9a5b71a776e3ae48b97bbb9f29adf2..feb59c411c8df488c748fe79e3fd485757fd0de0 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs @@ -15,6 +15,11 @@ pub mod genesis; +pub use bridge_hub_westend_runtime::{ + xcm_config::XcmConfig as BridgeHubWestendXcmConfig, + ExistentialDeposit as BridgeHubWestendExistentialDeposit, +}; + // Substrate use frame_support::traits::OnInitialize; diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml index 4c2a7d3c274dce6eade9c9d42be00301bd6dc462..87dfd73ab05bab063bedeebae9feb03bcc4af46f 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml @@ -13,12 +13,12 @@ workspace = true [dependencies] # Substrate -sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } -frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } +sp-core = { workspace = true } +frame-support = { workspace = true } # Cumulus -parachains-common = { path = "../../../../../../common" } -cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } -emulated-integration-tests-common = { path = "../../../../common", default-features = false } -collectives-westend-runtime = { path = "../../../../../../runtimes/collectives/collectives-westend" } -testnet-parachains-constants = { path = "../../../../../../runtimes/constants", features = ["westend"] } +parachains-common = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true } +emulated-integration-tests-common = { workspace = true } +collectives-westend-runtime = { workspace = true } +testnet-parachains-constants = { features = ["westend"], workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/lib.rs index a32e865dd9ce8497755a261c6922273aea8b49f6..f90d82231a3bb1ea64cfb6acad2759bcd486f1f9 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/lib.rs @@ -13,6 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +pub use collectives_westend_runtime; + pub mod genesis; // Substrate diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..6af3f270a905f504b471374d0b29687f766409e4 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "coretime-rococo-emulated-chain" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Coretime Rococo emulated chain" +publish = false + +[lints] +workspace = true + +[dependencies] + +# Substrate +sp-core = { workspace = true } +frame-support = { workspace = true } + +# Cumulus +parachains-common = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true } +coretime-rococo-runtime = { workspace = true, default-features = true } +emulated-integration-tests-common = { workspace = true } +testnet-parachains-constants = { features = ["rococo"], workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/src/genesis.rs new file mode 100644 index 0000000000000000000000000000000000000000..f72de52c4932474243f1bb06b775145df11779b6 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/src/genesis.rs @@ -0,0 +1,66 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Substrate +use sp_core::storage::Storage; + +// Cumulus +use emulated_integration_tests_common::{ + accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, +}; +use parachains_common::Balance; + +pub const PARA_ID: u32 = 1005; +pub const ED: Balance = testnet_parachains_constants::rococo::currency::EXISTENTIAL_DEPOSIT; + +pub fn genesis() -> Storage { + let genesis_config = coretime_rococo_runtime::RuntimeGenesisConfig { + system: coretime_rococo_runtime::SystemConfig::default(), + balances: coretime_rococo_runtime::BalancesConfig { + balances: accounts::init_balances().iter().cloned().map(|k| (k, ED * 4096)).collect(), + }, + parachain_info: coretime_rococo_runtime::ParachainInfoConfig { + parachain_id: PARA_ID.into(), + ..Default::default() + }, + collator_selection: coretime_rococo_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: coretime_rococo_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + coretime_rococo_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + polkadot_xcm: coretime_rococo_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + ..Default::default() + }; + + build_genesis_storage( + &genesis_config, + coretime_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), + ) +} diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..a15303a22e12d44020364fe173000ad4ded467d8 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/src/lib.rs @@ -0,0 +1,53 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub use coretime_rococo_runtime; + +pub mod genesis; + +// Substrate +use frame_support::traits::OnInitialize; + +// Cumulus +use emulated_integration_tests_common::{ + impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, + impls::Parachain, xcm_emulator::decl_test_parachains, +}; + +// CoretimeRococo Parachain declaration +decl_test_parachains! { + pub struct CoretimeRococo { + genesis = genesis::genesis(), + on_init = { + coretime_rococo_runtime::AuraExt::on_initialize(1); + }, + runtime = coretime_rococo_runtime, + core = { + XcmpMessageHandler: coretime_rococo_runtime::XcmpQueue, + LocationToAccountId: coretime_rococo_runtime::xcm_config::LocationToAccountId, + ParachainInfo: coretime_rococo_runtime::ParachainInfo, + MessageOrigin: cumulus_primitives_core::AggregateMessageOrigin, + }, + pallets = { + PolkadotXcm: coretime_rococo_runtime::PolkadotXcm, + Balances: coretime_rococo_runtime::Balances, + Broker: coretime_rococo_runtime::Broker, + } + }, +} + +// CoretimeRococo implementation +impl_accounts_helpers_for_parachain!(CoretimeRococo); +impl_assert_events_helpers_for_parachain!(CoretimeRococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..895a984eccb2d049d849f8cf65b44cc667990e4f --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "coretime-westend-emulated-chain" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Coretime Westend emulated chain" +publish = false + +[lints] +workspace = true + +[dependencies] + +# Substrate +sp-core = { workspace = true } +frame-support = { workspace = true } + +# Cumulus +parachains-common = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true } +coretime-westend-runtime = { workspace = true, default-features = true } +emulated-integration-tests-common = { workspace = true } +testnet-parachains-constants = { features = ["westend"], workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/src/genesis.rs new file mode 100644 index 0000000000000000000000000000000000000000..222ffe7a63ab48d007496db31114b769a335b7bb --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/src/genesis.rs @@ -0,0 +1,66 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Substrate +use sp_core::storage::Storage; + +// Cumulus +use emulated_integration_tests_common::{ + accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, +}; +use parachains_common::Balance; + +pub const PARA_ID: u32 = 1005; +pub const ED: Balance = testnet_parachains_constants::westend::currency::EXISTENTIAL_DEPOSIT; + +pub fn genesis() -> Storage { + let genesis_config = coretime_westend_runtime::RuntimeGenesisConfig { + system: coretime_westend_runtime::SystemConfig::default(), + balances: coretime_westend_runtime::BalancesConfig { + balances: accounts::init_balances().iter().cloned().map(|k| (k, ED * 4096)).collect(), + }, + parachain_info: coretime_westend_runtime::ParachainInfoConfig { + parachain_id: PARA_ID.into(), + ..Default::default() + }, + collator_selection: coretime_westend_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: coretime_westend_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + coretime_westend_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + polkadot_xcm: coretime_westend_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + ..Default::default() + }; + + build_genesis_storage( + &genesis_config, + coretime_westend_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), + ) +} diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..41949843b02be666c7c95a404ed89326f2e59983 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/src/lib.rs @@ -0,0 +1,53 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub use coretime_westend_runtime; + +pub mod genesis; + +// Substrate +use frame_support::traits::OnInitialize; + +// Cumulus +use emulated_integration_tests_common::{ + impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, + impls::Parachain, xcm_emulator::decl_test_parachains, +}; + +// CoretimeWestend Parachain declaration +decl_test_parachains! { + pub struct CoretimeWestend { + genesis = genesis::genesis(), + on_init = { + coretime_westend_runtime::AuraExt::on_initialize(1); + }, + runtime = coretime_westend_runtime, + core = { + XcmpMessageHandler: coretime_westend_runtime::XcmpQueue, + LocationToAccountId: coretime_westend_runtime::xcm_config::LocationToAccountId, + ParachainInfo: coretime_westend_runtime::ParachainInfo, + MessageOrigin: cumulus_primitives_core::AggregateMessageOrigin, + }, + pallets = { + PolkadotXcm: coretime_westend_runtime::PolkadotXcm, + Balances: coretime_westend_runtime::Balances, + Broker: coretime_westend_runtime::Broker, + } + }, +} + +// CoretimeWestend implementation +impl_accounts_helpers_for_parachain!(CoretimeWestend); +impl_assert_events_helpers_for_parachain!(CoretimeWestend); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/Cargo.toml index f7fe93d27775a28cb560d8791a3b0d8ed49c9d68..1549d6a2ab6ba1de05d9233ff7bc29951501a43d 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/Cargo.toml @@ -10,12 +10,12 @@ publish = false [dependencies] # Substrate -sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } -frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } +sp-core = { workspace = true } +frame-support = { workspace = true } # Cumulus -parachains-common = { path = "../../../../../../common" } -cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } -emulated-integration-tests-common = { path = "../../../../common", default-features = false } -people-rococo-runtime = { path = "../../../../../../runtimes/people/people-rococo" } -testnet-parachains-constants = { path = "../../../../../../runtimes/constants", features = ["rococo"] } +parachains-common = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true } +emulated-integration-tests-common = { workspace = true } +people-rococo-runtime = { workspace = true } +testnet-parachains-constants = { features = ["rococo"], workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/src/lib.rs index fa818bf81bf60ac6358c1c983faf8657cb139dd3..c8da97cc3e8bf6371ddcb2d6a122f06fb80cb518 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/src/lib.rs @@ -12,6 +12,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +pub use people_rococo_runtime; pub mod genesis; diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/Cargo.toml index 57a767e0c2a3eb7d23df7f8d95fd78128c996f35..9c5ac0bca9de7ae2f201aba958b8220b9a24a013 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/Cargo.toml @@ -10,12 +10,12 @@ publish = false [dependencies] # Substrate -sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } -frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } +sp-core = { workspace = true } +frame-support = { workspace = true } # Cumulus -parachains-common = { path = "../../../../../../common" } -cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } -emulated-integration-tests-common = { path = "../../../../common", default-features = false } -people-westend-runtime = { path = "../../../../../../runtimes/people/people-westend" } -testnet-parachains-constants = { path = "../../../../../../runtimes/constants", features = ["westend"] } +parachains-common = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true } +emulated-integration-tests-common = { workspace = true } +people-westend-runtime = { workspace = true } +testnet-parachains-constants = { features = ["westend"], workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/src/lib.rs index 775b89ac208b022f898c7c54423e8a21b7214ae3..904ce34d8c08a63500a1b3c815b8d1c469a89861 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/src/lib.rs @@ -12,6 +12,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +pub use people_westend_runtime; pub mod genesis; diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml index 2ac508273c6158ddae08615d8574102f98e3e788..9e6b14b585984d9b384f835f1b51f8a3e2e658a8 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml @@ -13,14 +13,14 @@ workspace = true [dependencies] # Substrate -sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } -frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } +sp-core = { workspace = true } +frame-support = { workspace = true } # Polkadot -xcm = { package = "staging-xcm", path = "../../../../../../../../polkadot/xcm", default-features = false } +xcm = { workspace = true } # Cumulus -parachains-common = { path = "../../../../../../common" } -cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } -emulated-integration-tests-common = { path = "../../../../common", default-features = false } -penpal-runtime = { path = "../../../../../../runtimes/testing/penpal" } +parachains-common = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true } +emulated-integration-tests-common = { workspace = true } +penpal-runtime = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs index c268b014bfa34e1b8c0a450ae2e446bb6f636c9d..91793d33f304fbbf4d1d2aeea0bf315730a5794f 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs @@ -13,11 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +pub use penpal_runtime::{self, xcm_config::RelayNetworkId as PenpalRelayNetworkId}; + mod genesis; pub use genesis::{genesis, PenpalAssetOwner, PenpalSudoAccount, ED, PARA_ID_A, PARA_ID_B}; -pub use penpal_runtime::xcm_config::{ - CustomizableAssetFromSystemAssetHub, RelayNetworkId as PenpalRelayNetworkId, -}; // Substrate use frame_support::traits::OnInitialize; diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml index 113036b4c00ea697507166a1f1da8d44458bacdd..9376687947e6c3683d5c1c58fdaf77452fd01449 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml @@ -13,17 +13,17 @@ workspace = true [dependencies] # Substrate -sp-core = { path = "../../../../../../../substrate/primitives/core", default-features = false } -sp-authority-discovery = { path = "../../../../../../../substrate/primitives/authority-discovery", default-features = false } -sp-consensus-babe = { path = "../../../../../../../substrate/primitives/consensus/babe", default-features = false } -sp-consensus-beefy = { path = "../../../../../../../substrate/primitives/consensus/beefy" } -sc-consensus-grandpa = { path = "../../../../../../../substrate/client/consensus/grandpa", default-features = false } +sp-core = { workspace = true } +sp-authority-discovery = { workspace = true } +sp-consensus-babe = { workspace = true } +sp-consensus-beefy = { workspace = true, default-features = true } +sc-consensus-grandpa = { workspace = true } # Polkadot -polkadot-primitives = { path = "../../../../../../../polkadot/primitives", default-features = false } -rococo-runtime-constants = { path = "../../../../../../../polkadot/runtime/rococo/constants", default-features = false } -rococo-runtime = { path = "../../../../../../../polkadot/runtime/rococo" } +polkadot-primitives = { workspace = true } +rococo-runtime-constants = { workspace = true } +rococo-runtime = { workspace = true } # Cumulus -parachains-common = { path = "../../../../../common" } -emulated-integration-tests-common = { path = "../../../common", default-features = false } +parachains-common = { workspace = true, default-features = true } +emulated-integration-tests-common = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs index 7a3a936ec972f0a8c99e3b472c7cce9e9914e29c..bd637a5f7965bca47b171283bb37473b009bdbc1 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs @@ -12,6 +12,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +pub use rococo_runtime; pub mod genesis; diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml index b952477c47a7c33277d9cd6bf09ea7a2ba1dd799..de285d9885a2f78fdea1a27ea8b8d9dc3840d300 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml @@ -13,21 +13,21 @@ workspace = true [dependencies] # Substrate -sp-core = { path = "../../../../../../../substrate/primitives/core", default-features = false } -sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } -sp-authority-discovery = { path = "../../../../../../../substrate/primitives/authority-discovery", default-features = false } -sp-consensus-babe = { path = "../../../../../../../substrate/primitives/consensus/babe", default-features = false } -sp-consensus-beefy = { path = "../../../../../../../substrate/primitives/consensus/beefy" } -sc-consensus-grandpa = { path = "../../../../../../../substrate/client/consensus/grandpa", default-features = false } -pallet-staking = { path = "../../../../../../../substrate/frame/staking", default-features = false } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-authority-discovery = { workspace = true } +sp-consensus-babe = { workspace = true } +sp-consensus-beefy = { workspace = true, default-features = true } +sc-consensus-grandpa = { workspace = true } +pallet-staking = { workspace = true } # Polkadot -polkadot-primitives = { path = "../../../../../../../polkadot/primitives", default-features = false } -westend-runtime-constants = { path = "../../../../../../../polkadot/runtime/westend/constants", default-features = false } -westend-runtime = { path = "../../../../../../../polkadot/runtime/westend" } -xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } -xcm-fee-payment-runtime-api = { path = "../../../../../../../polkadot/xcm/xcm-fee-payment-runtime-api", default-features = false } +polkadot-primitives = { workspace = true } +westend-runtime-constants = { workspace = true } +westend-runtime = { workspace = true } +xcm = { workspace = true } +xcm-runtime-apis = { workspace = true } # Cumulus -parachains-common = { path = "../../../../../common" } -emulated-integration-tests-common = { path = "../../../common", default-features = false } +parachains-common = { workspace = true, default-features = true } +emulated-integration-tests-common = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs index 83af58f61732d7c0e545c365ab2d049125f3777e..ce9fafcd5bda8bd815d197b7e4a1ee70f6eb426c 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs @@ -12,6 +12,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +pub use westend_runtime; pub mod genesis; diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index d9ec813232309998e8e50557138773d14c65c04b..7152f1dbc272bd8eef49e2343b2c5cbbeb9f1ba4 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -10,37 +10,37 @@ description = "Common resources for integration testing with xcm-emulator" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -paste = "1.0.14" +codec = { workspace = true } +paste = { workspace = true, default-features = true } # Substrate -sp-consensus-beefy = { path = "../../../../../substrate/primitives/consensus/beefy" } -sc-consensus-grandpa = { path = "../../../../../substrate/client/consensus/grandpa" } -sp-authority-discovery = { path = "../../../../../substrate/primitives/authority-discovery" } -sp-runtime = { path = "../../../../../substrate/primitives/runtime" } -frame-support = { path = "../../../../../substrate/frame/support" } -sp-core = { path = "../../../../../substrate/primitives/core" } -sp-consensus-babe = { path = "../../../../../substrate/primitives/consensus/babe" } -pallet-assets = { path = "../../../../../substrate/frame/assets" } -pallet-balances = { path = "../../../../../substrate/frame/balances" } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue" } +sp-consensus-beefy = { workspace = true, default-features = true } +sc-consensus-grandpa = { workspace = true, default-features = true } +sp-authority-discovery = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +frame-support = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +pallet-assets = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +pallet-message-queue = { workspace = true, default-features = true } # Polkadot -polkadot-primitives = { path = "../../../../../polkadot/primitives" } -polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain" } -polkadot-runtime-parachains = { path = "../../../../../polkadot/runtime/parachains" } -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm" } -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm" } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } +xcm = { workspace = true, default-features = true } +pallet-xcm = { workspace = true, default-features = true } # Cumulus -parachains-common = { path = "../../../common" } -cumulus-primitives-core = { path = "../../../../primitives/core" } -xcm-emulator = { path = "../../../../xcm/xcm-emulator" } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue" } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system" } -asset-test-utils = { path = "../../../runtimes/assets/test-utils" } +parachains-common = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true, default-features = true } +xcm-emulator = { workspace = true, default-features = true } +cumulus-pallet-xcmp-queue = { workspace = true, default-features = true } +cumulus-pallet-parachain-system = { workspace = true, default-features = true } +asset-test-utils = { workspace = true, default-features = true } # Bridges -bp-messages = { path = "../../../../../bridges/primitives/messages" } -pallet-bridge-messages = { path = "../../../../../bridges/modules/messages" } -bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common" } +bp-messages = { workspace = true, default-features = true } +pallet-bridge-messages = { workspace = true, default-features = true } +bridge-runtime-common = { workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 4a9d3b3a5aaf5bb885bf4fa92759f67f9165a85a..7077fbbb0a9aa2d1b572720da448ccae2fe95f03 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -51,11 +51,14 @@ pub const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; type AccountPublic = ::Signer; -// This asset is added to AH as Asset and reserved transfer between Parachain and AH +// (trust-backed) Asset registered on AH and reserve-transferred between Parachain and AH pub const RESERVABLE_ASSET_ID: u32 = 1; -// This asset is added to AH as ForeignAsset and teleported between Penpal and AH +// ForeignAsset registered on AH and teleported between Penpal and AH pub const TELEPORTABLE_ASSET_ID: u32 = 2; +// USDT registered on AH as (trust-backed) Asset and reserve-transferred between Parachain and AH +pub const USDT_ID: u32 = 1984; + pub const PENPAL_ID: u32 = 2000; pub const ASSETS_PALLET_ID: u8 = 50; diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index 6f6bbe41e01bd208ee6d40a9f3b4ba8f98f7975b..b11adacbde5cb6ddfbdf7cf9a1c192aa20ef7584 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -27,7 +27,7 @@ pub use xcm::{ prelude::{ AccountId32, All, Asset, AssetId, BuyExecution, DepositAsset, ExpectTransactStatus, Fungible, Here, Location, MaybeErrorCode, OriginKind, RefundSurplus, Transact, Unlimited, - VersionedXcm, WeightLimit, WithdrawAsset, Xcm, + VersionedAssets, VersionedXcm, WeightLimit, WithdrawAsset, Xcm, }, v3::Location as V3Location, }; @@ -130,3 +130,279 @@ macro_rules! test_parachain_is_trusted_teleporter { } }; } + +#[macro_export] +macro_rules! test_relay_is_trusted_teleporter { + ( $sender_relay:ty, $sender_xcm_config:ty, vec![$( $receiver_para:ty ),+], ($assets:expr, $amount:expr) ) => { + $crate::macros::paste::paste! { + // init Origin variables + let sender = [<$sender_relay Sender>]::get(); + let mut relay_sender_balance_before = + <$sender_relay as $crate::macros::Chain>::account_data_of(sender.clone()).free; + let origin = <$sender_relay as $crate::macros::Chain>::RuntimeOrigin::signed(sender.clone()); + let fee_asset_item = 0; + let weight_limit = $crate::macros::WeightLimit::Unlimited; + + $( + { + // init Destination variables + let receiver = [<$receiver_para Receiver>]::get(); + let para_receiver_balance_before = + <$receiver_para as $crate::macros::Chain>::account_data_of(receiver.clone()).free; + let para_destination = + <$sender_relay>::child_location_of(<$receiver_para>::para_id()); + let beneficiary: Location = + $crate::macros::AccountId32 { network: None, id: receiver.clone().into() }.into(); + + // Send XCM message from Relay + <$sender_relay>::execute_with(|| { + assert_ok!(<$sender_relay as [<$sender_relay Pallet>]>::XcmPallet::limited_teleport_assets( + origin.clone(), + bx!(para_destination.clone().into()), + bx!(beneficiary.clone().into()), + bx!($assets.clone().into()), + fee_asset_item, + weight_limit.clone(), + )); + + type RuntimeEvent = <$sender_relay as $crate::macros::Chain>::RuntimeEvent; + + assert_expected_events!( + $sender_relay, + vec![ + RuntimeEvent::XcmPallet( + $crate::macros::pallet_xcm::Event::Attempted { outcome: Outcome::Complete { .. } } + ) => {}, + RuntimeEvent::Balances( + $crate::macros::pallet_balances::Event::Burned { who: sender, amount } + ) => {}, + RuntimeEvent::XcmPallet( + $crate::macros::pallet_xcm::Event::Sent { .. } + ) => {}, + ] + ); + }); + + // Receive XCM message in Destination Parachain + <$receiver_para>::execute_with(|| { + type RuntimeEvent = <$receiver_para as $crate::macros::Chain>::RuntimeEvent; + + assert_expected_events!( + $receiver_para, + vec![ + RuntimeEvent::Balances( + $crate::macros::pallet_balances::Event::Minted { who: receiver, .. } + ) => {}, + RuntimeEvent::MessageQueue( + $crate::macros::pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + + // Check if balances are updated accordingly in Origin and Parachain + let relay_sender_balance_after = + <$sender_relay as $crate::macros::Chain>::account_data_of(sender.clone()).free; + let para_receiver_balance_after = + <$receiver_para as $crate::macros::Chain>::account_data_of(receiver.clone()).free; + let delivery_fees = <$sender_relay>::execute_with(|| { + $crate::macros::asset_test_utils::xcm_helpers::teleport_assets_delivery_fees::< + <$sender_xcm_config as xcm_executor::Config>::XcmSender, + >($assets.clone(), fee_asset_item, weight_limit.clone(), beneficiary, para_destination) + }); + + assert_eq!(relay_sender_balance_before - $amount - delivery_fees, relay_sender_balance_after); + assert!(para_receiver_balance_after > para_receiver_balance_before); + + // Update sender balance + relay_sender_balance_before = <$sender_relay as $crate::macros::Chain>::account_data_of(sender.clone()).free; + } + )+ + } + }; +} + +#[macro_export] +macro_rules! test_parachain_is_trusted_teleporter_for_relay { + ( $sender_para:ty, $sender_xcm_config:ty, $receiver_relay:ty, $amount:expr ) => { + $crate::macros::paste::paste! { + // init Origin variables + let sender = [<$sender_para Sender>]::get(); + let mut para_sender_balance_before = + <$sender_para as $crate::macros::Chain>::account_data_of(sender.clone()).free; + let origin = <$sender_para as $crate::macros::Chain>::RuntimeOrigin::signed(sender.clone()); + let assets: Assets = (Parent, $amount).into(); + let fee_asset_item = 0; + let weight_limit = $crate::macros::WeightLimit::Unlimited; + + // init Destination variables + let receiver = [<$receiver_relay Receiver>]::get(); + let relay_receiver_balance_before = + <$receiver_relay as $crate::macros::Chain>::account_data_of(receiver.clone()).free; + let relay_destination: Location = Parent.into(); + let beneficiary: Location = + $crate::macros::AccountId32 { network: None, id: receiver.clone().into() }.into(); + + // Send XCM message from Parachain + <$sender_para>::execute_with(|| { + assert_ok!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::limited_teleport_assets( + origin.clone(), + bx!(relay_destination.clone().into()), + bx!(beneficiary.clone().into()), + bx!(assets.clone().into()), + fee_asset_item, + weight_limit.clone(), + )); + + type RuntimeEvent = <$sender_para as $crate::macros::Chain>::RuntimeEvent; + + assert_expected_events!( + $sender_para, + vec![ + RuntimeEvent::PolkadotXcm( + $crate::macros::pallet_xcm::Event::Attempted { outcome: Outcome::Complete { .. } } + ) => {}, + RuntimeEvent::Balances( + $crate::macros::pallet_balances::Event::Burned { who: sender, amount } + ) => {}, + RuntimeEvent::PolkadotXcm( + $crate::macros::pallet_xcm::Event::Sent { .. } + ) => {}, + ] + ); + }); + + // Receive XCM message in Destination Parachain + <$receiver_relay>::execute_with(|| { + type RuntimeEvent = <$receiver_relay as $crate::macros::Chain>::RuntimeEvent; + + assert_expected_events!( + $receiver_relay, + vec![ + RuntimeEvent::Balances( + $crate::macros::pallet_balances::Event::Minted { who: receiver, .. } + ) => {}, + RuntimeEvent::MessageQueue( + $crate::macros::pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + + // Check if balances are updated accordingly in Origin and Relay Chain + let para_sender_balance_after = + <$sender_para as $crate::macros::Chain>::account_data_of(sender.clone()).free; + let relay_receiver_balance_after = + <$receiver_relay as $crate::macros::Chain>::account_data_of(receiver.clone()).free; + let delivery_fees = <$sender_para>::execute_with(|| { + $crate::macros::asset_test_utils::xcm_helpers::teleport_assets_delivery_fees::< + <$sender_xcm_config as xcm_executor::Config>::XcmSender, + >(assets, fee_asset_item, weight_limit.clone(), beneficiary, relay_destination) + }); + + assert_eq!(para_sender_balance_before - $amount - delivery_fees, para_sender_balance_after); + assert!(relay_receiver_balance_after > relay_receiver_balance_before); + + // Update sender balance + para_sender_balance_before = <$sender_para as $crate::macros::Chain>::account_data_of(sender.clone()).free; + } + }; +} + +#[macro_export] +macro_rules! test_chain_can_claim_assets { + ( $sender_para:ty, $runtime_call:ty, $network_id:expr, $assets:expr, $amount:expr ) => { + $crate::macros::paste::paste! { + let sender = [<$sender_para Sender>]::get(); + let origin = <$sender_para as $crate::macros::Chain>::RuntimeOrigin::signed(sender.clone()); + // Receiver is the same as sender + let beneficiary: Location = + $crate::macros::AccountId32 { network: Some($network_id), id: sender.clone().into() }.into(); + let versioned_assets: $crate::macros::VersionedAssets = $assets.clone().into(); + + <$sender_para>::execute_with(|| { + // Assets are trapped for whatever reason. + // The possible reasons for this might differ from runtime to runtime, so here we just drop them directly. + <$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::drop_assets( + &beneficiary, + $assets.clone().into(), + &XcmContext { origin: None, message_id: [0u8; 32], topic: None }, + ); + + type RuntimeEvent = <$sender_para as $crate::macros::Chain>::RuntimeEvent; + assert_expected_events!( + $sender_para, + vec![ + RuntimeEvent::PolkadotXcm( + $crate::macros::pallet_xcm::Event::AssetsTrapped { origin: beneficiary, assets: versioned_assets, .. } + ) => {}, + ] + ); + + let balance_before = <$sender_para as [<$sender_para Pallet>]>::Balances::free_balance(&sender); + + // Different origin or different assets won't work. + let other_origin = <$sender_para as $crate::macros::Chain>::RuntimeOrigin::signed([<$sender_para Receiver>]::get()); + assert!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::claim_assets( + other_origin, + bx!(versioned_assets.clone().into()), + bx!(beneficiary.clone().into()), + ).is_err()); + let other_versioned_assets: $crate::macros::VersionedAssets = Assets::new().into(); + assert!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::claim_assets( + origin.clone(), + bx!(other_versioned_assets.into()), + bx!(beneficiary.clone().into()), + ).is_err()); + + // Assets will be claimed to `beneficiary`, which is the same as `sender`. + assert_ok!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::claim_assets( + origin.clone(), + bx!(versioned_assets.clone().into()), + bx!(beneficiary.clone().into()), + )); + + assert_expected_events!( + $sender_para, + vec![ + RuntimeEvent::PolkadotXcm( + $crate::macros::pallet_xcm::Event::AssetsClaimed { origin: beneficiary, assets: versioned_assets, .. } + ) => {}, + ] + ); + + // After claiming the assets, the balance has increased. + let balance_after = <$sender_para as [<$sender_para Pallet>]>::Balances::free_balance(&sender); + assert_eq!(balance_after, balance_before + $amount); + + // Claiming the assets again doesn't work. + assert!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::claim_assets( + origin.clone(), + bx!(versioned_assets.clone().into()), + bx!(beneficiary.clone().into()), + ).is_err()); + + let balance = <$sender_para as [<$sender_para Pallet>]>::Balances::free_balance(&sender); + assert_eq!(balance, balance_after); + + // You can also claim assets and send them to a different account. + <$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::drop_assets( + &beneficiary, + $assets.clone().into(), + &XcmContext { origin: None, message_id: [0u8; 32], topic: None }, + ); + let receiver = [<$sender_para Receiver>]::get(); + let other_beneficiary: Location = + $crate::macros::AccountId32 { network: Some($network_id), id: receiver.clone().into() }.into(); + let balance_before = <$sender_para as [<$sender_para Pallet>]>::Balances::free_balance(&receiver); + assert_ok!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::claim_assets( + origin.clone(), + bx!(versioned_assets.clone().into()), + bx!(other_beneficiary.clone().into()), + )); + let balance_after = <$sender_para as [<$sender_para Pallet>]>::Balances::free_balance(&receiver); + assert_eq!(balance_after, balance_before + $amount); + }); + } + }; +} diff --git a/cumulus/parachains/integration-tests/emulated/networks/rococo-system/Cargo.toml b/cumulus/parachains/integration-tests/emulated/networks/rococo-system/Cargo.toml index eb0a8a850d06928d67147dc14a11f566d1ad7c9d..864f3c6edd7e3f91566666c65c509d2494009d4d 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/rococo-system/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/networks/rococo-system/Cargo.toml @@ -12,9 +12,10 @@ workspace = true [dependencies] # Cumulus -emulated-integration-tests-common = { path = "../../common", default-features = false } -rococo-emulated-chain = { path = "../../chains/relays/rococo" } -asset-hub-rococo-emulated-chain = { path = "../../chains/parachains/assets/asset-hub-rococo" } -bridge-hub-rococo-emulated-chain = { path = "../../chains/parachains/bridges/bridge-hub-rococo" } -people-rococo-emulated-chain = { path = "../../chains/parachains/people/people-rococo" } -penpal-emulated-chain = { path = "../../chains/parachains/testing/penpal" } +emulated-integration-tests-common = { workspace = true } +rococo-emulated-chain = { workspace = true } +asset-hub-rococo-emulated-chain = { workspace = true } +bridge-hub-rococo-emulated-chain = { workspace = true } +people-rococo-emulated-chain = { workspace = true } +penpal-emulated-chain = { workspace = true } +coretime-rococo-emulated-chain = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/networks/rococo-system/src/lib.rs b/cumulus/parachains/integration-tests/emulated/networks/rococo-system/src/lib.rs index 70f23ef8260ca408e55079e5797b09cc817872cd..53808bc5a8010128c6e490361127eadda56fecbb 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/rococo-system/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/networks/rococo-system/src/lib.rs @@ -15,12 +15,14 @@ pub use asset_hub_rococo_emulated_chain; pub use bridge_hub_rococo_emulated_chain; +pub use coretime_rococo_emulated_chain; pub use penpal_emulated_chain; pub use people_rococo_emulated_chain; pub use rococo_emulated_chain; use asset_hub_rococo_emulated_chain::AssetHubRococo; use bridge_hub_rococo_emulated_chain::BridgeHubRococo; +use coretime_rococo_emulated_chain::CoretimeRococo; use penpal_emulated_chain::{PenpalA, PenpalB}; use people_rococo_emulated_chain::PeopleRococo; use rococo_emulated_chain::Rococo; @@ -37,6 +39,7 @@ decl_test_networks! { parachains = vec![ AssetHubRococo, BridgeHubRococo, + CoretimeRococo, PenpalA, PenpalB, PeopleRococo, @@ -49,6 +52,7 @@ decl_test_sender_receiver_accounts_parameter_types! { RococoRelay { sender: ALICE, receiver: BOB }, AssetHubRococoPara { sender: ALICE, receiver: BOB }, BridgeHubRococoPara { sender: ALICE, receiver: BOB }, + CoretimeRococoPara { sender: ALICE, receiver: BOB }, PenpalAPara { sender: ALICE, receiver: BOB }, PenpalBPara { sender: ALICE, receiver: BOB }, PeopleRococoPara { sender: ALICE, receiver: BOB } diff --git a/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/Cargo.toml b/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/Cargo.toml index 744cbe4f8c1e31ed5a9b122a5b5939509234236a..cd0cb272b7f5ea9bea09835b7cf4612ad9c377be 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/Cargo.toml @@ -12,11 +12,11 @@ workspace = true [dependencies] # Cumulus -emulated-integration-tests-common = { path = "../../common", default-features = false } -rococo-emulated-chain = { path = "../../chains/relays/rococo" } -westend-emulated-chain = { path = "../../chains/relays/westend" } -asset-hub-rococo-emulated-chain = { path = "../../chains/parachains/assets/asset-hub-rococo" } -asset-hub-westend-emulated-chain = { path = "../../chains/parachains/assets/asset-hub-westend" } -bridge-hub-rococo-emulated-chain = { path = "../../chains/parachains/bridges/bridge-hub-rococo" } -bridge-hub-westend-emulated-chain = { path = "../../chains/parachains/bridges/bridge-hub-westend" } -penpal-emulated-chain = { path = "../../chains/parachains/testing/penpal" } +emulated-integration-tests-common = { workspace = true } +rococo-emulated-chain = { workspace = true } +westend-emulated-chain = { workspace = true, default-features = true } +asset-hub-rococo-emulated-chain = { workspace = true } +asset-hub-westend-emulated-chain = { workspace = true } +bridge-hub-rococo-emulated-chain = { workspace = true } +bridge-hub-westend-emulated-chain = { workspace = true } +penpal-emulated-chain = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml b/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml index 64bc91f442d1b27166fbc4f0a2dc22798c97ff39..cec2e3733b2a0fbe83608f75981e5c288c70ea7f 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml @@ -12,10 +12,11 @@ workspace = true [dependencies] # Cumulus -emulated-integration-tests-common = { path = "../../common", default-features = false } -westend-emulated-chain = { path = "../../chains/relays/westend", default-features = false } -asset-hub-westend-emulated-chain = { path = "../../chains/parachains/assets/asset-hub-westend" } -bridge-hub-westend-emulated-chain = { path = "../../chains/parachains/bridges/bridge-hub-westend" } -collectives-westend-emulated-chain = { path = "../../chains/parachains/collectives/collectives-westend" } -penpal-emulated-chain = { path = "../../chains/parachains/testing/penpal" } -people-westend-emulated-chain = { path = "../../chains/parachains/people/people-westend" } +emulated-integration-tests-common = { workspace = true } +westend-emulated-chain = { workspace = true } +asset-hub-westend-emulated-chain = { workspace = true } +bridge-hub-westend-emulated-chain = { workspace = true } +collectives-westend-emulated-chain = { workspace = true } +penpal-emulated-chain = { workspace = true } +people-westend-emulated-chain = { workspace = true } +coretime-westend-emulated-chain = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/networks/westend-system/src/lib.rs b/cumulus/parachains/integration-tests/emulated/networks/westend-system/src/lib.rs index 9fbc773bc50e136af3272e851f826d7cf63bc0b6..6949a985629d9cce5b774d3dce5a93e76d6e46c9 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/westend-system/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/networks/westend-system/src/lib.rs @@ -16,6 +16,7 @@ pub use asset_hub_westend_emulated_chain; pub use bridge_hub_westend_emulated_chain; pub use collectives_westend_emulated_chain; +pub use coretime_westend_emulated_chain; pub use penpal_emulated_chain; pub use people_westend_emulated_chain; pub use westend_emulated_chain; @@ -23,6 +24,7 @@ pub use westend_emulated_chain; use asset_hub_westend_emulated_chain::AssetHubWestend; use bridge_hub_westend_emulated_chain::BridgeHubWestend; use collectives_westend_emulated_chain::CollectivesWestend; +use coretime_westend_emulated_chain::CoretimeWestend; use penpal_emulated_chain::{PenpalA, PenpalB}; use people_westend_emulated_chain::PeopleWestend; use westend_emulated_chain::Westend; @@ -40,6 +42,7 @@ decl_test_networks! { AssetHubWestend, BridgeHubWestend, CollectivesWestend, + CoretimeWestend, PeopleWestend, PenpalA, PenpalB, @@ -53,6 +56,7 @@ decl_test_sender_receiver_accounts_parameter_types! { AssetHubWestendPara { sender: ALICE, receiver: BOB }, BridgeHubWestendPara { sender: ALICE, receiver: BOB }, CollectivesWestendPara { sender: ALICE, receiver: BOB }, + CoretimeWestendPara { sender: ALICE, receiver: BOB }, PeopleWestendPara { sender: ALICE, receiver: BOB }, PenpalAPara { sender: ALICE, receiver: BOB }, PenpalBPara { sender: ALICE, receiver: BOB } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml index 9abecbecc48a725448cfb17508351d5e76f848de..b4579da94cbf6fc6fbb5f5d0e47fdfabdb5134da 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml @@ -11,32 +11,29 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -assert_matches = "1.5.0" +codec = { workspace = true } +assert_matches = { workspace = true } # Substrate -sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } -frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false } -pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false } -pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false } -pallet-asset-conversion = { path = "../../../../../../../substrate/frame/asset-conversion", default-features = false } -pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false } -pallet-treasury = { path = "../../../../../../../substrate/frame/treasury", default-features = false } -pallet-utility = { path = "../../../../../../../substrate/frame/utility", default-features = false } +sp-runtime = { workspace = true } +frame-support = { workspace = true } +pallet-balances = { workspace = true } +pallet-assets = { workspace = true } +pallet-asset-conversion = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-treasury = { workspace = true } +pallet-utility = { workspace = true } # Polkadot -xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } -pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false } -rococo-runtime = { path = "../../../../../../../polkadot/runtime/rococo" } -polkadot-runtime-common = { path = "../../../../../../../polkadot/runtime/common" } -rococo-runtime-constants = { path = "../../../../../../../polkadot/runtime/rococo/constants" } +xcm = { workspace = true } +pallet-xcm = { workspace = true } +xcm-executor = { workspace = true } +polkadot-runtime-common = { workspace = true, default-features = true } +rococo-runtime-constants = { workspace = true, default-features = true } # Cumulus -asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } -cumulus-pallet-parachain-system = { path = "../../../../../../pallets/parachain-system", default-features = false } -parachains-common = { path = "../../../../../common" } -asset-hub-rococo-runtime = { path = "../../../../../runtimes/assets/asset-hub-rococo" } -penpal-runtime = { path = "../../../../../runtimes/testing/penpal" } -emulated-integration-tests-common = { path = "../../../common", default-features = false } -rococo-system-emulated-network = { path = "../../../networks/rococo-system" } +asset-test-utils = { workspace = true, default-features = true } +cumulus-pallet-parachain-system = { workspace = true } +parachains-common = { workspace = true, default-features = true } +emulated-integration-tests-common = { workspace = true } +rococo-system-emulated-network = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs index 2bd388bee400ed2e61869e126a1828b93422f2c0..eca35831705493c1ab7961b62f75ed26cde38c6c 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs @@ -46,14 +46,37 @@ mod imports { pub use parachains_common::Balance; pub use rococo_system_emulated_network::{ asset_hub_rococo_emulated_chain::{ + asset_hub_rococo_runtime::{ + xcm_config::{ + self as ahr_xcm_config, TokenLocation as RelayLocation, + XcmConfig as AssetHubRococoXcmConfig, + }, + AssetConversionOrigin as AssetHubRococoAssetConversionOrigin, + ExistentialDeposit as AssetHubRococoExistentialDeposit, + }, genesis::{AssetHubRococoAssetOwner, ED as ASSET_HUB_ROCOCO_ED}, AssetHubRococoParaPallet as AssetHubRococoPallet, }, penpal_emulated_chain::{ + penpal_runtime::xcm_config::{ + CustomizableAssetFromSystemAssetHub as PenpalCustomizableAssetFromSystemAssetHub, + LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub, + LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub, + }, PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner, PenpalBParaPallet as PenpalBPallet, ED as PENPAL_ED, }, - rococo_emulated_chain::{genesis::ED as ROCOCO_ED, RococoRelayPallet as RococoPallet}, + rococo_emulated_chain::{ + genesis::ED as ROCOCO_ED, + rococo_runtime::{ + governance as rococo_governance, + xcm_config::{ + UniversalLocation as RococoUniversalLocation, XcmConfig as RococoXcmConfig, + }, + OriginCaller as RococoOriginCaller, + }, + RococoRelayPallet as RococoPallet, + }, AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, AssetHubRococoParaSender as AssetHubRococoSender, BridgeHubRococoPara as BridgeHubRococo, BridgeHubRococoParaReceiver as BridgeHubRococoReceiver, PenpalAPara as PenpalA, @@ -62,18 +85,6 @@ mod imports { RococoRelayReceiver as RococoReceiver, RococoRelaySender as RococoSender, }; - // Runtimes - pub use asset_hub_rococo_runtime::xcm_config::{ - TokenLocation as RelayLocation, XcmConfig as AssetHubRococoXcmConfig, - }; - pub use penpal_runtime::xcm_config::{ - LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub, - LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub, - }; - pub use rococo_runtime::xcm_config::{ - UniversalLocation as RococoUniversalLocation, XcmConfig as RococoXcmConfig, - }; - pub const ASSET_ID: u32 = 3; pub const ASSET_MIN_BALANCE: u128 = 1000; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/claim_assets.rs new file mode 100644 index 0000000000000000000000000000000000000000..99b31aba4be010f48f0551cc1115b97caa63f409 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/claim_assets.rs @@ -0,0 +1,29 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests related to claiming assets trapped during XCM execution. + +use crate::imports::*; + +use emulated_integration_tests_common::test_chain_can_claim_assets; +use xcm_executor::traits::DropAssets; + +#[test] +fn assets_can_be_claimed() { + let amount = AssetHubRococoExistentialDeposit::get(); + let assets: Assets = (Parent, amount).into(); + + test_chain_can_claim_assets!(AssetHubRococo, RuntimeCall, NetworkId::Rococo, assets, amount); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs index edaaa998a9ca11f97b9d2c85e8b2b88d1c570fbc..7ff6d6c193c9b414632b13e267220a59c770449a 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs @@ -170,7 +170,7 @@ fn transfer_foreign_assets_from_asset_hub_to_para() { assert_ok!(::System::set_storage( ::RuntimeOrigin::root(), vec![( - penpal_runtime::xcm_config::CustomizableAssetFromSystemAssetHub::key().to_vec(), + PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), Location::new(2, [GlobalConsensus(Westend)]).encode(), )], )); @@ -300,7 +300,7 @@ fn transfer_foreign_assets_from_para_to_asset_hub() { assert_ok!(::System::set_storage( ::RuntimeOrigin::root(), vec![( - penpal_runtime::xcm_config::CustomizableAssetFromSystemAssetHub::key().to_vec(), + PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), Location::new(2, [GlobalConsensus(Westend)]).encode(), )], )); @@ -454,7 +454,7 @@ fn transfer_foreign_assets_from_para_to_para_through_asset_hub() { assert_ok!(::System::set_storage( ::RuntimeOrigin::root(), vec![( - penpal_runtime::xcm_config::CustomizableAssetFromSystemAssetHub::key().to_vec(), + PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), Location::new(2, [GlobalConsensus(Westend)]).encode(), )], )); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs index 138ce419757b98b03d4e9a6b26259d81ca779d69..8fffec23d73a58efc51a433ae2eb66c4028aca95 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +mod claim_assets; mod hybrid_transfers; mod reserve_transfer; mod send; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs index ec48e400ff545686fe728025eacc7ea5cd783d6f..16e0512da960559d192fb427ad55485fd0922172 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs @@ -17,10 +17,7 @@ use crate::imports::*; #[test] fn swap_locally_on_chain_using_local_assets() { - let asset_native = Box::new( - v3::Location::try_from(asset_hub_rococo_runtime::xcm_config::TokenLocation::get()) - .expect("conversion works"), - ); + let asset_native = Box::new(v3::Location::try_from(RelayLocation::get()).unwrap()); let asset_one = Box::new(v3::Location::new( 0, [ @@ -230,12 +227,12 @@ fn swap_locally_on_chain_using_foreign_assets() { #[test] fn cannot_create_pool_from_pool_assets() { - let asset_native = asset_hub_rococo_runtime::xcm_config::TokenLocation::get(); - let mut asset_one = asset_hub_rococo_runtime::xcm_config::PoolAssetsPalletLocation::get(); + let asset_native = RelayLocation::get(); + let mut asset_one = ahr_xcm_config::PoolAssetsPalletLocation::get(); asset_one.append_with(GeneralIndex(ASSET_ID.into())).expect("pool assets"); AssetHubRococo::execute_with(|| { - let pool_owner_account_id = asset_hub_rococo_runtime::AssetConversionOrigin::get(); + let pool_owner_account_id = AssetHubRococoAssetConversionOrigin::get(); assert_ok!(::PoolAssets::create( ::RuntimeOrigin::signed(pool_owner_account_id.clone()), @@ -255,8 +252,8 @@ fn cannot_create_pool_from_pool_assets() { assert_matches::assert_matches!( ::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubRococoSender::get()), - Box::new(v3::Location::try_from(asset_native).expect("conversion works")), - Box::new(v3::Location::try_from(asset_one).expect("conversion works")), + Box::new(v3::Location::try_from(asset_native).unwrap()), + Box::new(v3::Location::try_from(asset_one).unwrap()), ), Err(DispatchError::Module(ModuleError{index: _, error: _, message})) => assert_eq!(message, Some("Unknown")) ); @@ -265,9 +262,7 @@ fn cannot_create_pool_from_pool_assets() { #[test] fn pay_xcm_fee_with_some_asset_swapped_for_native() { - let asset_native = - v3::Location::try_from(asset_hub_rococo_runtime::xcm_config::TokenLocation::get()) - .expect("conversion works"); + let asset_native = v3::Location::try_from(RelayLocation::get()).unwrap(); let asset_one = xcm::v3::Location { parents: 0, interior: [ diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/treasury.rs index 01bf40ae8fdf2cf87092c83ef604ef25427e2939..f8190e11c51c8b202804dcee9cf689d93ef33678 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/treasury.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/treasury.rs @@ -20,12 +20,11 @@ use frame_support::{ sp_runtime::traits::Dispatchable, traits::{ fungible::Inspect, - fungibles::{Create, Inspect as FungiblesInspect, Mutate}, + fungibles::{Inspect as FungiblesInspect, Mutate}, }, }; use parachains_common::AccountId; use polkadot_runtime_common::impls::VersionedLocatableAsset; -use rococo_runtime::OriginCaller; use rococo_runtime_constants::currency::GRAND; use xcm_executor::traits::ConvertLocation; @@ -67,7 +66,7 @@ fn spend_roc_on_asset_hub() { let treasury_location: Location = (Parent, PalletInstance(18)).into(); let teleport_call = RuntimeCall::Utility(pallet_utility::Call::::dispatch_as { - as_origin: bx!(OriginCaller::system(RawOrigin::Signed(treasury_account))), + as_origin: bx!(RococoOriginCaller::system(RawOrigin::Signed(treasury_account))), call: bx!(RuntimeCall::XcmPallet(pallet_xcm::Call::::teleport_assets { dest: bx!(VersionedLocation::V4(asset_hub_location.clone())), beneficiary: bx!(VersionedLocation::V4(treasury_location)), @@ -99,7 +98,7 @@ fn spend_roc_on_asset_hub() { // Fund Alice account from Rococo Treasury account on Asset Hub. let treasury_origin: RuntimeOrigin = - rococo_runtime::governance::pallet_custom_origins::Origin::Treasurer.into(); + rococo_governance::pallet_custom_origins::Origin::Treasurer.into(); let alice_location: Location = [Junction::AccountId32 { network: None, id: Rococo::account_id_of(ALICE).into() }] @@ -163,15 +162,12 @@ fn spend_roc_on_asset_hub() { #[test] fn create_and_claim_treasury_spend_in_usdt() { const ASSET_ID: u32 = 1984; - const SPEND_AMOUNT: u128 = 1_000_000; + const SPEND_AMOUNT: u128 = 10_000_000; // treasury location from a sibling parachain. let treasury_location: Location = Location::new(1, PalletInstance(18)); // treasury account on a sibling parachain. let treasury_account = - asset_hub_rococo_runtime::xcm_config::LocationToAccountId::convert_location( - &treasury_location, - ) - .unwrap(); + ahr_xcm_config::LocationToAccountId::convert_location(&treasury_location).unwrap(); let asset_hub_location = v3::Location::new(0, v3::Junction::Parachain(AssetHubRococo::para_id().into())); let root = ::RuntimeOrigin::root(); @@ -190,13 +186,7 @@ fn create_and_claim_treasury_spend_in_usdt() { AssetHubRococo::execute_with(|| { type Assets = ::Assets; - // create an asset class and mint some assets to the treasury account. - assert_ok!(>::create( - ASSET_ID, - treasury_account.clone(), - true, - SPEND_AMOUNT / 2 - )); + // USDT created at genesis, mint some assets to the treasury account. assert_ok!(>::mint_into(ASSET_ID, &treasury_account, SPEND_AMOUNT * 4)); // beneficiary has zero balance. assert_eq!(>::balance(ASSET_ID, &alice,), 0u128,); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml index e0f29cd801c346a064a4773efa5754b0e2f399f4..6b50b6f473ed087e55ba994fd7cae0f97c48dace 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml @@ -11,38 +11,35 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -assert_matches = "1.5.0" +codec = { workspace = true } +assert_matches = { workspace = true } # Substrate -sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } -sp-keyring = { path = "../../../../../../../substrate/primitives/keyring", default-features = false } -sp-core = { path = "../../../../../../../substrate/primitives/core", default-features = false } -frame-metadata-hash-extension = { path = "../../../../../../../substrate/frame/metadata-hash-extension" } -frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../../../../substrate/frame/system", default-features = false } -pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false } -pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false } -pallet-asset-conversion = { path = "../../../../../../../substrate/frame/asset-conversion", default-features = false } -pallet-treasury = { path = "../../../../../../../substrate/frame/treasury", default-features = false } -pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false } -pallet-transaction-payment = { path = "../../../../../../../substrate/frame/transaction-payment", default-features = false } -pallet-asset-tx-payment = { path = "../../../../../../../substrate/frame/transaction-payment/asset-tx-payment", default-features = false } +sp-runtime = { workspace = true } +sp-keyring = { workspace = true } +sp-core = { workspace = true } +frame-metadata-hash-extension = { workspace = true, default-features = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-balances = { workspace = true } +pallet-assets = { workspace = true } +pallet-asset-conversion = { workspace = true } +pallet-treasury = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-asset-tx-payment = { workspace = true } # Polkadot -polkadot-runtime-common = { path = "../../../../../../../polkadot/runtime/common" } -xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false } -pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false } -xcm-fee-payment-runtime-api = { path = "../../../../../../../polkadot/xcm/xcm-fee-payment-runtime-api", default-features = false } -westend-runtime = { path = "../../../../../../../polkadot/runtime/westend" } +polkadot-runtime-common = { workspace = true, default-features = true } +xcm = { workspace = true } +xcm-executor = { workspace = true } +pallet-xcm = { workspace = true } +xcm-runtime-apis = { workspace = true } # Cumulus -parachains-common = { path = "../../../../../common" } -penpal-runtime = { path = "../../../../../runtimes/testing/penpal" } -asset-hub-westend-runtime = { path = "../../../../../runtimes/assets/asset-hub-westend" } -asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } -cumulus-pallet-xcmp-queue = { path = "../../../../../../pallets/xcmp-queue", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../../../pallets/parachain-system", default-features = false } -emulated-integration-tests-common = { path = "../../../common", default-features = false } -westend-system-emulated-network = { path = "../../../networks/westend-system" } +parachains-common = { workspace = true, default-features = true } +asset-test-utils = { workspace = true, default-features = true } +cumulus-pallet-xcmp-queue = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +emulated-integration-tests-common = { workspace = true } +westend-system-emulated-network = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs index 1c4a0ef4c8d2af7f773fbb6916391012ec9fdfc2..9401621c5ba371b516cbda874d9a729f6f7d1808 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs @@ -46,15 +46,34 @@ mod imports { pub use parachains_common::{AccountId, Balance}; pub use westend_system_emulated_network::{ asset_hub_westend_emulated_chain::{ + asset_hub_westend_runtime::{ + xcm_config::{ + self as ahw_xcm_config, WestendLocation as RelayLocation, + XcmConfig as AssetHubWestendXcmConfig, + }, + AssetConversionOrigin as AssetHubWestendAssetConversionOrigin, + ExistentialDeposit as AssetHubWestendExistentialDeposit, + }, genesis::{AssetHubWestendAssetOwner, ED as ASSET_HUB_WESTEND_ED}, AssetHubWestendParaPallet as AssetHubWestendPallet, }, collectives_westend_emulated_chain::CollectivesWestendParaPallet as CollectivesWestendPallet, penpal_emulated_chain::{ + penpal_runtime::xcm_config::{ + CustomizableAssetFromSystemAssetHub as PenpalCustomizableAssetFromSystemAssetHub, + LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub, + LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub, + }, PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner, PenpalBParaPallet as PenpalBPallet, }, - westend_emulated_chain::{genesis::ED as WESTEND_ED, WestendRelayPallet as WestendPallet}, + westend_emulated_chain::{ + genesis::ED as WESTEND_ED, + westend_runtime::xcm_config::{ + UniversalLocation as WestendUniversalLocation, XcmConfig as WestendXcmConfig, + }, + WestendRelayPallet as WestendPallet, + }, AssetHubWestendPara as AssetHubWestend, AssetHubWestendParaReceiver as AssetHubWestendReceiver, AssetHubWestendParaSender as AssetHubWestendSender, @@ -66,18 +85,6 @@ mod imports { WestendRelayReceiver as WestendReceiver, WestendRelaySender as WestendSender, }; - // Runtimes - pub use asset_hub_westend_runtime::xcm_config::{ - WestendLocation as RelayLocation, XcmConfig as AssetHubWestendXcmConfig, - }; - pub use penpal_runtime::xcm_config::{ - LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub, - LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub, - }; - pub use westend_runtime::xcm_config::{ - UniversalLocation as WestendUniversalLocation, XcmConfig as WestendXcmConfig, - }; - pub const ASSET_ID: u32 = 3; pub const ASSET_MIN_BALANCE: u128 = 1000; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/claim_assets.rs new file mode 100644 index 0000000000000000000000000000000000000000..de58839634f1b438c50d369bb025fc8750bda396 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/claim_assets.rs @@ -0,0 +1,29 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests related to claiming assets trapped during XCM execution. + +use crate::imports::*; + +use emulated_integration_tests_common::test_chain_can_claim_assets; +use xcm_executor::traits::DropAssets; + +#[test] +fn assets_can_be_claimed() { + let amount = AssetHubWestendExistentialDeposit::get(); + let assets: Assets = (Parent, amount).into(); + + test_chain_can_claim_assets!(AssetHubWestend, RuntimeCall, NetworkId::Westend, assets, amount); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs index 2d02e90f47fb834326a7268394671f5ef03f84e7..15f4fe33bddc1b65f079832facc4ce495823ad84 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs @@ -28,10 +28,7 @@ fn create_and_claim_treasury_spend() { Location::new(1, [Parachain(CollectivesWestend::para_id().into()), PalletInstance(65)]); // treasury account on a sibling parachain. let treasury_account = - asset_hub_westend_runtime::xcm_config::LocationToAccountId::convert_location( - &treasury_location, - ) - .unwrap(); + ahw_xcm_config::LocationToAccountId::convert_location(&treasury_location).unwrap(); let asset_hub_location = Location::new(1, [Parachain(AssetHubWestend::para_id().into())]); let root = ::RuntimeOrigin::root(); // asset kind to be spent from the treasury. diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/hybrid_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/hybrid_transfers.rs index d39c72c7c5f0d21815ca0091e9fd888b5ab54924..49dfe8d58394c9ae7b69fba75e8147e7fa94e2db 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/hybrid_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/hybrid_transfers.rs @@ -170,7 +170,7 @@ fn transfer_foreign_assets_from_asset_hub_to_para() { assert_ok!(::System::set_storage( ::RuntimeOrigin::root(), vec![( - penpal_runtime::xcm_config::CustomizableAssetFromSystemAssetHub::key().to_vec(), + PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), Location::new(2, [GlobalConsensus(Rococo)]).encode(), )], )); @@ -300,7 +300,7 @@ fn transfer_foreign_assets_from_para_to_asset_hub() { assert_ok!(::System::set_storage( ::RuntimeOrigin::root(), vec![( - penpal_runtime::xcm_config::CustomizableAssetFromSystemAssetHub::key().to_vec(), + PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), Location::new(2, [GlobalConsensus(Rococo)]).encode(), )], )); @@ -455,7 +455,7 @@ fn transfer_foreign_assets_from_para_to_para_through_asset_hub() { assert_ok!(::System::set_storage( ::RuntimeOrigin::root(), vec![( - penpal_runtime::xcm_config::CustomizableAssetFromSystemAssetHub::key().to_vec(), + PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), Location::new(2, [GlobalConsensus(Rococo)]).encode(), )], )); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs index 61eb70524fc9ae2a23e5061400c57ca719bae4e1..73b73b239a1bb54e818cad575084ae775c6f9db1 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +mod claim_assets; mod fellowship_treasury; mod hybrid_transfers; mod reserve_transfer; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs index f6b6580988658f5fadead0250a6bcc886c9f125d..cf429378cf6d8eb79eb0c53a9da1c882fc86537a 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs @@ -17,10 +17,8 @@ use crate::imports::*; #[test] fn swap_locally_on_chain_using_local_assets() { - let asset_native = Box::new( - v3::Location::try_from(asset_hub_westend_runtime::xcm_config::WestendLocation::get()) - .expect("conversion works"), - ); + let asset_native = + Box::new(v3::Location::try_from(RelayLocation::get()).expect("conversion works")); let asset_one = Box::new(v3::Location { parents: 0, interior: [ @@ -229,12 +227,12 @@ fn swap_locally_on_chain_using_foreign_assets() { #[test] fn cannot_create_pool_from_pool_assets() { - let asset_native = asset_hub_westend_runtime::xcm_config::WestendLocation::get(); - let mut asset_one = asset_hub_westend_runtime::xcm_config::PoolAssetsPalletLocation::get(); + let asset_native = RelayLocation::get(); + let mut asset_one = ahw_xcm_config::PoolAssetsPalletLocation::get(); asset_one.append_with(GeneralIndex(ASSET_ID.into())).expect("pool assets"); AssetHubWestend::execute_with(|| { - let pool_owner_account_id = asset_hub_westend_runtime::AssetConversionOrigin::get(); + let pool_owner_account_id = AssetHubWestendAssetConversionOrigin::get(); assert_ok!(::PoolAssets::create( ::RuntimeOrigin::signed(pool_owner_account_id.clone()), @@ -264,9 +262,7 @@ fn cannot_create_pool_from_pool_assets() { #[test] fn pay_xcm_fee_with_some_asset_swapped_for_native() { - let asset_native = - v3::Location::try_from(asset_hub_westend_runtime::xcm_config::WestendLocation::get()) - .expect("conversion works"); + let asset_native = v3::Location::try_from(RelayLocation::get()).expect("conversion works"); let asset_one = xcm::v3::Location { parents: 0, interior: [ diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs index 6d8c0f5e5de6ae70559f5d60545959db5e74f735..8cbce3e0d223277e240e159e99f76696b7b339be 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs @@ -27,10 +27,7 @@ fn create_and_claim_treasury_spend() { let treasury_location: Location = Location::new(1, PalletInstance(37)); // treasury account on a sibling parachain. let treasury_account = - asset_hub_westend_runtime::xcm_config::LocationToAccountId::convert_location( - &treasury_location, - ) - .unwrap(); + ahw_xcm_config::LocationToAccountId::convert_location(&treasury_location).unwrap(); let asset_hub_location = Location::new(0, Parachain(AssetHubWestend::para_id().into())); let root = ::RuntimeOrigin::root(); // asset kind to be spend from the treasury. diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs index dc89ef1f7a44e6afc218de787bc47d452ae50fa8..c01aa7825336348f5077c89a73c61e7b128a6200 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs @@ -18,7 +18,7 @@ use crate::imports::*; use frame_system::RawOrigin; -use xcm_fee_payment_runtime_api::{ +use xcm_runtime_apis::{ dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, }; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml index bed5af92f6e55b37f7f12518dbe1ed1b290dd5aa..a5787885329d75a05fe50ce18690fd6d4076db51 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml @@ -11,40 +11,38 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } -hex-literal = "0.4.1" +codec = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +hex-literal = { workspace = true, default-features = true } # Substrate -sp-core = { path = "../../../../../../../substrate/primitives/core", default-features = false } -frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false } -pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false } -pallet-asset-conversion = { path = "../../../../../../../substrate/frame/asset-conversion", default-features = false } -pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false } -pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue" } -sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } +sp-core = { workspace = true } +frame-support = { workspace = true } +pallet-assets = { workspace = true } +pallet-asset-conversion = { workspace = true } +pallet-balances = { workspace = true } +pallet-message-queue = { workspace = true, default-features = true } +sp-runtime = { workspace = true } # Polkadot -xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } -pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false } +xcm = { workspace = true } +pallet-xcm = { workspace = true } +xcm-executor = { workspace = true } # Bridges -pallet-bridge-messages = { path = "../../../../../../../bridges/modules/messages", default-features = false } +pallet-bridge-messages = { workspace = true } # Cumulus -parachains-common = { path = "../../../../../common" } -testnet-parachains-constants = { path = "../../../../../runtimes/constants", features = ["rococo"] } -cumulus-pallet-xcmp-queue = { path = "../../../../../../pallets/xcmp-queue", default-features = false } -bridge-hub-rococo-runtime = { path = "../../../../../runtimes/bridge-hubs/bridge-hub-rococo", default-features = false } -emulated-integration-tests-common = { path = "../../../common", default-features = false } -rococo-westend-system-emulated-network = { path = "../../../networks/rococo-westend-system" } -rococo-system-emulated-network = { path = "../../../networks/rococo-system" } -asset-hub-rococo-runtime = { path = "../../../../../runtimes/assets/asset-hub-rococo", default-features = false } +cumulus-pallet-xcmp-queue = { workspace = true } +emulated-integration-tests-common = { workspace = true } +parachains-common = { workspace = true, default-features = true } +rococo-system-emulated-network = { workspace = true } +rococo-westend-system-emulated-network = { workspace = true } +testnet-parachains-constants = { features = ["rococo"], workspace = true, default-features = true } # Snowbridge -snowbridge-core = { path = "../../../../../../../bridges/snowbridge/primitives/core", default-features = false } -snowbridge-router-primitives = { path = "../../../../../../../bridges/snowbridge/primitives/router", default-features = false } -snowbridge-pallet-system = { path = "../../../../../../../bridges/snowbridge/pallets/system", default-features = false } -snowbridge-pallet-outbound-queue = { path = "../../../../../../../bridges/snowbridge/pallets/outbound-queue", default-features = false } -snowbridge-pallet-inbound-queue-fixtures = { path = "../../../../../../../bridges/snowbridge/pallets/inbound-queue/fixtures" } +snowbridge-core = { workspace = true } +snowbridge-router-primitives = { workspace = true } +snowbridge-pallet-system = { workspace = true } +snowbridge-pallet-outbound-queue = { workspace = true } +snowbridge-pallet-inbound-queue-fixtures = { workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs index 0415af580ef8add90c92620e93052e356abe2de9..3ee509389c67ccb5105f249667815aa587b1d29d 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs @@ -35,19 +35,30 @@ mod imports { xcm_emulator::{ assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, TestExt, }, + ASSETS_PALLET_ID, USDT_ID, }; pub use parachains_common::AccountId; pub use rococo_westend_system_emulated_network::{ asset_hub_rococo_emulated_chain::{ - genesis::ED as ASSET_HUB_ROCOCO_ED, AssetHubRococoParaPallet as AssetHubRococoPallet, + asset_hub_rococo_runtime::xcm_config as ahr_xcm_config, + genesis::{AssetHubRococoAssetOwner, ED as ASSET_HUB_ROCOCO_ED}, + AssetHubRococoParaPallet as AssetHubRococoPallet, }, asset_hub_westend_emulated_chain::{ genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, }, bridge_hub_rococo_emulated_chain::{ - genesis::ED as BRIDGE_HUB_ROCOCO_ED, BridgeHubRococoParaPallet as BridgeHubRococoPallet, + genesis::ED as BRIDGE_HUB_ROCOCO_ED, BridgeHubRococoExistentialDeposit, + BridgeHubRococoParaPallet as BridgeHubRococoPallet, BridgeHubRococoRuntimeOrigin, + BridgeHubRococoXcmConfig, EthereumBeaconClient, EthereumInboundQueue, + }, + penpal_emulated_chain::{ + penpal_runtime::xcm_config::{ + CustomizableAssetFromSystemAssetHub as PenpalCustomizableAssetFromSystemAssetHub, + UniversalLocation as PenpalUniversalLocation, + }, + PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner, }, - penpal_emulated_chain::{PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner}, rococo_emulated_chain::{genesis::ED as ROCOCO_ED, RococoRelayPallet as RococoPallet}, AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, AssetHubRococoParaSender as AssetHubRococoSender, AssetHubWestendPara as AssetHubWestend, diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs index 87fb70e4de23857bf929ed1a663fd2dcc3120e93..6053936487b26e97fe8575cd5b666a03cff7ccf6 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs @@ -15,168 +15,140 @@ use crate::tests::*; -fn send_asset_from_asset_hub_rococo_to_asset_hub_westend(id: Location, amount: u128) { - let destination = asset_hub_westend_location(); - +fn send_assets_over_bridge(send_fn: F) { // fund the AHR's SA on BHR for paying bridge transport fees BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), 10_000_000_000_000u128); // set XCM versions - AssetHubRococo::force_xcm_version(destination.clone(), XCM_VERSION); + let local_asset_hub = PenpalA::sibling_location_of(AssetHubRococo::para_id()); + PenpalA::force_xcm_version(local_asset_hub.clone(), XCM_VERSION); + AssetHubRococo::force_xcm_version(asset_hub_westend_location(), XCM_VERSION); BridgeHubRococo::force_xcm_version(bridge_hub_westend_location(), XCM_VERSION); // send message over bridge - assert_ok!(send_asset_from_asset_hub_rococo(destination, (id, amount))); + send_fn(); + + // process and verify intermediary hops assert_bridge_hub_rococo_message_accepted(true); assert_bridge_hub_westend_message_received(); } -fn send_asset_from_penpal_rococo_through_local_asset_hub_to_westend_asset_hub( - id: Location, - transfer_amount: u128, -) { - let destination = asset_hub_westend_location(); - let local_asset_hub: Location = PenpalA::sibling_location_of(AssetHubRococo::para_id()); - let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of( - AssetHubRococo::sibling_location_of(PenpalA::para_id()), - ); - let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( - Westend, - AssetHubWestend::para_id(), - ); - - // fund the AHR's SA on BHR for paying bridge transport fees - BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), 10_000_000_000_000u128); +fn set_up_rocs_for_penpal_rococo_through_ahr_to_ahw( + sender: &AccountId, + amount: u128, +) -> (Location, v3::Location) { + let roc_at_rococo_parachains = roc_at_ah_rococo(); + let roc_at_asset_hub_westend = bridged_roc_at_ah_westend().try_into().unwrap(); + create_foreign_on_ah_westend(roc_at_asset_hub_westend, true); - // set XCM versions - PenpalA::force_xcm_version(local_asset_hub.clone(), XCM_VERSION); - AssetHubRococo::force_xcm_version(destination.clone(), XCM_VERSION); - BridgeHubRococo::force_xcm_version(bridge_hub_westend_location(), XCM_VERSION); - - // send message over bridge - assert_ok!(PenpalA::execute_with(|| { - let signed_origin = ::RuntimeOrigin::signed(PenpalASender::get()); - let beneficiary: Location = - AccountId32Junction { network: None, id: AssetHubWestendReceiver::get().into() }.into(); - let assets: Assets = (id.clone(), transfer_amount).into(); - let fees_id: AssetId = id.into(); - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(assets.len() as u32)), - beneficiary, - }]); + let penpal_location = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location); + // fund Penpal's sovereign account on AssetHub + AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), amount * 2)]); + // fund Penpal's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + roc_at_rococo_parachains.clone(), + sender.clone(), + amount * 2, + ); + (roc_at_rococo_parachains, roc_at_asset_hub_westend) +} - ::PolkadotXcm::transfer_assets_using_type_and_then( - signed_origin, - bx!(destination.into()), - bx!(assets.clone().into()), - bx!(TransferType::RemoteReserve(local_asset_hub.clone().into())), - bx!(fees_id.into()), - bx!(TransferType::RemoteReserve(local_asset_hub.into())), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - WeightLimit::Unlimited, - ) - })); - AssetHubRococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - AssetHubRococo, - vec![ - // Amount to reserve transfer is withdrawn from Penpal's sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } - ) => { - who: *who == sov_penpal_on_ahr.clone().into(), - amount: *amount == transfer_amount, - }, - // Amount deposited in AHW's sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == sov_ahw_on_ahr.clone().into(), - }, - RuntimeEvent::XcmpQueue( - cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } - ) => {}, - ] +fn send_assets_from_penpal_rococo_through_rococo_ah_to_westend_ah( + destination: Location, + assets: (Assets, TransferType), + fees: (AssetId, TransferType), + custom_xcm_on_dest: Xcm<()>, +) { + send_assets_over_bridge(|| { + let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of( + AssetHubRococo::sibling_location_of(PenpalA::para_id()), ); + let sov_ahw_on_ahr = + AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( + Westend, + AssetHubWestend::para_id(), + ); + // send message over bridge + assert_ok!(PenpalA::execute_with(|| { + let signed_origin = ::RuntimeOrigin::signed(PenpalASender::get()); + ::PolkadotXcm::transfer_assets_using_type_and_then( + signed_origin, + bx!(destination.into()), + bx!(assets.0.into()), + bx!(assets.1), + bx!(fees.0.into()), + bx!(fees.1), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + WeightLimit::Unlimited, + ) + })); + // verify intermediary AH Rococo hop + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + AssetHubRococo, + vec![ + // Amount to reserve transfer is withdrawn from Penpal's sovereign account + RuntimeEvent::Balances( + pallet_balances::Event::Burned { who, .. } + ) => { + who: *who == sov_penpal_on_ahr.clone().into(), + }, + // Amount deposited in AHW's sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { + who: *who == sov_ahw_on_ahr.clone().into(), + }, + RuntimeEvent::XcmpQueue( + cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } + ) => {}, + ] + ); + }); }); - assert_bridge_hub_rococo_message_accepted(true); - assert_bridge_hub_westend_message_received(); } #[test] -fn send_rocs_from_asset_hub_rococo_to_asset_hub_westend() { - let roc_at_asset_hub_rococo: v3::Location = v3::Parent.into(); - let roc_at_asset_hub_westend = - v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Rococo)]); - let owner: AccountId = AssetHubWestend::account_id_of(ALICE); - AssetHubWestend::force_create_foreign_asset( - roc_at_asset_hub_westend, - owner, - true, - ASSET_MIN_BALANCE, - vec![], - ); +/// Test transfer of ROC, USDT and wETH from AssetHub Rococo to AssetHub Westend. +/// +/// This mix of assets should cover the whole range: +/// - native assets: ROC, +/// - trust-based assets: USDT (exists only on Rococo, Westend gets it from Rococo over bridge), +/// - foreign asset / bridged asset (other bridge / Snowfork): wETH (bridged from Ethereum to Rococo +/// over Snowbridge, then bridged over to Westend through this bridge). +fn send_roc_usdt_and_weth_from_asset_hub_rococo_to_asset_hub_westend() { + let amount = ASSET_HUB_ROCOCO_ED * 1_000_000; + let sender = AssetHubRococoSender::get(); + let receiver = AssetHubWestendReceiver::get(); + let roc_at_asset_hub_rococo: v3::Location = roc_at_ah_rococo().try_into().unwrap(); + let bridged_roc_at_asset_hub_westend = bridged_roc_at_ah_westend().try_into().unwrap(); + + create_foreign_on_ah_westend(bridged_roc_at_asset_hub_westend, true); + set_up_pool_with_wnd_on_ah_westend(bridged_roc_at_asset_hub_westend); + + //////////////////////////////////////////////////////////// + // Let's first send over just some ROCs as a simple example + //////////////////////////////////////////////////////////// let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( Westend, AssetHubWestend::para_id(), ); - - AssetHubWestend::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - // setup a pool to pay xcm fees with `roc_at_asset_hub_westend` tokens - assert_ok!(::ForeignAssets::mint( - ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - roc_at_asset_hub_westend.into(), - AssetHubWestendSender::get().into(), - 3_000_000_000_000, - )); - - assert_ok!(::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - Box::new(xcm::v3::Parent.into()), - Box::new(roc_at_asset_hub_westend), - )); - - assert_expected_events!( - AssetHubWestend, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, - ] - ); - - assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - Box::new(xcm::v3::Parent.into()), - Box::new(roc_at_asset_hub_westend), - 1_000_000_000_000, - 2_000_000_000_000, - 1, - 1, - AssetHubWestendSender::get().into() - )); - - assert_expected_events!( - AssetHubWestend, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {..}) => {}, - ] - ); - }); - let rocs_in_reserve_on_ahr_before = ::account_data_of(sov_ahw_on_ahr.clone()).free; - let sender_rocs_before = - ::account_data_of(AssetHubRococoSender::get()).free; - let receiver_rocs_before = AssetHubWestend::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(roc_at_asset_hub_westend, &AssetHubWestendReceiver::get()) + let sender_rocs_before = ::account_data_of(sender.clone()).free; + let receiver_rocs_before = + foreign_balance_on_ah_westend(bridged_roc_at_asset_hub_westend, &receiver); + + // send ROCs, use them for fees + send_assets_over_bridge(|| { + let destination = asset_hub_westend_location(); + let assets: Assets = (Location::try_from(roc_at_asset_hub_rococo).unwrap(), amount).into(); + let fee_idx = 0; + assert_ok!(send_assets_from_asset_hub_rococo(destination, assets, fee_idx)); }); - let amount = ASSET_HUB_ROCOCO_ED * 1_000_000; - send_asset_from_asset_hub_rococo_to_asset_hub_westend( - roc_at_asset_hub_rococo.try_into().unwrap(), - amount, - ); + // verify expected events on final destination AssetHubWestend::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( @@ -185,7 +157,7 @@ fn send_rocs_from_asset_hub_rococo_to_asset_hub_westend() { // issue ROCs on AHW RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { asset_id: *asset_id == roc_at_asset_hub_rococo, - owner: *owner == AssetHubWestendReceiver::get(), + owner: owner == &receiver, }, // message processed successfully RuntimeEvent::MessageQueue( @@ -195,36 +167,100 @@ fn send_rocs_from_asset_hub_rococo_to_asset_hub_westend() { ); }); - let sender_rocs_after = - ::account_data_of(AssetHubRococoSender::get()).free; - let receiver_rocs_after = AssetHubWestend::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(roc_at_asset_hub_westend, &AssetHubWestendReceiver::get()) - }); + let sender_rocs_after = ::account_data_of(sender.clone()).free; + let receiver_rocs_after = + foreign_balance_on_ah_westend(bridged_roc_at_asset_hub_westend, &receiver); let rocs_in_reserve_on_ahr_after = ::account_data_of(sov_ahw_on_ahr.clone()).free; - // Sender's balance is reduced + // Sender's ROC balance is reduced assert!(sender_rocs_before > sender_rocs_after); - // Receiver's balance is increased + // Receiver's ROC balance is increased assert!(receiver_rocs_after > receiver_rocs_before); - // Reserve balance is increased by sent amount + // Reserve ROC balance is increased by sent amount assert_eq!(rocs_in_reserve_on_ahr_after, rocs_in_reserve_on_ahr_before + amount); + + ///////////////////////////////////////////////////////////// + // Now let's send over USDTs + wETH (and pay fees with USDT) + ///////////////////////////////////////////////////////////// + + let usdt_at_asset_hub_rococo = usdt_at_ah_rococo(); + let bridged_usdt_at_asset_hub_westend = bridged_usdt_at_ah_westend().try_into().unwrap(); + // wETH has same relative location on both Rococo and Westend AssetHubs + let bridged_weth_at_ah = weth_at_asset_hubs().try_into().unwrap(); + + // mint USDT in sender's account (USDT already created in genesis) + AssetHubRococo::mint_asset( + ::RuntimeOrigin::signed(AssetHubRococoAssetOwner::get()), + USDT_ID, + sender.clone(), + amount * 2, + ); + // create wETH at src and dest and prefund sender's account + create_foreign_on_ah_rococo(bridged_weth_at_ah, true, vec![(sender.clone(), amount * 2)]); + create_foreign_on_ah_westend(bridged_weth_at_ah, true); + create_foreign_on_ah_westend(bridged_usdt_at_asset_hub_westend, true); + set_up_pool_with_wnd_on_ah_westend(bridged_usdt_at_asset_hub_westend); + + let receiver_usdts_before = + foreign_balance_on_ah_westend(bridged_usdt_at_asset_hub_westend, &receiver); + let receiver_weth_before = foreign_balance_on_ah_westend(bridged_weth_at_ah, &receiver); + + // send USDTs and wETHs + let assets: Assets = vec![ + (usdt_at_asset_hub_rococo.clone(), amount).into(), + (Location::try_from(bridged_weth_at_ah).unwrap(), amount).into(), + ] + .into(); + // use USDT for fees + let fee: AssetId = usdt_at_asset_hub_rococo.into(); + + // use the more involved transfer extrinsic + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(assets.len() as u32)), + beneficiary: AccountId32Junction { network: None, id: receiver.clone().into() }.into(), + }]); + assert_ok!(AssetHubRococo::execute_with(|| { + ::PolkadotXcm::transfer_assets_using_type_and_then( + ::RuntimeOrigin::signed(sender.into()), + bx!(asset_hub_westend_location().into()), + bx!(assets.into()), + bx!(TransferType::LocalReserve), + bx!(fee.into()), + bx!(TransferType::LocalReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + WeightLimit::Unlimited, + ) + })); + // verify hops (also advances the message through the hops) + assert_bridge_hub_rococo_message_accepted(true); + assert_bridge_hub_westend_message_received(); + AssetHubWestend::execute_with(|| { + AssetHubWestend::assert_xcmp_queue_success(None); + }); + + let receiver_usdts_after = + foreign_balance_on_ah_westend(bridged_usdt_at_asset_hub_westend, &receiver); + let receiver_weth_after = foreign_balance_on_ah_westend(bridged_weth_at_ah, &receiver); + + // Receiver's USDT balance is increased by almost `amount` (minus fees) + assert!(receiver_usdts_after > receiver_usdts_before); + assert!(receiver_usdts_after < receiver_usdts_before + amount); + // Receiver's wETH balance is increased by sent amount + assert_eq!(receiver_weth_after, receiver_weth_before + amount); } #[test] -fn send_wnds_from_asset_hub_rococo_to_asset_hub_westend() { +/// Send bridged WNDs "back" from AssetHub Rococo to AssetHub Westend. +fn send_back_wnds_from_asset_hub_rococo_to_asset_hub_westend() { let prefund_amount = 10_000_000_000_000u128; - let wnd_at_asset_hub_rococo = - v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Westend)]); - let owner: AccountId = AssetHubRococo::account_id_of(ALICE); - AssetHubRococo::force_create_foreign_asset( - wnd_at_asset_hub_rococo, - owner, - true, - ASSET_MIN_BALANCE, - vec![(AssetHubRococoSender::get(), prefund_amount)], - ); + let amount_to_send = ASSET_HUB_WESTEND_ED * 1_000; + let sender = AssetHubRococoSender::get(); + let receiver = AssetHubWestendReceiver::get(); + let wnd_at_asset_hub_rococo = bridged_wnd_at_ah_rococo(); + let wnd_at_asset_hub_rococo_v3 = wnd_at_asset_hub_rococo.clone().try_into().unwrap(); + let prefund_accounts = vec![(sender.clone(), prefund_amount)]; + create_foreign_on_ah_rococo(wnd_at_asset_hub_rococo_v3, true, prefund_accounts); // fund the AHR's SA on AHW with the WND tokens held in reserve let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( @@ -236,19 +272,19 @@ fn send_wnds_from_asset_hub_rococo_to_asset_hub_westend() { let wnds_in_reserve_on_ahw_before = ::account_data_of(sov_ahr_on_ahw.clone()).free; assert_eq!(wnds_in_reserve_on_ahw_before, prefund_amount); - let sender_wnds_before = AssetHubRococo::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(wnd_at_asset_hub_rococo, &AssetHubRococoSender::get()) - }); + + let sender_wnds_before = foreign_balance_on_ah_rococo(wnd_at_asset_hub_rococo_v3, &sender); assert_eq!(sender_wnds_before, prefund_amount); - let receiver_wnds_before = - ::account_data_of(AssetHubWestendReceiver::get()).free; + let receiver_wnds_before = ::account_data_of(receiver.clone()).free; + + // send back WNDs, use them for fees + send_assets_over_bridge(|| { + let destination = asset_hub_westend_location(); + let assets: Assets = (wnd_at_asset_hub_rococo, amount_to_send).into(); + let fee_idx = 0; + assert_ok!(send_assets_from_asset_hub_rococo(destination, assets, fee_idx)); + }); - let amount_to_send = ASSET_HUB_WESTEND_ED * 1_000; - send_asset_from_asset_hub_rococo_to_asset_hub_westend( - Location::try_from(wnd_at_asset_hub_rococo).unwrap(), - amount_to_send, - ); AssetHubWestend::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( @@ -263,7 +299,7 @@ fn send_wnds_from_asset_hub_rococo_to_asset_hub_westend() { }, // WNDs deposited to beneficiary RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == AssetHubWestendReceiver::get(), + who: who == &receiver, }, // message processed successfully RuntimeEvent::MessageQueue( @@ -273,12 +309,8 @@ fn send_wnds_from_asset_hub_rococo_to_asset_hub_westend() { ); }); - let sender_wnds_after = AssetHubRococo::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(wnd_at_asset_hub_rococo, &AssetHubRococoSender::get()) - }); - let receiver_wnds_after = - ::account_data_of(AssetHubWestendReceiver::get()).free; + let sender_wnds_after = foreign_balance_on_ah_rococo(wnd_at_asset_hub_rococo_v3, &sender); + let receiver_wnds_after = ::account_data_of(receiver).free; let wnds_in_reserve_on_ahw_after = ::account_data_of(sov_ahr_on_ahw).free; @@ -292,55 +324,47 @@ fn send_wnds_from_asset_hub_rococo_to_asset_hub_westend() { #[test] fn send_rocs_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_westend() { - let roc_at_rococo_parachains: Location = Parent.into(); - let roc_at_asset_hub_westend = Location::new(2, [Junction::GlobalConsensus(NetworkId::Rococo)]); - let owner: AccountId = AssetHubWestend::account_id_of(ALICE); - AssetHubWestend::force_create_foreign_asset( - roc_at_asset_hub_westend.clone().try_into().unwrap(), - owner, - true, - ASSET_MIN_BALANCE, - vec![], - ); + let amount = ASSET_HUB_ROCOCO_ED * 10_000_000; + let sender = PenpalASender::get(); + let receiver = AssetHubWestendReceiver::get(); + let local_asset_hub = PenpalA::sibling_location_of(AssetHubRococo::para_id()); + let (roc_at_rococo_parachains, roc_at_asset_hub_westend) = + set_up_rocs_for_penpal_rococo_through_ahr_to_ahw(&sender, amount); + let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( Westend, AssetHubWestend::para_id(), ); - - let amount = ASSET_HUB_ROCOCO_ED * 10_000_000; - let penpal_location = AssetHubRococo::sibling_location_of(PenpalA::para_id()); - let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location); - // fund Penpal's sovereign account on AssetHub - AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), amount * 2)]); - // fund Penpal's sender account - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(PenpalAssetOwner::get()), - roc_at_rococo_parachains.clone(), - PenpalASender::get(), - amount * 2, - ); - let rocs_in_reserve_on_ahr_before = ::account_data_of(sov_ahw_on_ahr.clone()).free; let sender_rocs_before = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; - >::balance( - roc_at_rococo_parachains.clone(), - &PenpalASender::get(), - ) + >::balance(roc_at_rococo_parachains.clone(), &sender) }); - let receiver_rocs_before = AssetHubWestend::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance( - roc_at_asset_hub_westend.clone().try_into().unwrap(), - &AssetHubWestendReceiver::get(), - ) - }); - send_asset_from_penpal_rococo_through_local_asset_hub_to_westend_asset_hub( - roc_at_rococo_parachains.clone(), - amount, - ); + let receiver_rocs_before = foreign_balance_on_ah_westend(roc_at_asset_hub_westend, &receiver); + + // Send ROCs over bridge + { + let destination = asset_hub_westend_location(); + let assets: Assets = (roc_at_rococo_parachains.clone(), amount).into(); + let asset_transfer_type = TransferType::RemoteReserve(local_asset_hub.clone().into()); + let fees_id: AssetId = roc_at_rococo_parachains.clone().into(); + let fees_transfer_type = TransferType::RemoteReserve(local_asset_hub.into()); + let beneficiary: Location = + AccountId32Junction { network: None, id: receiver.clone().into() }.into(); + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(assets.len() as u32)), + beneficiary, + }]); + send_assets_from_penpal_rococo_through_rococo_ah_to_westend_ah( + destination, + (assets, asset_transfer_type), + (fees_id, fees_transfer_type), + custom_xcm_on_dest, + ); + } + // process AHW incoming message and check events AssetHubWestend::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( @@ -349,7 +373,7 @@ fn send_rocs_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_westend() // issue ROCs on AHW RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { asset_id: *asset_id == roc_at_rococo_parachains.clone().try_into().unwrap(), - owner: *owner == AssetHubWestendReceiver::get(), + owner: owner == &receiver, }, // message processed successfully RuntimeEvent::MessageQueue( @@ -361,15 +385,9 @@ fn send_rocs_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_westend() let sender_rocs_after = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; - >::balance(roc_at_rococo_parachains, &PenpalASender::get()) - }); - let receiver_rocs_after = AssetHubWestend::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance( - roc_at_asset_hub_westend.try_into().unwrap(), - &AssetHubWestendReceiver::get(), - ) + >::balance(roc_at_rococo_parachains, &sender) }); + let receiver_rocs_after = foreign_balance_on_ah_westend(roc_at_asset_hub_westend, &receiver); let rocs_in_reserve_on_ahr_after = ::account_data_of(sov_ahw_on_ahr.clone()).free; @@ -381,3 +399,121 @@ fn send_rocs_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_westend() assert!(rocs_in_reserve_on_ahr_after > rocs_in_reserve_on_ahr_before); assert!(rocs_in_reserve_on_ahr_after <= rocs_in_reserve_on_ahr_before + amount); } + +#[test] +fn send_back_wnds_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_westend() { + let wnd_at_rococo_parachains = bridged_wnd_at_ah_rococo(); + let wnd_at_rococo_parachains_v3 = wnd_at_rococo_parachains.clone().try_into().unwrap(); + let amount = ASSET_HUB_ROCOCO_ED * 10_000_000; + let sender = PenpalASender::get(); + let receiver = AssetHubWestendReceiver::get(); + + // set up ROCs for transfer + let (roc_at_rococo_parachains, _) = + set_up_rocs_for_penpal_rococo_through_ahr_to_ahw(&sender, amount); + + // set up WNDs for transfer + let penpal_location = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location); + let prefund_accounts = vec![(sov_penpal_on_ahr, amount * 2)]; + create_foreign_on_ah_rococo(wnd_at_rococo_parachains_v3, true, prefund_accounts); + let asset_owner: AccountId = AssetHubRococo::account_id_of(ALICE); + PenpalA::force_create_foreign_asset( + wnd_at_rococo_parachains.clone(), + asset_owner.clone(), + true, + ASSET_MIN_BALANCE, + vec![(sender.clone(), amount * 2)], + ); + + // fund the AHR's SA on AHW with the WND tokens held in reserve + let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( + NetworkId::Rococo, + AssetHubRococo::para_id(), + ); + AssetHubWestend::fund_accounts(vec![(sov_ahr_on_ahw.clone(), amount * 2)]); + + // balances before + let sender_wnds_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains.clone().into(), &sender) + }); + let receiver_wnds_before = ::account_data_of(receiver.clone()).free; + + // send WNDs over the bridge, ROCs only used to pay fees on local AH, pay with WND on remote AH + { + let final_destination = asset_hub_westend_location(); + let intermediary_hop = PenpalA::sibling_location_of(AssetHubRococo::para_id()); + let context = PenpalA::execute_with(|| PenpalUniversalLocation::get()); + + // what happens at final destination + let beneficiary = AccountId32Junction { network: None, id: receiver.clone().into() }.into(); + // use WND as fees on the final destination (AHW) + let remote_fees: Asset = (wnd_at_rococo_parachains.clone(), amount).into(); + let remote_fees = remote_fees.reanchored(&final_destination, &context).unwrap(); + // buy execution using WNDs, then deposit all remaining WNDs + let xcm_on_final_dest = Xcm::<()>(vec![ + BuyExecution { fees: remote_fees, weight_limit: WeightLimit::Unlimited }, + DepositAsset { assets: Wild(AllCounted(1)), beneficiary }, + ]); + + // what happens at intermediary hop + // reanchor final dest (Asset Hub Westend) to the view of hop (Asset Hub Rococo) + let mut final_destination = final_destination.clone(); + final_destination.reanchor(&intermediary_hop, &context).unwrap(); + // reanchor WNDs to the view of hop (Asset Hub Rococo) + let asset: Asset = (wnd_at_rococo_parachains.clone(), amount).into(); + let asset = asset.reanchored(&intermediary_hop, &context).unwrap(); + // on Asset Hub Rococo, forward a request to withdraw WNDs from reserve on Asset Hub Westend + let xcm_on_hop = Xcm::<()>(vec![InitiateReserveWithdraw { + assets: Definite(asset.into()), // WNDs + reserve: final_destination, // AHW + xcm: xcm_on_final_dest, // XCM to execute on AHW + }]); + // assets to send from Penpal and how they reach the intermediary hop + let assets: Assets = vec![ + (wnd_at_rococo_parachains.clone(), amount).into(), + (roc_at_rococo_parachains.clone(), amount).into(), + ] + .into(); + let asset_transfer_type = TransferType::DestinationReserve; + let fees_id: AssetId = roc_at_rococo_parachains.into(); + let fees_transfer_type = TransferType::DestinationReserve; + + // initiate the transfer + send_assets_from_penpal_rococo_through_rococo_ah_to_westend_ah( + intermediary_hop, + (assets, asset_transfer_type), + (fees_id, fees_transfer_type), + xcm_on_hop, + ); + } + + // process AHW incoming message and check events + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + AssetHubWestend, + vec![ + // issue ROCs on AHW + RuntimeEvent::Balances(pallet_balances::Event::Issued { .. }) => {}, + // message processed successfully + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + + let sender_wnds_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains.into(), &sender) + }); + let receiver_wnds_after = ::account_data_of(receiver).free; + + // Sender's balance is reduced by sent "amount" + assert_eq!(sender_wnds_after, sender_wnds_before - amount); + // Receiver's balance is increased by no more than "amount" + assert!(receiver_wnds_after > receiver_wnds_before); + assert!(receiver_wnds_after <= receiver_wnds_before + amount); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/claim_assets.rs new file mode 100644 index 0000000000000000000000000000000000000000..e61dc35bdf8a3cecbaa1cb42582582b1b7c1183f --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/claim_assets.rs @@ -0,0 +1,29 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests related to claiming assets trapped during XCM execution. + +use crate::imports::*; + +use emulated_integration_tests_common::test_chain_can_claim_assets; +use xcm_executor::traits::DropAssets; + +#[test] +fn assets_can_be_claimed() { + let amount = BridgeHubRococoExistentialDeposit::get(); + let assets: Assets = (Parent, amount).into(); + + test_chain_can_claim_assets!(AssetHubRococo, RuntimeCall, NetworkId::Rococo, assets, amount); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs index 88dad06434b0d4a28295708c303907e02e70927b..ceccf98a0240dade42b8a00372e1ee8737cf1e03 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs @@ -16,44 +16,147 @@ use crate::imports::*; mod asset_transfers; +mod claim_assets; mod send_xcm; mod snowbridge; mod teleport; pub(crate) fn asset_hub_westend_location() -> Location { + Location::new(2, [GlobalConsensus(Westend), Parachain(AssetHubWestend::para_id().into())]) +} +pub(crate) fn bridge_hub_westend_location() -> Location { + Location::new(2, [GlobalConsensus(Westend), Parachain(BridgeHubWestend::para_id().into())]) +} + +// ROC and wROC +pub(crate) fn roc_at_ah_rococo() -> Location { + Parent.into() +} +pub(crate) fn bridged_roc_at_ah_westend() -> Location { + Location::new(2, [GlobalConsensus(Rococo)]) +} + +// wWND +pub(crate) fn bridged_wnd_at_ah_rococo() -> Location { + Location::new(2, [GlobalConsensus(Westend)]) +} + +// USDT and wUSDT +pub(crate) fn usdt_at_ah_rococo() -> Location { + Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into())]) +} +pub(crate) fn bridged_usdt_at_ah_westend() -> Location { Location::new( 2, - [GlobalConsensus(NetworkId::Westend), Parachain(AssetHubWestend::para_id().into())], + [ + GlobalConsensus(Rococo), + Parachain(AssetHubRococo::para_id().into()), + PalletInstance(ASSETS_PALLET_ID), + GeneralIndex(USDT_ID.into()), + ], ) } -pub(crate) fn bridge_hub_westend_location() -> Location { +// wETH has same relative location on both Rococo and Westend AssetHubs +pub(crate) fn weth_at_asset_hubs() -> Location { Location::new( 2, - [GlobalConsensus(NetworkId::Westend), Parachain(BridgeHubWestend::para_id().into())], + [ + GlobalConsensus(Ethereum { chain_id: snowbridge::CHAIN_ID }), + AccountKey20 { network: None, key: snowbridge::WETH }, + ], ) } -pub(crate) fn send_asset_from_asset_hub_rococo( +pub(crate) fn create_foreign_on_ah_rococo( + id: v3::Location, + sufficient: bool, + prefund_accounts: Vec<(AccountId, u128)>, +) { + let owner = AssetHubRococo::account_id_of(ALICE); + let min = ASSET_MIN_BALANCE; + AssetHubRococo::force_create_foreign_asset(id, owner, sufficient, min, prefund_accounts); +} + +pub(crate) fn create_foreign_on_ah_westend(id: v3::Location, sufficient: bool) { + let owner = AssetHubWestend::account_id_of(ALICE); + AssetHubWestend::force_create_foreign_asset(id, owner, sufficient, ASSET_MIN_BALANCE, vec![]); +} + +pub(crate) fn foreign_balance_on_ah_rococo(id: v3::Location, who: &AccountId) -> u128 { + AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(id, who) + }) +} +pub(crate) fn foreign_balance_on_ah_westend(id: v3::Location, who: &AccountId) -> u128 { + AssetHubWestend::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(id, who) + }) +} + +// set up pool +pub(crate) fn set_up_pool_with_wnd_on_ah_westend(foreign_asset: v3::Location) { + let wnd: v3::Location = v3::Parent.into(); + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + let owner = AssetHubWestendSender::get(); + let signed_owner = ::RuntimeOrigin::signed(owner.clone()); + + assert_ok!(::ForeignAssets::mint( + signed_owner.clone(), + foreign_asset.into(), + owner.clone().into(), + 3_000_000_000_000, + )); + assert_ok!(::AssetConversion::create_pool( + signed_owner.clone(), + Box::new(wnd), + Box::new(foreign_asset), + )); + assert_expected_events!( + AssetHubWestend, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, + ] + ); + assert_ok!(::AssetConversion::add_liquidity( + signed_owner.clone(), + Box::new(wnd), + Box::new(foreign_asset), + 1_000_000_000_000, + 2_000_000_000_000, + 1, + 1, + owner.into() + )); + assert_expected_events!( + AssetHubWestend, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {..}) => {}, + ] + ); + }); +} + +pub(crate) fn send_assets_from_asset_hub_rococo( destination: Location, - (id, amount): (Location, u128), + assets: Assets, + fee_idx: u32, ) -> DispatchResult { let signed_origin = ::RuntimeOrigin::signed(AssetHubRococoSender::get().into()); - let beneficiary: Location = AccountId32Junction { network: None, id: AssetHubWestendReceiver::get().into() }.into(); - let assets: Assets = (id, amount).into(); - let fee_asset_item = 0; - AssetHubRococo::execute_with(|| { ::PolkadotXcm::limited_reserve_transfer_assets( signed_origin, bx!(destination.into()), bx!(beneficiary.into()), bx!(assets.into()), - fee_asset_item, + fee_idx, WeightLimit::Unlimited, ) }) diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs index 78788634e6ff45c10b5fbebc91da4843d8f595e3..652447fa56010918d8816187207bc86e2ae99ea5 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs @@ -81,7 +81,11 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { // send XCM from AssetHubRococo - fails - destination version not known assert_err!( - send_asset_from_asset_hub_rococo(destination.clone(), (native_token.clone(), amount)), + send_assets_from_asset_hub_rococo( + destination.clone(), + (native_token.clone(), amount).into(), + 0 + ), DispatchError::Module(sp_runtime::ModuleError { index: 31, error: [1, 0, 0, 0], @@ -98,9 +102,10 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { newer_xcm_version, ); // send XCM from AssetHubRococo - ok - assert_ok!(send_asset_from_asset_hub_rococo( + assert_ok!(send_assets_from_asset_hub_rococo( destination.clone(), - (native_token.clone(), amount) + (native_token.clone(), amount).into(), + 0, )); // `ExportMessage` on local BridgeHub - fails - remote BridgeHub version not known @@ -115,9 +120,10 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { ); // send XCM from AssetHubRococo - ok - assert_ok!(send_asset_from_asset_hub_rococo( + assert_ok!(send_assets_from_asset_hub_rococo( destination.clone(), - (native_token.clone(), amount) + (native_token.clone(), amount).into(), + 0, )); assert_bridge_hub_rococo_message_accepted(true); assert_bridge_hub_westend_message_received(); diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs index 8196b27cfe028087e1a6279d4bac1f6c0cf691e5..40a1968ec557bd99730fd27e151a4aa9f2f2cfd9 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs @@ -13,12 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. use crate::imports::*; -use bridge_hub_rococo_runtime::{EthereumBeaconClient, EthereumInboundQueue, RuntimeOrigin}; use codec::{Decode, Encode}; use emulated_integration_tests_common::xcm_emulator::ConvertLocation; use frame_support::pallet_prelude::TypeInfo; use hex_literal::hex; -use rococo_system_emulated_network::penpal_emulated_chain::CustomizableAssetFromSystemAssetHub; use rococo_westend_system_emulated_network::BridgeHubRococoParaSender as BridgeHubRococoSender; use snowbridge_core::{inbound::InboundQueueFixture, outbound::OperatingMode}; use snowbridge_pallet_inbound_queue_fixtures::{ @@ -34,10 +32,10 @@ use sp_runtime::{DispatchError::Token, TokenError::FundsUnavailable}; use testnet_parachains_constants::rococo::snowbridge::EthereumNetwork; const INITIAL_FUND: u128 = 5_000_000_000 * ROCOCO_ED; -const CHAIN_ID: u64 = 11155111; +pub const CHAIN_ID: u64 = 11155111; const TREASURY_ACCOUNT: [u8; 32] = hex!("6d6f646c70792f74727372790000000000000000000000000000000000000000"); -const WETH: [u8; 20] = hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d"); +pub const WETH: [u8; 20] = hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d"); const ETHEREUM_DESTINATION_ADDRESS: [u8; 20] = hex!("44a57ee2f2FCcb85FDa2B0B18EBD0D8D2333700e"); const INSUFFICIENT_XCM_FEE: u128 = 1000; const XCM_FEE: u128 = 4_000_000_000; @@ -64,7 +62,7 @@ pub fn send_inbound_message(fixture: InboundQueueFixture) -> DispatchResult { ) .unwrap(); EthereumInboundQueue::submit( - RuntimeOrigin::signed(BridgeHubRococoSender::get()), + BridgeHubRococoRuntimeOrigin::signed(BridgeHubRococoSender::get()), fixture.message, ) } @@ -298,7 +296,7 @@ fn send_token_from_ethereum_to_penpal() { assert_ok!(::System::set_storage( ::RuntimeOrigin::root(), vec![( - CustomizableAssetFromSystemAssetHub::key().to_vec(), + PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), Location::new(2, [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })]).encode(), )], )); @@ -379,7 +377,7 @@ fn send_token_from_ethereum_to_penpal() { /// - returning the token to Ethereum #[test] fn send_weth_asset_from_asset_hub_to_ethereum() { - use asset_hub_rococo_runtime::xcm_config::bridging::to_ethereum::DefaultBridgeHubEthereumBaseFee; + use ahr_xcm_config::bridging::to_ethereum::DefaultBridgeHubEthereumBaseFee; let assethub_location = BridgeHubRococo::sibling_location_of(AssetHubRococo::para_id()); let assethub_sovereign = BridgeHubRococo::sovereign_account_id_of(assethub_location); diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/teleport.rs index 8f51f5b180004d3f694cc68ba6d3c11ab46df95a..1fb03748d926c9a422ede319977c5e39c0f24b16 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/teleport.rs @@ -13,8 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::tests::*; -use bridge_hub_rococo_runtime::xcm_config::XcmConfig; +use crate::imports::*; #[test] fn teleport_to_other_system_parachains_works() { @@ -22,9 +21,9 @@ fn teleport_to_other_system_parachains_works() { let native_asset: Assets = (Parent, amount).into(); test_parachain_is_trusted_teleporter!( - BridgeHubRococo, // Origin - XcmConfig, // XCM configuration - vec![AssetHubRococo], // Destinations + BridgeHubRococo, // Origin + BridgeHubRococoXcmConfig, // XCM configuration + vec![AssetHubRococo], // Destinations (native_asset, amount) ); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml index 6aebf8862d62e794a24e6926ff487d1956ed792b..6b83479eaf89a5677a77816b748948c8ba93fa53 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml @@ -11,26 +11,26 @@ publish = false workspace = true [dependencies] +hex-literal = { workspace = true, default-features = true } # Substrate -frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false } -pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false } -pallet-asset-conversion = { path = "../../../../../../../substrate/frame/asset-conversion", default-features = false } -pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false } -pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue" } -sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } +frame-support = { workspace = true } +pallet-assets = { workspace = true } +pallet-asset-conversion = { workspace = true } +pallet-balances = { workspace = true } +pallet-message-queue = { workspace = true, default-features = true } +sp-runtime = { workspace = true } # Polkadot -xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } -pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false } +xcm = { workspace = true } +pallet-xcm = { workspace = true } +xcm-executor = { workspace = true } # Bridges -pallet-bridge-messages = { path = "../../../../../../../bridges/modules/messages", default-features = false } +pallet-bridge-messages = { workspace = true } # Cumulus -parachains-common = { path = "../../../../../common" } -cumulus-pallet-xcmp-queue = { path = "../../../../../../pallets/xcmp-queue", default-features = false } -bridge-hub-westend-runtime = { path = "../../../../../runtimes/bridge-hubs/bridge-hub-westend", default-features = false } -emulated-integration-tests-common = { path = "../../../common", default-features = false } -rococo-westend-system-emulated-network = { path = "../../../networks/rococo-westend-system" } +cumulus-pallet-xcmp-queue = { workspace = true } +emulated-integration-tests-common = { workspace = true } +parachains-common = { workspace = true, default-features = true } +rococo-westend-system-emulated-network = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs index 36b846e103131882e36b899bdb323d9b969cddde..782b83bac4754ba6888b8d513a13887d5cb7ecf3 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs @@ -36,20 +36,25 @@ mod imports { xcm_emulator::{ assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, TestExt, }, + ASSETS_PALLET_ID, USDT_ID, }; pub use parachains_common::AccountId; pub use rococo_westend_system_emulated_network::{ asset_hub_rococo_emulated_chain::{ - genesis::ED as ASSET_HUB_ROCOCO_ED, AssetHubRococoParaPallet as AssetHubRococoPallet, + genesis::{AssetHubRococoAssetOwner, ED as ASSET_HUB_ROCOCO_ED}, + AssetHubRococoParaPallet as AssetHubRococoPallet, }, asset_hub_westend_emulated_chain::{ genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, }, bridge_hub_westend_emulated_chain::{ - genesis::ED as BRIDGE_HUB_WESTEND_ED, - BridgeHubWestendParaPallet as BridgeHubWestendPallet, + genesis::ED as BRIDGE_HUB_WESTEND_ED, BridgeHubWestendExistentialDeposit, + BridgeHubWestendParaPallet as BridgeHubWestendPallet, BridgeHubWestendXcmConfig, + }, + penpal_emulated_chain::{ + penpal_runtime::xcm_config::UniversalLocation as PenpalUniversalLocation, + PenpalAssetOwner, PenpalBParaPallet as PenpalBPallet, }, - penpal_emulated_chain::{PenpalAssetOwner, PenpalBParaPallet as PenpalBPallet}, westend_emulated_chain::WestendRelayPallet as WestendPallet, AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, AssetHubRococoParaSender as AssetHubRococoSender, AssetHubWestendPara as AssetHubWestend, diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs index 597e77d9049cf030fc2b0f0d8e986da53f1f08e2..0c0b04cd45a91c42592052799ba9580bd6e4219a 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs @@ -14,165 +14,132 @@ // limitations under the License. use crate::tests::*; -fn send_asset_from_asset_hub_westend_to_asset_hub_rococo(id: Location, amount: u128) { - let destination = asset_hub_rococo_location(); - +fn send_assets_over_bridge(send_fn: F) { // fund the AHW's SA on BHW for paying bridge transport fees BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), 10_000_000_000_000u128); // set XCM versions - AssetHubWestend::force_xcm_version(destination.clone(), XCM_VERSION); + let local_asset_hub = PenpalB::sibling_location_of(AssetHubWestend::para_id()); + PenpalB::force_xcm_version(local_asset_hub.clone(), XCM_VERSION); + AssetHubWestend::force_xcm_version(asset_hub_rococo_location(), XCM_VERSION); BridgeHubWestend::force_xcm_version(bridge_hub_rococo_location(), XCM_VERSION); // send message over bridge - assert_ok!(send_asset_from_asset_hub_westend(destination, (id, amount))); + send_fn(); + + // process and verify intermediary hops assert_bridge_hub_westend_message_accepted(true); assert_bridge_hub_rococo_message_received(); } -fn send_asset_from_penpal_westend_through_local_asset_hub_to_rococo_asset_hub( - id: Location, - transfer_amount: u128, -) { - let destination = asset_hub_rococo_location(); - let local_asset_hub: Location = PenpalB::sibling_location_of(AssetHubWestend::para_id()); - let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of( - AssetHubWestend::sibling_location_of(PenpalB::para_id()), - ); - let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( - Rococo, - AssetHubRococo::para_id(), - ); - - // fund the AHW's SA on BHW for paying bridge transport fees - BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), 10_000_000_000_000u128); +fn set_up_wnds_for_penpal_westend_through_ahw_to_ahr( + sender: &AccountId, + amount: u128, +) -> (Location, v3::Location) { + let wnd_at_westend_parachains = wnd_at_ah_westend(); + let wnd_at_asset_hub_rococo = bridged_wnd_at_ah_rococo().try_into().unwrap(); + create_foreign_on_ah_rococo(wnd_at_asset_hub_rococo, true); - // set XCM versions - PenpalB::force_xcm_version(local_asset_hub.clone(), XCM_VERSION); - AssetHubWestend::force_xcm_version(destination.clone(), XCM_VERSION); - BridgeHubWestend::force_xcm_version(bridge_hub_rococo_location(), XCM_VERSION); - - // send message over bridge - assert_ok!(PenpalB::execute_with(|| { - let signed_origin = ::RuntimeOrigin::signed(PenpalBSender::get()); - let beneficiary: Location = - AccountId32Junction { network: None, id: AssetHubRococoReceiver::get().into() }.into(); - let assets: Assets = (id.clone(), transfer_amount).into(); - let fees_id: AssetId = id.into(); - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(assets.len() as u32)), - beneficiary, - }]); + let penpal_location = AssetHubWestend::sibling_location_of(PenpalB::para_id()); + let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of(penpal_location); + // fund Penpal's sovereign account on AssetHub + AssetHubWestend::fund_accounts(vec![(sov_penpal_on_ahw.into(), amount * 2)]); + // fund Penpal's sender account + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + wnd_at_westend_parachains.clone(), + sender.clone(), + amount * 2, + ); + (wnd_at_westend_parachains, wnd_at_asset_hub_rococo) +} - ::PolkadotXcm::transfer_assets_using_type_and_then( - signed_origin, - bx!(destination.into()), - bx!(assets.into()), - bx!(TransferType::RemoteReserve(local_asset_hub.clone().into())), - bx!(fees_id.into()), - bx!(TransferType::RemoteReserve(local_asset_hub.into())), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - WeightLimit::Unlimited, - ) - })); - AssetHubWestend::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - AssetHubWestend, - vec![ - // Amount to reserve transfer is withdrawn from Penpal's sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } - ) => { - who: *who == sov_penpal_on_ahw.clone().into(), - amount: *amount == transfer_amount, - }, - // Amount deposited in AHR's sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == sov_ahr_on_ahw.clone().into(), - }, - RuntimeEvent::XcmpQueue( - cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } - ) => {}, - ] +fn send_assets_from_penpal_westend_through_westend_ah_to_rococo_ah( + destination: Location, + assets: (Assets, TransferType), + fees: (AssetId, TransferType), + custom_xcm_on_dest: Xcm<()>, +) { + send_assets_over_bridge(|| { + let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalB::para_id()), ); + let sov_ahr_on_ahw = + AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( + Rococo, + AssetHubRococo::para_id(), + ); + + // send message over bridge + assert_ok!(PenpalB::execute_with(|| { + let signed_origin = ::RuntimeOrigin::signed(PenpalBSender::get()); + ::PolkadotXcm::transfer_assets_using_type_and_then( + signed_origin, + bx!(destination.into()), + bx!(assets.0.into()), + bx!(assets.1), + bx!(fees.0.into()), + bx!(fees.1), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + WeightLimit::Unlimited, + ) + })); + // verify intermediary AH Westend hop + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + AssetHubWestend, + vec![ + // Amount to reserve transfer is withdrawn from Penpal's sovereign account + RuntimeEvent::Balances( + pallet_balances::Event::Burned { who, .. } + ) => { + who: *who == sov_penpal_on_ahw.clone().into(), + }, + // Amount deposited in AHR's sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { + who: *who == sov_ahr_on_ahw.clone().into(), + }, + RuntimeEvent::XcmpQueue( + cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } + ) => {}, + ] + ); + }); }); - assert_bridge_hub_westend_message_accepted(true); - assert_bridge_hub_rococo_message_received(); } #[test] +/// Test transfer of WND from AssetHub Westend to AssetHub Rococo. fn send_wnds_from_asset_hub_westend_to_asset_hub_rococo() { - let wnd_at_asset_hub_westend: Location = Parent.into(); - let wnd_at_asset_hub_rococo = - v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Westend)]); - let owner: AccountId = AssetHubRococo::account_id_of(ALICE); - AssetHubRococo::force_create_foreign_asset( - wnd_at_asset_hub_rococo, - owner, - true, - ASSET_MIN_BALANCE, - vec![], - ); + let amount = ASSET_HUB_WESTEND_ED * 1_000; + let sender = AssetHubWestendSender::get(); + let receiver = AssetHubRococoReceiver::get(); + let wnd_at_asset_hub_westend = wnd_at_ah_westend(); + let bridged_wnd_at_asset_hub_rococo = bridged_wnd_at_ah_rococo().try_into().unwrap(); + create_foreign_on_ah_rococo(bridged_wnd_at_asset_hub_rococo, true); + + set_up_pool_with_roc_on_ah_rococo(bridged_wnd_at_asset_hub_rococo, true); + let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( Rococo, AssetHubRococo::para_id(), ); - - AssetHubRococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - // setup a pool to pay xcm fees with `wnd_at_asset_hub_rococo` tokens - assert_ok!(::ForeignAssets::mint( - ::RuntimeOrigin::signed(AssetHubRococoSender::get()), - wnd_at_asset_hub_rococo.into(), - AssetHubRococoSender::get().into(), - 3_000_000_000_000, - )); - - assert_ok!(::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubRococoSender::get()), - Box::new(xcm::v3::Parent.into()), - Box::new(wnd_at_asset_hub_rococo), - )); - - assert_expected_events!( - AssetHubRococo, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, - ] - ); - - assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed(AssetHubRococoSender::get()), - Box::new(xcm::v3::Parent.into()), - Box::new(wnd_at_asset_hub_rococo), - 1_000_000_000_000, - 2_000_000_000_000, - 1, - 1, - AssetHubRococoSender::get().into() - )); - - assert_expected_events!( - AssetHubRococo, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {..}) => {}, - ] - ); - }); - let wnds_in_reserve_on_ahw_before = ::account_data_of(sov_ahr_on_ahw.clone()).free; - let sender_wnds_before = - ::account_data_of(AssetHubWestendSender::get()).free; - let receiver_wnds_before = AssetHubRococo::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(wnd_at_asset_hub_rococo, &AssetHubRococoReceiver::get()) + let sender_wnds_before = ::account_data_of(sender.clone()).free; + let receiver_wnds_before = + foreign_balance_on_ah_rococo(bridged_wnd_at_asset_hub_rococo, &receiver); + + // send WNDs, use them for fees + send_assets_over_bridge(|| { + let destination = asset_hub_rococo_location(); + let assets: Assets = (wnd_at_asset_hub_westend, amount).into(); + let fee_idx = 0; + assert_ok!(send_assets_from_asset_hub_westend(destination, assets, fee_idx)); }); - let amount = ASSET_HUB_WESTEND_ED * 1_000; - send_asset_from_asset_hub_westend_to_asset_hub_rococo(wnd_at_asset_hub_westend, amount); + // verify expected events on final destination AssetHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( @@ -180,8 +147,8 @@ fn send_wnds_from_asset_hub_westend_to_asset_hub_rococo() { vec![ // issue WNDs on AHR RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == wnd_at_asset_hub_rococo, - owner: *owner == AssetHubRococoReceiver::get(), + asset_id: *asset_id == bridged_wnd_at_asset_hub_rococo, + owner: *owner == receiver, }, // message processed successfully RuntimeEvent::MessageQueue( @@ -191,12 +158,9 @@ fn send_wnds_from_asset_hub_westend_to_asset_hub_rococo() { ); }); - let sender_wnds_after = - ::account_data_of(AssetHubWestendSender::get()).free; - let receiver_wnds_after = AssetHubRococo::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(wnd_at_asset_hub_rococo, &AssetHubRococoReceiver::get()) - }); + let sender_wnds_after = ::account_data_of(sender).free; + let receiver_wnds_after = + foreign_balance_on_ah_rococo(bridged_wnd_at_asset_hub_rococo, &receiver); let wnds_in_reserve_on_ahw_after = ::account_data_of(sov_ahr_on_ahw).free; @@ -209,18 +173,28 @@ fn send_wnds_from_asset_hub_westend_to_asset_hub_rococo() { } #[test] -fn send_rocs_from_asset_hub_westend_to_asset_hub_rococo() { +/// Send bridged assets "back" from AssetHub Rococo to AssetHub Westend. +/// +/// This mix of assets should cover the whole range: +/// - bridged native assets: ROC, +/// - bridged trust-based assets: USDT (exists only on Rococo, Westend gets it from Rococo over +/// bridge), +/// - bridged foreign asset / double-bridged asset (other bridge / Snowfork): wETH (bridged from +/// Ethereum to Rococo over Snowbridge, then bridged over to Westend through this bridge). +fn send_back_rocs_usdt_and_weth_from_asset_hub_westend_to_asset_hub_rococo() { let prefund_amount = 10_000_000_000_000u128; - let roc_at_asset_hub_westend = - v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Rococo)]); - let owner: AccountId = AssetHubWestend::account_id_of(ALICE); - AssetHubWestend::force_create_foreign_asset( - roc_at_asset_hub_westend, - owner, - true, - ASSET_MIN_BALANCE, - vec![(AssetHubWestendSender::get(), prefund_amount)], - ); + let amount_to_send = ASSET_HUB_ROCOCO_ED * 1_000; + let sender = AssetHubWestendSender::get(); + let receiver = AssetHubRococoReceiver::get(); + let bridged_roc_at_asset_hub_westend = bridged_roc_at_ah_westend(); + let bridged_roc_at_asset_hub_westend_v3 = + bridged_roc_at_asset_hub_westend.clone().try_into().unwrap(); + let prefund_accounts = vec![(sender.clone(), prefund_amount)]; + create_foreign_on_ah_westend(bridged_roc_at_asset_hub_westend_v3, true, prefund_accounts); + + //////////////////////////////////////////////////////////// + // Let's first send back just some ROCs as a simple example + //////////////////////////////////////////////////////////// // fund the AHW's SA on AHR with the ROC tokens held in reserve let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( @@ -232,19 +206,20 @@ fn send_rocs_from_asset_hub_westend_to_asset_hub_rococo() { let rocs_in_reserve_on_ahr_before = ::account_data_of(sov_ahw_on_ahr.clone()).free; assert_eq!(rocs_in_reserve_on_ahr_before, prefund_amount); - let sender_rocs_before = AssetHubWestend::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(roc_at_asset_hub_westend, &AssetHubWestendSender::get()) - }); + + let sender_rocs_before = + foreign_balance_on_ah_westend(bridged_roc_at_asset_hub_westend_v3, &sender); assert_eq!(sender_rocs_before, prefund_amount); - let receiver_rocs_before = - ::account_data_of(AssetHubRococoReceiver::get()).free; + let receiver_rocs_before = ::account_data_of(receiver.clone()).free; + + // send back ROCs, use them for fees + send_assets_over_bridge(|| { + let destination = asset_hub_rococo_location(); + let assets: Assets = (bridged_roc_at_asset_hub_westend, amount_to_send).into(); + let fee_idx = 0; + assert_ok!(send_assets_from_asset_hub_westend(destination, assets, fee_idx)); + }); - let amount_to_send = ASSET_HUB_ROCOCO_ED * 1_000; - send_asset_from_asset_hub_westend_to_asset_hub_rococo( - roc_at_asset_hub_westend.try_into().unwrap(), - amount_to_send, - ); AssetHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( @@ -259,7 +234,7 @@ fn send_rocs_from_asset_hub_westend_to_asset_hub_rococo() { }, // ROCs deposited to beneficiary RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == AssetHubRococoReceiver::get(), + who: *who == receiver, }, // message processed successfully RuntimeEvent::MessageQueue( @@ -269,12 +244,9 @@ fn send_rocs_from_asset_hub_westend_to_asset_hub_rococo() { ); }); - let sender_rocs_after = AssetHubWestend::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(roc_at_asset_hub_westend, &AssetHubWestendSender::get()) - }); - let receiver_rocs_after = - ::account_data_of(AssetHubRococoReceiver::get()).free; + let sender_rocs_after = + foreign_balance_on_ah_westend(bridged_roc_at_asset_hub_westend_v3, &sender); + let receiver_rocs_after = ::account_data_of(receiver.clone()).free; let rocs_in_reserve_on_ahr_after = ::account_data_of(sov_ahw_on_ahr.clone()).free; @@ -284,59 +256,141 @@ fn send_rocs_from_asset_hub_westend_to_asset_hub_rococo() { assert!(receiver_rocs_after > receiver_rocs_before); // Reserve balance is reduced by sent amount assert_eq!(rocs_in_reserve_on_ahr_after, rocs_in_reserve_on_ahr_before - amount_to_send); + + ////////////////////////////////////////////////////////////////// + // Now let's send back over USDTs + wETH (and pay fees with USDT) + ////////////////////////////////////////////////////////////////// + + // wETH has same relative location on both Rococo and Westend AssetHubs + let bridged_weth_at_ah = weth_at_asset_hubs().try_into().unwrap(); + let bridged_usdt_at_asset_hub_westend = bridged_usdt_at_ah_westend().try_into().unwrap(); + + // set up destination chain AH Rococo: + // create a ROC/USDT pool to be able to pay fees with USDT (USDT created in genesis) + set_up_pool_with_roc_on_ah_rococo(usdt_at_ah_rococo().try_into().unwrap(), false); + // create wETH on Rococo (IRL it's already created by Snowbridge) + create_foreign_on_ah_rococo(bridged_weth_at_ah, true); + // prefund AHW's sovereign account on AHR to be able to withdraw USDT and wETH from reserves + let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( + Westend, + AssetHubWestend::para_id(), + ); + AssetHubRococo::mint_asset( + ::RuntimeOrigin::signed(AssetHubRococoAssetOwner::get()), + USDT_ID, + sov_ahw_on_ahr.clone(), + amount_to_send * 2, + ); + AssetHubRococo::mint_foreign_asset( + ::RuntimeOrigin::signed(AssetHubRococo::account_id_of(ALICE)), + bridged_weth_at_ah, + sov_ahw_on_ahr, + amount_to_send * 2, + ); + + // set up source chain AH Westend: + // create wETH and USDT foreign assets on Westend and prefund sender's account + let prefund_accounts = vec![(sender.clone(), amount_to_send * 2)]; + create_foreign_on_ah_westend(bridged_weth_at_ah, true, prefund_accounts.clone()); + create_foreign_on_ah_westend(bridged_usdt_at_asset_hub_westend, true, prefund_accounts); + + // check balances before + let receiver_usdts_before = AssetHubRococo::execute_with(|| { + type Assets = ::Assets; + >::balance(USDT_ID, &receiver) + }); + let receiver_weth_before = foreign_balance_on_ah_rococo(bridged_weth_at_ah, &receiver); + + let usdt_id: AssetId = Location::try_from(bridged_usdt_at_asset_hub_westend).unwrap().into(); + // send USDTs and wETHs + let assets: Assets = vec![ + (usdt_id.clone(), amount_to_send).into(), + (Location::try_from(bridged_weth_at_ah).unwrap(), amount_to_send).into(), + ] + .into(); + // use USDT for fees + let fee = usdt_id; + + // use the more involved transfer extrinsic + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(assets.len() as u32)), + beneficiary: AccountId32Junction { network: None, id: receiver.clone().into() }.into(), + }]); + assert_ok!(AssetHubWestend::execute_with(|| { + ::PolkadotXcm::transfer_assets_using_type_and_then( + ::RuntimeOrigin::signed(sender.into()), + bx!(asset_hub_rococo_location().into()), + bx!(assets.into()), + bx!(TransferType::DestinationReserve), + bx!(fee.into()), + bx!(TransferType::DestinationReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + WeightLimit::Unlimited, + ) + })); + // verify hops (also advances the message through the hops) + assert_bridge_hub_westend_message_accepted(true); + assert_bridge_hub_rococo_message_received(); + AssetHubRococo::execute_with(|| { + AssetHubRococo::assert_xcmp_queue_success(None); + }); + + let receiver_usdts_after = AssetHubRococo::execute_with(|| { + type Assets = ::Assets; + >::balance(USDT_ID, &receiver) + }); + let receiver_weth_after = foreign_balance_on_ah_rococo(bridged_weth_at_ah, &receiver); + + // Receiver's USDT balance is increased by almost `amount_to_send` (minus fees) + assert!(receiver_usdts_after > receiver_usdts_before); + assert!(receiver_usdts_after < receiver_usdts_before + amount_to_send); + // Receiver's wETH balance is increased by `amount_to_send` + assert_eq!(receiver_weth_after, receiver_weth_before + amount_to_send); } #[test] fn send_wnds_from_penpal_westend_through_asset_hub_westend_to_asset_hub_rococo() { - let wnd_at_westend_parachains: Location = Parent.into(); - let wnd_at_asset_hub_rococo = Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]); - let owner: AccountId = AssetHubRococo::account_id_of(ALICE); - AssetHubRococo::force_create_foreign_asset( - wnd_at_asset_hub_rococo.clone().try_into().unwrap(), - owner, - true, - ASSET_MIN_BALANCE, - vec![], - ); + let amount = ASSET_HUB_WESTEND_ED * 10_000_000; + let sender = PenpalBSender::get(); + let receiver = AssetHubRococoReceiver::get(); + let local_asset_hub = PenpalB::sibling_location_of(AssetHubWestend::para_id()); + let (wnd_at_westend_parachains, wnd_at_asset_hub_rococo) = + set_up_wnds_for_penpal_westend_through_ahw_to_ahr(&sender, amount); + let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( Rococo, AssetHubRococo::para_id(), ); - - let amount = ASSET_HUB_WESTEND_ED * 10_000_000; - let penpal_location = AssetHubWestend::sibling_location_of(PenpalB::para_id()); - let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of(penpal_location); - // fund Penpal's sovereign account on AssetHub - AssetHubWestend::fund_accounts(vec![(sov_penpal_on_ahw.into(), amount * 2)]); - // fund Penpal's sender account - PenpalB::mint_foreign_asset( - ::RuntimeOrigin::signed(PenpalAssetOwner::get()), - wnd_at_westend_parachains.clone(), - PenpalBSender::get(), - amount * 2, - ); - let wnds_in_reserve_on_ahw_before = ::account_data_of(sov_ahr_on_ahw.clone()).free; let sender_wnds_before = PenpalB::execute_with(|| { type ForeignAssets = ::ForeignAssets; - >::balance( - wnd_at_westend_parachains.clone(), - &PenpalBSender::get(), - ) + >::balance(wnd_at_westend_parachains.clone(), &sender) }); - let receiver_wnds_before = AssetHubRococo::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance( - wnd_at_asset_hub_rococo.clone().try_into().unwrap(), - &AssetHubRococoReceiver::get(), - ) - }); - send_asset_from_penpal_westend_through_local_asset_hub_to_rococo_asset_hub( - wnd_at_westend_parachains.clone(), - amount, - ); + let receiver_wnds_before = foreign_balance_on_ah_rococo(wnd_at_asset_hub_rococo, &receiver); + + // Send WNDs over bridge + { + let destination = asset_hub_rococo_location(); + let assets: Assets = (wnd_at_westend_parachains.clone(), amount).into(); + let asset_transfer_type = TransferType::RemoteReserve(local_asset_hub.clone().into()); + let fees_id: AssetId = wnd_at_westend_parachains.clone().into(); + let fees_transfer_type = TransferType::RemoteReserve(local_asset_hub.into()); + let beneficiary: Location = + AccountId32Junction { network: None, id: receiver.clone().into() }.into(); + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(assets.len() as u32)), + beneficiary, + }]); + send_assets_from_penpal_westend_through_westend_ah_to_rococo_ah( + destination, + (assets, asset_transfer_type), + (fees_id, fees_transfer_type), + custom_xcm_on_dest, + ); + } + // process AHR incoming message and check events AssetHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( @@ -345,7 +399,7 @@ fn send_wnds_from_penpal_westend_through_asset_hub_westend_to_asset_hub_rococo() // issue WNDs on AHR RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { asset_id: *asset_id == wnd_at_westend_parachains.clone().try_into().unwrap(), - owner: *owner == AssetHubRococoReceiver::get(), + owner: owner == &receiver, }, // message processed successfully RuntimeEvent::MessageQueue( @@ -357,15 +411,9 @@ fn send_wnds_from_penpal_westend_through_asset_hub_westend_to_asset_hub_rococo() let sender_wnds_after = PenpalB::execute_with(|| { type ForeignAssets = ::ForeignAssets; - >::balance(wnd_at_westend_parachains, &PenpalBSender::get()) - }); - let receiver_wnds_after = AssetHubRococo::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance( - wnd_at_asset_hub_rococo.try_into().unwrap(), - &AssetHubRococoReceiver::get(), - ) + >::balance(wnd_at_westend_parachains, &sender) }); + let receiver_wnds_after = foreign_balance_on_ah_rococo(wnd_at_asset_hub_rococo, &receiver); let wnds_in_reserve_on_ahw_after = ::account_data_of(sov_ahr_on_ahw.clone()).free; @@ -377,3 +425,121 @@ fn send_wnds_from_penpal_westend_through_asset_hub_westend_to_asset_hub_rococo() assert!(wnds_in_reserve_on_ahw_after > wnds_in_reserve_on_ahw_before); assert!(wnds_in_reserve_on_ahw_after <= wnds_in_reserve_on_ahw_before + amount); } + +#[test] +fn send_back_rocs_from_penpal_westend_through_asset_hub_westend_to_asset_hub_rococo() { + let roc_at_westend_parachains = bridged_roc_at_ah_westend(); + let roc_at_westend_parachains_v3 = roc_at_westend_parachains.clone().try_into().unwrap(); + let amount = ASSET_HUB_WESTEND_ED * 10_000_000; + let sender = PenpalBSender::get(); + let receiver = AssetHubRococoReceiver::get(); + + // set up WNDs for transfer + let (wnd_at_westend_parachains, _) = + set_up_wnds_for_penpal_westend_through_ahw_to_ahr(&sender, amount); + + // set up ROCs for transfer + let penpal_location = AssetHubWestend::sibling_location_of(PenpalB::para_id()); + let sov_penpal_on_ahr = AssetHubWestend::sovereign_account_id_of(penpal_location); + let prefund_accounts = vec![(sov_penpal_on_ahr, amount * 2)]; + create_foreign_on_ah_westend(roc_at_westend_parachains_v3, true, prefund_accounts); + let asset_owner: AccountId = AssetHubWestend::account_id_of(ALICE); + PenpalB::force_create_foreign_asset( + roc_at_westend_parachains.clone(), + asset_owner.clone(), + true, + ASSET_MIN_BALANCE, + vec![(sender.clone(), amount * 2)], + ); + + // fund the AHW's SA on AHR with the ROC tokens held in reserve + let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( + NetworkId::Westend, + AssetHubWestend::para_id(), + ); + AssetHubRococo::fund_accounts(vec![(sov_ahw_on_ahr.clone(), amount * 2)]); + + // balances before + let sender_rocs_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_at_westend_parachains.clone().into(), &sender) + }); + let receiver_rocs_before = ::account_data_of(receiver.clone()).free; + + // send ROCs over the bridge, WNDs only used to pay fees on local AH, pay with ROC on remote AH + { + let final_destination = asset_hub_rococo_location(); + let intermediary_hop = PenpalB::sibling_location_of(AssetHubWestend::para_id()); + let context = PenpalB::execute_with(|| PenpalUniversalLocation::get()); + + // what happens at final destination + let beneficiary = AccountId32Junction { network: None, id: receiver.clone().into() }.into(); + // use ROC as fees on the final destination (AHW) + let remote_fees: Asset = (roc_at_westend_parachains.clone(), amount).into(); + let remote_fees = remote_fees.reanchored(&final_destination, &context).unwrap(); + // buy execution using ROCs, then deposit all remaining ROCs + let xcm_on_final_dest = Xcm::<()>(vec![ + BuyExecution { fees: remote_fees, weight_limit: WeightLimit::Unlimited }, + DepositAsset { assets: Wild(AllCounted(1)), beneficiary }, + ]); + + // what happens at intermediary hop + // reanchor final dest (Asset Hub Rococo) to the view of hop (Asset Hub Westend) + let mut final_destination = final_destination.clone(); + final_destination.reanchor(&intermediary_hop, &context).unwrap(); + // reanchor ROCs to the view of hop (Asset Hub Westend) + let asset: Asset = (roc_at_westend_parachains.clone(), amount).into(); + let asset = asset.reanchored(&intermediary_hop, &context).unwrap(); + // on Asset Hub Westend, forward a request to withdraw ROCs from reserve on Asset Hub Rococo + let xcm_on_hop = Xcm::<()>(vec![InitiateReserveWithdraw { + assets: Definite(asset.into()), // ROCs + reserve: final_destination, // AHR + xcm: xcm_on_final_dest, // XCM to execute on AHR + }]); + // assets to send from Penpal and how they reach the intermediary hop + let assets: Assets = vec![ + (roc_at_westend_parachains.clone(), amount).into(), + (wnd_at_westend_parachains.clone(), amount).into(), + ] + .into(); + let asset_transfer_type = TransferType::DestinationReserve; + let fees_id: AssetId = wnd_at_westend_parachains.into(); + let fees_transfer_type = TransferType::DestinationReserve; + + // initiate the transfer + send_assets_from_penpal_westend_through_westend_ah_to_rococo_ah( + intermediary_hop, + (assets, asset_transfer_type), + (fees_id, fees_transfer_type), + xcm_on_hop, + ); + } + + // process AHR incoming message and check events + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + AssetHubRococo, + vec![ + // issue WNDs on AHR + RuntimeEvent::Balances(pallet_balances::Event::Issued { .. }) => {}, + // message processed successfully + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + + let sender_rocs_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_at_westend_parachains.into(), &sender) + }); + let receiver_rocs_after = ::account_data_of(receiver).free; + + // Sender's balance is reduced by sent "amount" + assert_eq!(sender_rocs_after, sender_rocs_before - amount); + // Receiver's balance is increased by no more than "amount" + assert!(receiver_rocs_after > receiver_rocs_before); + assert!(receiver_rocs_after <= receiver_rocs_before + amount); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/claim_assets.rs new file mode 100644 index 0000000000000000000000000000000000000000..e62ce6843258e641ddd1e86dc0c5b006db31e4df --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/claim_assets.rs @@ -0,0 +1,29 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests related to claiming assets trapped during XCM execution. + +use crate::imports::*; + +use emulated_integration_tests_common::test_chain_can_claim_assets; +use xcm_executor::traits::DropAssets; + +#[test] +fn assets_can_be_claimed() { + let amount = BridgeHubWestendExistentialDeposit::get(); + let assets: Assets = (Parent, amount).into(); + + test_chain_can_claim_assets!(AssetHubWestend, RuntimeCall, NetworkId::Westend, assets, amount); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs index b781d6e987ca1fc7f2a64710263f432c1cc8b3c6..768b647a13fc19fae244a6ede2f8d527726e9963 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs @@ -16,43 +16,165 @@ use crate::imports::*; mod asset_transfers; +mod claim_assets; mod send_xcm; mod teleport; +mod snowbridge { + pub const CHAIN_ID: u64 = 11155111; + pub const WETH: [u8; 20] = hex_literal::hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d"); +} + pub(crate) fn asset_hub_rococo_location() -> Location { + Location::new(2, [GlobalConsensus(Rococo), Parachain(AssetHubRococo::para_id().into())]) +} + +pub(crate) fn bridge_hub_rococo_location() -> Location { + Location::new(2, [GlobalConsensus(Rococo), Parachain(BridgeHubRococo::para_id().into())]) +} + +// WND and wWND +pub(crate) fn wnd_at_ah_westend() -> Location { + Parent.into() +} +pub(crate) fn bridged_wnd_at_ah_rococo() -> Location { + Location::new(2, [GlobalConsensus(Westend)]) +} + +// wROC +pub(crate) fn bridged_roc_at_ah_westend() -> Location { + Location::new(2, [GlobalConsensus(Rococo)]) +} + +// USDT and wUSDT +pub(crate) fn usdt_at_ah_rococo() -> Location { + Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into())]) +} +pub(crate) fn bridged_usdt_at_ah_westend() -> Location { Location::new( 2, - [GlobalConsensus(NetworkId::Rococo), Parachain(AssetHubRococo::para_id().into())], + [ + GlobalConsensus(Rococo), + Parachain(AssetHubRococo::para_id().into()), + PalletInstance(ASSETS_PALLET_ID), + GeneralIndex(USDT_ID.into()), + ], ) } -pub(crate) fn bridge_hub_rococo_location() -> Location { +// wETH has same relative location on both Rococo and Westend AssetHubs +pub(crate) fn weth_at_asset_hubs() -> Location { Location::new( 2, - [GlobalConsensus(NetworkId::Rococo), Parachain(BridgeHubRococo::para_id().into())], + [ + GlobalConsensus(Ethereum { chain_id: snowbridge::CHAIN_ID }), + AccountKey20 { network: None, key: snowbridge::WETH }, + ], ) } -pub(crate) fn send_asset_from_asset_hub_westend( +pub(crate) fn create_foreign_on_ah_rococo(id: v3::Location, sufficient: bool) { + let owner = AssetHubRococo::account_id_of(ALICE); + AssetHubRococo::force_create_foreign_asset(id, owner, sufficient, ASSET_MIN_BALANCE, vec![]); +} + +pub(crate) fn create_foreign_on_ah_westend( + id: v3::Location, + sufficient: bool, + prefund_accounts: Vec<(AccountId, u128)>, +) { + let owner = AssetHubWestend::account_id_of(ALICE); + let min = ASSET_MIN_BALANCE; + AssetHubWestend::force_create_foreign_asset(id, owner, sufficient, min, prefund_accounts); +} + +pub(crate) fn foreign_balance_on_ah_rococo(id: v3::Location, who: &AccountId) -> u128 { + AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(id, who) + }) +} +pub(crate) fn foreign_balance_on_ah_westend(id: v3::Location, who: &AccountId) -> u128 { + AssetHubWestend::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(id, who) + }) +} + +// set up pool +pub(crate) fn set_up_pool_with_roc_on_ah_rococo(asset: v3::Location, is_foreign: bool) { + let roc: v3::Location = v3::Parent.into(); + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + let owner = AssetHubRococoSender::get(); + let signed_owner = ::RuntimeOrigin::signed(owner.clone()); + + if is_foreign { + assert_ok!(::ForeignAssets::mint( + signed_owner.clone(), + asset.into(), + owner.clone().into(), + 3_000_000_000_000, + )); + } else { + let asset_id = match asset.interior.split_last() { + (_, Some(v3::Junction::GeneralIndex(id))) => id as u32, + _ => unreachable!(), + }; + assert_ok!(::Assets::mint( + signed_owner.clone(), + asset_id.into(), + owner.clone().into(), + 3_000_000_000_000, + )); + } + assert_ok!(::AssetConversion::create_pool( + signed_owner.clone(), + Box::new(roc), + Box::new(asset), + )); + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, + ] + ); + assert_ok!(::AssetConversion::add_liquidity( + signed_owner.clone(), + Box::new(roc), + Box::new(asset), + 1_000_000_000_000, + 2_000_000_000_000, + 1, + 1, + owner.into() + )); + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {..}) => {}, + ] + ); + }); +} + +pub(crate) fn send_assets_from_asset_hub_westend( destination: Location, - (id, amount): (Location, u128), + assets: Assets, + fee_idx: u32, ) -> DispatchResult { let signed_origin = ::RuntimeOrigin::signed(AssetHubWestendSender::get().into()); - let beneficiary: Location = AccountId32Junction { network: None, id: AssetHubRococoReceiver::get().into() }.into(); - let assets: Assets = (id, amount).into(); - let fee_asset_item = 0; - AssetHubWestend::execute_with(|| { ::PolkadotXcm::limited_reserve_transfer_assets( signed_origin, bx!(destination.into()), bx!(beneficiary.into()), bx!(assets.into()), - fee_asset_item, + fee_idx, WeightLimit::Unlimited, ) }) diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs index 8539df97be9331ea1126a56a70a47ac3a597ce5b..dee411bea8b7353f07b5542b1a81f08ed2dbd966 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs @@ -81,7 +81,11 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { // send XCM from AssetHubWestend - fails - destination version not known assert_err!( - send_asset_from_asset_hub_westend(destination.clone(), (native_token.clone(), amount)), + send_assets_from_asset_hub_westend( + destination.clone(), + (native_token.clone(), amount).into(), + 0 + ), DispatchError::Module(sp_runtime::ModuleError { index: 31, error: [1, 0, 0, 0], @@ -98,9 +102,10 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { newer_xcm_version, ); // send XCM from AssetHubWestend - ok - assert_ok!(send_asset_from_asset_hub_westend( + assert_ok!(send_assets_from_asset_hub_westend( destination.clone(), - (native_token.clone(), amount) + (native_token.clone(), amount).into(), + 0 )); // `ExportMessage` on local BridgeHub - fails - remote BridgeHub version not known @@ -115,9 +120,10 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { ); // send XCM from AssetHubWestend - ok - assert_ok!(send_asset_from_asset_hub_westend( + assert_ok!(send_assets_from_asset_hub_westend( destination.clone(), - (native_token.clone(), amount) + (native_token.clone(), amount).into(), + 0 )); assert_bridge_hub_westend_message_accepted(true); assert_bridge_hub_rococo_message_received(); diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/teleport.rs index c960233c08b73df30b2f873f2ef5333ea15bf428..64378a844f52a7cd14fecd2808fd1b5051d62528 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/teleport.rs @@ -13,8 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::tests::*; -use bridge_hub_westend_runtime::xcm_config::XcmConfig; +use crate::imports::*; #[test] fn teleport_to_other_system_parachains_works() { @@ -22,9 +21,9 @@ fn teleport_to_other_system_parachains_works() { let native_asset: Assets = (Parent, amount).into(); test_parachain_is_trusted_teleporter!( - BridgeHubWestend, // Origin - XcmConfig, // XCM configuration - vec![AssetHubWestend], // Destinations + BridgeHubWestend, // Origin + BridgeHubWestendXcmConfig, // XCM configuration + vec![AssetHubWestend], // Destinations (native_asset, amount) ); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/Cargo.toml index 297f68de6218317017a36c9535ad581aa86e2883..3012e2b19f5326f9df8e61521a82afeaaaa73fae 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/Cargo.toml @@ -11,33 +11,30 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -assert_matches = "1.5.0" +codec = { workspace = true } +assert_matches = { workspace = true } # Substrate -sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } -frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false } -pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false } -pallet-asset-rate = { path = "../../../../../../../substrate/frame/asset-rate", default-features = false } -pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false } -pallet-treasury = { path = "../../../../../../../substrate/frame/treasury", default-features = false } -pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false } -pallet-utility = { path = "../../../../../../../substrate/frame/utility", default-features = false } +sp-runtime = { workspace = true } +frame-support = { workspace = true } +pallet-balances = { workspace = true } +pallet-asset-rate = { workspace = true } +pallet-assets = { workspace = true } +pallet-treasury = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-utility = { workspace = true } # Polkadot -polkadot-runtime-common = { path = "../../../../../../../polkadot/runtime/common" } -xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false } -pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false } -westend-runtime = { path = "../../../../../../../polkadot/runtime/westend" } -westend-runtime-constants = { path = "../../../../../../../polkadot/runtime/westend/constants" } +polkadot-runtime-common = { workspace = true, default-features = true } +xcm = { workspace = true } +xcm-executor = { workspace = true } +pallet-xcm = { workspace = true } +westend-runtime-constants = { workspace = true, default-features = true } # Cumulus -parachains-common = { path = "../../../../../../parachains/common" } -testnet-parachains-constants = { path = "../../../../../runtimes/constants", features = ["westend"] } -asset-hub-westend-runtime = { path = "../../../../../runtimes/assets/asset-hub-westend" } -collectives-westend-runtime = { path = "../../../../../runtimes/collectives/collectives-westend" } -cumulus-pallet-xcmp-queue = { default-features = false, path = "../../../../../../pallets/xcmp-queue" } -cumulus-pallet-parachain-system = { default-features = false, path = "../../../../../../pallets/parachain-system" } -emulated-integration-tests-common = { path = "../../../common", default-features = false } -westend-system-emulated-network = { path = "../../../networks/westend-system" } +parachains-common = { workspace = true, default-features = true } +testnet-parachains-constants = { features = ["westend"], workspace = true, default-features = true } +cumulus-pallet-xcmp-queue = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +emulated-integration-tests-common = { workspace = true } +westend-system-emulated-network = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/lib.rs index 97239330216ac8f66a7684811d1de30b13f56f7e..e2048b62c311254ab474172ee49494aa87166c85 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/lib.rs @@ -15,15 +15,42 @@ pub use xcm::{prelude::*, v3}; -pub use emulated_integration_tests_common::xcm_emulator::{ - assert_expected_events, bx, Chain, RelayChain as Relay, TestExt, +pub use emulated_integration_tests_common::{ + accounts::ALICE, + test_parachain_is_trusted_teleporter, + xcm_emulator::{assert_expected_events, bx, Chain, Parachain, RelayChain as Relay, TestExt}, }; pub use westend_system_emulated_network::{ - asset_hub_westend_emulated_chain::AssetHubWestendParaPallet as AssetHubWestendPallet, - collectives_westend_emulated_chain::CollectivesWestendParaPallet as CollectivesWestendPallet, - westend_emulated_chain::WestendRelayPallet as WestendPallet, - AssetHubWestendPara as AssetHubWestend, CollectivesWestendPara as CollectivesWestend, - WestendRelay as Westend, + asset_hub_westend_emulated_chain::{ + asset_hub_westend_runtime::xcm_config::{ + LocationToAccountId as AssetHubLocationToAccountId, + XcmConfig as AssetHubWestendXcmConfig, + }, + genesis::ED as ASSET_HUB_WESTEND_ED, + AssetHubWestendParaPallet as AssetHubWestendPallet, + }, + collectives_westend_emulated_chain::{ + collectives_westend_runtime::{ + fellowship as collectives_fellowship, + xcm_config::XcmConfig as CollectivesWestendXcmConfig, + }, + genesis::ED as COLLECTIVES_WESTEND_ED, + CollectivesWestendParaPallet as CollectivesWestendPallet, + }, + westend_emulated_chain::{ + genesis::ED as WESTEND_ED, + westend_runtime::{ + governance as westend_governance, xcm_config::XcmConfig as WestendXcmConfig, + OriginCaller as WestendOriginCaller, + }, + WestendRelayPallet as WestendPallet, + }, + AssetHubWestendPara as AssetHubWestend, AssetHubWestendParaReceiver as AssetHubWestendReceiver, + AssetHubWestendParaSender as AssetHubWestendSender, + CollectivesWestendPara as CollectivesWestend, + CollectivesWestendParaReceiver as CollectivesWestendReceiver, + CollectivesWestendParaSender as CollectivesWestendSender, WestendRelay as Westend, + WestendRelayReceiver as WestendReceiver, WestendRelaySender as WestendSender, }; #[cfg(test)] diff --git a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship_treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship_treasury.rs index bde1220e2495bc544e507be1a8b40d77fcbde894..943f8965540d5cb0c17c7a0b1aac8797cbd3ed42 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship_treasury.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship_treasury.rs @@ -14,14 +14,11 @@ // limitations under the License. use crate::*; -use asset_hub_westend_runtime::xcm_config::LocationToAccountId as AssetHubLocationToAccountId; -use emulated_integration_tests_common::accounts::ALICE; use frame_support::{ assert_ok, dispatch::RawOrigin, instances::Instance1, sp_runtime::traits::Dispatchable, traits::fungible::Inspect, }; use polkadot_runtime_common::impls::VersionedLocatableAsset; -use westend_runtime::OriginCaller; use westend_runtime_constants::currency::UNITS; use xcm_executor::traits::ConvertLocation; @@ -65,7 +62,7 @@ fn fellowship_treasury_spend() { let treasury_location: Location = (Parent, PalletInstance(37)).into(); let teleport_call = RuntimeCall::Utility(pallet_utility::Call::::dispatch_as { - as_origin: bx!(OriginCaller::system(RawOrigin::Signed(treasury_account))), + as_origin: bx!(WestendOriginCaller::system(RawOrigin::Signed(treasury_account))), call: bx!(RuntimeCall::XcmPallet(pallet_xcm::Call::::teleport_assets { dest: bx!(VersionedLocation::V4(asset_hub_location.clone())), beneficiary: bx!(VersionedLocation::V4(treasury_location)), @@ -97,7 +94,7 @@ fn fellowship_treasury_spend() { // Fund Fellowship Treasury from Westend Treasury. let treasury_origin: RuntimeOrigin = - westend_runtime::governance::pallet_custom_origins::Origin::Treasurer.into(); + westend_governance::pallet_custom_origins::Origin::Treasurer.into(); let fellowship_treasury_location: Location = Location::new(1, [Parachain(1001), PalletInstance(65)]); let asset_hub_location: Location = [Parachain(1000)].into(); @@ -170,8 +167,7 @@ fn fellowship_treasury_spend() { // Fund Alice account from Fellowship Treasury. let fellows_origin: RuntimeOrigin = - collectives_westend_runtime::fellowship::pallet_fellowship_origins::Origin::Fellows - .into(); + collectives_fellowship::pallet_fellowship_origins::Origin::Fellows.into(); let asset_hub_location: Location = (Parent, Parachain(1000)).into(); let native_asset = Location::parent(); diff --git a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/mod.rs index a9f65df34b647835b4ce5585be6b53b0489de578..40e98a8b68694b48d9554e98555770a97c3e6b46 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/mod.rs @@ -14,3 +14,4 @@ // limitations under the License. mod fellowship_treasury; +mod teleport; diff --git a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/teleport.rs new file mode 100644 index 0000000000000000000000000000000000000000..32f543406d759da1a5f0d06de851930f8ae2b00f --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/teleport.rs @@ -0,0 +1,66 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::*; +use emulated_integration_tests_common::{ + test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, +}; +use frame_support::assert_ok; + +#[test] +fn teleport_from_and_to_relay() { + let amount = WESTEND_ED * 10; + let native_asset: Assets = (Here, amount).into(); + + test_relay_is_trusted_teleporter!( + Westend, // Origin + WestendXcmConfig, // XCM Configuration + vec![CollectivesWestend], // Destinations + (native_asset, amount) + ); + + test_parachain_is_trusted_teleporter_for_relay!( + CollectivesWestend, // Origin + CollectivesWestendXcmConfig, // XCM Configuration + Westend, // Destination + amount + ); +} + +#[test] +fn teleport_from_collectives_to_asset_hub() { + let amount = ASSET_HUB_WESTEND_ED * 100; + let native_asset: Assets = (Parent, amount).into(); + + test_parachain_is_trusted_teleporter!( + CollectivesWestend, // Origin + CollectivesWestendXcmConfig, // XCM Configuration + vec![AssetHubWestend], // Destinations + (native_asset, amount) + ); +} + +#[test] +fn teleport_from_asset_hub_to_collectives() { + let amount = COLLECTIVES_WESTEND_ED * 100; + let native_asset: Assets = (Parent, amount).into(); + + test_parachain_is_trusted_teleporter!( + AssetHubWestend, // Origin + AssetHubWestendXcmConfig, // XCM Configuration + vec![CollectivesWestend], // Destinations + (native_asset, amount) + ); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..259be790c3e5f789b8ee180fef068e596b2c1fdd --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "coretime-rococo-integration-tests" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Coretime Rococo runtime integration tests with xcm-emulator" +publish = false + +[dependencies] + +# Substrate +frame-support = { workspace = true } +pallet-balances = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-identity = { workspace = true } +sp-runtime = { workspace = true } + +# Polkadot +polkadot-runtime-common = { workspace = true, default-features = true } +rococo-runtime-constants = { workspace = true, default-features = true } +xcm = { workspace = true } +xcm-executor = { workspace = true } + +# Cumulus +emulated-integration-tests-common = { workspace = true } +rococo-system-emulated-network = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..ad3c4fd58da991af243db4b611fd1e6279429f5d --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs @@ -0,0 +1,40 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[cfg(test)] +mod imports { + + // Substrate + pub use frame_support::assert_ok; + + // Polkadot + pub use xcm::prelude::*; + + // Cumulus + pub use emulated_integration_tests_common::xcm_emulator::{ + assert_expected_events, bx, TestExt, + }; + pub use rococo_system_emulated_network::{ + coretime_rococo_emulated_chain::{ + coretime_rococo_runtime::ExistentialDeposit as CoretimeRococoExistentialDeposit, + CoretimeRococoParaPallet as CoretimeRococoPallet, + }, + CoretimeRococoPara as CoretimeRococo, CoretimeRococoParaReceiver as CoretimeRococoReceiver, + CoretimeRococoParaSender as CoretimeRococoSender, + }; +} + +#[cfg(test)] +mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/claim_assets.rs new file mode 100644 index 0000000000000000000000000000000000000000..e37b915174d36d33d86ce0ff2c7fbef2b3c91024 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/claim_assets.rs @@ -0,0 +1,29 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests related to claiming assets trapped during XCM execution. + +use crate::imports::*; + +use emulated_integration_tests_common::test_chain_can_claim_assets; +use xcm_executor::traits::DropAssets; + +#[test] +fn assets_can_be_claimed() { + let amount = CoretimeRococoExistentialDeposit::get(); + let assets: Assets = (Parent, amount).into(); + + test_chain_can_claim_assets!(CoretimeRococo, RuntimeCall, NetworkId::Rococo, assets, amount); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..0e78351bce03110a3722cf699c7c70fa9b9a5341 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/mod.rs @@ -0,0 +1,16 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +mod claim_assets; diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..a8fa905d2e5ee4f1905bcf420fa135f8612c7796 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "coretime-westend-integration-tests" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Coretime Westend runtime integration tests with xcm-emulator" +publish = false + +[dependencies] + +# Substrate +frame-support = { workspace = true } +pallet-balances = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-identity = { workspace = true } +sp-runtime = { workspace = true } + +# Polkadot +polkadot-runtime-common = { workspace = true, default-features = true } +westend-runtime-constants = { workspace = true, default-features = true } +xcm = { workspace = true } +xcm-executor = { workspace = true } + +# Cumulus +emulated-integration-tests-common = { workspace = true } +westend-system-emulated-network = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..838ca6eeafb67db1c78159f78877a35a207c2a41 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs @@ -0,0 +1,41 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[cfg(test)] +mod imports { + + // Substrate + pub use frame_support::assert_ok; + + // Polkadot + pub use xcm::prelude::*; + + // Cumulus + pub use emulated_integration_tests_common::xcm_emulator::{ + assert_expected_events, bx, TestExt, + }; + pub use westend_system_emulated_network::{ + coretime_westend_emulated_chain::{ + coretime_westend_runtime::ExistentialDeposit as CoretimeWestendExistentialDeposit, + CoretimeWestendParaPallet as CoretimeWestendPallet, + }, + CoretimeWestendPara as CoretimeWestend, + CoretimeWestendParaReceiver as CoretimeWestendReceiver, + CoretimeWestendParaSender as CoretimeWestendSender, + }; +} + +#[cfg(test)] +mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/claim_assets.rs new file mode 100644 index 0000000000000000000000000000000000000000..c8d853698444c3dfc047ae1b860eee742efca004 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/claim_assets.rs @@ -0,0 +1,29 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests related to claiming assets trapped during XCM execution. + +use crate::imports::*; + +use emulated_integration_tests_common::test_chain_can_claim_assets; +use xcm_executor::traits::DropAssets; + +#[test] +fn assets_can_be_claimed() { + let amount = CoretimeWestendExistentialDeposit::get(); + let assets: Assets = (Parent, amount).into(); + + test_chain_can_claim_assets!(CoretimeWestend, RuntimeCall, NetworkId::Westend, assets, amount); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..0e78351bce03110a3722cf699c7c70fa9b9a5341 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/mod.rs @@ -0,0 +1,16 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +mod claim_assets; diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/Cargo.toml index 29a939951e597a939de5ed9d244193ac8455e4d5..011be93ecac73f06a73616802d19a0e871cd8b30 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/Cargo.toml @@ -8,25 +8,23 @@ description = "People Rococo runtime integration tests with xcm-emulator" publish = false [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } +codec = { workspace = true } # Substrate -sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } -frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false } -pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false } -pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false } -pallet-identity = { path = "../../../../../../../substrate/frame/identity", default-features = false } +frame-support = { workspace = true } +pallet-balances = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-identity = { workspace = true } +sp-runtime = { workspace = true } # Polkadot -xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false } -rococo-runtime = { path = "../../../../../../../polkadot/runtime/rococo" } -rococo-runtime-constants = { path = "../../../../../../../polkadot/runtime/rococo/constants" } -polkadot-runtime-common = { path = "../../../../../../../polkadot/runtime/common" } +polkadot-runtime-common = { workspace = true, default-features = true } +rococo-runtime-constants = { workspace = true, default-features = true } +xcm = { workspace = true } +xcm-executor = { workspace = true } # Cumulus -asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } -parachains-common = { path = "../../../../../common" } -people-rococo-runtime = { path = "../../../../../runtimes/people/people-rococo" } -emulated-integration-tests-common = { path = "../../../common", default-features = false } -rococo-system-emulated-network = { path = "../../../networks/rococo-system" } +asset-test-utils = { workspace = true, default-features = true } +emulated-integration-tests-common = { workspace = true } +parachains-common = { workspace = true, default-features = true } +rococo-system-emulated-network = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/lib.rs index 38ff08b486d4703513ab74d681ae5f07107931ec..3c0533f775e2702bd63cf5c7ef7ef806a8fa84f3 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/lib.rs @@ -37,9 +37,22 @@ mod imports { pub use parachains_common::Balance; pub use rococo_system_emulated_network::{ people_rococo_emulated_chain::{ - genesis::ED as PEOPLE_ROCOCO_ED, PeopleRococoParaPallet as PeopleRococoPallet, + genesis::ED as PEOPLE_ROCOCO_ED, + people_rococo_runtime::{ + people, xcm_config::XcmConfig as PeopleRococoXcmConfig, + ExistentialDeposit as PeopleRococoExistentialDeposit, Runtime as PeopleRuntime, + }, + PeopleRococoParaPallet as PeopleRococoPallet, + }, + rococo_emulated_chain::{ + genesis::ED as ROCOCO_ED, + rococo_runtime::{ + xcm_config::XcmConfig as RococoXcmConfig, BasicDeposit, ByteDeposit, + MaxAdditionalFields, MaxSubAccounts, Runtime as RococoRuntime, + RuntimeOrigin as RococoOrigin, SubAccountDeposit, + }, + RococoRelayPallet as RococoPallet, }, - rococo_emulated_chain::{genesis::ED as ROCOCO_ED, RococoRelayPallet as RococoPallet}, PeopleRococoPara as PeopleRococo, PeopleRococoParaReceiver as PeopleRococoReceiver, PeopleRococoParaSender as PeopleRococoSender, RococoRelay as Rococo, RococoRelayReceiver as RococoReceiver, RococoRelaySender as RococoSender, diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/claim_assets.rs new file mode 100644 index 0000000000000000000000000000000000000000..793200e1d06b870327942229252d56bcb46405f9 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/claim_assets.rs @@ -0,0 +1,29 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests related to claiming assets trapped during XCM execution. + +use crate::imports::*; + +use emulated_integration_tests_common::test_chain_can_claim_assets; +use xcm_executor::traits::DropAssets; + +#[test] +fn assets_can_be_claimed() { + let amount = PeopleRococoExistentialDeposit::get(); + let assets: Assets = (Parent, amount).into(); + + test_chain_can_claim_assets!(PeopleRococo, RuntimeCall, NetworkId::Rococo, assets, amount); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/mod.rs index 80c00021ca53db3850d6d32c1584ae7ae924933f..3f18621224acabcbb5a2df4de4344db6b2408999 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/mod.rs @@ -13,5 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. +mod claim_assets; mod reap_identity; mod teleport; diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/reap_identity.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/reap_identity.rs index 3f1f8638d6fa1491288cd6bbd60f08c13af566dd..10f0c61ed63cfd12f235e1f4f2c3391b78a8ebc0 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/reap_identity.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/reap_identity.rs @@ -41,15 +41,11 @@ use crate::imports::*; use frame_support::BoundedVec; use pallet_balances::Event as BalancesEvent; -use pallet_identity::{legacy::IdentityInfo, Data, Event as IdentityEvent}; -use people_rococo_runtime::people::{ +use pallet_identity::{legacy::IdentityInfo, Data, Event as IdentityEvent, IdentityOf, SubsOf}; +use people::{ BasicDeposit as BasicDepositParachain, ByteDeposit as ByteDepositParachain, IdentityInfo as IdentityInfoParachain, SubAccountDeposit as SubAccountDepositParachain, }; -use rococo_runtime::{ - BasicDeposit, ByteDeposit, MaxAdditionalFields, MaxSubAccounts, RuntimeOrigin as RococoOrigin, - SubAccountDeposit, -}; use rococo_runtime_constants::currency::*; use rococo_system_emulated_network::{ rococo_emulated_chain::RococoRelayPallet, RococoRelay, RococoRelaySender, @@ -270,9 +266,9 @@ fn assert_set_id_parachain(id: &Identity) { // No amount should be reserved as deposit amounts are set to 0. let reserved_balance = PeopleRococoBalances::reserved_balance(PeopleRococoSender::get()); assert_eq!(reserved_balance, 0); - assert!(PeopleRococoIdentity::identity(PeopleRococoSender::get()).is_some()); + assert!(IdentityOf::::get(PeopleRococoSender::get()).is_some()); - let (_, sub_accounts) = PeopleRococoIdentity::subs_of(PeopleRococoSender::get()); + let (_, sub_accounts) = SubsOf::::get(PeopleRococoSender::get()); match id.subs { Subs::Zero => assert_eq!(sub_accounts.len(), 0), @@ -318,10 +314,10 @@ fn assert_reap_id_relay(total_deposit: Balance, id: &Identity) { ] ); // Identity should be gone. - assert!(PeopleRococoIdentity::identity(RococoRelaySender::get()).is_none()); + assert!(IdentityOf::::get(RococoRelaySender::get()).is_none()); // Subs should be gone. - let (_, sub_accounts) = RococoIdentity::subs_of(RococoRelaySender::get()); + let (_, sub_accounts) = SubsOf::::get(RococoRelaySender::get()); assert_eq!(sub_accounts.len(), 0); let reserved_balance = RococoBalances::reserved_balance(RococoRelaySender::get()); diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs index 350d87d638ab25bd66a411a67fa3f109bdaffff9..4410d1bd40dcc1276bb5441962f855823861d1cd 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs @@ -14,8 +14,6 @@ // limitations under the License. use crate::imports::*; -use people_rococo_runtime::xcm_config::XcmConfig as PeopleRococoXcmConfig; -use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig; fn relay_origin_assertions(t: RelayToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/Cargo.toml index 6eab6f52aa72172ecc19fa891109fc9df859ec3c..f7e1cce85a2cf7895d178cb3f95a24070c790198 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/Cargo.toml @@ -8,25 +8,23 @@ description = "People Westend runtime integration tests with xcm-emulator" publish = false [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } +codec = { workspace = true } # Substrate -sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } -frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false } -pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false } -pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false } -pallet-identity = { path = "../../../../../../../substrate/frame/identity", default-features = false } +frame-support = { workspace = true } +pallet-balances = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-identity = { workspace = true } +sp-runtime = { workspace = true } # Polkadot -xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false } -westend-runtime = { path = "../../../../../../../polkadot/runtime/westend" } -westend-runtime-constants = { path = "../../../../../../../polkadot/runtime/westend/constants" } -polkadot-runtime-common = { path = "../../../../../../../polkadot/runtime/common" } +polkadot-runtime-common = { workspace = true, default-features = true } +westend-runtime-constants = { workspace = true, default-features = true } +xcm = { workspace = true } +xcm-executor = { workspace = true } # Cumulus -asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } -parachains-common = { path = "../../../../../common" } -people-westend-runtime = { path = "../../../../../runtimes/people/people-westend" } -emulated-integration-tests-common = { path = "../../../common", default-features = false } -westend-system-emulated-network = { path = "../../../networks/westend-system" } +asset-test-utils = { workspace = true, default-features = true } +emulated-integration-tests-common = { workspace = true } +parachains-common = { workspace = true, default-features = true } +westend-system-emulated-network = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs index 77ac7cfc78c78c6f51ea174b2436d05ee612e0b7..689409fe5040708b822892357eff14d3ac0c591a 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs @@ -35,10 +35,24 @@ mod imports { }; pub use parachains_common::Balance; pub use westend_system_emulated_network::{ + self, people_westend_emulated_chain::{ - genesis::ED as PEOPLE_WESTEND_ED, PeopleWestendParaPallet as PeopleWestendPallet, + genesis::ED as PEOPLE_WESTEND_ED, + people_westend_runtime::{ + people, xcm_config::XcmConfig as PeopleWestendXcmConfig, + ExistentialDeposit as PeopleWestendExistentialDeposit, Runtime as PeopleRuntime, + }, + PeopleWestendParaPallet as PeopleWestendPallet, + }, + westend_emulated_chain::{ + genesis::ED as WESTEND_ED, + westend_runtime::{ + xcm_config::XcmConfig as WestendXcmConfig, BasicDeposit, ByteDeposit, + MaxAdditionalFields, MaxSubAccounts, Runtime as WestendRuntime, + RuntimeOrigin as WestendOrigin, SubAccountDeposit, + }, + WestendRelayPallet as WestendPallet, }, - westend_emulated_chain::{genesis::ED as WESTEND_ED, WestendRelayPallet as WestendPallet}, PeopleWestendPara as PeopleWestend, PeopleWestendParaReceiver as PeopleWestendReceiver, PeopleWestendParaSender as PeopleWestendSender, WestendRelay as Westend, WestendRelayReceiver as WestendReceiver, WestendRelaySender as WestendSender, diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/claim_assets.rs new file mode 100644 index 0000000000000000000000000000000000000000..42ccc459286a2dde06c0fc96dc125a527e649973 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/claim_assets.rs @@ -0,0 +1,29 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests related to claiming assets trapped during XCM execution. + +use crate::imports::*; + +use emulated_integration_tests_common::test_chain_can_claim_assets; +use xcm_executor::traits::DropAssets; + +#[test] +fn assets_can_be_claimed() { + let amount = PeopleWestendExistentialDeposit::get(); + let assets: Assets = (Parent, amount).into(); + + test_chain_can_claim_assets!(PeopleWestend, RuntimeCall, NetworkId::Westend, assets, amount); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/mod.rs index 80c00021ca53db3850d6d32c1584ae7ae924933f..3f18621224acabcbb5a2df4de4344db6b2408999 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/mod.rs @@ -13,5 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. +mod claim_assets; mod reap_identity; mod teleport; diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/reap_identity.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/reap_identity.rs index 3ed8592918d65b81737a4e8206a3bc23b3684b5f..cfbf4d7d95800e589dec0774149325ccaeb96762 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/reap_identity.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/reap_identity.rs @@ -41,15 +41,11 @@ use crate::imports::*; use frame_support::BoundedVec; use pallet_balances::Event as BalancesEvent; -use pallet_identity::{legacy::IdentityInfo, Data, Event as IdentityEvent}; -use people_westend_runtime::people::{ +use pallet_identity::{legacy::IdentityInfo, Data, Event as IdentityEvent, IdentityOf, SubsOf}; +use people::{ BasicDeposit as BasicDepositParachain, ByteDeposit as ByteDepositParachain, IdentityInfo as IdentityInfoParachain, SubAccountDeposit as SubAccountDepositParachain, }; -use westend_runtime::{ - BasicDeposit, ByteDeposit, MaxAdditionalFields, MaxSubAccounts, RuntimeOrigin as WestendOrigin, - SubAccountDeposit, -}; use westend_runtime_constants::currency::*; use westend_system_emulated_network::{ westend_emulated_chain::WestendRelayPallet, WestendRelay, WestendRelaySender, @@ -270,9 +266,9 @@ fn assert_set_id_parachain(id: &Identity) { // No amount should be reserved as deposit amounts are set to 0. let reserved_balance = PeopleWestendBalances::reserved_balance(PeopleWestendSender::get()); assert_eq!(reserved_balance, 0); - assert!(PeopleWestendIdentity::identity(PeopleWestendSender::get()).is_some()); + assert!(IdentityOf::::get(PeopleWestendSender::get()).is_some()); - let (_, sub_accounts) = PeopleWestendIdentity::subs_of(PeopleWestendSender::get()); + let (_, sub_accounts) = SubsOf::::get(PeopleWestendSender::get()); match id.subs { Subs::Zero => assert_eq!(sub_accounts.len(), 0), @@ -318,10 +314,10 @@ fn assert_reap_id_relay(total_deposit: Balance, id: &Identity) { ] ); // Identity should be gone. - assert!(PeopleWestendIdentity::identity(WestendRelaySender::get()).is_none()); + assert!(IdentityOf::::get(WestendRelaySender::get()).is_none()); // Subs should be gone. - let (_, sub_accounts) = WestendIdentity::subs_of(WestendRelaySender::get()); + let (_, sub_accounts) = SubsOf::::get(WestendRelaySender::get()); assert_eq!(sub_accounts.len(), 0); let reserved_balance = WestendBalances::reserved_balance(WestendRelaySender::get()); diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs index 8697477ba769329755b40a87132c62b213861cc4..6fd3cdeb61fbc3d3deb5445a7edf57a5008367c6 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs @@ -14,8 +14,6 @@ // limitations under the License. use crate::imports::*; -use people_westend_runtime::xcm_config::XcmConfig as PeopleWestendXcmConfig; -use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig; fn relay_origin_assertions(t: RelayToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; diff --git a/cumulus/parachains/pallets/collective-content/Cargo.toml b/cumulus/parachains/pallets/collective-content/Cargo.toml index 92e0a54631394154634900829c708431b2931b67..c52021f67e36233eb46c2fe703c9c6cef963ab76 100644 --- a/cumulus/parachains/pallets/collective-content/Cargo.toml +++ b/cumulus/parachains/pallets/collective-content/Cargo.toml @@ -10,19 +10,18 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { features = ["derive", "max-encoded-len"], workspace = true } +scale-info = { features = ["derive"], workspace = true } -frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../substrate/frame/system", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } +sp-core = { workspace = true } +sp-runtime = { workspace = true } [dev-dependencies] -sp-io = { path = "../../../../substrate/primitives/io", default-features = false } +sp-io = { workspace = true } [features] default = ["std"] @@ -48,5 +47,4 @@ std = [ "sp-core/std", "sp-io/std", "sp-runtime/std", - "sp-std/std", ] diff --git a/cumulus/parachains/pallets/collective-content/src/lib.rs b/cumulus/parachains/pallets/collective-content/src/lib.rs index b1c960ad6a0d337d6b84aaaba59f7fa0625a8124..7ea3c2d79fa793fd3726bf9ee0b59eaac598eb38 100644 --- a/cumulus/parachains/pallets/collective-content/src/lib.rs +++ b/cumulus/parachains/pallets/collective-content/src/lib.rs @@ -46,7 +46,6 @@ pub use weights::WeightInfo; use frame_support::{traits::schedule::DispatchTime, BoundedVec}; use sp_core::ConstU32; -use sp_std::prelude::*; /// IPFS compatible CID. // Worst case 2 bytes base and codec, 2 bytes hash type and size, 64 bytes hash digest. diff --git a/cumulus/parachains/pallets/collective-content/src/tests.rs b/cumulus/parachains/pallets/collective-content/src/tests.rs index 4910b30b89af84430a60e2eab011ed2c5c6a3d03..7fee5eea101dbc94e2180b104cdfb2d8a1d040cd 100644 --- a/cumulus/parachains/pallets/collective-content/src/tests.rs +++ b/cumulus/parachains/pallets/collective-content/src/tests.rs @@ -16,7 +16,8 @@ //! Tests. use super::{mock::*, *}; -use frame_support::{assert_noop, assert_ok, error::BadOrigin, pallet_prelude::Pays}; +use frame_support::{assert_noop, assert_ok, pallet_prelude::Pays}; +use sp_runtime::traits::BadOrigin; /// returns CID hash of 68 bytes of given `i`. fn create_cid(i: u8) -> OpaqueCid { diff --git a/cumulus/parachains/pallets/parachain-info/Cargo.toml b/cumulus/parachains/pallets/parachain-info/Cargo.toml index 01ee12bf4e719a9fde63fa4adb43bc6ff4e5c3ea..e0bed23c4f8c0931d1b5b13c36a696378f62fd83 100644 --- a/cumulus/parachains/pallets/parachain-info/Cargo.toml +++ b/cumulus/parachains/pallets/parachain-info/Cargo.toml @@ -10,16 +10,15 @@ description = "Pallet to store the parachain ID" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../substrate/frame/system", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } +sp-runtime = { workspace = true } -cumulus-primitives-core = { path = "../../../primitives/core", default-features = false } +cumulus-primitives-core = { workspace = true } [features] default = ["std"] @@ -30,7 +29,6 @@ std = [ "frame-system/std", "scale-info/std", "sp-runtime/std", - "sp-std/std", ] try-runtime = [ "frame-support/try-runtime", diff --git a/cumulus/parachains/pallets/parachain-info/src/lib.rs b/cumulus/parachains/pallets/parachain-info/src/lib.rs index a4ef448a6b6b9b934e9e49a4a4797a590ad55d6b..0aaa7adaa51c0198fa1025337a31ff790df2113b 100644 --- a/cumulus/parachains/pallets/parachain-info/src/lib.rs +++ b/cumulus/parachains/pallets/parachain-info/src/lib.rs @@ -41,7 +41,7 @@ pub mod pallet { #[pallet::genesis_config] pub struct GenesisConfig { #[serde(skip)] - pub _config: sp_std::marker::PhantomData, + pub _config: core::marker::PhantomData, pub parachain_id: ParaId, } diff --git a/cumulus/parachains/pallets/ping/Cargo.toml b/cumulus/parachains/pallets/ping/Cargo.toml index f51946e9ebd5d2c5fd471683a217fe2dbe8f2f61..51fc384a4f1408ba7ad9c05f9d172146290d4cd5 100644 --- a/cumulus/parachains/pallets/ping/Cargo.toml +++ b/cumulus/parachains/pallets/ping/Cargo.toml @@ -10,18 +10,17 @@ description = "Ping Pallet for Cumulus XCM/UMP testing." workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../substrate/frame/system", default-features = false } +sp-runtime = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } -xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false } +xcm = { workspace = true } -cumulus-primitives-core = { path = "../../../primitives/core", default-features = false } -cumulus-pallet-xcm = { path = "../../../pallets/xcm", default-features = false } +cumulus-primitives-core = { workspace = true } +cumulus-pallet-xcm = { workspace = true } [features] default = ["std"] @@ -33,7 +32,6 @@ std = [ "frame-system/std", "scale-info/std", "sp-runtime/std", - "sp-std/std", "xcm/std", ] diff --git a/cumulus/parachains/pallets/ping/src/lib.rs b/cumulus/parachains/pallets/ping/src/lib.rs index a738c05e0366bc44da562f59f7e9a638a8251d9c..729494cbd251d6ff5ea3271a040c28bb786ea849 100644 --- a/cumulus/parachains/pallets/ping/src/lib.rs +++ b/cumulus/parachains/pallets/ping/src/lib.rs @@ -18,12 +18,14 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + +use alloc::{vec, vec::Vec}; use cumulus_pallet_xcm::{ensure_sibling_para, Origin as CumulusOrigin}; use cumulus_primitives_core::ParaId; use frame_support::{parameter_types, BoundedVec}; use frame_system::Config as SystemConfig; use sp_runtime::traits::Saturating; -use sp_std::prelude::*; use xcm::latest::prelude::*; pub use pallet::*; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index b8670c2957d8f7d176d7216bd210a6d69bd7201f..98df41090a4072f45177326b70f617bf967d735b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -10,97 +10,96 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } -hex-literal = { version = "0.4.1" } +codec = { features = ["derive", "max-encoded-len"], workspace = true } +hex-literal = { workspace = true, default-features = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } # Substrate -frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } -frame-metadata-hash-extension = { path = "../../../../../substrate/frame/metadata-hash-extension", default-features = false } -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../../substrate/frame/system", default-features = false } -frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true } -frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false } -frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } -pallet-asset-conversion-tx-payment = { path = "../../../../../substrate/frame/transaction-payment/asset-conversion-tx-payment", default-features = false } -pallet-assets = { path = "../../../../../substrate/frame/assets", default-features = false } -pallet-asset-conversion-ops = { path = "../../../../../substrate/frame/asset-conversion/ops", default-features = false } -pallet-asset-conversion = { path = "../../../../../substrate/frame/asset-conversion", default-features = false } -pallet-assets-freezer = { path = "../../../../../substrate/frame/assets-freezer", default-features = false } -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } -pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false } -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } -pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false } -pallet-nft-fractionalization = { path = "../../../../../substrate/frame/nft-fractionalization", default-features = false } -pallet-nfts = { path = "../../../../../substrate/frame/nfts", default-features = false } -pallet-nfts-runtime-api = { path = "../../../../../substrate/frame/nfts/runtime-api", default-features = false } -pallet-proxy = { path = "../../../../../substrate/frame/proxy", default-features = false } -pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } -pallet-uniques = { path = "../../../../../substrate/frame/uniques", default-features = false } -pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false } -sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false } -sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } -sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -sp-session = { path = "../../../../../substrate/primitives/session", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-storage = { path = "../../../../../substrate/primitives/storage", default-features = false } -sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } -sp-version = { path = "../../../../../substrate/primitives/version", default-features = false } -sp-weights = { path = "../../../../../substrate/primitives/weights", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-executive = { workspace = true } +frame-metadata-hash-extension = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-benchmarking = { optional = true, workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +frame-try-runtime = { optional = true, workspace = true } +pallet-asset-conversion-tx-payment = { workspace = true } +pallet-assets = { workspace = true } +pallet-asset-conversion-ops = { workspace = true } +pallet-asset-conversion = { workspace = true } +pallet-assets-freezer = { workspace = true } +pallet-aura = { workspace = true } +pallet-authorship = { workspace = true } +pallet-balances = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-multisig = { workspace = true } +pallet-nft-fractionalization = { workspace = true } +pallet-nfts = { workspace = true } +pallet-nfts-runtime-api = { workspace = true } +pallet-proxy = { workspace = true } +pallet-session = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-uniques = { workspace = true } +pallet-utility = { workspace = true } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-core = { workspace = true } +sp-inherents = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-storage = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } +sp-weights = { workspace = true } # num-traits feature needed for dex integer sq root: -primitive-types = { version = "0.12.1", default-features = false, features = ["codec", "num-traits", "scale-info"] } +primitive-types = { features = ["codec", "num-traits", "scale-info"], workspace = true } # Polkadot -rococo-runtime-constants = { path = "../../../../../polkadot/runtime/rococo/constants", default-features = false } -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } -pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } -polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false } -polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } -xcm-fee-payment-runtime-api = { path = "../../../../../polkadot/xcm/xcm-fee-payment-runtime-api", default-features = false } +rococo-runtime-constants = { workspace = true } +pallet-xcm = { workspace = true } +pallet-xcm-benchmarks = { optional = true, workspace = true } +polkadot-parachain-primitives = { workspace = true } +polkadot-runtime-common = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm-runtime-apis = { workspace = true } # Cumulus -cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } -cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false } -cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false, features = ["bridging"] } -cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } -cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } -cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } -pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } -testnet-parachains-constants = { path = "../../constants", default-features = false, features = ["rococo"] } -assets-common = { path = "../common", default-features = false } +cumulus-pallet-aura-ext = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-session-benchmarking = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { features = ["bridging"], workspace = true } +cumulus-primitives-aura = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-utility = { workspace = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true } +pallet-collator-selection = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } +testnet-parachains-constants = { features = ["rococo"], workspace = true } +assets-common = { workspace = true } # Bridges -pallet-xcm-bridge-hub-router = { path = "../../../../../bridges/modules/xcm-bridge-hub-router", default-features = false } -bp-asset-hub-rococo = { path = "../../../../../bridges/chains/chain-asset-hub-rococo", default-features = false } -bp-asset-hub-westend = { path = "../../../../../bridges/chains/chain-asset-hub-westend", default-features = false } -bp-bridge-hub-rococo = { path = "../../../../../bridges/chains/chain-bridge-hub-rococo", default-features = false } -bp-bridge-hub-westend = { path = "../../../../../bridges/chains/chain-bridge-hub-westend", default-features = false } -snowbridge-router-primitives = { path = "../../../../../bridges/snowbridge/primitives/router", default-features = false } +pallet-xcm-bridge-hub-router = { workspace = true } +bp-asset-hub-rococo = { workspace = true } +bp-asset-hub-westend = { workspace = true } +bp-bridge-hub-rococo = { workspace = true } +bp-bridge-hub-westend = { workspace = true } +snowbridge-router-primitives = { workspace = true } [dev-dependencies] -asset-test-utils = { path = "../test-utils" } +asset-test-utils = { workspace = true, default-features = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [features] default = ["std"] @@ -139,7 +138,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", - "xcm-fee-payment-runtime-api/runtime-benchmarks", + "xcm-runtime-apis/runtime-benchmarks", ] try-runtime = [ "cumulus-pallet-aura-ext/try-runtime", @@ -241,7 +240,6 @@ std = [ "sp-offchain/std", "sp-runtime/std", "sp-session/std", - "sp-std/std", "sp-storage/std", "sp-transaction-pool/std", "sp-version/std", @@ -250,7 +248,7 @@ std = [ "testnet-parachains-constants/std", "xcm-builder/std", "xcm-executor/std", - "xcm-fee-payment-runtime-api/std", + "xcm-runtime-apis/std", "xcm/std", ] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 423f9549edcc8b9f932575111f623a6ec2a23664..83bc12cf9b41fc887451fe672ca65f6bf056257f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -27,6 +27,9 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); mod weights; pub mod xcm_config; +extern crate alloc; + +use alloc::{vec, vec::Vec}; use assets_common::{ foreign_creators::ForeignCreators, local_and_foreign_assets::{LocalFromLeft, TargetFromLeft}, @@ -45,7 +48,6 @@ use sp_runtime::{ }; use testnet_parachains_constants::rococo::snowbridge::EthereumNetwork; -use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -69,7 +71,7 @@ use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, EnsureSigned, EnsureSignedBy, }; -use pallet_asset_conversion_tx_payment::AssetConversionAdapter; +use pallet_asset_conversion_tx_payment::SwapAssetAdapter; use pallet_nfts::PalletFeatures; use parachains_common::{ impls::DealWithFees, @@ -100,7 +102,7 @@ use xcm::{ latest::prelude::{AssetId, BodyId}, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, }; -use xcm_fee_payment_runtime_api::{ +use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, }; @@ -118,7 +120,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 1_013_000, + spec_version: 1_014_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 16, @@ -796,11 +798,19 @@ impl pallet_collator_selection::Config for Runtime { type WeightInfo = weights::pallet_collator_selection::WeightInfo; } +parameter_types! { + pub StakingPot: AccountId = CollatorSelection::account_id(); +} + impl pallet_asset_conversion_tx_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Fungibles = LocalAndForeignAssets; - type OnChargeAssetTransaction = - AssetConversionAdapter; + type AssetId = xcm::v3::Location; + type OnChargeAssetTransaction = SwapAssetAdapter< + TokenLocationV3, + NativeAndAssets, + AssetConversion, + ResolveAssetTo, + >; } parameter_types! { @@ -1161,7 +1171,7 @@ impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { Runtime::metadata_versions() } } @@ -1322,7 +1332,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { let acceptable_assets = vec![AssetId(xcm_config::TokenLocation::get())]; PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) @@ -1335,11 +1345,11 @@ impl_runtime_apis! { Ok(WeightToFee::weight_to_fee(&weight)) }, Ok(asset_id) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); Err(XcmPaymentApiError::AssetNotFound) }, Err(_) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); Err(XcmPaymentApiError::VersionedConversionFailed) } } @@ -1354,7 +1364,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + impl xcm_runtime_apis::dry_run::DryRunApi for Runtime { fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { PolkadotXcm::dry_run_call::(origin, call) } @@ -1364,6 +1374,18 @@ impl_runtime_apis! { } } + impl xcm_runtime_apis::conversions::LocationToAccountApi for Runtime { + fn convert_location(location: VersionedLocation) -> Result< + AccountId, + xcm_runtime_apis::conversions::Error + > { + xcm_runtime_apis::conversions::LocationToAccountHelper::< + AccountId, + xcm_config::LocationToAccountId, + >::convert_location(location) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) @@ -1433,7 +1455,7 @@ impl_runtime_apis! { use frame_system_benchmarking::Pallet as SystemBench; impl frame_system_benchmarking::Config for Runtime { - fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { + fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); Ok(()) } @@ -1503,7 +1525,7 @@ impl_runtime_apis! { } fn set_up_complex_asset_transfer( - ) -> Option<(XcmAssets, u32, Location, Box)> { + ) -> Option<(XcmAssets, u32, Location, alloc::boxed::Box)> { // Transfer to Relay some local AH asset (local-reserve-transfer) while paying // fees using teleported native token. // (We don't care that Relay doesn't accept incoming unknown AH local asset) @@ -1538,7 +1560,7 @@ impl_runtime_apis! { let fee_index = if assets.get(0).unwrap().eq(&fee_asset) { 0 } else { 1 }; // verify transferred successfully - let verify = Box::new(move || { + let verify = alloc::boxed::Box::new(move || { // verify native balance after transfer, decreased by transferred fee amount // (plus transport fees) assert!(Balances::free_balance(&who) <= balance - fee_amount); @@ -1572,7 +1594,7 @@ impl_runtime_apis! { let bridged_asset_hub = xcm_config::bridging::to_westend::AssetHubWestend::get(); let _ = PolkadotXcm::force_xcm_version( RuntimeOrigin::root(), - Box::new(bridged_asset_hub.clone()), + alloc::boxed::Box::new(bridged_asset_hub.clone()), XCM_VERSION, ).map_err(|e| { log::error!( diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_parachain_system.rs index c1e5c6a74293995b6e3702f19b8b3750c34b192f..fc63a0814d0a4af4ac9e264db8757e5abe2da36d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_parachain_system.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_parachain_system.rs @@ -47,7 +47,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `cumulus_pallet_parachain_system`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_message_queue.rs index 45531ccfa797c52ead00833f765347f1282816c7..cd72703104ad0fee8744b904e950def1872d2456 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_message_queue.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_message_queue.rs @@ -43,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `pallet_message_queue`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs index 775bc3bdb80f54a8db97d1c1fdbf5a837fdb95b1..0a86037391b42d71340d8d0665a9210d8b9a0281 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_xcm_bridge_hub_router` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -49,32 +49,32 @@ use core::marker::PhantomData; pub struct WeightInfo(PhantomData); impl pallet_xcm_bridge_hub_router::WeightInfo for WeightInfo { /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `ToWestendXcmRouter::Bridge` (r:1 w:1) /// Proof: `ToWestendXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) fn on_initialize_when_non_congested() -> Weight { // Proof Size summary in bytes: // Measured: `154` - // Estimated: `1639` - // Minimum execution time: 7_853_000 picoseconds. - Weight::from_parts(8_443_000, 0) - .saturating_add(Weight::from_parts(0, 1639)) + // Estimated: `5487` + // Minimum execution time: 8_078_000 picoseconds. + Weight::from_parts(8_455_000, 0) + .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) fn on_initialize_when_congested() -> Weight { // Proof Size summary in bytes: // Measured: `144` - // Estimated: `1629` - // Minimum execution time: 4_333_000 picoseconds. - Weight::from_parts(4_501_000, 0) - .saturating_add(Weight::from_parts(0, 1629)) + // Estimated: `5487` + // Minimum execution time: 4_291_000 picoseconds. + Weight::from_parts(4_548_000, 0) + .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(2)) } /// Storage: `ToWestendXcmRouter::Bridge` (r:1 w:1) @@ -83,14 +83,12 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `150` // Estimated: `1502` - // Minimum execution time: 10_167_000 picoseconds. - Weight::from_parts(10_667_000, 0) + // Minimum execution time: 9_959_000 picoseconds. + Weight::from_parts(10_372_000, 0) .saturating_add(Weight::from_parts(0, 1502)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) @@ -100,7 +98,9 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// Storage: `ToWestendXcmRouter::Bridge` (r:1 w:1) /// Proof: `ToWestendXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) @@ -108,17 +108,17 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) - /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) fn send_message() -> Weight { // Proof Size summary in bytes: // Measured: `448` // Estimated: `6388` - // Minimum execution time: 60_584_000 picoseconds. - Weight::from_parts(62_467_000, 0) + // Minimum execution time: 45_888_000 picoseconds. + Weight::from_parts(47_022_000, 0) .saturating_add(Weight::from_parts(0, 6388)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs index 8e675ad0cf8e627a1f547a181db1737767e84d7c..8c52ecd9f1b1fa66bc027be7b1d376ff6882517a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs @@ -18,10 +18,10 @@ mod pallet_xcm_benchmarks_fungible; mod pallet_xcm_benchmarks_generic; use crate::{xcm_config::MaxAssetsIntoHolding, Runtime}; +use alloc::vec::Vec; use frame_support::weights::Weight; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; -use sp_std::prelude::*; use xcm::{latest::prelude::*, DoubleEncoded}; trait WeighAssets { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 7fab35842509deceba14e89e5bbf6bebe2240528..03d3785dccbd7f213eee3d8aa51cde7eb5980b48 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -43,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::fungible`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 4454494badcbfe9b4f429312e24b63786b83ef75..bee6bcdf21cf3fed11ef63d593b5b0dfb1f0f10b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -43,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::generic`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index cf5a3905e581641fb504d43318cc562c32bca8b8..a11dca4f6d7ccf8095c1a1095e436e131c508370 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -55,11 +55,11 @@ use xcm_builder::{ EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint, NetworkExportTableItem, NoChecking, NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset, - RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + RelayChainAsNative, SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignPaidRemoteExporter, SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; @@ -337,10 +337,11 @@ impl xcm_executor::Config for XcmConfig { type OriginConverter = XcmOriginToTransactDispatchOrigin; // Asset Hub trusts only particular, pre-configured bridged locations from a different consensus // as reserve locations (we trust the Bridge Hub to relay the message that a reserve is being - // held). Asset Hub may _act_ as a reserve location for ROC and assets created - // under `pallet-assets`. Users must use teleport where allowed (e.g. ROC with the Relay Chain). + // held). On Rococo Asset Hub, we allow Westend Asset Hub to act as reserve for any asset native + // to the Westend ecosystem. We also allow Ethereum contracts to act as reserves for the foreign + // assets identified by the same respective contracts locations. type IsReserve = ( - bridging::to_westend::IsTrustedBridgedReserveLocationForConcreteAsset, + bridging::to_westend::WestendAssetFromAssetHubWestend, bridging::to_ethereum::IsTrustedBridgedReserveLocationForForeignAsset, ); type IsTeleporter = TrustedTeleporters; @@ -412,7 +413,7 @@ impl xcm_executor::Config for XcmConfig { type AssetExchanger = (); type FeeManager = XcmFeeManagerFromComponents< WaivedLocations, - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = @@ -510,8 +511,8 @@ impl pallet_assets::BenchmarkHelper for XcmBenchmarkHelper { /// All configuration related to bridging pub mod bridging { use super::*; + use alloc::collections::btree_set::BTreeSet; use assets_common::matching; - use sp_std::collections::btree_set::BTreeSet; // common/shared parameters parameter_types! { @@ -540,13 +541,13 @@ pub mod bridging { /// (`AssetId` has to be aligned with `BridgeTable`) pub XcmBridgeHubRouterFeeAssetId: AssetId = TokenLocation::get().into(); - pub BridgeTable: sp_std::vec::Vec = - sp_std::vec::Vec::new().into_iter() + pub BridgeTable: alloc::vec::Vec = + alloc::vec::Vec::new().into_iter() .chain(to_westend::BridgeTable::get()) .collect(); - pub EthereumBridgeTable: sp_std::vec::Vec = - sp_std::vec::Vec::new().into_iter() + pub EthereumBridgeTable: alloc::vec::Vec = + alloc::vec::Vec::new().into_iter() .chain(to_ethereum::BridgeTable::get()) .collect(); } @@ -568,20 +569,19 @@ pub mod bridging { ); pub const WestendNetwork: NetworkId = NetworkId::Westend; - pub AssetHubWestend: Location = Location::new(2, [GlobalConsensus(WestendNetwork::get()), Parachain(bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID)]); + pub WestendEcosystem: Location = Location::new(2, [GlobalConsensus(WestendNetwork::get())]); pub WndLocation: Location = Location::new(2, [GlobalConsensus(WestendNetwork::get())]); - - pub WndFromAssetHubWestend: (AssetFilter, Location) = ( - Wild(AllOf { fun: WildFungible, id: AssetId(WndLocation::get()) }), - AssetHubWestend::get() - ); + pub AssetHubWestend: Location = Location::new(2, [ + GlobalConsensus(WestendNetwork::get()), + Parachain(bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID) + ]); /// Set up exporters configuration. /// `Option` represents static "base fee" which is used for total delivery fee calculation. - pub BridgeTable: sp_std::vec::Vec = sp_std::vec![ + pub BridgeTable: alloc::vec::Vec = alloc::vec![ NetworkExportTableItem::new( WestendNetwork::get(), - Some(sp_std::vec![ + Some(alloc::vec![ AssetHubWestend::get().interior.split_global().expect("invalid configuration for AssetHubWestend").1, ]), SiblingBridgeHub::get(), @@ -595,7 +595,7 @@ pub mod bridging { /// Universal aliases pub UniversalAliases: BTreeSet<(Location, Junction)> = BTreeSet::from_iter( - sp_std::vec![ + alloc::vec![ (SiblingBridgeHubWithBridgeHubWestendInstance::get(), GlobalConsensus(WestendNetwork::get())) ] ); @@ -607,17 +607,9 @@ pub mod bridging { } } - /// Trusted reserve locations filter for `xcm_executor::Config::IsReserve`. - /// Locations from which the runtime accepts reserved assets. - pub type IsTrustedBridgedReserveLocationForConcreteAsset = - matching::IsTrustedBridgedReserveLocationForConcreteAsset< - UniversalLocation, - ( - // allow receive WND from AssetHubWestend - xcm_builder::Case, - // and nothing else - ), - >; + /// Allow any asset native to the Westend ecosystem if it comes from Westend Asset Hub. + pub type WestendAssetFromAssetHubWestend = + matching::RemoteAssetFromLocation, AssetHubWestend>; impl Contains for ToWestendXcmRouter { fn contains(call: &RuntimeCall) -> bool { @@ -651,10 +643,10 @@ pub mod bridging { /// Set up exporters configuration. /// `Option` represents static "base fee" which is used for total delivery fee calculation. - pub BridgeTable: sp_std::vec::Vec = sp_std::vec![ + pub BridgeTable: alloc::vec::Vec = alloc::vec![ NetworkExportTableItem::new( EthereumNetwork::get(), - Some(sp_std::vec![Junctions::Here]), + Some(alloc::vec![Junctions::Here]), SiblingBridgeHub::get(), Some(( XcmBridgeHubRouterFeeAssetId::get(), @@ -665,14 +657,14 @@ pub mod bridging { /// Universal aliases pub UniversalAliases: BTreeSet<(Location, Junction)> = BTreeSet::from_iter( - sp_std::vec![ + alloc::vec![ (SiblingBridgeHubWithEthereumInboundQueueInstance::get(), GlobalConsensus(EthereumNetwork::get())), ] ); } pub type IsTrustedBridgedReserveLocationForForeignAsset = - matching::IsForeignConcreteAsset>; + IsForeignConcreteAsset>; impl Contains<(Location, Junction)> for UniversalAliases { fn contains(alias: &(Location, Junction)) -> bool { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs index f670c5f424efeac0e00ddf472f1948e06d93bd68..ee1461b7f9c85664e25dca1d02b4f248812d4219 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -34,6 +34,7 @@ use asset_test_utils::{ ExtBuilder, SlotDurations, }; use codec::{Decode, Encode}; +use core::ops::Mul; use cumulus_primitives_utility::ChargeWeightInFungibles; use frame_support::{ assert_noop, assert_ok, @@ -48,7 +49,6 @@ use frame_support::{ use parachains_common::{AccountId, AssetIdForTrustBackedAssets, AuraId, Balance}; use sp_consensus_aura::SlotDuration; use sp_runtime::traits::MaybeEquivalence; -use sp_std::ops::Mul; use std::convert::Into; use testnet_parachains_constants::rococo::{consensus::*, currency::UNITS, fee::WeightToFee}; use xcm::latest::prelude::{Assets as XcmAssets, *}; @@ -1277,7 +1277,7 @@ mod asset_hub_rococo_tests { collator_session_keys(), bridging_to_asset_hub_westend, || { - sp_std::vec![ + vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, Transact { origin_kind: OriginKind::Xcm, @@ -1287,16 +1287,16 @@ mod asset_hub_rococo_tests { bp_asset_hub_rococo::XcmBridgeHubRouterCall::report_bridge_status { bridge_id: Default::default(), is_congested: true, - } + }, ) .encode() .into(), - } + }, ] .into() }, || { - sp_std::vec![ + vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, Transact { origin_kind: OriginKind::Xcm, @@ -1306,11 +1306,11 @@ mod asset_hub_rococo_tests { bp_asset_hub_rococo::XcmBridgeHubRouterCall::report_bridge_status { bridge_id: Default::default(), is_congested: false, - } + }, ) .encode() .into(), - } + }, ] .into() }, diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index f310b2e031335910744ffd35f4770f88ac58df86..6b1bf769ace3511cc91cb1b557d4a7d5a754fd92 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -10,96 +10,95 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } -hex-literal = { version = "0.4.1" } +codec = { features = ["derive", "max-encoded-len"], workspace = true } +hex-literal = { workspace = true, default-features = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } # Substrate -frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } -frame-metadata-hash-extension = { path = "../../../../../substrate/frame/metadata-hash-extension", default-features = false } -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../../substrate/frame/system", default-features = false } -frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true } -frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false } -frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } -pallet-asset-conversion-ops = { path = "../../../../../substrate/frame/asset-conversion/ops", default-features = false } -pallet-asset-conversion-tx-payment = { path = "../../../../../substrate/frame/transaction-payment/asset-conversion-tx-payment", default-features = false } -pallet-assets = { path = "../../../../../substrate/frame/assets", default-features = false } -pallet-asset-conversion = { path = "../../../../../substrate/frame/asset-conversion", default-features = false } -pallet-assets-freezer = { path = "../../../../../substrate/frame/assets-freezer", default-features = false } -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } -pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false } -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } -pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false } -pallet-nft-fractionalization = { path = "../../../../../substrate/frame/nft-fractionalization", default-features = false } -pallet-nfts = { path = "../../../../../substrate/frame/nfts", default-features = false } -pallet-nfts-runtime-api = { path = "../../../../../substrate/frame/nfts/runtime-api", default-features = false } -pallet-proxy = { path = "../../../../../substrate/frame/proxy", default-features = false } -pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } -pallet-state-trie-migration = { path = "../../../../../substrate/frame/state-trie-migration", default-features = false } -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } -pallet-uniques = { path = "../../../../../substrate/frame/uniques", default-features = false } -pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false } -sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } -sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false } -sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -sp-session = { path = "../../../../../substrate/primitives/session", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-storage = { path = "../../../../../substrate/primitives/storage", default-features = false } -sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } -sp-version = { path = "../../../../../substrate/primitives/version", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-executive = { workspace = true } +frame-metadata-hash-extension = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-benchmarking = { optional = true, workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +frame-try-runtime = { optional = true, workspace = true } +pallet-asset-conversion-ops = { workspace = true } +pallet-asset-conversion-tx-payment = { workspace = true } +pallet-assets = { workspace = true } +pallet-asset-conversion = { workspace = true } +pallet-assets-freezer = { workspace = true } +pallet-aura = { workspace = true } +pallet-authorship = { workspace = true } +pallet-balances = { workspace = true } +pallet-multisig = { workspace = true } +pallet-nft-fractionalization = { workspace = true } +pallet-nfts = { workspace = true } +pallet-nfts-runtime-api = { workspace = true } +pallet-proxy = { workspace = true } +pallet-session = { workspace = true } +pallet-state-trie-migration = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-uniques = { workspace = true } +pallet-utility = { workspace = true } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-core = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-storage = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } # num-traits feature needed for dex integer sq root: -primitive-types = { version = "0.12.1", default-features = false, features = ["codec", "num-traits", "scale-info"] } +primitive-types = { features = ["codec", "num-traits", "scale-info"], workspace = true } # Polkadot -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } -pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } -polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false } -polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false } -westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } -xcm-fee-payment-runtime-api = { path = "../../../../../polkadot/xcm/xcm-fee-payment-runtime-api", default-features = false } +pallet-xcm = { workspace = true } +pallet-xcm-benchmarks = { optional = true, workspace = true } +polkadot-parachain-primitives = { workspace = true } +polkadot-runtime-common = { workspace = true } +westend-runtime-constants = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm-runtime-apis = { workspace = true } # Cumulus -cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } -cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false } -cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false, features = ["bridging"] } -cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } -cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } -cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } -pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } -testnet-parachains-constants = { path = "../../constants", default-features = false, features = ["westend"] } -assets-common = { path = "../common", default-features = false } +cumulus-pallet-aura-ext = { workspace = true } +pallet-message-queue = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-session-benchmarking = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { features = ["bridging"], workspace = true } +cumulus-primitives-aura = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-utility = { workspace = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true } +pallet-collator-selection = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } +testnet-parachains-constants = { features = ["westend"], workspace = true } +assets-common = { workspace = true } # Bridges -pallet-xcm-bridge-hub-router = { path = "../../../../../bridges/modules/xcm-bridge-hub-router", default-features = false } -bp-asset-hub-rococo = { path = "../../../../../bridges/chains/chain-asset-hub-rococo", default-features = false } -bp-asset-hub-westend = { path = "../../../../../bridges/chains/chain-asset-hub-westend", default-features = false } -bp-bridge-hub-rococo = { path = "../../../../../bridges/chains/chain-bridge-hub-rococo", default-features = false } -bp-bridge-hub-westend = { path = "../../../../../bridges/chains/chain-bridge-hub-westend", default-features = false } +pallet-xcm-bridge-hub-router = { workspace = true } +bp-asset-hub-rococo = { workspace = true } +bp-asset-hub-westend = { workspace = true } +bp-bridge-hub-rococo = { workspace = true } +bp-bridge-hub-westend = { workspace = true } [dev-dependencies] -asset-test-utils = { path = "../test-utils" } +asset-test-utils = { workspace = true, default-features = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [features] default = ["std"] @@ -138,7 +137,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", - "xcm-fee-payment-runtime-api/runtime-benchmarks", + "xcm-runtime-apis/runtime-benchmarks", ] try-runtime = [ "cumulus-pallet-aura-ext/try-runtime", @@ -240,7 +239,6 @@ std = [ "sp-offchain/std", "sp-runtime/std", "sp-session/std", - "sp-std/std", "sp-storage/std", "sp-transaction-pool/std", "sp-version/std", @@ -249,7 +247,7 @@ std = [ "westend-runtime-constants/std", "xcm-builder/std", "xcm-executor/std", - "xcm-fee-payment-runtime-api/std", + "xcm-runtime-apis/std", "xcm/std", ] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 6764242cc3395ac4a645b60c1bf2ee6066a567d9..2d9de07f251f9b157f01cb3c05c63b7bb55ba5f6 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -27,6 +27,9 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); mod weights; pub mod xcm_config; +extern crate alloc; + +use alloc::{vec, vec::Vec}; use assets_common::{ local_and_foreign_assets::{LocalFromLeft, TargetFromLeft}, AssetIdForTrustBackedAssetsConvert, @@ -52,7 +55,7 @@ use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, EnsureSigned, EnsureSignedBy, }; -use pallet_asset_conversion_tx_payment::AssetConversionAdapter; +use pallet_asset_conversion_tx_payment::SwapAssetAdapter; use pallet_nfts::{DestroyWitness, PalletFeatures}; use pallet_xcm::EnsureXcm; use parachains_common::{ @@ -68,7 +71,6 @@ use sp_runtime::{ transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, Perbill, Permill, RuntimeDebug, }; -use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -85,10 +87,10 @@ pub use sp_runtime::BuildStorage; use assets_common::{foreign_creators::ForeignCreators, matching::FromSiblingParachain}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; -use xcm::prelude::{VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}; - -// We exclude `Assets` since it's the name of a pallet -use xcm::latest::prelude::AssetId; +use xcm::{ + latest::prelude::AssetId, + prelude::{VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}, +}; #[cfg(feature = "runtime-benchmarks")] use xcm::latest::prelude::{ @@ -96,7 +98,7 @@ use xcm::latest::prelude::{ NetworkId, NonFungible, Parent, ParentThen, Response, XCM_VERSION, }; -use xcm_fee_payment_runtime_api::{ +use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, }; @@ -117,7 +119,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westmint"), impl_name: create_runtime_str!("westmint"), authoring_version: 1, - spec_version: 1_013_000, + spec_version: 1_014_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 16, @@ -785,11 +787,19 @@ impl pallet_collator_selection::Config for Runtime { type WeightInfo = weights::pallet_collator_selection::WeightInfo; } +parameter_types! { + pub StakingPot: AccountId = CollatorSelection::account_id(); +} + impl pallet_asset_conversion_tx_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Fungibles = LocalAndForeignAssets; - type OnChargeAssetTransaction = - AssetConversionAdapter; + type AssetId = xcm::v3::Location; + type OnChargeAssetTransaction = SwapAssetAdapter< + WestendLocationV3, + NativeAndAssets, + AssetConversion, + ResolveAssetTo, + >; } parameter_types! { @@ -1206,7 +1216,7 @@ impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { Runtime::metadata_versions() } } @@ -1350,7 +1360,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { let acceptable_assets = vec![AssetId(xcm_config::WestendLocation::get())]; PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) @@ -1363,11 +1373,11 @@ impl_runtime_apis! { Ok(WeightToFee::weight_to_fee(&weight)) }, Ok(asset_id) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); Err(XcmPaymentApiError::AssetNotFound) }, Err(_) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); Err(XcmPaymentApiError::VersionedConversionFailed) } } @@ -1382,7 +1392,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + impl xcm_runtime_apis::dry_run::DryRunApi for Runtime { fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { PolkadotXcm::dry_run_call::(origin, call) } @@ -1392,6 +1402,18 @@ impl_runtime_apis! { } } + impl xcm_runtime_apis::conversions::LocationToAccountApi for Runtime { + fn convert_location(location: VersionedLocation) -> Result< + AccountId, + xcm_runtime_apis::conversions::Error + > { + xcm_runtime_apis::conversions::LocationToAccountHelper::< + AccountId, + xcm_config::LocationToAccountId, + >::convert_location(location) + } + } + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi for Runtime { @@ -1524,7 +1546,7 @@ impl_runtime_apis! { use frame_system_benchmarking::Pallet as SystemBench; impl frame_system_benchmarking::Config for Runtime { - fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { + fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); Ok(()) } @@ -1589,7 +1611,7 @@ impl_runtime_apis! { } fn set_up_complex_asset_transfer( - ) -> Option<(XcmAssets, u32, Location, Box)> { + ) -> Option<(XcmAssets, u32, Location, alloc::boxed::Box)> { // Transfer to Relay some local AH asset (local-reserve-transfer) while paying // fees using teleported native token. // (We don't care that Relay doesn't accept incoming unknown AH local asset) @@ -1624,7 +1646,7 @@ impl_runtime_apis! { let fee_index = if assets.get(0).unwrap().eq(&fee_asset) { 0 } else { 1 }; // verify transferred successfully - let verify = Box::new(move || { + let verify = alloc::boxed::Box::new(move || { // verify native balance after transfer, decreased by transferred fee amount // (plus transport fees) assert!(Balances::free_balance(&who) <= balance - fee_amount); @@ -1663,7 +1685,7 @@ impl_runtime_apis! { let bridged_asset_hub = xcm_config::bridging::to_rococo::AssetHubRococo::get(); let _ = PolkadotXcm::force_xcm_version( RuntimeOrigin::root(), - Box::new(bridged_asset_hub.clone()), + alloc::boxed::Box::new(bridged_asset_hub.clone()), XCM_VERSION, ).map_err(|e| { log::error!( diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_parachain_system.rs index c1e5c6a74293995b6e3702f19b8b3750c34b192f..fc63a0814d0a4af4ac9e264db8757e5abe2da36d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_parachain_system.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_parachain_system.rs @@ -47,7 +47,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `cumulus_pallet_parachain_system`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_message_queue.rs index 45531ccfa797c52ead00833f765347f1282816c7..cd72703104ad0fee8744b904e950def1872d2456 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_message_queue.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_message_queue.rs @@ -43,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `pallet_message_queue`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs index 84d717b0283c764cac14cce63ca34f81c9f58e8c..21d15c75af553da60ecf0648186a26255bb72890 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_xcm_bridge_hub_router` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -49,48 +49,46 @@ use core::marker::PhantomData; pub struct WeightInfo(PhantomData); impl pallet_xcm_bridge_hub_router::WeightInfo for WeightInfo { /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) /// Proof: `ToRococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) fn on_initialize_when_non_congested() -> Weight { // Proof Size summary in bytes: - // Measured: `193` - // Estimated: `1678` - // Minimum execution time: 8_095_000 picoseconds. - Weight::from_parts(8_393_000, 0) - .saturating_add(Weight::from_parts(0, 1678)) + // Measured: `226` + // Estimated: `5487` + // Minimum execution time: 8_363_000 picoseconds. + Weight::from_parts(8_620_000, 0) + .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) fn on_initialize_when_congested() -> Weight { // Proof Size summary in bytes: // Measured: `111` - // Estimated: `1596` - // Minimum execution time: 3_417_000 picoseconds. - Weight::from_parts(3_583_000, 0) - .saturating_add(Weight::from_parts(0, 1596)) + // Estimated: `5487` + // Minimum execution time: 3_436_000 picoseconds. + Weight::from_parts(3_586_000, 0) + .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(2)) } /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) /// Proof: `ToRococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) fn report_bridge_status() -> Weight { // Proof Size summary in bytes: - // Measured: `117` + // Measured: `150` // Estimated: `1502` - // Minimum execution time: 10_280_000 picoseconds. - Weight::from_parts(10_703_000, 0) + // Minimum execution time: 9_706_000 picoseconds. + Weight::from_parts(10_139_000, 0) .saturating_add(Weight::from_parts(0, 1502)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) @@ -100,7 +98,9 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) /// Proof: `ToRococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) @@ -108,18 +108,18 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) - /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) fn send_message() -> Weight { // Proof Size summary in bytes: - // Measured: `487` - // Estimated: `6427` - // Minimum execution time: 63_624_000 picoseconds. - Weight::from_parts(66_071_000, 0) - .saturating_add(Weight::from_parts(0, 6427)) + // Measured: `520` + // Estimated: `6460` + // Minimum execution time: 46_250_000 picoseconds. + Weight::from_parts(47_801_000, 0) + .saturating_add(Weight::from_parts(0, 6460)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs index 8c77774da2dd747f4c3321ae9e2dfb3984cedb0f..d39052c5c03b84f8c02f8257bd9f5a739f4f8624 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs @@ -17,10 +17,10 @@ mod pallet_xcm_benchmarks_fungible; mod pallet_xcm_benchmarks_generic; use crate::{xcm_config::MaxAssetsIntoHolding, Runtime}; +use alloc::vec::Vec; use frame_support::weights::Weight; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; -use sp_std::prelude::*; use xcm::{latest::prelude::*, DoubleEncoded}; trait WeighAssets { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index eaf07aac52cefa88f524e6f3a2180ab9faf2b088..fe8d186139256fbaac3989e0c56fb3acc494d63e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -42,7 +42,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::fungible`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index fc196abea0f5e61d746760e2b2bf5a7d8d0a476b..127bc173c103741839ac2466b0d6ae7d5942ea7f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -42,7 +42,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::generic`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index ff1fc99cba8a7f982ab7f2a58602a48ab3420701..5ecfce18b6dacf5fd1b1b0c012d98c4cd4c70fb7 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -51,11 +51,10 @@ use xcm_builder::{ EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint, NetworkExportTableItem, NoChecking, NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset, - RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + RelayChainAsNative, SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, - XcmFeeToAccount, }; use xcm_executor::XcmExecutor; @@ -357,9 +356,9 @@ impl xcm_executor::Config for XcmConfig { type OriginConverter = XcmOriginToTransactDispatchOrigin; // Asset Hub trusts only particular, pre-configured bridged locations from a different consensus // as reserve locations (we trust the Bridge Hub to relay the message that a reserve is being - // held). Asset Hub may _act_ as a reserve location for WND and assets created - // under `pallet-assets`. Users must use teleport where allowed (e.g. WND with the Relay Chain). - type IsReserve = (bridging::to_rococo::IsTrustedBridgedReserveLocationForConcreteAsset,); + // held). On Westend Asset Hub, we allow Rococo Asset Hub to act as reserve for any asset native + // to the Rococo or Ethereum ecosystems. + type IsReserve = (bridging::to_rococo::RococoOrEthereumAssetFromAssetHubRococo,); type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; @@ -429,7 +428,7 @@ impl xcm_executor::Config for XcmConfig { type AssetExchanger = (); type FeeManager = XcmFeeManagerFromComponents< WaivedLocations, - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = (bridging::to_rococo::UniversalAliases,); @@ -519,8 +518,8 @@ impl pallet_assets::BenchmarkHelper for XcmBenchmarkHelper { /// All configuration related to bridging pub mod bridging { use super::*; + use alloc::collections::btree_set::BTreeSet; use assets_common::matching; - use sp_std::collections::btree_set::BTreeSet; parameter_types! { /// Base price of every byte of the Westend -> Rococo message. Can be adjusted via @@ -548,8 +547,8 @@ pub mod bridging { /// (`AssetId` has to be aligned with `BridgeTable`) pub XcmBridgeHubRouterFeeAssetId: AssetId = WestendLocation::get().into(); - pub BridgeTable: sp_std::vec::Vec = - sp_std::vec::Vec::new().into_iter() + pub BridgeTable: alloc::vec::Vec = + alloc::vec::Vec::new().into_iter() .chain(to_rococo::BridgeTable::get()) .collect(); } @@ -569,20 +568,21 @@ pub mod bridging { ); pub const RococoNetwork: NetworkId = NetworkId::Rococo; - pub AssetHubRococo: Location = Location::new(2, [GlobalConsensus(RococoNetwork::get()), Parachain(bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID)]); + pub const EthereumNetwork: NetworkId = NetworkId::Ethereum { chain_id: 11155111 }; + pub RococoEcosystem: Location = Location::new(2, [GlobalConsensus(RococoNetwork::get())]); pub RocLocation: Location = Location::new(2, [GlobalConsensus(RococoNetwork::get())]); - - pub RocFromAssetHubRococo: (AssetFilter, Location) = ( - Wild(AllOf { fun: WildFungible, id: AssetId(RocLocation::get()) }), - AssetHubRococo::get() - ); + pub EthereumEcosystem: Location = Location::new(2, [GlobalConsensus(EthereumNetwork::get())]); + pub AssetHubRococo: Location = Location::new(2, [ + GlobalConsensus(RococoNetwork::get()), + Parachain(bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID) + ]); /// Set up exporters configuration. /// `Option` represents static "base fee" which is used for total delivery fee calculation. - pub BridgeTable: sp_std::vec::Vec = sp_std::vec![ + pub BridgeTable: alloc::vec::Vec = alloc::vec![ NetworkExportTableItem::new( RococoNetwork::get(), - Some(sp_std::vec![ + Some(alloc::vec![ AssetHubRococo::get().interior.split_global().expect("invalid configuration for AssetHubRococo").1, ]), SiblingBridgeHub::get(), @@ -596,7 +596,7 @@ pub mod bridging { /// Universal aliases pub UniversalAliases: BTreeSet<(Location, Junction)> = BTreeSet::from_iter( - sp_std::vec![ + alloc::vec![ (SiblingBridgeHubWithBridgeHubRococoInstance::get(), GlobalConsensus(RococoNetwork::get())) ] ); @@ -608,17 +608,12 @@ pub mod bridging { } } - /// Reserve locations filter for `xcm_executor::Config::IsReserve`. - /// Locations from which the runtime accepts reserved assets. - pub type IsTrustedBridgedReserveLocationForConcreteAsset = - matching::IsTrustedBridgedReserveLocationForConcreteAsset< - UniversalLocation, - ( - // allow receive ROC from AssetHubRococo - xcm_builder::Case, - // and nothing else - ), - >; + /// Allow any asset native to the Rococo or Ethereum ecosystems if it comes from Rococo + /// Asset Hub. + pub type RococoOrEthereumAssetFromAssetHubRococo = matching::RemoteAssetFromLocation< + (StartsWith, StartsWith), + AssetHubRococo, + >; impl Contains for ToRococoXcmRouter { fn contains(call: &RuntimeCall) -> bool { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index b5957dd5df92ff1180909535cb6e604deadd8829..48e6c11d268c7c2e915c3ce4c0213ede2c883911 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -1258,7 +1258,7 @@ fn report_bridge_status_from_xcm_bridge_router_for_rococo_works() { collator_session_keys(), bridging_to_asset_hub_rococo, || { - sp_std::vec![ + vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, Transact { origin_kind: OriginKind::Xcm, @@ -1268,16 +1268,16 @@ fn report_bridge_status_from_xcm_bridge_router_for_rococo_works() { bp_asset_hub_westend::XcmBridgeHubRouterCall::report_bridge_status { bridge_id: Default::default(), is_congested: true, - } + }, ) .encode() .into(), - } + }, ] .into() }, || { - sp_std::vec![ + vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, Transact { origin_kind: OriginKind::Xcm, @@ -1287,11 +1287,11 @@ fn report_bridge_status_from_xcm_bridge_router_for_rococo_works() { bp_asset_hub_westend::XcmBridgeHubRouterCall::report_bridge_status { bridge_id: Default::default(), is_congested: false, - } + }, ) .encode() .into(), - } + }, ] .into() }, diff --git a/cumulus/parachains/runtimes/assets/common/Cargo.toml b/cumulus/parachains/runtimes/assets/common/Cargo.toml index 4664e0cb9a7f817ed419936dfa9e5d0ac52f599e..c6740269339d808f14d9dd2879f2ddd74b4e842b 100644 --- a/cumulus/parachains/runtimes/assets/common/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/common/Cargo.toml @@ -10,30 +10,29 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } log = { workspace = true } -impl-trait-for-tuples = "0.2.2" +impl-trait-for-tuples = { workspace = true } # Substrate -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -pallet-asset-conversion = { path = "../../../../../substrate/frame/asset-conversion", default-features = false } +frame-support = { workspace = true } +sp-api = { workspace = true } +sp-runtime = { workspace = true } +pallet-asset-conversion = { workspace = true } # Polkadot -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } +pallet-xcm = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } # Cumulus -parachains-common = { path = "../../../common", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } +parachains-common = { workspace = true } +cumulus-primitives-core = { workspace = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder" } +substrate-wasm-builder = { workspace = true, default-features = true } [features] default = ["std"] @@ -48,7 +47,6 @@ std = [ "scale-info/std", "sp-api/std", "sp-runtime/std", - "sp-std/std", "xcm-builder/std", "xcm-executor/std", "xcm/std", diff --git a/cumulus/parachains/runtimes/assets/common/src/benchmarks.rs b/cumulus/parachains/runtimes/assets/common/src/benchmarks.rs index 44bda1eb3709c74d808e696d5d3728a3354b747a..d59fddc4e8f0289fd8ab4aebe7465551c83c136a 100644 --- a/cumulus/parachains/runtimes/assets/common/src/benchmarks.rs +++ b/cumulus/parachains/runtimes/assets/common/src/benchmarks.rs @@ -13,9 +13,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +use core::marker::PhantomData; use cumulus_primitives_core::ParaId; use sp_runtime::traits::Get; -use sp_std::marker::PhantomData; use xcm::latest::prelude::*; /// Creates asset pairs for liquidity pools with `Target` always being the first asset. diff --git a/cumulus/parachains/runtimes/assets/common/src/foreign_creators.rs b/cumulus/parachains/runtimes/assets/common/src/foreign_creators.rs index a9fd79bf939f575ac60007cd6920ac6db3ded773..95edb31da06e5a0ff1f9d40f3d385f6bd2c21e35 100644 --- a/cumulus/parachains/runtimes/assets/common/src/foreign_creators.rs +++ b/cumulus/parachains/runtimes/assets/common/src/foreign_creators.rs @@ -23,7 +23,7 @@ use xcm_executor::traits::ConvertLocation; /// `EnsureOriginWithArg` impl for `CreateOrigin` that allows only XCM origins that are locations /// containing the class location. pub struct ForeignCreators( - sp_std::marker::PhantomData<(IsForeign, AccountOf, AccountId, L)>, + core::marker::PhantomData<(IsForeign, AccountOf, AccountId, L)>, ); impl< IsForeign: ContainsPair, @@ -41,7 +41,7 @@ where fn try_origin( origin: RuntimeOrigin, asset_location: &L, - ) -> sp_std::result::Result { + ) -> core::result::Result { let origin_location = EnsureXcm::::try_origin(origin.clone())?; if !IsForeign::contains(asset_location, &origin_location) { return Err(origin) diff --git a/cumulus/parachains/runtimes/assets/common/src/fungible_conversion.rs b/cumulus/parachains/runtimes/assets/common/src/fungible_conversion.rs index e21203485a764c350b3d9890d7dcdaa89110babf..27ee2d6b5653c91bd922045005201439870c324a 100644 --- a/cumulus/parachains/runtimes/assets/common/src/fungible_conversion.rs +++ b/cumulus/parachains/runtimes/assets/common/src/fungible_conversion.rs @@ -16,9 +16,10 @@ //! Runtime API definition for assets. use crate::runtime_api::FungiblesAccessError; +use alloc::vec::Vec; +use core::borrow::Borrow; use frame_support::traits::Contains; use sp_runtime::traits::MaybeEquivalence; -use sp_std::{borrow::Borrow, vec::Vec}; use xcm::latest::{Asset, Location}; use xcm_builder::{ConvertedConcreteId, MatchedConvertedConcreteId}; use xcm_executor::traits::MatchesFungibles; diff --git a/cumulus/parachains/runtimes/assets/common/src/lib.rs b/cumulus/parachains/runtimes/assets/common/src/lib.rs index 431b5766147aeb8279ed2b1298691ceede856e5e..4bb593f98929e4dfcaf2879e759f863138f49282 100644 --- a/cumulus/parachains/runtimes/assets/common/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/common/src/lib.rs @@ -23,6 +23,8 @@ pub mod local_and_foreign_assets; pub mod matching; pub mod runtime_api; +extern crate alloc; + use crate::matching::{LocalLocationPattern, ParentLocation}; use frame_support::traits::{Equals, EverythingBut}; use parachains_common::{AssetIdForTrustBackedAssets, CollectionId, ItemId}; diff --git a/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs b/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs index 58f5d2d57a7669b73876897f90e0da3e20730cbb..8a89089c7187726d30cc485b9280853a9da277e3 100644 --- a/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs +++ b/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs @@ -13,13 +13,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +use core::marker::PhantomData; use frame_support::traits::Get; use sp_runtime::{ traits::{Convert, MaybeEquivalence}, Either, Either::{Left, Right}, }; -use sp_std::marker::PhantomData; use xcm::latest::Location; /// Converts a given [`Location`] to [`Either::Left`] when equal to `Target`, or diff --git a/cumulus/parachains/runtimes/assets/common/src/matching.rs b/cumulus/parachains/runtimes/assets/common/src/matching.rs index 3aad88e177caad1095a3dbe21dd3a3308b103680..9bb35d0c5328b8de455f6f3c75f4d2965d5fe44f 100644 --- a/cumulus/parachains/runtimes/assets/common/src/matching.rs +++ b/cumulus/parachains/runtimes/assets/common/src/matching.rs @@ -14,7 +14,10 @@ // limitations under the License. use cumulus_primitives_core::ParaId; -use frame_support::{pallet_prelude::Get, traits::ContainsPair}; +use frame_support::{ + pallet_prelude::Get, + traits::{Contains, ContainsPair}, +}; use xcm::prelude::*; use xcm_builder::ensure_is_remote; @@ -25,7 +28,7 @@ frame_support::parameter_types! { } /// Accepts an asset if it is from the origin. -pub struct IsForeignConcreteAsset(sp_std::marker::PhantomData); +pub struct IsForeignConcreteAsset(core::marker::PhantomData); impl> ContainsPair for IsForeignConcreteAsset { @@ -38,7 +41,7 @@ impl> ContainsPair /// Checks if `a` is from sibling location `b`. Checks that `Location-a` starts with /// `Location-b`, and that the `ParaId` of `b` is not equal to `a`. pub struct FromSiblingParachain( - sp_std::marker::PhantomData<(SelfParaId, L)>, + core::marker::PhantomData<(SelfParaId, L)>, ); impl, L: TryFrom + TryInto + Clone> ContainsPair for FromSiblingParachain @@ -62,7 +65,7 @@ impl, L: TryFrom + TryInto + Clone> /// Checks if `a` is from the expected global consensus network. Checks that `Location-a` /// starts with `Location-b`, and that network is a foreign consensus system. pub struct FromNetwork( - sp_std::marker::PhantomData<(UniversalLocation, ExpectedNetworkId, L)>, + core::marker::PhantomData<(UniversalLocation, ExpectedNetworkId, L)>, ); impl< UniversalLocation: Get, @@ -94,36 +97,33 @@ impl< } } -/// Adapter verifies if it is allowed to receive `Asset` from `Location`. -/// -/// Note: `Location` has to be from a different global consensus. -pub struct IsTrustedBridgedReserveLocationForConcreteAsset( - sp_std::marker::PhantomData<(UniversalLocation, Reserves)>, +/// Accept an asset if it is native to `AssetsAllowedNetworks` and it is coming from +/// `OriginLocation`. +pub struct RemoteAssetFromLocation( + core::marker::PhantomData<(AssetsAllowedNetworks, OriginLocation)>, ); -impl, Reserves: ContainsPair> - ContainsPair - for IsTrustedBridgedReserveLocationForConcreteAsset +impl, OriginLocation: Get> + ContainsPair for RemoteAssetFromLocation { fn contains(asset: &Asset, origin: &Location) -> bool { - let universal_source = UniversalLocation::get(); - log::trace!( - target: "xcm::contains", - "IsTrustedBridgedReserveLocationForConcreteAsset asset: {:?}, origin: {:?}, universal_source: {:?}", - asset, origin, universal_source - ); - - // check remote origin - if ensure_is_remote(universal_source.clone(), origin.clone()).is_err() { + let expected_origin = OriginLocation::get(); + // ensure `origin` is expected `OriginLocation` + if !expected_origin.eq(origin) { log::trace!( target: "xcm::contains", - "IsTrustedBridgedReserveLocationForConcreteAsset origin: {:?} is not remote to the universal_source: {:?}", - origin, universal_source + "RemoteAssetFromLocation asset: {:?}, origin: {:?} is not from expected {:?}", + asset, origin, expected_origin, ); return false + } else { + log::trace!( + target: "xcm::contains", + "RemoteAssetFromLocation asset: {asset:?}, origin: {origin:?}", + ); } - // check asset according to the configured reserve locations - Reserves::contains(asset, origin) + // ensure `asset` is from remote consensus listed in `AssetsAllowedNetworks` + AssetsAllowedNetworks::contains(&asset.id.0) } } diff --git a/cumulus/parachains/runtimes/assets/common/src/runtime_api.rs b/cumulus/parachains/runtimes/assets/common/src/runtime_api.rs index 19977cbedab07b638f71f32470d3768cabeba322..799b2f45b4dfbff288383821598954f30612f806 100644 --- a/cumulus/parachains/runtimes/assets/common/src/runtime_api.rs +++ b/cumulus/parachains/runtimes/assets/common/src/runtime_api.rs @@ -18,7 +18,7 @@ use codec::{Codec, Decode, Encode}; use sp_runtime::RuntimeDebug; #[cfg(feature = "std")] -use {sp_std::vec::Vec, xcm::latest::Asset}; +use {alloc::vec::Vec, xcm::latest::Asset}; /// The possible errors that can happen querying the storage of assets. #[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] diff --git a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml index af5b4a64680724abcbf0d659ba8a7b2b45cd0e80..529d6460fc4e46b6a7d04ae77c01f7135f6eed9d 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml @@ -10,42 +10,41 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { features = ["derive", "max-encoded-len"], workspace = true } # Substrate -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../../substrate/frame/system", default-features = false } -pallet-assets = { path = "../../../../../substrate/frame/assets", default-features = false } -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } -sp-io = { path = "../../../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-assets = { workspace = true } +pallet-balances = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-session = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } # Cumulus -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } -pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } -parachains-common = { path = "../../../common", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-runtimes-test-utils = { path = "../../test-utils", default-features = false } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +pallet-collator-selection = { workspace = true } +parachains-common = { workspace = true } +cumulus-primitives-core = { workspace = true } +parachain-info = { workspace = true } +parachains-runtimes-test-utils = { workspace = true } # Polkadot -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +pallet-xcm = { workspace = true } # Bridges -pallet-xcm-bridge-hub-router = { path = "../../../../../bridges/modules/xcm-bridge-hub-router", default-features = false } +pallet-xcm-bridge-hub-router = { workspace = true } [dev-dependencies] -hex-literal = "0.4.1" +hex-literal = { workspace = true, default-features = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder" } +substrate-wasm-builder = { workspace = true, default-features = true } [features] default = ["std"] @@ -68,7 +67,6 @@ std = [ "parachains-runtimes-test-utils/std", "sp-io/std", "sp-runtime/std", - "sp-std/std", "xcm-builder/std", "xcm-executor/std", "xcm/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 5e8639eed36b99413e66684ce627ae049eb6d0ad..7a60a3f6484027d1972d947d21b36d2b2f4ede36 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -10,124 +10,123 @@ license = "Apache-2.0" workspace = true [build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ +codec = { features = [ "derive", -] } -hex-literal = { version = "0.4.1" } +], workspace = true } +hex-literal = { workspace = true, default-features = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = [ +scale-info = { features = [ "derive", -] } +], workspace = true } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Substrate -frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../../substrate/frame/system", default-features = false } -frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true } -frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false } -frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } -pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false } -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } -pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } -pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false } -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } -pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false } -sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } -sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false } -sp-io = { path = "../../../../../substrate/primitives/io", default-features = false } -sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -sp-session = { path = "../../../../../substrate/primitives/session", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-storage = { path = "../../../../../substrate/primitives/storage", default-features = false } -sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } -sp-version = { path = "../../../../../substrate/primitives/version", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-executive = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-benchmarking = { optional = true, workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +frame-try-runtime = { optional = true, workspace = true } +pallet-aura = { workspace = true } +pallet-authorship = { workspace = true } +pallet-balances = { workspace = true } +pallet-session = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-multisig = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-utility = { workspace = true } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-core = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } +sp-io = { workspace = true } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-std = { workspace = true } +sp-storage = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } # Polkadot -rococo-runtime-constants = { path = "../../../../../polkadot/runtime/rococo/constants", default-features = false } -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } -pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } -polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false } -polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } -xcm-fee-payment-runtime-api = { path = "../../../../../polkadot/xcm/xcm-fee-payment-runtime-api", default-features = false } +rococo-runtime-constants = { workspace = true } +pallet-xcm = { workspace = true } +pallet-xcm-benchmarks = { optional = true, workspace = true } +polkadot-parachain-primitives = { workspace = true } +polkadot-runtime-common = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm-runtime-apis = { workspace = true } # Cumulus -cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } -cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false } -cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false, features = [ +cumulus-pallet-aura-ext = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-session-benchmarking = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { features = [ "bridging", -] } -cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } -cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } -cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } -pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } -testnet-parachains-constants = { path = "../../constants", default-features = false, features = ["rococo"] } +], workspace = true } +cumulus-primitives-aura = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true } +cumulus-primitives-utility = { workspace = true } +pallet-collator-selection = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } +testnet-parachains-constants = { features = ["rococo"], workspace = true } # Bridges -bp-asset-hub-rococo = { path = "../../../../../bridges/chains/chain-asset-hub-rococo", default-features = false } -bp-asset-hub-westend = { path = "../../../../../bridges/chains/chain-asset-hub-westend", default-features = false } -bp-bridge-hub-polkadot = { path = "../../../../../bridges/chains/chain-bridge-hub-polkadot", default-features = false } -bp-bridge-hub-rococo = { path = "../../../../../bridges/chains/chain-bridge-hub-rococo", default-features = false } -bp-bridge-hub-westend = { path = "../../../../../bridges/chains/chain-bridge-hub-westend", default-features = false } -bp-header-chain = { path = "../../../../../bridges/primitives/header-chain", default-features = false } -bp-messages = { path = "../../../../../bridges/primitives/messages", default-features = false } -bp-parachains = { path = "../../../../../bridges/primitives/parachains", default-features = false } -bp-polkadot-bulletin = { path = "../../../../../bridges/chains/chain-polkadot-bulletin", default-features = false } -bp-polkadot-core = { path = "../../../../../bridges/primitives/polkadot-core", default-features = false } -bp-relayers = { path = "../../../../../bridges/primitives/relayers", default-features = false } -bp-runtime = { path = "../../../../../bridges/primitives/runtime", default-features = false } -bp-rococo = { path = "../../../../../bridges/chains/chain-rococo", default-features = false } -bp-westend = { path = "../../../../../bridges/chains/chain-westend", default-features = false } -pallet-bridge-grandpa = { path = "../../../../../bridges/modules/grandpa", default-features = false } -pallet-bridge-messages = { path = "../../../../../bridges/modules/messages", default-features = false } -pallet-bridge-parachains = { path = "../../../../../bridges/modules/parachains", default-features = false } -pallet-bridge-relayers = { path = "../../../../../bridges/modules/relayers", default-features = false } -pallet-xcm-bridge-hub = { path = "../../../../../bridges/modules/xcm-bridge-hub", default-features = false } -bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", default-features = false } +bp-asset-hub-rococo = { workspace = true } +bp-asset-hub-westend = { workspace = true } +bp-bridge-hub-polkadot = { workspace = true } +bp-bridge-hub-rococo = { workspace = true } +bp-bridge-hub-westend = { workspace = true } +bp-header-chain = { workspace = true } +bp-messages = { workspace = true } +bp-parachains = { workspace = true } +bp-polkadot-bulletin = { workspace = true } +bp-polkadot-core = { workspace = true } +bp-relayers = { workspace = true } +bp-runtime = { features = ["test-helpers"], workspace = true } +bp-rococo = { workspace = true } +bp-westend = { workspace = true } +pallet-bridge-grandpa = { workspace = true } +pallet-bridge-messages = { workspace = true } +pallet-bridge-parachains = { workspace = true } +pallet-bridge-relayers = { workspace = true } +pallet-xcm-bridge-hub = { workspace = true } +bridge-runtime-common = { workspace = true } # Ethereum Bridge (Snowbridge) -snowbridge-beacon-primitives = { path = "../../../../../bridges/snowbridge/primitives/beacon", default-features = false } -snowbridge-pallet-system = { path = "../../../../../bridges/snowbridge/pallets/system", default-features = false } -snowbridge-system-runtime-api = { path = "../../../../../bridges/snowbridge/pallets/system/runtime-api", default-features = false } -snowbridge-core = { path = "../../../../../bridges/snowbridge/primitives/core", default-features = false } -snowbridge-pallet-ethereum-client = { path = "../../../../../bridges/snowbridge/pallets/ethereum-client", default-features = false } -snowbridge-pallet-inbound-queue = { path = "../../../../../bridges/snowbridge/pallets/inbound-queue", default-features = false } -snowbridge-pallet-outbound-queue = { path = "../../../../../bridges/snowbridge/pallets/outbound-queue", default-features = false } -snowbridge-outbound-queue-runtime-api = { path = "../../../../../bridges/snowbridge/pallets/outbound-queue/runtime-api", default-features = false } -snowbridge-router-primitives = { path = "../../../../../bridges/snowbridge/primitives/router", default-features = false } -snowbridge-runtime-common = { path = "../../../../../bridges/snowbridge/runtime/runtime-common", default-features = false } +snowbridge-beacon-primitives = { workspace = true } +snowbridge-pallet-system = { workspace = true } +snowbridge-system-runtime-api = { workspace = true } +snowbridge-core = { workspace = true } +snowbridge-pallet-ethereum-client = { workspace = true } +snowbridge-pallet-inbound-queue = { workspace = true } +snowbridge-pallet-outbound-queue = { workspace = true } +snowbridge-outbound-queue-runtime-api = { workspace = true } +snowbridge-router-primitives = { workspace = true } +snowbridge-runtime-common = { workspace = true } -bridge-hub-common = { path = "../common", default-features = false } +bridge-hub-common = { workspace = true } [dev-dependencies] -static_assertions = "1.1" -bridge-hub-test-utils = { path = "../test-utils" } -bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", features = [ +bridge-hub-test-utils = { workspace = true, default-features = true } +bridge-runtime-common = { features = [ "integrity-test", -] } -sp-keyring = { path = "../../../../../substrate/primitives/keyring" } -snowbridge-runtime-test-common = { path = "../../../../../bridges/snowbridge/runtime/test-common" } +], workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +snowbridge-runtime-test-common = { workspace = true, default-features = true } [features] default = ["std"] @@ -219,7 +218,7 @@ std = [ "testnet-parachains-constants/std", "xcm-builder/std", "xcm-executor/std", - "xcm-fee-payment-runtime-api/std", + "xcm-runtime-apis/std", "xcm/std", ] @@ -262,7 +261,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", - "xcm-fee-payment-runtime-api/runtime-benchmarks", + "xcm-runtime-apis/runtime-benchmarks", ] try-runtime = [ diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs index 5551b05e202547c99501b279e8839611efcc7f66..779cc537ee96dcc2fadc38452dfcd01c4c320789 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs @@ -21,14 +21,9 @@ //! For example, the messaging pallet needs to know the sending and receiving chains, but the //! GRANDPA tracking pallet only needs to be aware of one chain. -use super::{ - weights, AccountId, Balance, Balances, BlockNumber, Runtime, RuntimeEvent, RuntimeOrigin, -}; +use super::{weights, AccountId, Balance, Balances, BlockNumber, Runtime, RuntimeEvent}; use bp_parachains::SingleParaStoredHeaderDataBuilder; -use bp_runtime::UnderlyingChainProvider; -use bridge_runtime_common::messages::ThisChainWithMessages; use frame_support::{parameter_types, traits::ConstU32}; -use sp_runtime::RuntimeDebug; parameter_types! { pub const RelayChainHeadersToKeep: u32 = 1024; @@ -103,15 +98,3 @@ impl pallet_bridge_grandpa::Config for Runt // weights are also the same for both bridges. type WeightInfo = weights::pallet_bridge_grandpa::WeightInfo; } - -/// BridgeHubRococo chain from message lane point of view. -#[derive(RuntimeDebug, Clone, Copy)] -pub struct BridgeHubRococo; - -impl UnderlyingChainProvider for BridgeHubRococo { - type Chain = bp_bridge_hub_rococo::BridgeHubRococo; -} - -impl ThisChainWithMessages for BridgeHubRococo { - type RuntimeOrigin = RuntimeOrigin; -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs index 94b936889b77c4460f9921956d6f7abef1ecb52c..83b92918dc4f442d3574d0476d25de90e9dc160a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs @@ -20,23 +20,19 @@ //! are reusing Polkadot Bulletin chain primitives everywhere here. use crate::{ - bridge_common_config::BridgeHubRococo, weights, xcm_config::UniversalLocation, AccountId, - BridgeRococoBulletinGrandpa, BridgeRococoBulletinMessages, PolkadotXcm, Runtime, RuntimeEvent, - XcmOverRococoBulletin, XcmRouter, + weights, xcm_config::UniversalLocation, BridgeRococoBulletinGrandpa, + BridgeRococoBulletinMessages, PolkadotXcm, Runtime, RuntimeEvent, XcmOverRococoBulletin, + XcmRouter, +}; +use bp_messages::{ + source_chain::FromBridgedChainMessagesDeliveryProof, + target_chain::FromBridgedChainMessagesProof, LaneId, }; -use bp_messages::LaneId; -use bp_runtime::Chain; use bridge_runtime_common::{ extensions::refund_relayer_extension::{ ActualFeeRefund, RefundBridgedMessages, RefundSignedExtensionAdapter, RefundableMessagesLane, }, - messages, - messages::{ - source::{FromBridgedChainMessagesDeliveryProof, TargetHeaderChainAdapter}, - target::{FromBridgedChainMessagesProof, SourceHeaderChainAdapter}, - MessageBridge, UnderlyingChainProvider, - }, messages_xcm_extension::{ SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, @@ -44,7 +40,6 @@ use bridge_runtime_common::{ }; use frame_support::{parameter_types, traits::PalletInfoAccess}; -use sp_runtime::RuntimeDebug; use xcm::{ latest::prelude::*, prelude::{InteriorLocation, NetworkId}, @@ -52,17 +47,6 @@ use xcm::{ use xcm_builder::BridgeBlobDispatcher; parameter_types! { - /// Maximal number of entries in the unrewarded relayers vector at the Rococo Bridge Hub. It matches the - /// maximal number of unrewarded relayers that the single confirmation transaction at Rococo Bulletin Chain - /// may process. - pub const MaxUnrewardedRelayerEntriesAtInboundLane: bp_messages::MessageNonce = - bp_polkadot_bulletin::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; - /// Maximal number of unconfirmed messages at the Rococo Bridge Hub. It matches the maximal number of - /// unconfirmed messages that the single confirmation transaction at Rococo Bulletin Chain may process. - pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce = - bp_polkadot_bulletin::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; - /// Bridge specific chain (network) identifier of the Rococo Bulletin Chain. - pub const RococoBulletinChainId: bp_runtime::ChainId = bp_polkadot_bulletin::PolkadotBulletin::ID; /// Interior location (relative to this runtime) of the with-RococoBulletin messages pallet. pub BridgeRococoToRococoBulletinMessagesPalletInstance: InteriorLocation = [ PalletInstance(::index() as u8) @@ -100,7 +84,7 @@ parameter_types! { XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, ); /// All active routes and their destinations. - pub ActiveLanes: sp_std::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = sp_std::vec![ + pub ActiveLanes: alloc::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = alloc::vec![ ( FromRococoPeopleToRococoBulletinRoute::get(), (RococoBulletinGlobalConsensusNetwork::get(), Here) @@ -142,31 +126,6 @@ impl XcmBlobHauler for ToRococoBulletinXcmBlobHauler { type OnMessagesDeliveredFromRococoBulletin = XcmBlobHaulerAdapter; -/// Messaging Bridge configuration for BridgeHubRococo -> Rococo Bulletin. -pub struct WithRococoBulletinMessageBridge; -impl MessageBridge for WithRococoBulletinMessageBridge { - // Bulletin chain assumes it is bridged with Polkadot Bridge Hub - const BRIDGED_MESSAGES_PALLET_NAME: &'static str = - bp_bridge_hub_polkadot::WITH_BRIDGE_HUB_POLKADOT_MESSAGES_PALLET_NAME; - type ThisChain = BridgeHubRococo; - type BridgedChain = RococoBulletin; - type BridgedHeaderChain = BridgeRococoBulletinGrandpa; -} - -/// Maximal outbound payload size of BridgeHubRococo -> RococoBulletin messages. -pub type ToRococoBulletinMaximalOutboundPayloadSize = - messages::source::FromThisChainMaximalOutboundPayloadSize; - -/// RococoBulletin chain from message lane point of view. -#[derive(RuntimeDebug, Clone, Copy)] -pub struct RococoBulletin; - -impl UnderlyingChainProvider for RococoBulletin { - type Chain = bp_polkadot_bulletin::PolkadotBulletin; -} - -impl messages::BridgedChainWithMessages for RococoBulletin {} - /// Signed extension that refunds relayers that are delivering messages from the Rococo Bulletin /// chain. pub type OnBridgeHubRococoRefundRococoBulletinMessages = RefundSignedExtensionAdapter< @@ -189,22 +148,20 @@ impl pallet_bridge_messages::Config for Runt type RuntimeEvent = RuntimeEvent; type WeightInfo = weights::pallet_bridge_messages_rococo_to_rococo_bulletin::WeightInfo; - type BridgedChainId = RococoBulletinChainId; + + type ThisChain = bp_bridge_hub_rococo::BridgeHubRococo; + type BridgedChain = bp_polkadot_bulletin::PolkadotBulletin; + type BridgedHeaderChain = BridgeRococoBulletinGrandpa; + type ActiveOutboundLanes = ActiveOutboundLanesToRococoBulletin; - type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; - type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; - type MaximalOutboundPayloadSize = ToRococoBulletinMaximalOutboundPayloadSize; type OutboundPayload = XcmAsPlainPayload; type InboundPayload = XcmAsPlainPayload; - type InboundRelayer = AccountId; type DeliveryPayments = (); - type TargetHeaderChain = TargetHeaderChainAdapter; type DeliveryConfirmationPayments = (); - type SourceHeaderChain = SourceHeaderChainAdapter; type MessageDispatch = XcmBlobMessageDispatch; type OnMessagesDelivered = OnMessagesDeliveredFromRococoBulletin; @@ -267,8 +224,7 @@ mod tests { runtime: Runtime, with_bridged_chain_grandpa_instance: BridgeGrandpaRococoBulletinInstance, with_bridged_chain_messages_instance: WithRococoBulletinMessagesInstance, - bridge: WithRococoBulletinMessageBridge, - this_chain: bp_rococo::Rococo, + this_chain: bp_bridge_hub_rococo::BridgeHubRococo, bridged_chain: bp_polkadot_bulletin::PolkadotBulletin, ); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs index 1681ac7f4687493c82c0a3233439b2a9d47a1ad0..9880e8a17c2b80d34ae6b62f9c8a588625105e70 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs @@ -17,27 +17,20 @@ //! Bridge definitions used on BridgeHubRococo for bridging to BridgeHubWestend. use crate::{ - bridge_common_config::{ - BridgeHubRococo, BridgeParachainWestendInstance, DeliveryRewardInBalance, - }, + bridge_common_config::{BridgeParachainWestendInstance, DeliveryRewardInBalance}, weights, xcm_config::UniversalLocation, - AccountId, BridgeWestendMessages, PolkadotXcm, Runtime, RuntimeEvent, XcmOverBridgeHubWestend, - XcmRouter, + BridgeWestendMessages, PolkadotXcm, Runtime, RuntimeEvent, XcmOverBridgeHubWestend, XcmRouter, +}; +use bp_messages::{ + source_chain::FromBridgedChainMessagesDeliveryProof, + target_chain::FromBridgedChainMessagesProof, LaneId, }; -use bp_messages::LaneId; -use bp_runtime::Chain; use bridge_runtime_common::{ extensions::refund_relayer_extension::{ ActualFeeRefund, RefundBridgedMessages, RefundSignedExtensionAdapter, RefundableMessagesLane, }, - messages, - messages::{ - source::{FromBridgedChainMessagesDeliveryProof, TargetHeaderChainAdapter}, - target::{FromBridgedChainMessagesProof, SourceHeaderChainAdapter}, - MessageBridge, UnderlyingChainProvider, - }, messages_xcm_extension::{ SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, @@ -46,7 +39,6 @@ use bridge_runtime_common::{ use codec::Encode; use frame_support::{parameter_types, traits::PalletInfoAccess}; -use sp_runtime::RuntimeDebug; use xcm::{ latest::prelude::*, prelude::{InteriorLocation, NetworkId}, @@ -54,11 +46,6 @@ use xcm::{ use xcm_builder::BridgeBlobDispatcher; parameter_types! { - pub const MaxUnrewardedRelayerEntriesAtInboundLane: bp_messages::MessageNonce = - bp_bridge_hub_rococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; - pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce = - bp_bridge_hub_rococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; - pub const BridgeHubWestendChainId: bp_runtime::ChainId = BridgeHubWestend::ID; pub BridgeRococoToWestendMessagesPalletInstance: InteriorLocation = [PalletInstance(::index() as u8)].into(); pub WestendGlobalConsensusNetwork: NetworkId = NetworkId::Westend; pub WestendGlobalConsensusNetworkLocation: Location = Location::new( @@ -82,7 +69,7 @@ parameter_types! { ParentThen([Parachain(AssetHubRococoParaId::get().into())].into()).into(), XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, ); - pub ActiveLanes: sp_std::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = sp_std::vec![ + pub ActiveLanes: alloc::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = alloc::vec![ ( FromAssetHubRococoToAssetHubWestendRoute::get(), (WestendGlobalConsensusNetwork::get(), [Parachain(AssetHubWestendParaId::get().into())].into()) @@ -102,8 +89,8 @@ parameter_types! { } pub const XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND: LaneId = LaneId([0, 0, 0, 2]); -fn build_congestion_message(is_congested: bool) -> sp_std::vec::Vec> { - sp_std::vec![ +fn build_congestion_message(is_congested: bool) -> alloc::vec::Vec> { + alloc::vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, Transact { origin_kind: OriginKind::Xcm, @@ -148,34 +135,6 @@ impl XcmBlobHauler for ToBridgeHubWestendXcmBlobHauler { type OnMessagesDeliveredFromWestend = XcmBlobHaulerAdapter; -/// Messaging Bridge configuration for BridgeHubRococo -> BridgeHubWestend -pub struct WithBridgeHubWestendMessageBridge; -impl MessageBridge for WithBridgeHubWestendMessageBridge { - const BRIDGED_MESSAGES_PALLET_NAME: &'static str = - bp_bridge_hub_rococo::WITH_BRIDGE_HUB_ROCOCO_MESSAGES_PALLET_NAME; - type ThisChain = BridgeHubRococo; - type BridgedChain = BridgeHubWestend; - type BridgedHeaderChain = pallet_bridge_parachains::ParachainHeaders< - Runtime, - BridgeParachainWestendInstance, - bp_bridge_hub_westend::BridgeHubWestend, - >; -} - -/// Maximal outbound payload size of BridgeHubRococo -> BridgeHubWestend messages. -pub type ToBridgeHubWestendMaximalOutboundPayloadSize = - messages::source::FromThisChainMaximalOutboundPayloadSize; - -/// BridgeHubWestend chain from message lane point of view. -#[derive(RuntimeDebug, Clone, Copy)] -pub struct BridgeHubWestend; - -impl UnderlyingChainProvider for BridgeHubWestend { - type Chain = bp_bridge_hub_westend::BridgeHubWestend; -} - -impl messages::BridgedChainWithMessages for BridgeHubWestend {} - /// Signed extension that refunds relayers that are delivering messages from the Westend parachain. pub type OnBridgeHubRococoRefundBridgeHubWestendMessages = RefundSignedExtensionAdapter< RefundBridgedMessages< @@ -196,26 +155,28 @@ pub type WithBridgeHubWestendMessagesInstance = pallet_bridge_messages::Instance impl pallet_bridge_messages::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = weights::pallet_bridge_messages_rococo_to_westend::WeightInfo; - type BridgedChainId = BridgeHubWestendChainId; + + type ThisChain = bp_bridge_hub_rococo::BridgeHubRococo; + type BridgedChain = bp_bridge_hub_westend::BridgeHubWestend; + type BridgedHeaderChain = pallet_bridge_parachains::ParachainHeaders< + Runtime, + BridgeParachainWestendInstance, + bp_bridge_hub_westend::BridgeHubWestend, + >; + type ActiveOutboundLanes = ActiveOutboundLanesToBridgeHubWestend; - type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; - type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; - type MaximalOutboundPayloadSize = ToBridgeHubWestendMaximalOutboundPayloadSize; type OutboundPayload = XcmAsPlainPayload; type InboundPayload = XcmAsPlainPayload; - type InboundRelayer = AccountId; type DeliveryPayments = (); - type TargetHeaderChain = TargetHeaderChainAdapter; type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< Runtime, WithBridgeHubWestendMessagesInstance, DeliveryRewardInBalance, >; - type SourceHeaderChain = SourceHeaderChainAdapter; type MessageDispatch = XcmBlobMessageDispatch< FromWestendMessageBlobDispatcher, Self::WeightInfo, @@ -248,9 +209,8 @@ mod tests { assert_complete_bridge_types, extensions::refund_relayer_extension::RefundableParachain, integrity::{ - assert_complete_bridge_constants, check_message_lane_weights, - AssertBridgeMessagesPalletConstants, AssertBridgePalletNames, AssertChainConstants, - AssertCompleteBridgeConstants, + assert_complete_with_parachain_bridge_constants, check_message_lane_weights, + AssertChainConstants, AssertCompleteBridgeConstants, }, }; use parachains_common::Balance; @@ -292,36 +252,20 @@ mod tests { runtime: Runtime, with_bridged_chain_grandpa_instance: BridgeGrandpaWestendInstance, with_bridged_chain_messages_instance: WithBridgeHubWestendMessagesInstance, - bridge: WithBridgeHubWestendMessageBridge, - this_chain: bp_rococo::Rococo, - bridged_chain: bp_westend::Westend, + this_chain: bp_bridge_hub_rococo::BridgeHubRococo, + bridged_chain: bp_bridge_hub_westend::BridgeHubWestend, ); - assert_complete_bridge_constants::< + assert_complete_with_parachain_bridge_constants::< Runtime, BridgeGrandpaWestendInstance, WithBridgeHubWestendMessagesInstance, - WithBridgeHubWestendMessageBridge, + bp_westend::Westend, >(AssertCompleteBridgeConstants { this_chain_constants: AssertChainConstants { block_length: bp_bridge_hub_rococo::BlockLength::get(), block_weights: bp_bridge_hub_rococo::BlockWeightsForAsyncBacking::get(), }, - messages_pallet_constants: AssertBridgeMessagesPalletConstants { - max_unrewarded_relayers_in_bridged_confirmation_tx: - bp_bridge_hub_westend::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, - max_unconfirmed_messages_in_bridged_confirmation_tx: - bp_bridge_hub_westend::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, - bridged_chain_id: BridgeHubWestend::ID, - }, - pallet_names: AssertBridgePalletNames { - with_this_chain_messages_pallet_name: - bp_bridge_hub_rococo::WITH_BRIDGE_HUB_ROCOCO_MESSAGES_PALLET_NAME, - with_bridged_chain_grandpa_pallet_name: - bp_westend::WITH_WESTEND_GRANDPA_PALLET_NAME, - with_bridged_chain_messages_pallet_name: - bp_bridge_hub_westend::WITH_BRIDGE_HUB_WESTEND_MESSAGES_PALLET_NAME, - }, }); bridge_runtime_common::extensions::priority_calculator::per_relay_header::ensure_priority_boost_is_sane::< @@ -332,7 +276,7 @@ mod tests { bridge_runtime_common::extensions::priority_calculator::per_parachain_header::ensure_priority_boost_is_sane::< Runtime, - RefundableParachain, + RefundableParachain, PriorityBoostPerParachainHeader, >(FEE_BOOST_PER_PARACHAIN_HEADER); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 12707d78550092a254fae909cbfee12f7ef0ca96..062996ad4115232a2789a28cccc894d523ce3cf1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -35,6 +35,9 @@ pub mod bridge_to_westend_config; mod weights; pub mod xcm_config; +extern crate alloc; + +use alloc::{vec, vec::Vec}; use bridge_runtime_common::extensions::{ check_obsolete_extension::{ CheckAndBoostBridgeGrandpaTransactions, CheckAndBoostBridgeParachainsTransactions, @@ -58,7 +61,6 @@ use sp_runtime::{ ApplyExtrinsicResult, FixedU128, }; -use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -98,7 +100,7 @@ pub use sp_runtime::BuildStorage; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use rococo_runtime_constants::system_parachain::{ASSET_HUB_ID, BRIDGE_HUB_ID}; use xcm::prelude::*; -use xcm_fee_payment_runtime_api::{ +use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, }; @@ -110,6 +112,8 @@ use parachains_common::{ AVERAGE_ON_INITIALIZE_RATIO, NORMAL_DISPATCH_RATIO, }; +#[cfg(feature = "runtime-benchmarks")] +use alloc::boxed::Box; #[cfg(feature = "runtime-benchmarks")] use benchmark_helpers::DoNothingRouter; @@ -214,7 +218,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bridge-hub-rococo"), impl_name: create_runtime_str!("bridge-hub-rococo"), authoring_version: 1, - spec_version: 1_013_000, + spec_version: 1_014_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 5, @@ -862,7 +866,7 @@ impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { Runtime::metadata_versions() } } @@ -966,7 +970,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { let acceptable_assets = vec![AssetId(xcm_config::TokenLocation::get())]; PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) @@ -979,11 +983,11 @@ impl_runtime_apis! { Ok(WeightToFee::weight_to_fee(&weight)) }, Ok(asset_id) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); Err(XcmPaymentApiError::AssetNotFound) }, Err(_) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); Err(XcmPaymentApiError::VersionedConversionFailed) } } @@ -998,7 +1002,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + impl xcm_runtime_apis::dry_run::DryRunApi for Runtime { fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { PolkadotXcm::dry_run_call::(origin, call) } @@ -1008,6 +1012,18 @@ impl_runtime_apis! { } } + impl xcm_runtime_apis::conversions::LocationToAccountApi for Runtime { + fn convert_location(location: VersionedLocation) -> Result< + AccountId, + xcm_runtime_apis::conversions::Error + > { + xcm_runtime_apis::conversions::LocationToAccountHelper::< + AccountId, + xcm_config::LocationToAccountId, + >::convert_location(location) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) @@ -1185,7 +1201,7 @@ impl_runtime_apis! { use frame_system_benchmarking::Pallet as SystemBench; impl frame_system_benchmarking::Config for Runtime { - fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { + fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); Ok(()) } @@ -1400,7 +1416,8 @@ impl_runtime_apis! { impl BridgeMessagesConfig for Runtime { fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { let bench_lane_id = >::bench_lane_id(); - let bridged_chain_id = bridge_to_westend_config::BridgeHubWestendChainId::get(); + use bp_runtime::Chain; + let bridged_chain_id =>::BridgedChain::ID; pallet_bridge_relayers::Pallet::::relayer_reward( relayer, bp_relayers::RewardsAccountParams::new( @@ -1420,7 +1437,7 @@ impl_runtime_apis! { prepare_message_proof_from_parachain::< Runtime, bridge_common_config::BridgeGrandpaWestendInstance, - bridge_to_westend_config::WithBridgeHubWestendMessageBridge, + bridge_to_westend_config::WithBridgeHubWestendMessagesInstance, >(params, generate_xcm_builder_bridge_message_sample([GlobalConsensus(Rococo), Parachain(42)].into())) } @@ -1430,7 +1447,7 @@ impl_runtime_apis! { prepare_message_delivery_proof_from_parachain::< Runtime, bridge_common_config::BridgeGrandpaWestendInstance, - bridge_to_westend_config::WithBridgeHubWestendMessageBridge, + bridge_to_westend_config::WithBridgeHubWestendMessagesInstance, >(params) } @@ -1455,7 +1472,7 @@ impl_runtime_apis! { prepare_message_proof_from_grandpa_chain::< Runtime, bridge_common_config::BridgeGrandpaRococoBulletinInstance, - bridge_to_bulletin_config::WithRococoBulletinMessageBridge, + bridge_to_bulletin_config::WithRococoBulletinMessagesInstance, >(params, generate_xcm_builder_bridge_message_sample([GlobalConsensus(Rococo), Parachain(42)].into())) } @@ -1465,7 +1482,7 @@ impl_runtime_apis! { prepare_message_delivery_proof_from_grandpa_chain::< Runtime, bridge_common_config::BridgeGrandpaRococoBulletinInstance, - bridge_to_bulletin_config::WithRococoBulletinMessageBridge, + bridge_to_bulletin_config::WithRococoBulletinMessagesInstance, >(params) } @@ -1491,7 +1508,7 @@ impl_runtime_apis! { fn prepare_parachain_heads_proof( parachains: &[bp_polkadot_core::parachains::ParaId], parachain_head_size: u32, - proof_size: bp_runtime::StorageProofSize, + proof_params: bp_runtime::UnverifiedStorageProofParams, ) -> ( pallet_bridge_parachains::RelayBlockNumber, pallet_bridge_parachains::RelayBlockHash, @@ -1501,7 +1518,7 @@ impl_runtime_apis! { prepare_parachain_heads_proof::( parachains, parachain_head_size, - proof_size, + proof_params, ) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_parachain_system.rs index dc480c391636a92aad6e303a515524b5ce7ff2b1..8fcd7b10d931b03ec4cd9cc063e0bacf8878ed16 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_parachain_system.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_parachain_system.rs @@ -47,7 +47,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `cumulus_pallet_parachain_system`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs index 11e1439a1f6df2423421faf85ce6dd75c37e045b..4ce57b2e50161a812ddf17a9bbd20d5fc58682a7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_grandpa` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-05-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-07-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vicqj8em-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-yaoqqom-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,15 +64,17 @@ impl pallet_bridge_grandpa::WeightInfo for WeightInfo Weight { + fn submit_finality_proof(p: u32, v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `438 + p * (60 ยฑ0)` // Estimated: `51735` - // Minimum execution time: 300_829_000 picoseconds. - Weight::from_parts(321_573_000, 0) + // Minimum execution time: 325_365_000 picoseconds. + Weight::from_parts(14_958_535, 0) .saturating_add(Weight::from_parts(0, 51735)) - // Standard Error: 25_917 - .saturating_add(Weight::from_parts(48_613_160, 0).saturating_mul(p.into())) + // Standard Error: 15_085 + .saturating_add(Weight::from_parts(41_227_904, 0).saturating_mul(p.into())) + // Standard Error: 50_338 + .saturating_add(Weight::from_parts(2_664_555, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -90,8 +92,8 @@ impl pallet_bridge_grandpa::WeightInfo for WeightInfo pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `621` + // Measured: `654` // Estimated: `52645` - // Minimum execution time: 36_661_000 picoseconds. - Weight::from_parts(38_106_000, 0) + // Minimum execution time: 37_206_000 picoseconds. + Weight::from_parts(38_545_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) @@ -74,13 +74,17 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn receive_two_messages_proof() -> Weight { + /// The range of component `n` is `[1, 4076]`. + /// The range of component `n` is `[1, 4076]`. + fn receive_n_messages_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `621` + // Measured: `654` // Estimated: `52645` - // Minimum execution time: 47_599_000 picoseconds. - Weight::from_parts(49_731_000, 0) + // Minimum execution time: 37_075_000 picoseconds. + Weight::from_parts(37_757_000, 0) .saturating_add(Weight::from_parts(0, 52645)) + // Standard Error: 5_776 + .saturating_add(Weight::from_parts(11_586_768, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -94,10 +98,10 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `621` + // Measured: `654` // Estimated: `52645` - // Minimum execution time: 42_211_000 picoseconds. - Weight::from_parts(43_454_000, 0) + // Minimum execution time: 42_087_000 picoseconds. + Weight::from_parts(42_970_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) @@ -108,30 +112,20 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::InboundLanes` (r:1 w:1) /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - fn receive_single_message_proof_1_kb() -> Weight { - // Proof Size summary in bytes: - // Measured: `589` - // Estimated: `52645` - // Minimum execution time: 36_072_000 picoseconds. - Weight::from_parts(37_260_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgePolkadotBulletinMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) - /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) - /// Storage: `BridgePolkadotBulletinMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - fn receive_single_message_proof_16_kb() -> Weight { + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 16384]`. + /// The range of component `n` is `[1, 16384]`. + fn receive_single_n_bytes_message_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `589` + // Measured: `654` // Estimated: `52645` - // Minimum execution time: 66_995_000 picoseconds. - Weight::from_parts(68_661_000, 0) + // Minimum execution time: 35_055_000 picoseconds. + Weight::from_parts(36_987_740, 0) .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(3)) + // Standard Error: 4 + .saturating_add(Weight::from_parts(2_316, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) @@ -142,10 +136,10 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `588` + // Measured: `621` // Estimated: `2543` - // Minimum execution time: 25_553_000 picoseconds. - Weight::from_parts(26_205_000, 0) + // Minimum execution time: 24_326_000 picoseconds. + Weight::from_parts(25_169_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -158,10 +152,10 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `588` + // Measured: `621` // Estimated: `2543` - // Minimum execution time: 25_610_000 picoseconds. - Weight::from_parts(26_273_000, 0) + // Minimum execution time: 24_484_000 picoseconds. + Weight::from_parts(25_130_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -174,10 +168,10 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `588` + // Measured: `621` // Estimated: `2543` - // Minimum execution time: 25_651_000 picoseconds. - Weight::from_parts(26_172_000, 0) + // Minimum execution time: 24_450_000 picoseconds. + Weight::from_parts(25_164_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -191,7 +185,7 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -201,20 +195,20 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) - /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `i` is `[128, 2048]`. - /// The range of component `i` is `[128, 2048]`. - fn receive_single_message_proof_with_dispatch(i: u32, ) -> Weight { + /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 16384]`. + /// The range of component `n` is `[1, 16384]`. + fn receive_single_n_bytes_message_proof_with_dispatch(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `780` + // Measured: `813` // Estimated: `52645` - // Minimum execution time: 64_219_000 picoseconds. - Weight::from_parts(65_848_290, 0) + // Minimum execution time: 54_317_000 picoseconds. + Weight::from_parts(59_171_547, 0) .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 43 - .saturating_add(Weight::from_parts(7_577, 0).saturating_mul(i.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(7_566, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs index 30ea9eed4a5b4f187ea76633400cff8c39991b46..9c05dae979daa0107e7754cc7107f80c3f753b7e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_bridge_messages` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -51,7 +51,7 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) @@ -60,10 +60,10 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `605` + // Measured: `658` // Estimated: `52645` - // Minimum execution time: 40_349_000 picoseconds. - Weight::from_parts(41_856_000, 0) + // Minimum execution time: 41_396_000 picoseconds. + Weight::from_parts(43_141_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) @@ -71,27 +71,31 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn receive_two_messages_proof() -> Weight { + /// The range of component `n` is `[1, 4076]`. + /// The range of component `n` is `[1, 4076]`. + fn receive_n_messages_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `605` + // Measured: `658` // Estimated: `52645` - // Minimum execution time: 50_514_000 picoseconds. - Weight::from_parts(52_254_000, 0) + // Minimum execution time: 41_095_000 picoseconds. + Weight::from_parts(42_030_000, 0) .saturating_add(Weight::from_parts(0, 52645)) + // Standard Error: 5_702 + .saturating_add(Weight::from_parts(11_627_951, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) @@ -100,10 +104,10 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `605` + // Measured: `658` // Estimated: `52645` - // Minimum execution time: 45_761_000 picoseconds. - Weight::from_parts(47_075_000, 0) + // Minimum execution time: 45_912_000 picoseconds. + Weight::from_parts(47_564_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) @@ -111,37 +115,25 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - fn receive_single_message_proof_1_kb() -> Weight { - // Proof Size summary in bytes: - // Measured: `573` - // Estimated: `52645` - // Minimum execution time: 39_098_000 picoseconds. - Weight::from_parts(40_577_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - fn receive_single_message_proof_16_kb() -> Weight { + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 16384]`. + /// The range of component `n` is `[1, 16384]`. + fn receive_single_n_bytes_message_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `573` + // Measured: `658` // Estimated: `52645` - // Minimum execution time: 69_120_000 picoseconds. - Weight::from_parts(71_810_000, 0) + // Minimum execution time: 39_175_000 picoseconds. + Weight::from_parts(41_674_095, 0) .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) + // Standard Error: 4 + .saturating_add(Weight::from_parts(2_305, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) @@ -156,11 +148,11 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `447` - // Estimated: `3912` - // Minimum execution time: 32_325_000 picoseconds. - Weight::from_parts(33_070_000, 0) - .saturating_add(Weight::from_parts(0, 3912)) + // Measured: `501` + // Estimated: `3966` + // Minimum execution time: 32_033_000 picoseconds. + Weight::from_parts(33_131_000, 0) + .saturating_add(Weight::from_parts(0, 3966)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -176,11 +168,11 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `447` - // Estimated: `3912` - // Minimum execution time: 32_180_000 picoseconds. - Weight::from_parts(33_202_000, 0) - .saturating_add(Weight::from_parts(0, 3912)) + // Measured: `501` + // Estimated: `3966` + // Minimum execution time: 32_153_000 picoseconds. + Weight::from_parts(33_126_000, 0) + .saturating_add(Weight::from_parts(0, 3966)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -196,10 +188,10 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `447` + // Measured: `501` // Estimated: `6086` - // Minimum execution time: 36_774_000 picoseconds. - Weight::from_parts(37_774_000, 0) + // Minimum execution time: 36_387_000 picoseconds. + Weight::from_parts(37_396_000, 0) .saturating_add(Weight::from_parts(0, 6086)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) @@ -207,7 +199,7 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) @@ -215,7 +207,7 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -225,18 +217,18 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) - /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `i` is `[128, 2048]`. - /// The range of component `i` is `[128, 2048]`. - fn receive_single_message_proof_with_dispatch(i: u32, ) -> Weight { + /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 16384]`. + /// The range of component `n` is `[1, 16384]`. + fn receive_single_n_bytes_message_proof_with_dispatch(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `736` + // Measured: `789` // Estimated: `52645` - // Minimum execution time: 65_934_000 picoseconds. - Weight::from_parts(67_915_916, 0) + // Minimum execution time: 56_562_000 picoseconds. + Weight::from_parts(61_452_871, 0) .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 65 - .saturating_add(Weight::from_parts(7_190, 0).saturating_mul(i.into())) + // Standard Error: 9 + .saturating_add(Weight::from_parts(7_587, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs index ea68852804e3955577bf822d42887bf5bd772657..8eb291ea14523b15d6c44b8ee72d637fcbe11166 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_bridge_parachains` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -56,20 +56,22 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf /// Proof: `BridgeWestendParachains::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHashes` (r:1 w:1) /// Proof: `BridgeWestendParachains::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::FreeHeadersRemaining` (r:1 w:1) + /// Proof: `BridgeWestendGrandpa::FreeHeadersRemaining` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:0 w:1) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 2]`. fn submit_parachain_heads_with_n_parachains(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `434` + // Measured: `558` // Estimated: `2543` - // Minimum execution time: 31_135_000 picoseconds. - Weight::from_parts(32_061_351, 0) + // Minimum execution time: 34_889_000 picoseconds. + Weight::from_parts(36_100_759, 0) .saturating_add(Weight::from_parts(0, 2543)) - // Standard Error: 80_309 - .saturating_add(Weight::from_parts(99_724, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + // Standard Error: 102_466 + .saturating_add(Weight::from_parts(178_820, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `BridgeWestendParachains::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendParachains::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) @@ -79,17 +81,19 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf /// Proof: `BridgeWestendParachains::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHashes` (r:1 w:1) /// Proof: `BridgeWestendParachains::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::FreeHeadersRemaining` (r:1 w:1) + /// Proof: `BridgeWestendGrandpa::FreeHeadersRemaining` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:0 w:1) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) fn submit_parachain_heads_with_1kb_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `434` + // Measured: `558` // Estimated: `2543` - // Minimum execution time: 32_263_000 picoseconds. - Weight::from_parts(33_139_000, 0) + // Minimum execution time: 36_501_000 picoseconds. + Weight::from_parts(37_266_000, 0) .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `BridgeWestendParachains::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendParachains::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) @@ -99,16 +103,18 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf /// Proof: `BridgeWestendParachains::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHashes` (r:1 w:1) /// Proof: `BridgeWestendParachains::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendGrandpa::FreeHeadersRemaining` (r:1 w:1) + /// Proof: `BridgeWestendGrandpa::FreeHeadersRemaining` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:0 w:1) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) fn submit_parachain_heads_with_16kb_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `434` + // Measured: `558` // Estimated: `2543` - // Minimum execution time: 61_313_000 picoseconds. - Weight::from_parts(62_200_000, 0) + // Minimum execution time: 66_059_000 picoseconds. + Weight::from_parts(67_139_000, 0) .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs index 5ab4cb900d848f37f1a5777b686d294837688495..f8bb983e80aa776ae7fe8c9a756935096956e7dd 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_bridge_relayers` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -54,10 +54,10 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn claim_rewards() -> Weight { // Proof Size summary in bytes: - // Measured: `244` + // Measured: `278` // Estimated: `3593` - // Minimum execution time: 45_393_000 picoseconds. - Weight::from_parts(46_210_000, 0) + // Minimum execution time: 44_224_000 picoseconds. + Weight::from_parts(44_905_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -70,10 +70,10 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< /// Proof: `Balances::Reserves` (`max_values`: None, `max_size`: Some(1249), added: 3724, mode: `MaxEncodedLen`) fn register() -> Weight { // Proof Size summary in bytes: - // Measured: `97` + // Measured: `131` // Estimated: `4714` - // Minimum execution time: 23_767_000 picoseconds. - Weight::from_parts(24_217_000, 0) + // Minimum execution time: 23_902_000 picoseconds. + Weight::from_parts(24_702_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -84,10 +84,10 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< /// Proof: `Balances::Reserves` (`max_values`: None, `max_size`: Some(1249), added: 3724, mode: `MaxEncodedLen`) fn deregister() -> Weight { // Proof Size summary in bytes: - // Measured: `197` + // Measured: `231` // Estimated: `4714` - // Minimum execution time: 25_745_000 picoseconds. - Weight::from_parts(26_319_000, 0) + // Minimum execution time: 24_469_000 picoseconds. + Weight::from_parts(25_176_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -100,10 +100,10 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn slash_and_deregister() -> Weight { // Proof Size summary in bytes: - // Measured: `300` + // Measured: `334` // Estimated: `4714` - // Minimum execution time: 27_497_000 picoseconds. - Weight::from_parts(27_939_000, 0) + // Minimum execution time: 27_518_000 picoseconds. + Weight::from_parts(28_068_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -112,10 +112,10 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn register_relayer_reward() -> Weight { // Proof Size summary in bytes: - // Measured: `42` + // Measured: `76` // Estimated: `3538` - // Minimum execution time: 5_584_000 picoseconds. - Weight::from_parts(5_908_000, 0) + // Minimum execution time: 5_484_000 picoseconds. + Weight::from_parts(5_718_000, 0) .saturating_add(Weight::from_parts(0, 3538)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_message_queue.rs index 2fcd573ceb277116bda67180da8e0701593ab453..b6fee47d1435162a3e24dd204b896eb849a7e146 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_message_queue.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_message_queue.rs @@ -43,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `pallet_message_queue`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs index 4f5bae0fe597b88b1c23fa4ab806cec98bf7d746..b40cbfeeb8f2770bbc15e77d2a0a657b209a45ef 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs @@ -17,11 +17,11 @@ mod pallet_xcm_benchmarks_fungible; mod pallet_xcm_benchmarks_generic; use crate::{xcm_config::MaxAssetsIntoHolding, Runtime}; +use alloc::vec::Vec; use codec::Encode; use frame_support::weights::Weight; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; -use sp_std::prelude::*; use xcm::{latest::prelude::*, DoubleEncoded}; trait WeighAssets { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index d7e8c41ff8ac41acfeb60f30774e8282939b6c1c..057dc4313510f79aa1daa1216141538ceb357012 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -43,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::fungible`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index abd84f8e89b07799758c36b002c30db742305927..9c58072d402c91a13f63795bf5b4184f80ab2c0b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -43,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::generic`. pub struct WeightInfo(PhantomData); @@ -68,8 +68,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 61_813_000 picoseconds. - Weight::from_parts(62_996_000, 6196) + // Minimum execution time: 60_119_000 picoseconds. + Weight::from_parts(61_871_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -77,8 +77,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_044_000 picoseconds. - Weight::from_parts(2_112_000, 0) + // Minimum execution time: 998_000 picoseconds. + Weight::from_parts(1_038_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -86,58 +86,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 7_472_000 picoseconds. - Weight::from_parts(7_723_000, 3497) + // Minimum execution time: 6_327_000 picoseconds. + Weight::from_parts(6_520_000, 3497) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_414_000 picoseconds. - Weight::from_parts(8_765_000, 0) + // Minimum execution time: 6_783_000 picoseconds. + Weight::from_parts(7_117_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_192_000 picoseconds. - Weight::from_parts(2_243_000, 0) + // Minimum execution time: 1_589_000 picoseconds. + Weight::from_parts(1_655_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_866_000 picoseconds. - Weight::from_parts(1_931_000, 0) + // Minimum execution time: 1_013_000 picoseconds. + Weight::from_parts(1_045_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_847_000 picoseconds. - Weight::from_parts(1_921_000, 0) + // Minimum execution time: 1_005_000 picoseconds. + Weight::from_parts(1_044_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_797_000 picoseconds. - Weight::from_parts(1_880_000, 0) + // Minimum execution time: 964_000 picoseconds. + Weight::from_parts(1_011_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_458_000 picoseconds. - Weight::from_parts(2_523_000, 0) + // Minimum execution time: 1_005_000 picoseconds. + Weight::from_parts(1_027_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_833_000 picoseconds. - Weight::from_parts(1_906_000, 0) + // Minimum execution time: 980_000 picoseconds. + Weight::from_parts(1_009_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -159,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 54_659_000 picoseconds. - Weight::from_parts(56_025_000, 6196) + // Minimum execution time: 56_726_000 picoseconds. + Weight::from_parts(59_300_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -170,8 +170,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 10_953_000 picoseconds. - Weight::from_parts(11_220_000, 3555) + // Minimum execution time: 8_962_000 picoseconds. + Weight::from_parts(9_519_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +179,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_834_000 picoseconds. - Weight::from_parts(1_892_000, 0) + // Minimum execution time: 999_000 picoseconds. + Weight::from_parts(1_035_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -200,8 +200,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 22_238_000 picoseconds. - Weight::from_parts(22_690_000, 3503) + // Minimum execution time: 20_313_000 picoseconds. + Weight::from_parts(21_000_000, 3503) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -211,44 +211,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_798_000 picoseconds. - Weight::from_parts(3_936_000, 0) + // Minimum execution time: 2_820_000 picoseconds. + Weight::from_parts(2_949_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_985_000 picoseconds. - Weight::from_parts(3_099_000, 0) + // Minimum execution time: 1_293_000 picoseconds. + Weight::from_parts(1_354_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_955_000 picoseconds. - Weight::from_parts(2_050_000, 0) + // Minimum execution time: 1_076_000 picoseconds. + Weight::from_parts(1_114_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_939_000 picoseconds. - Weight::from_parts(1_990_000, 0) + // Minimum execution time: 1_014_000 picoseconds. + Weight::from_parts(1_055_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_841_000 picoseconds. - Weight::from_parts(1_900_000, 0) + // Minimum execution time: 979_000 picoseconds. + Weight::from_parts(1_019_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_081_000 picoseconds. - Weight::from_parts(2_145_000, 0) + // Minimum execution time: 1_161_000 picoseconds. + Weight::from_parts(1_208_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -270,8 +270,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 59_600_000 picoseconds. - Weight::from_parts(61_572_000, 6196) + // Minimum execution time: 62_250_000 picoseconds. + Weight::from_parts(64_477_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -279,8 +279,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_390_000 picoseconds. - Weight::from_parts(4_517_000, 0) + // Minimum execution time: 4_286_000 picoseconds. + Weight::from_parts(4_476_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -302,8 +302,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 53_864_000 picoseconds. - Weight::from_parts(55_527_000, 6196) + // Minimum execution time: 58_253_000 picoseconds. + Weight::from_parts(59_360_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -311,22 +311,22 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_879_000 picoseconds. - Weight::from_parts(1_947_000, 0) + // Minimum execution time: 1_026_000 picoseconds. + Weight::from_parts(1_065_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_827_000 picoseconds. - Weight::from_parts(1_900_000, 0) + // Minimum execution time: 993_000 picoseconds. + Weight::from_parts(1_015_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_824_000 picoseconds. - Weight::from_parts(1_898_000, 0) + // Minimum execution time: 966_000 picoseconds. + Weight::from_parts(999_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -339,16 +339,16 @@ impl WeightInfo { // Storage: `BridgeWestendMessages::OutboundLanesCongestedSignals` (r:1 w:0) // Proof: `BridgeWestendMessages::OutboundLanesCongestedSignals` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) // Storage: `BridgeWestendMessages::OutboundMessages` (r:0 w:1) - // Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(2621472), added: 2623947, mode: `MaxEncodedLen`) + // Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) /// The range of component `x` is `[1, 1000]`. pub fn export_message(x: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `190` // Estimated: `6130` - // Minimum execution time: 41_598_000 picoseconds. - Weight::from_parts(42_219_173, 6130) - // Standard Error: 426 - .saturating_add(Weight::from_parts(452_460, 0).saturating_mul(x.into())) + // Minimum execution time: 37_014_000 picoseconds. + Weight::from_parts(38_096_655, 6130) + // Standard Error: 61 + .saturating_add(Weight::from_parts(45_146, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -356,14 +356,14 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_812_000 picoseconds. - Weight::from_parts(1_898_000, 0) + // Minimum execution time: 996_000 picoseconds. + Weight::from_parts(1_025_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_915_000 picoseconds. - Weight::from_parts(1_976_000, 0) + // Minimum execution time: 1_001_000 picoseconds. + Weight::from_parts(1_044_000, 0) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index a0d2e91dffd2e9240ad9364e18ef52a7b3cab3b1..8c077470ba1aea7e0ab513626182addd56bb492f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs @@ -21,7 +21,7 @@ use super::{ }; use bp_messages::LaneId; use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams}; -use bp_runtime::ChainId; +use core::marker::PhantomData; use frame_support::{ parameter_types, traits::{tokens::imbalance::ResolveTo, ConstU32, Contains, Equals, Everything, Nothing}, @@ -41,7 +41,6 @@ use polkadot_runtime_common::xcm_sender::ExponentialPrice; use snowbridge_runtime_common::XcmExportFeeToSibling; use sp_core::Get; use sp_runtime::traits::AccountIdConversion; -use sp_std::marker::PhantomData; use testnet_parachains_constants::rococo::snowbridge::EthereumNetwork; use xcm::latest::prelude::*; use xcm_builder::{ @@ -49,10 +48,10 @@ use xcm_builder::{ AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, HandleFee, IsConcrete, ParentAsSuperuser, - ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeToAccount, + ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::{ traits::{FeeManager, FeeReason, FeeReason::Export, TransactAsset}, @@ -212,7 +211,7 @@ impl xcm_executor::Config for XcmConfig { Self::AssetTransactor, crate::bridge_to_westend_config::WestendGlobalConsensusNetwork, crate::bridge_to_westend_config::AssetHubWestendParaId, - crate::bridge_to_westend_config::BridgeHubWestendChainId, + bp_bridge_hub_westend::BridgeHubWestend, crate::bridge_to_westend_config::AssetHubRococoToAssetHubWestendMessagesLane, >, XcmExportFeeToSibling< @@ -223,7 +222,7 @@ impl xcm_executor::Config for XcmConfig { Self::AssetTransactor, crate::EthereumOutboundQueue, >, - XcmFeeToAccount, + SendXcmFeeToAccount, ), >; type MessageExporter = ( @@ -302,22 +301,22 @@ pub struct XcmExportFeeToRelayerRewardAccounts< AssetTransactor, DestNetwork, DestParaId, - DestBridgedChainId, + DestBridgedChain, BridgeLaneId, ->(PhantomData<(AssetTransactor, DestNetwork, DestParaId, DestBridgedChainId, BridgeLaneId)>); +>(PhantomData<(AssetTransactor, DestNetwork, DestParaId, DestBridgedChain, BridgeLaneId)>); impl< AssetTransactor: TransactAsset, DestNetwork: Get, DestParaId: Get, - DestBridgedChainId: Get, + DestBridgedChain: bp_runtime::Chain, BridgeLaneId: Get, > HandleFee for XcmExportFeeToRelayerRewardAccounts< AssetTransactor, DestNetwork, DestParaId, - DestBridgedChainId, + DestBridgedChain, BridgeLaneId, > { @@ -326,6 +325,8 @@ impl< if bridged_network == DestNetwork::get() && destination == [Parachain(DestParaId::get().into())]) { + let bridged_chain_id = DestBridgedChain::ID; + // We have 2 relayer rewards accounts: // - the SA of the source parachain on this BH: this pays the relayers for delivering // Source para -> Target Para message delivery confirmations @@ -337,7 +338,7 @@ impl< AccountId, >::rewards_account(RewardsAccountParams::new( BridgeLaneId::get(), - DestBridgedChainId::get(), + bridged_chain_id, RewardsAccountOwner::ThisChain, )); @@ -346,7 +347,7 @@ impl< AccountId, >::rewards_account(RewardsAccountParams::new( BridgeLaneId::get(), - DestBridgedChainId::get(), + bridged_chain_id, RewardsAccountOwner::BridgedChain, )); @@ -354,24 +355,27 @@ impl< match asset.fun { Fungible(total_fee) => { let source_fee = total_fee / 2; - deposit_or_burn_fee::( + deposit_or_burn_fee::( Asset { id: asset.id.clone(), fun: Fungible(source_fee) }.into(), maybe_context, - source_para_account.clone(), + AccountId32 { network: None, id: source_para_account.clone().into() } + .into(), ); let dest_fee = total_fee - source_fee; - deposit_or_burn_fee::( + deposit_or_burn_fee::( Asset { id: asset.id, fun: Fungible(dest_fee) }.into(), maybe_context, - dest_para_account.clone(), + AccountId32 { network: None, id: dest_para_account.clone().into() } + .into(), ); }, NonFungible(_) => { - deposit_or_burn_fee::( + deposit_or_burn_fee::( asset.into(), maybe_context, - source_para_account.clone(), + AccountId32 { network: None, id: source_para_account.clone().into() } + .into(), ); }, } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index b309232825db3aa964b2fa1a1d8d739f06ec3153..ca0d89f038cbc690eb900829442eef46fb2367de 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -147,9 +147,8 @@ mod bridge_hub_westend_tests { }; use bridge_hub_test_utils::test_cases::from_parachain; use bridge_to_westend_config::{ - BridgeHubWestendChainId, BridgeHubWestendLocation, WestendGlobalConsensusNetwork, - WithBridgeHubWestendMessageBridge, WithBridgeHubWestendMessagesInstance, - XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, + BridgeHubWestendLocation, WestendGlobalConsensusNetwork, + WithBridgeHubWestendMessagesInstance, XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, }; // Para id of sibling chain used in tests. @@ -162,7 +161,6 @@ mod bridge_hub_westend_tests { BridgeGrandpaWestendInstance, BridgeParachainWestendInstance, WithBridgeHubWestendMessagesInstance, - WithBridgeHubWestendMessageBridge, >; #[test] @@ -315,11 +313,14 @@ mod bridge_hub_westend_tests { } }), || ExportMessage { network: Westend, destination: [Parachain(bridge_to_westend_config::AssetHubWestendParaId::get().into())].into(), xcm: Xcm(vec![]) }, - XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, Some((TokenLocation::get(), ExistentialDeposit::get()).into()), // value should be >= than value generated by `can_calculate_weight_for_paid_export_message_with_reserve_transfer` Some((TokenLocation::get(), bp_bridge_hub_rococo::BridgeHubRococoBaseXcmFeeInRocs::get()).into()), - || PolkadotXcm::force_xcm_version(RuntimeOrigin::root(), Box::new(BridgeHubWestendLocation::get()), XCM_VERSION).expect("version saved!"), + || { + PolkadotXcm::force_xcm_version(RuntimeOrigin::root(), Box::new(BridgeHubWestendLocation::get()), XCM_VERSION).expect("version saved!"); + + XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND + }, ) } @@ -352,8 +353,7 @@ mod bridge_hub_westend_tests { _ => None, } }), - XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, - || (), + || XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, ) } @@ -365,11 +365,9 @@ mod bridge_hub_westend_tests { slot_durations(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, - BridgeHubWestendChainId::get(), SIBLING_PARACHAIN_ID, Rococo, - XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, - || (), + || XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, construct_and_apply_extrinsic, ) } @@ -382,11 +380,9 @@ mod bridge_hub_westend_tests { slot_durations(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, - BridgeHubWestendChainId::get(), SIBLING_PARACHAIN_ID, Rococo, - XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, - || (), + || XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, construct_and_apply_extrinsic, ) } @@ -456,8 +452,7 @@ mod bridge_hub_bulletin_tests { use bridge_common_config::BridgeGrandpaRococoBulletinInstance; use bridge_hub_test_utils::test_cases::from_grandpa_chain; use bridge_to_bulletin_config::{ - RococoBulletinChainId, RococoBulletinGlobalConsensusNetwork, - RococoBulletinGlobalConsensusNetworkLocation, WithRococoBulletinMessageBridge, + RococoBulletinGlobalConsensusNetwork, RococoBulletinGlobalConsensusNetworkLocation, WithRococoBulletinMessagesInstance, XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, }; @@ -470,7 +465,6 @@ mod bridge_hub_bulletin_tests { AllPalletsWithoutSystem, BridgeGrandpaRococoBulletinInstance, WithRococoBulletinMessagesInstance, - WithRococoBulletinMessageBridge, >; #[test] @@ -522,10 +516,13 @@ mod bridge_hub_bulletin_tests { destination: Here, xcm: Xcm(vec![]), }, - XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, Some((TokenLocation::get(), ExistentialDeposit::get()).into()), None, - || PolkadotXcm::force_xcm_version(RuntimeOrigin::root(), Box::new(RococoBulletinGlobalConsensusNetworkLocation::get()), XCM_VERSION).expect("version saved!"), + || { + PolkadotXcm::force_xcm_version(RuntimeOrigin::root(), Box::new(RococoBulletinGlobalConsensusNetworkLocation::get()), XCM_VERSION).expect("version saved!"); + + XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN + }, ) } @@ -558,8 +555,7 @@ mod bridge_hub_bulletin_tests { _ => None, } }), - XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, - || (), + || XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, ) } @@ -570,11 +566,9 @@ mod bridge_hub_bulletin_tests { collator_session_keys(), slot_durations(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - RococoBulletinChainId::get(), SIBLING_PARACHAIN_ID, Rococo, - XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, - || (), + || XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, construct_and_apply_extrinsic, ) } @@ -586,52 +580,10 @@ mod bridge_hub_bulletin_tests { collator_session_keys(), slot_durations(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - RococoBulletinChainId::get(), SIBLING_PARACHAIN_ID, Rococo, - XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, - || (), + || XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, construct_and_apply_extrinsic, ) } - - #[test] - pub fn can_calculate_fee_for_standalone_message_delivery_transaction() { - bridge_hub_test_utils::check_sane_fees_values( - "bp_bridge_hub_rococo::BridgeHubRococoBaseDeliveryFeeInRocs", - bp_bridge_hub_rococo::BridgeHubRococoBaseDeliveryFeeInRocs::get(), - || { - from_grandpa_chain::can_calculate_fee_for_standalone_message_delivery_transaction::< - RuntimeTestsAdapter, - >(collator_session_keys(), construct_and_estimate_extrinsic_fee) - }, - Perbill::from_percent(33), - None, /* we don't want lowering according to the Bulletin setup, because - * `from_grandpa_chain` is cheaper then `from_parachain_chain` */ - &format!( - "Estimate fee for `single message delivery` for runtime: {:?}", - ::Version::get() - ), - ) - } - - #[test] - pub fn can_calculate_fee_for_standalone_message_confirmation_transaction() { - bridge_hub_test_utils::check_sane_fees_values( - "bp_bridge_hub_rococo::BridgeHubRococoBaseConfirmationFeeInRocs", - bp_bridge_hub_rococo::BridgeHubRococoBaseConfirmationFeeInRocs::get(), - || { - from_grandpa_chain::can_calculate_fee_for_standalone_message_confirmation_transaction::< - RuntimeTestsAdapter, - >(collator_session_keys(), construct_and_estimate_extrinsic_fee) - }, - Perbill::from_percent(33), - None, /* we don't want lowering according to the Bulletin setup, because - * `from_grandpa_chain` is cheaper then `from_parachain_chain` */ - &format!( - "Estimate fee for `single message confirmation` for runtime: {:?}", - ::Version::get() - ), - ) - } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index ba8e4cdc8147cca39cf0432cb72bdb924672169a..4326cbf926d654ff604cd4066d5a19db98556637 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -10,101 +10,100 @@ license = "Apache-2.0" workspace = true [build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -hex-literal = { version = "0.4.1" } +codec = { features = ["derive"], workspace = true } +hex-literal = { workspace = true, default-features = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Substrate -frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../../substrate/frame/system", default-features = false } -frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true } -frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false } -frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } -pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false } -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } -pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } -pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false } -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } -pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false } -sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } -sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false } -sp-io = { path = "../../../../../substrate/primitives/io", default-features = false } -sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -sp-session = { path = "../../../../../substrate/primitives/session", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-storage = { path = "../../../../../substrate/primitives/storage", default-features = false } -sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } -sp-version = { path = "../../../../../substrate/primitives/version", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-executive = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-benchmarking = { optional = true, workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +frame-try-runtime = { optional = true, workspace = true } +pallet-aura = { workspace = true } +pallet-authorship = { workspace = true } +pallet-balances = { workspace = true } +pallet-session = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-multisig = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-utility = { workspace = true } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-core = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } +sp-io = { workspace = true } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-std = { workspace = true } +sp-storage = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } # Polkadot -westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants", default-features = false } -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } -pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } -polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false } -polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } -xcm-fee-payment-runtime-api = { path = "../../../../../polkadot/xcm/xcm-fee-payment-runtime-api", default-features = false } +westend-runtime-constants = { workspace = true } +pallet-xcm = { workspace = true } +pallet-xcm-benchmarks = { optional = true, workspace = true } +polkadot-parachain-primitives = { workspace = true } +polkadot-runtime-common = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm-runtime-apis = { workspace = true } # Cumulus -cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } -cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false } -cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false, features = ["bridging"] } -cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } -cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } -cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } +cumulus-pallet-aura-ext = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-session-benchmarking = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { features = ["bridging"], workspace = true } +cumulus-primitives-aura = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-utility = { workspace = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true } -pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } -testnet-parachains-constants = { path = "../../constants", default-features = false, features = ["westend"] } +pallet-collator-selection = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } +testnet-parachains-constants = { features = ["westend"], workspace = true } # Bridges -bp-asset-hub-rococo = { path = "../../../../../bridges/chains/chain-asset-hub-rococo", default-features = false } -bp-asset-hub-westend = { path = "../../../../../bridges/chains/chain-asset-hub-westend", default-features = false } -bp-bridge-hub-rococo = { path = "../../../../../bridges/chains/chain-bridge-hub-rococo", default-features = false } -bp-bridge-hub-westend = { path = "../../../../../bridges/chains/chain-bridge-hub-westend", default-features = false } -bp-header-chain = { path = "../../../../../bridges/primitives/header-chain", default-features = false } -bp-messages = { path = "../../../../../bridges/primitives/messages", default-features = false } -bp-parachains = { path = "../../../../../bridges/primitives/parachains", default-features = false } -bp-polkadot-core = { path = "../../../../../bridges/primitives/polkadot-core", default-features = false } -bp-relayers = { path = "../../../../../bridges/primitives/relayers", default-features = false } -bp-runtime = { path = "../../../../../bridges/primitives/runtime", default-features = false } -bp-rococo = { path = "../../../../../bridges/chains/chain-rococo", default-features = false } -bp-westend = { path = "../../../../../bridges/chains/chain-westend", default-features = false } -pallet-bridge-grandpa = { path = "../../../../../bridges/modules/grandpa", default-features = false } -pallet-bridge-messages = { path = "../../../../../bridges/modules/messages", default-features = false } -pallet-bridge-parachains = { path = "../../../../../bridges/modules/parachains", default-features = false } -pallet-bridge-relayers = { path = "../../../../../bridges/modules/relayers", default-features = false } -pallet-xcm-bridge-hub = { path = "../../../../../bridges/modules/xcm-bridge-hub", default-features = false } -bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", default-features = false } -bridge-hub-common = { path = "../common", default-features = false } +bp-asset-hub-rococo = { workspace = true } +bp-asset-hub-westend = { workspace = true } +bp-bridge-hub-rococo = { workspace = true } +bp-bridge-hub-westend = { workspace = true } +bp-header-chain = { workspace = true } +bp-messages = { workspace = true } +bp-parachains = { workspace = true } +bp-polkadot-core = { workspace = true } +bp-relayers = { workspace = true } +bp-runtime = { features = ["test-helpers"], workspace = true } +bp-rococo = { workspace = true } +bp-westend = { workspace = true } +pallet-bridge-grandpa = { workspace = true } +pallet-bridge-messages = { workspace = true } +pallet-bridge-parachains = { workspace = true } +pallet-bridge-relayers = { workspace = true } +pallet-xcm-bridge-hub = { workspace = true } +bridge-runtime-common = { workspace = true } +bridge-hub-common = { workspace = true } [dev-dependencies] -static_assertions = "1.1" -bridge-hub-test-utils = { path = "../test-utils" } -bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", features = ["integrity-test"] } -sp-keyring = { path = "../../../../../substrate/primitives/keyring" } +bridge-hub-test-utils = { workspace = true, default-features = true } +bridge-runtime-common = { features = ["integrity-test"], workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } [features] default = ["std"] @@ -184,7 +183,7 @@ std = [ "westend-runtime-constants/std", "xcm-builder/std", "xcm-executor/std", - "xcm-fee-payment-runtime-api/std", + "xcm-runtime-apis/std", "xcm/std", ] @@ -219,7 +218,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", - "xcm-fee-payment-runtime-api/runtime-benchmarks", + "xcm-runtime-apis/runtime-benchmarks", ] try-runtime = [ diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs index 425b53da30fc8a176fcddfe145fab66a41b60f8a..be4d40c2275f28f09191b782bdad88bc7526b8bd 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs @@ -18,23 +18,18 @@ use crate::{ bridge_common_config::DeliveryRewardInBalance, weights, xcm_config::UniversalLocation, - AccountId, BridgeRococoMessages, PolkadotXcm, Runtime, RuntimeEvent, RuntimeOrigin, - XcmOverBridgeHubRococo, XcmRouter, + BridgeRococoMessages, PolkadotXcm, Runtime, RuntimeEvent, XcmOverBridgeHubRococo, XcmRouter, +}; +use bp_messages::{ + source_chain::FromBridgedChainMessagesDeliveryProof, + target_chain::FromBridgedChainMessagesProof, LaneId, }; -use bp_messages::LaneId; use bp_parachains::SingleParaStoredHeaderDataBuilder; -use bp_runtime::Chain; use bridge_runtime_common::{ extensions::refund_relayer_extension::{ ActualFeeRefund, RefundBridgedMessages, RefundSignedExtensionAdapter, RefundableMessagesLane, }, - messages, - messages::{ - source::{FromBridgedChainMessagesDeliveryProof, TargetHeaderChainAdapter}, - target::{FromBridgedChainMessagesProof, SourceHeaderChainAdapter}, - MessageBridge, ThisChainWithMessages, UnderlyingChainProvider, - }, messages_xcm_extension::{ SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, @@ -45,7 +40,6 @@ use frame_support::{ parameter_types, traits::{ConstU32, PalletInfoAccess}, }; -use sp_runtime::RuntimeDebug; use xcm::{ latest::prelude::*, prelude::{InteriorLocation, NetworkId}, @@ -59,11 +53,6 @@ parameter_types! { pub const RococoBridgeParachainPalletName: &'static str = "Paras"; pub const MaxRococoParaHeadDataSize: u32 = bp_rococo::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE; - pub const MaxUnrewardedRelayerEntriesAtInboundLane: bp_messages::MessageNonce = - bp_bridge_hub_westend::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; - pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce = - bp_bridge_hub_westend::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; - pub const BridgeHubRococoChainId: bp_runtime::ChainId = BridgeHubRococo::ID; pub BridgeWestendToRococoMessagesPalletInstance: InteriorLocation = [PalletInstance(::index() as u8)].into(); pub RococoGlobalConsensusNetwork: NetworkId = NetworkId::Rococo; pub RococoGlobalConsensusNetworkLocation: Location = Location::new( @@ -87,7 +76,7 @@ parameter_types! { ParentThen([Parachain(AssetHubWestendParaId::get().into())].into()).into(), XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, ); - pub ActiveLanes: sp_std::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = sp_std::vec![ + pub ActiveLanes: alloc::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = alloc::vec![ ( FromAssetHubWestendToAssetHubRococoRoute::get(), (RococoGlobalConsensusNetwork::get(), [Parachain(AssetHubRococoParaId::get().into())].into()) @@ -107,8 +96,8 @@ parameter_types! { } pub const XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO: LaneId = LaneId([0, 0, 0, 2]); -fn build_congestion_message(is_congested: bool) -> sp_std::vec::Vec> { - sp_std::vec![ +fn build_congestion_message(is_congested: bool) -> alloc::vec::Vec> { + alloc::vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, Transact { origin_kind: OriginKind::Xcm, @@ -153,46 +142,6 @@ impl XcmBlobHauler for ToBridgeHubRococoXcmBlobHauler { /// On messages delivered callback. type OnMessagesDelivered = XcmBlobHaulerAdapter; -/// Messaging Bridge configuration for BridgeHubWestend -> BridgeHubRococo -pub struct WithBridgeHubRococoMessageBridge; -impl MessageBridge for WithBridgeHubRococoMessageBridge { - const BRIDGED_MESSAGES_PALLET_NAME: &'static str = - bp_bridge_hub_westend::WITH_BRIDGE_HUB_WESTEND_MESSAGES_PALLET_NAME; - type ThisChain = BridgeHubWestend; - type BridgedChain = BridgeHubRococo; - type BridgedHeaderChain = pallet_bridge_parachains::ParachainHeaders< - Runtime, - BridgeParachainRococoInstance, - bp_bridge_hub_rococo::BridgeHubRococo, - >; -} - -/// Maximal outbound payload size of BridgeHubWestend -> BridgeHubRococo messages. -type ToBridgeHubRococoMaximalOutboundPayloadSize = - messages::source::FromThisChainMaximalOutboundPayloadSize; - -/// BridgeHubRococo chain from message lane point of view. -#[derive(RuntimeDebug, Clone, Copy)] -pub struct BridgeHubRococo; - -impl UnderlyingChainProvider for BridgeHubRococo { - type Chain = bp_bridge_hub_rococo::BridgeHubRococo; -} - -impl messages::BridgedChainWithMessages for BridgeHubRococo {} - -/// BridgeHubWestend chain from message lane point of view. -#[derive(RuntimeDebug, Clone, Copy)] -pub struct BridgeHubWestend; - -impl UnderlyingChainProvider for BridgeHubWestend { - type Chain = bp_bridge_hub_westend::BridgeHubWestend; -} - -impl ThisChainWithMessages for BridgeHubWestend { - type RuntimeOrigin = RuntimeOrigin; -} - /// Signed extension that refunds relayers that are delivering messages from the Rococo parachain. pub type OnBridgeHubWestendRefundBridgeHubRococoMessages = RefundSignedExtensionAdapter< RefundBridgedMessages< @@ -237,26 +186,28 @@ pub type WithBridgeHubRococoMessagesInstance = pallet_bridge_messages::Instance1 impl pallet_bridge_messages::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = weights::pallet_bridge_messages::WeightInfo; - type BridgedChainId = BridgeHubRococoChainId; + + type ThisChain = bp_bridge_hub_westend::BridgeHubWestend; + type BridgedChain = bp_bridge_hub_rococo::BridgeHubRococo; + type BridgedHeaderChain = pallet_bridge_parachains::ParachainHeaders< + Runtime, + BridgeParachainRococoInstance, + bp_bridge_hub_rococo::BridgeHubRococo, + >; + type ActiveOutboundLanes = ActiveOutboundLanesToBridgeHubRococo; - type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; - type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; - type MaximalOutboundPayloadSize = ToBridgeHubRococoMaximalOutboundPayloadSize; type OutboundPayload = XcmAsPlainPayload; type InboundPayload = XcmAsPlainPayload; - type InboundRelayer = AccountId; type DeliveryPayments = (); - type TargetHeaderChain = TargetHeaderChainAdapter; type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< Runtime, WithBridgeHubRococoMessagesInstance, DeliveryRewardInBalance, >; - type SourceHeaderChain = SourceHeaderChainAdapter; type MessageDispatch = XcmBlobMessageDispatch< FromRococoMessageBlobDispatcher, Self::WeightInfo, @@ -287,9 +238,8 @@ mod tests { assert_complete_bridge_types, extensions::refund_relayer_extension::RefundableParachain, integrity::{ - assert_complete_bridge_constants, check_message_lane_weights, - AssertBridgeMessagesPalletConstants, AssertBridgePalletNames, AssertChainConstants, - AssertCompleteBridgeConstants, + assert_complete_with_parachain_bridge_constants, check_message_lane_weights, + AssertChainConstants, AssertCompleteBridgeConstants, }, }; use parachains_common::Balance; @@ -331,35 +281,20 @@ mod tests { runtime: Runtime, with_bridged_chain_grandpa_instance: BridgeGrandpaRococoInstance, with_bridged_chain_messages_instance: WithBridgeHubRococoMessagesInstance, - bridge: WithBridgeHubRococoMessageBridge, - this_chain: bp_westend::Westend, - bridged_chain: bp_rococo::Rococo, + this_chain: bp_bridge_hub_westend::BridgeHubWestend, + bridged_chain: bp_bridge_hub_rococo::BridgeHubRococo, ); - assert_complete_bridge_constants::< + assert_complete_with_parachain_bridge_constants::< Runtime, BridgeGrandpaRococoInstance, WithBridgeHubRococoMessagesInstance, - WithBridgeHubRococoMessageBridge, + bp_rococo::Rococo, >(AssertCompleteBridgeConstants { this_chain_constants: AssertChainConstants { block_length: bp_bridge_hub_westend::BlockLength::get(), block_weights: bp_bridge_hub_westend::BlockWeightsForAsyncBacking::get(), }, - messages_pallet_constants: AssertBridgeMessagesPalletConstants { - max_unrewarded_relayers_in_bridged_confirmation_tx: - bp_bridge_hub_rococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, - max_unconfirmed_messages_in_bridged_confirmation_tx: - bp_bridge_hub_rococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, - bridged_chain_id: BridgeHubRococo::ID, - }, - pallet_names: AssertBridgePalletNames { - with_this_chain_messages_pallet_name: - bp_bridge_hub_westend::WITH_BRIDGE_HUB_WESTEND_MESSAGES_PALLET_NAME, - with_bridged_chain_grandpa_pallet_name: bp_rococo::WITH_ROCOCO_GRANDPA_PALLET_NAME, - with_bridged_chain_messages_pallet_name: - bp_bridge_hub_rococo::WITH_BRIDGE_HUB_ROCOCO_MESSAGES_PALLET_NAME, - }, }); bridge_runtime_common::extensions::priority_calculator::per_relay_header::ensure_priority_boost_is_sane::< @@ -370,7 +305,7 @@ mod tests { bridge_runtime_common::extensions::priority_calculator::per_parachain_header::ensure_priority_boost_is_sane::< Runtime, - RefundableParachain, + RefundableParachain, PriorityBoostPerParachainHeader, >(FEE_BOOST_PER_PARACHAIN_HEADER); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 6b2d67e29c4a6e5f4bf1bc0b2b95c0d727f2a4fb..42c768861bde10baa5bb81612f127acb574c30c8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -32,6 +32,9 @@ pub mod bridge_to_rococo_config; mod weights; pub mod xcm_config; +extern crate alloc; + +use alloc::{vec, vec::Vec}; use bridge_runtime_common::extensions::{ check_obsolete_extension::{ CheckAndBoostBridgeGrandpaTransactions, CheckAndBoostBridgeParachainsTransactions, @@ -49,7 +52,6 @@ use sp_runtime::{ ApplyExtrinsicResult, }; -use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -75,7 +77,7 @@ pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; use xcm_config::{XcmOriginToTransactDispatchOrigin, XcmRouter}; -use xcm_fee_payment_runtime_api::{ +use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, }; @@ -189,7 +191,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bridge-hub-westend"), impl_name: create_runtime_str!("bridge-hub-westend"), authoring_version: 1, - spec_version: 1_013_000, + spec_version: 1_014_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 5, @@ -612,7 +614,7 @@ impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { Runtime::metadata_versions() } } @@ -716,7 +718,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { let acceptable_assets = vec![AssetId(xcm_config::WestendLocation::get())]; PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) @@ -729,11 +731,11 @@ impl_runtime_apis! { Ok(WeightToFee::weight_to_fee(&weight)) }, Ok(asset_id) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); Err(XcmPaymentApiError::AssetNotFound) }, Err(_) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); Err(XcmPaymentApiError::VersionedConversionFailed) } } @@ -748,7 +750,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + impl xcm_runtime_apis::dry_run::DryRunApi for Runtime { fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { PolkadotXcm::dry_run_call::(origin, call) } @@ -758,6 +760,18 @@ impl_runtime_apis! { } } + impl xcm_runtime_apis::conversions::LocationToAccountApi for Runtime { + fn convert_location(location: VersionedLocation) -> Result< + AccountId, + xcm_runtime_apis::conversions::Error + > { + xcm_runtime_apis::conversions::LocationToAccountHelper::< + AccountId, + xcm_config::LocationToAccountId, + >::convert_location(location) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) @@ -874,7 +888,7 @@ impl_runtime_apis! { use frame_system_benchmarking::Pallet as SystemBench; impl frame_system_benchmarking::Config for Runtime { - fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { + fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); Ok(()) } @@ -916,7 +930,7 @@ impl_runtime_apis! { } fn set_up_complex_asset_transfer( - ) -> Option<(Assets, u32, Location, Box)> { + ) -> Option<(Assets, u32, Location, alloc::boxed::Box)> { // BH only supports teleports to system parachain. // Relay/native token can be teleported between BH and Relay. let native_location = Parent.into(); @@ -1039,7 +1053,7 @@ impl_runtime_apis! { // save XCM version for remote bridge hub let _ = PolkadotXcm::force_xcm_version( RuntimeOrigin::root(), - Box::new(bridge_to_rococo_config::BridgeHubRococoLocation::get()), + alloc::boxed::Box::new(bridge_to_rococo_config::BridgeHubRococoLocation::get()), XCM_VERSION, ).map_err(|e| { log::error!( @@ -1086,7 +1100,8 @@ impl_runtime_apis! { impl BridgeMessagesConfig for Runtime { fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { let bench_lane_id = >::bench_lane_id(); - let bridged_chain_id = bridge_to_rococo_config::BridgeHubRococoChainId::get(); + use bp_runtime::Chain; + let bridged_chain_id =>::BridgedChain::ID; pallet_bridge_relayers::Pallet::::relayer_reward( relayer, bp_relayers::RewardsAccountParams::new( @@ -1106,7 +1121,7 @@ impl_runtime_apis! { prepare_message_proof_from_parachain::< Runtime, bridge_to_rococo_config::BridgeGrandpaRococoInstance, - bridge_to_rococo_config::WithBridgeHubRococoMessageBridge, + bridge_to_rococo_config::WithBridgeHubRococoMessagesInstance, >(params, generate_xcm_builder_bridge_message_sample([GlobalConsensus(Westend), Parachain(42)].into())) } @@ -1116,7 +1131,7 @@ impl_runtime_apis! { prepare_message_delivery_proof_from_parachain::< Runtime, bridge_to_rococo_config::BridgeGrandpaRococoInstance, - bridge_to_rococo_config::WithBridgeHubRococoMessageBridge, + bridge_to_rococo_config::WithBridgeHubRococoMessagesInstance, >(params) } @@ -1142,7 +1157,7 @@ impl_runtime_apis! { fn prepare_parachain_heads_proof( parachains: &[bp_polkadot_core::parachains::ParaId], parachain_head_size: u32, - proof_size: bp_runtime::StorageProofSize, + proof_params: bp_runtime::UnverifiedStorageProofParams, ) -> ( pallet_bridge_parachains::RelayBlockNumber, pallet_bridge_parachains::RelayBlockHash, @@ -1152,7 +1167,7 @@ impl_runtime_apis! { prepare_parachain_heads_proof::( parachains, parachain_head_size, - proof_size, + proof_params, ) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_parachain_system.rs index dc480c391636a92aad6e303a515524b5ce7ff2b1..8fcd7b10d931b03ec4cd9cc063e0bacf8878ed16 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_parachain_system.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_parachain_system.rs @@ -47,7 +47,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `cumulus_pallet_parachain_system`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs index e98be6ba39be74c3532290ea4a7b483640466c10..fa7efc260489bead50ba63969571e018248ddefe 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_grandpa` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-05-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-07-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vicqj8em-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-yaoqqom-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -68,13 +68,13 @@ impl pallet_bridge_grandpa::WeightInfo for WeightInfo pallet_bridge_grandpa::WeightInfo for WeightInfo pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) @@ -60,10 +60,10 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `502` + // Measured: `522` // Estimated: `52645` - // Minimum execution time: 40_646_000 picoseconds. - Weight::from_parts(41_754_000, 0) + // Minimum execution time: 40_748_000 picoseconds. + Weight::from_parts(41_836_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) @@ -71,27 +71,30 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn receive_two_messages_proof() -> Weight { + /// The range of component `n` is `[1, 4076]`. + fn receive_n_messages_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `502` + // Measured: `522` // Estimated: `52645` - // Minimum execution time: 50_898_000 picoseconds. - Weight::from_parts(52_743_000, 0) + // Minimum execution time: 40_923_000 picoseconds. + Weight::from_parts(41_287_000, 0) .saturating_add(Weight::from_parts(0, 52645)) + // Standard Error: 9_774 + .saturating_add(Weight::from_parts(11_469_207, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) @@ -100,10 +103,10 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `502` + // Measured: `522` // Estimated: `52645` - // Minimum execution time: 45_848_000 picoseconds. - Weight::from_parts(47_036_000, 0) + // Minimum execution time: 45_946_000 picoseconds. + Weight::from_parts(47_547_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) @@ -111,37 +114,24 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - fn receive_single_message_proof_1_kb() -> Weight { - // Proof Size summary in bytes: - // Measured: `433` - // Estimated: `52645` - // Minimum execution time: 39_085_000 picoseconds. - Weight::from_parts(41_623_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) - fn receive_single_message_proof_16_kb() -> Weight { + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 16384]`. + fn receive_single_n_bytes_message_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `433` + // Measured: `522` // Estimated: `52645` - // Minimum execution time: 72_754_000 picoseconds. - Weight::from_parts(74_985_000, 0) + // Minimum execution time: 39_668_000 picoseconds. + Weight::from_parts(41_908_980, 0) .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) + // Standard Error: 11 + .saturating_add(Weight::from_parts(2_209, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) @@ -156,11 +146,11 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `337` - // Estimated: `3802` - // Minimum execution time: 31_479_000 picoseconds. - Weight::from_parts(32_280_000, 0) - .saturating_add(Weight::from_parts(0, 3802)) + // Measured: `357` + // Estimated: `3822` + // Minimum execution time: 30_544_000 picoseconds. + Weight::from_parts(31_171_000, 0) + .saturating_add(Weight::from_parts(0, 3822)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -176,11 +166,11 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `337` - // Estimated: `3802` - // Minimum execution time: 31_807_000 picoseconds. - Weight::from_parts(32_219_000, 0) - .saturating_add(Weight::from_parts(0, 3802)) + // Measured: `357` + // Estimated: `3822` + // Minimum execution time: 30_593_000 picoseconds. + Weight::from_parts(31_261_000, 0) + .saturating_add(Weight::from_parts(0, 3822)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -196,10 +186,10 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `337` + // Measured: `357` // Estimated: `6086` - // Minimum execution time: 36_450_000 picoseconds. - Weight::from_parts(37_288_000, 0) + // Minimum execution time: 34_682_000 picoseconds. + Weight::from_parts(35_277_000, 0) .saturating_add(Weight::from_parts(0, 6086)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) @@ -207,7 +197,7 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) @@ -215,7 +205,7 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -225,17 +215,17 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) - /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `i` is `[128, 2048]`. - fn receive_single_message_proof_with_dispatch(i: u32, ) -> Weight { + /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 16384]`. + fn receive_single_n_bytes_message_proof_with_dispatch(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `633` + // Measured: `653` // Estimated: `52645` - // Minimum execution time: 67_047_000 picoseconds. - Weight::from_parts(68_717_105, 0) + // Minimum execution time: 56_465_000 picoseconds. + Weight::from_parts(61_575_775, 0) .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 138 - .saturating_add(Weight::from_parts(8_056, 0).saturating_mul(i.into())) + // Standard Error: 15 + .saturating_add(Weight::from_parts(7_197, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs index 9819bd4065411bec6799de3f2aa41c318f53a122..b4748f1417059e91e482c650f5046ef09b76a7af 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_bridge_parachains` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -56,18 +56,20 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf /// Proof: `BridgeRococoParachains::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHashes` (r:1 w:1) /// Proof: `BridgeRococoParachains::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoGrandpa::FreeHeadersRemaining` (r:1 w:1) + /// Proof: `BridgeRococoGrandpa::FreeHeadersRemaining` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:0 w:1) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 2]`. fn submit_parachain_heads_with_n_parachains(_p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `291` + // Measured: `315` // Estimated: `2543` - // Minimum execution time: 29_994_000 picoseconds. - Weight::from_parts(31_005_636, 0) + // Minimum execution time: 34_177_000 picoseconds. + Weight::from_parts(35_662_308, 0) .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `BridgeRococoParachains::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoParachains::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) @@ -77,17 +79,19 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf /// Proof: `BridgeRococoParachains::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHashes` (r:1 w:1) /// Proof: `BridgeRococoParachains::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoGrandpa::FreeHeadersRemaining` (r:1 w:1) + /// Proof: `BridgeRococoGrandpa::FreeHeadersRemaining` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:0 w:1) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) fn submit_parachain_heads_with_1kb_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `291` + // Measured: `315` // Estimated: `2543` - // Minimum execution time: 31_425_000 picoseconds. - Weight::from_parts(32_163_000, 0) + // Minimum execution time: 35_975_000 picoseconds. + Weight::from_parts(36_510_000, 0) .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `BridgeRococoParachains::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoParachains::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) @@ -97,16 +101,18 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf /// Proof: `BridgeRococoParachains::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHashes` (r:1 w:1) /// Proof: `BridgeRococoParachains::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoGrandpa::FreeHeadersRemaining` (r:1 w:1) + /// Proof: `BridgeRococoGrandpa::FreeHeadersRemaining` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:0 w:1) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) fn submit_parachain_heads_with_16kb_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `291` + // Measured: `315` // Estimated: `2543` - // Minimum execution time: 60_062_000 picoseconds. - Weight::from_parts(61_201_000, 0) + // Minimum execution time: 62_837_000 picoseconds. + Weight::from_parts(63_562_000, 0) .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs index ed96f0cd87c9e73ee8c842ab9f4f5d60bf81c2ac..60d81dc3082a86ea3cea3951d4ed59cf9be8ed56 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_bridge_relayers` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -56,8 +56,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `207` // Estimated: `3593` - // Minimum execution time: 45_732_000 picoseconds. - Weight::from_parts(46_282_000, 0) + // Minimum execution time: 43_132_000 picoseconds. + Weight::from_parts(43_923_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -72,8 +72,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `61` // Estimated: `4714` - // Minimum execution time: 22_934_000 picoseconds. - Weight::from_parts(23_531_000, 0) + // Minimum execution time: 22_765_000 picoseconds. + Weight::from_parts(23_576_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -86,8 +86,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `160` // Estimated: `4714` - // Minimum execution time: 25_187_000 picoseconds. - Weight::from_parts(25_679_000, 0) + // Minimum execution time: 24_013_000 picoseconds. + Weight::from_parts(24_460_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -102,8 +102,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `263` // Estimated: `4714` - // Minimum execution time: 27_015_000 picoseconds. - Weight::from_parts(27_608_000, 0) + // Minimum execution time: 26_946_000 picoseconds. + Weight::from_parts(27_485_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -114,8 +114,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `6` // Estimated: `3538` - // Minimum execution time: 5_207_000 picoseconds. - Weight::from_parts(5_394_000, 0) + // Minimum execution time: 4_658_000 picoseconds. + Weight::from_parts(4_902_000, 0) .saturating_add(Weight::from_parts(0, 3538)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_message_queue.rs index 2fcd573ceb277116bda67180da8e0701593ab453..b6fee47d1435162a3e24dd204b896eb849a7e146 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_message_queue.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_message_queue.rs @@ -43,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `pallet_message_queue`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs index e8950678b40fd7b4e7afca8c998bc20c619e65ef..3961cc6d5cdd63a67b5ea4cbc805448e01f98939 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs @@ -18,11 +18,11 @@ mod pallet_xcm_benchmarks_fungible; mod pallet_xcm_benchmarks_generic; use crate::{xcm_config::MaxAssetsIntoHolding, Runtime}; +use alloc::vec::Vec; use codec::Encode; use frame_support::weights::Weight; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; -use sp_std::prelude::*; use xcm::{latest::prelude::*, DoubleEncoded}; trait WeighAssets { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 295abd481d7dc6decd39032bf6b0972cdc7ccf20..4310b24564758c4a3d95d27f047dd8988a43395c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -43,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::fungible`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 9281a880c7e1266d65d29436ca88e51e896c0363..ba434ff29629ff89a92d6ea663e5fcf8184d102f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-westend-dev"), DB CACHE: 1024 // Executed Command: @@ -43,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::generic`. pub struct WeightInfo(PhantomData); @@ -68,8 +68,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 61_577_000 picoseconds. - Weight::from_parts(63_216_000, 6196) + // Minimum execution time: 58_505_000 picoseconds. + Weight::from_parts(60_437_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -77,8 +77,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_019_000 picoseconds. - Weight::from_parts(2_146_000, 0) + // Minimum execution time: 510_000 picoseconds. + Weight::from_parts(569_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -86,58 +86,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 7_473_000 picoseconds. - Weight::from_parts(7_784_000, 3497) + // Minimum execution time: 5_597_000 picoseconds. + Weight::from_parts(5_884_000, 3497) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_385_000 picoseconds. - Weight::from_parts(8_768_000, 0) + // Minimum execution time: 5_320_000 picoseconds. + Weight::from_parts(5_594_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_181_000 picoseconds. - Weight::from_parts(2_304_000, 0) + // Minimum execution time: 1_164_000 picoseconds. + Weight::from_parts(1_227_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_858_000 picoseconds. - Weight::from_parts(1_919_000, 0) + // Minimum execution time: 528_000 picoseconds. + Weight::from_parts(586_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_855_000 picoseconds. - Weight::from_parts(1_979_000, 0) + // Minimum execution time: 509_000 picoseconds. + Weight::from_parts(571_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_823_000 picoseconds. - Weight::from_parts(1_890_000, 0) + // Minimum execution time: 511_000 picoseconds. + Weight::from_parts(546_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_407_000 picoseconds. - Weight::from_parts(2_507_000, 0) + // Minimum execution time: 560_000 picoseconds. + Weight::from_parts(600_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_838_000 picoseconds. - Weight::from_parts(1_894_000, 0) + // Minimum execution time: 514_000 picoseconds. + Weight::from_parts(558_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -159,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 54_847_000 picoseconds. - Weight::from_parts(55_742_000, 6196) + // Minimum execution time: 55_871_000 picoseconds. + Weight::from_parts(57_172_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -170,8 +170,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 10_614_000 picoseconds. - Weight::from_parts(11_344_000, 3555) + // Minimum execution time: 8_487_000 picoseconds. + Weight::from_parts(8_800_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +179,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_826_000 picoseconds. - Weight::from_parts(1_899_000, 0) + // Minimum execution time: 528_000 picoseconds. + Weight::from_parts(569_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -200,8 +200,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 22_312_000 picoseconds. - Weight::from_parts(22_607_000, 3503) + // Minimum execution time: 19_803_000 picoseconds. + Weight::from_parts(20_368_000, 3503) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -211,44 +211,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_728_000 picoseconds. - Weight::from_parts(3_914_000, 0) + // Minimum execution time: 2_185_000 picoseconds. + Weight::from_parts(2_332_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_054_000 picoseconds. - Weight::from_parts(3_140_000, 0) + // Minimum execution time: 822_000 picoseconds. + Weight::from_parts(928_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_996_000 picoseconds. - Weight::from_parts(2_148_000, 0) + // Minimum execution time: 603_000 picoseconds. + Weight::from_parts(643_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_008_000 picoseconds. - Weight::from_parts(2_077_000, 0) + // Minimum execution time: 503_000 picoseconds. + Weight::from_parts(580_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_837_000 picoseconds. - Weight::from_parts(1_913_000, 0) + // Minimum execution time: 534_000 picoseconds. + Weight::from_parts(577_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_052_000 picoseconds. - Weight::from_parts(2_120_000, 0) + // Minimum execution time: 694_000 picoseconds. + Weight::from_parts(745_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -270,8 +270,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 58_725_000 picoseconds. - Weight::from_parts(60_271_000, 6196) + // Minimum execution time: 61_083_000 picoseconds. + Weight::from_parts(62_214_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -279,8 +279,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_570_000 picoseconds. - Weight::from_parts(4_707_000, 0) + // Minimum execution time: 3_261_000 picoseconds. + Weight::from_parts(3_483_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -302,8 +302,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 54_903_000 picoseconds. - Weight::from_parts(55_711_000, 6196) + // Minimum execution time: 56_270_000 picoseconds. + Weight::from_parts(57_443_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -311,22 +311,22 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_872_000 picoseconds. - Weight::from_parts(1_938_000, 0) + // Minimum execution time: 565_000 picoseconds. + Weight::from_parts(628_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_836_000 picoseconds. - Weight::from_parts(1_903_000, 0) + // Minimum execution time: 496_000 picoseconds. + Weight::from_parts(563_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_847_000 picoseconds. - Weight::from_parts(1_900_000, 0) + // Minimum execution time: 518_000 picoseconds. + Weight::from_parts(557_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -339,16 +339,16 @@ impl WeightInfo { // Storage: `BridgeRococoMessages::OutboundLanesCongestedSignals` (r:1 w:0) // Proof: `BridgeRococoMessages::OutboundLanesCongestedSignals` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) // Storage: `BridgeRococoMessages::OutboundMessages` (r:0 w:1) - // Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(2621472), added: 2623947, mode: `MaxEncodedLen`) + // Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) /// The range of component `x` is `[1, 1000]`. pub fn export_message(x: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `225` // Estimated: `6165` - // Minimum execution time: 41_750_000 picoseconds. - Weight::from_parts(43_496_915, 6165) - // Standard Error: 623 - .saturating_add(Weight::from_parts(457_907, 0).saturating_mul(x.into())) + // Minimum execution time: 36_288_000 picoseconds. + Weight::from_parts(37_707_751, 6165) + // Standard Error: 124 + .saturating_add(Weight::from_parts(51_290, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -356,14 +356,14 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_826_000 picoseconds. - Weight::from_parts(1_911_000, 0) + // Minimum execution time: 485_000 picoseconds. + Weight::from_parts(540_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_967_000 picoseconds. - Weight::from_parts(2_096_000, 0) + // Minimum execution time: 542_000 picoseconds. + Weight::from_parts(586_000, 0) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs index c2ca8e47f2a61cf6d66613daa205caddafe192b0..7f94b76a005bf933d7dead5309a2fc0bdec5a4e8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs @@ -42,10 +42,10 @@ use xcm_builder::{ AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; @@ -195,7 +195,7 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type FeeManager = XcmFeeManagerFromComponents< WaivedLocations, - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (crate::bridge_to_rococo_config::ToBridgeHubRococoHaulBlobExporter,); type UniversalAliases = Nothing; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index 836594140b2328081ff6c0de8cac40ea82dfb6f7..98a789eb4e0014de1068ece72068befb8a58ba94 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -27,8 +27,7 @@ use bridge_hub_westend_runtime::{ SignedExtra, TransactionPayment, UncheckedExtrinsic, }; use bridge_to_rococo_config::{ - BridgeGrandpaRococoInstance, BridgeHubRococoChainId, BridgeHubRococoLocation, - BridgeParachainRococoInstance, WithBridgeHubRococoMessageBridge, + BridgeGrandpaRococoInstance, BridgeHubRococoLocation, BridgeParachainRococoInstance, WithBridgeHubRococoMessagesInstance, XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, }; use codec::{Decode, Encode}; @@ -53,7 +52,6 @@ type RuntimeTestsAdapter = from_parachain::WithRemoteParachainHelperAdapter< BridgeGrandpaRococoInstance, BridgeParachainRococoInstance, WithBridgeHubRococoMessagesInstance, - WithBridgeHubRococoMessageBridge, >; parameter_types! { @@ -213,11 +211,14 @@ fn handle_export_message_from_system_parachain_add_to_outbound_queue_works() { } }), || ExportMessage { network: Rococo, destination: [Parachain(bridge_to_rococo_config::AssetHubRococoParaId::get().into())].into(), xcm: Xcm(vec![]) }, - XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, Some((WestendLocation::get(), ExistentialDeposit::get()).into()), // value should be >= than value generated by `can_calculate_weight_for_paid_export_message_with_reserve_transfer` Some((WestendLocation::get(), bp_bridge_hub_westend::BridgeHubWestendBaseXcmFeeInWnds::get()).into()), - || PolkadotXcm::force_xcm_version(RuntimeOrigin::root(), Box::new(BridgeHubRococoLocation::get()), XCM_VERSION).expect("version saved!"), + || { + PolkadotXcm::force_xcm_version(RuntimeOrigin::root(), Box::new(BridgeHubRococoLocation::get()), XCM_VERSION).expect("version saved!"); + + XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO + }, ) } @@ -249,8 +250,7 @@ fn message_dispatch_routing_works() { _ => None, } }), - XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, - || (), + || XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, ) } @@ -261,11 +261,9 @@ fn relayed_incoming_message_works() { slot_durations(), bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - BridgeHubRococoChainId::get(), SIBLING_PARACHAIN_ID, Westend, - XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, - || (), + || XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, construct_and_apply_extrinsic, ) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml index aece34613e6a6c4dfe100e84b0317a96ad7ee97c..3ae43075000ba2ccd34c9efe1edfc91681201944 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml @@ -7,16 +7,15 @@ description = "Bridge hub common utilities" license = "Apache-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } -snowbridge-core = { path = "../../../../../bridges/snowbridge/primitives/core", default-features = false } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } +frame-support = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +cumulus-primitives-core = { workspace = true } +xcm = { workspace = true } +pallet-message-queue = { workspace = true } +snowbridge-core = { workspace = true } [features] default = ["std"] @@ -29,7 +28,6 @@ std = [ "snowbridge-core/std", "sp-core/std", "sp-runtime/std", - "sp-std/std", "xcm/std", ] diff --git a/cumulus/parachains/runtimes/bridge-hubs/common/src/message_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/common/src/message_queue.rs index c1bba65b0abc3c6949f94e9e904a5649f1a9d285..5f91897262f4b8eed44a2da7ad945945dda67cc4 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/common/src/message_queue.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/common/src/message_queue.rs @@ -14,6 +14,7 @@ // limitations under the License. //! Runtime configuration for MessageQueue pallet use codec::{Decode, Encode, MaxEncodedLen}; +use core::marker::PhantomData; use cumulus_primitives_core::{AggregateMessageOrigin as CumulusAggregateMessageOrigin, ParaId}; use frame_support::{ traits::{ProcessMessage, ProcessMessageError, QueueFootprint, QueuePausedQuery}, @@ -22,7 +23,6 @@ use frame_support::{ use pallet_message_queue::OnQueueChanged; use scale_info::TypeInfo; use snowbridge_core::ChannelId; -use sp_std::{marker::PhantomData, prelude::*}; use xcm::v4::{Junction, Location}; /// The aggregate origin of an inbound message. diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml index 80f0114cc4cadb6cd7871454eead80a0988d5e7e..44a8646142d6c38d265c0b9cd518b1b7ddd192e3 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -10,47 +10,46 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } -impl-trait-for-tuples = "0.2" +codec = { features = ["derive", "max-encoded-len"], workspace = true } +impl-trait-for-tuples = { workspace = true } log = { workspace = true } # Substrate -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../../substrate/frame/system", default-features = false } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-io = { path = "../../../../../substrate/primitives/io", default-features = false } -sp-keyring = { path = "../../../../../substrate/primitives/keyring" } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-tracing = { path = "../../../../../substrate/primitives/tracing" } -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } -pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false } -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-keyring = { workspace = true, default-features = true } +sp-runtime = { workspace = true } +sp-tracing = { workspace = true, default-features = true } +pallet-balances = { workspace = true } +pallet-utility = { workspace = true } +pallet-timestamp = { workspace = true } # Cumulus -asset-test-utils = { path = "../../assets/test-utils" } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } -parachains-common = { path = "../../../common", default-features = false } -parachains-runtimes-test-utils = { path = "../../test-utils", default-features = false } +asset-test-utils = { workspace = true, default-features = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +parachains-common = { workspace = true } +parachains-runtimes-test-utils = { workspace = true } # Polkadot -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } # Bridges -bp-header-chain = { path = "../../../../../bridges/primitives/header-chain", default-features = false } -bp-messages = { path = "../../../../../bridges/primitives/messages", default-features = false } -bp-polkadot-core = { path = "../../../../../bridges/primitives/polkadot-core", default-features = false } -bp-relayers = { path = "../../../../../bridges/primitives/relayers", default-features = false } -bp-runtime = { path = "../../../../../bridges/primitives/runtime", default-features = false } -bp-test-utils = { path = "../../../../../bridges/primitives/test-utils", default-features = false } -pallet-bridge-grandpa = { path = "../../../../../bridges/modules/grandpa", default-features = false } -pallet-bridge-parachains = { path = "../../../../../bridges/modules/parachains", default-features = false } -pallet-bridge-messages = { path = "../../../../../bridges/modules/messages", default-features = false } -pallet-bridge-relayers = { path = "../../../../../bridges/modules/relayers", default-features = false } -bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", default-features = false } +bp-header-chain = { workspace = true } +bp-messages = { workspace = true } +bp-polkadot-core = { workspace = true } +bp-relayers = { workspace = true } +bp-runtime = { workspace = true } +bp-test-utils = { workspace = true } +pallet-bridge-grandpa = { workspace = true } +pallet-bridge-parachains = { workspace = true } +pallet-bridge-messages = { features = ["test-helpers"], workspace = true } +pallet-bridge-relayers = { workspace = true } +bridge-runtime-common = { workspace = true } [features] default = ["std"] @@ -81,7 +80,6 @@ std = [ "sp-core/std", "sp-io/std", "sp-runtime/std", - "sp-std/std", "xcm-builder/std", "xcm-executor/std", "xcm/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs index 1874f38de2df17e85c1f49723271d090e962eb70..0b3463f0df974dcc9ce46c1d811b363d5011bbb4 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs @@ -19,6 +19,8 @@ pub mod test_cases; pub mod test_data; +extern crate alloc; + pub use bp_test_utils::test_header; pub use parachains_runtimes_test_utils::*; use sp_runtime::Perbill; diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs index bfa2f0f50f94ca3ba2f663f9646be3165dd48220..f2f0ccecba132b9199f5ad75e124932fd1f5e320 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs @@ -22,22 +22,14 @@ use crate::{ test_data, }; +use alloc::{boxed::Box, vec}; use bp_header_chain::ChainWithGrandpa; -use bp_messages::{ - source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, LaneId, - UnrewardedRelayersState, -}; +use bp_messages::{LaneId, UnrewardedRelayersState}; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; -use bp_runtime::{HashOf, UnderlyingChainOf}; -use bridge_runtime_common::{ - messages::{ - source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, - BridgedChain as MessageBridgedChain, MessageBridge, ThisChain as MessageThisChain, - }, - messages_xcm_extension::XcmAsPlainPayload, -}; +use bridge_runtime_common::messages_xcm_extension::XcmAsPlainPayload; use frame_support::traits::{OnFinalize, OnInitialize}; use frame_system::pallet_prelude::BlockNumberFor; +use pallet_bridge_messages::{BridgedChainOf, ThisChainOf}; use parachains_runtimes_test_utils::{ AccountIdOf, BasicParachainRuntime, CollatorSessionKeys, RuntimeCallOf, SlotDurations, }; @@ -53,13 +45,10 @@ pub trait WithRemoteGrandpaChainHelper { /// This chain runtime. type Runtime: BasicParachainRuntime + cumulus_pallet_xcmp_queue::Config - + BridgeGrandpaConfig< - Self::GPI, - BridgedChain = UnderlyingChainOf>, - > + BridgeMessagesConfig< + + BridgeGrandpaConfig> + + BridgeMessagesConfig< Self::MPI, InboundPayload = XcmAsPlainPayload, - InboundRelayer = bp_runtime::AccountIdOf>, OutboundPayload = XcmAsPlainPayload, > + pallet_bridge_relayers::Config; /// All pallets of this chain, excluding system pallet. @@ -69,38 +58,33 @@ pub trait WithRemoteGrandpaChainHelper { type GPI: 'static; /// Instance of the `pallet-bridge-messages`, used to bridge with remote GRANDPA chain. type MPI: 'static; - /// Messages bridge definition. - type MB: MessageBridge; } /// Adapter struct that implements [`WithRemoteGrandpaChainHelper`]. -pub struct WithRemoteGrandpaChainHelperAdapter( - sp_std::marker::PhantomData<(Runtime, AllPalletsWithoutSystem, GPI, MPI, MB)>, +pub struct WithRemoteGrandpaChainHelperAdapter( + core::marker::PhantomData<(Runtime, AllPalletsWithoutSystem, GPI, MPI)>, ); -impl WithRemoteGrandpaChainHelper - for WithRemoteGrandpaChainHelperAdapter +impl WithRemoteGrandpaChainHelper + for WithRemoteGrandpaChainHelperAdapter where Runtime: BasicParachainRuntime + cumulus_pallet_xcmp_queue::Config - + BridgeGrandpaConfig>> + + BridgeGrandpaConfig> + BridgeMessagesConfig< MPI, InboundPayload = XcmAsPlainPayload, - InboundRelayer = bp_runtime::AccountIdOf>, OutboundPayload = XcmAsPlainPayload, > + pallet_bridge_relayers::Config, AllPalletsWithoutSystem: OnInitialize> + OnFinalize>, GPI: 'static, MPI: 'static, - MB: MessageBridge, { type Runtime = Runtime; type AllPalletsWithoutSystem = AllPalletsWithoutSystem; type GPI = GPI; type MPI = MPI; - type MB = MB; } /// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer, @@ -110,11 +94,9 @@ pub fn relayed_incoming_message_works( collator_session_key: CollatorSessionKeys, slot_durations: SlotDurations, runtime_para_id: u32, - bridged_chain_id: bp_runtime::ChainId, sibling_parachain_id: u32, local_relay_chain_id: NetworkId, - lane_id: LaneId, - prepare_configuration: impl Fn(), + prepare_configuration: impl Fn() -> LaneId, construct_and_apply_extrinsic: fn( sp_keyring::AccountKeyring, RuntimeCallOf, @@ -124,13 +106,7 @@ pub fn relayed_incoming_message_works( AccountIdOf: From, RuntimeCallOf: From> + From>, - UnderlyingChainOf>: ChainWithGrandpa, - >::SourceHeaderChain: - SourceHeaderChain< - MessagesProof = FromBridgedChainMessagesProof< - HashOf>, - >, - >, + BridgedChainOf: ChainWithGrandpa, { helpers::relayed_incoming_message_works::< RuntimeHelper::Runtime, @@ -147,10 +123,11 @@ pub fn relayed_incoming_message_works( relayer_id_at_bridged_chain, message_destination, message_nonce, - xcm| { + xcm, + bridged_chain_id| { let relay_header_number = 5u32.into(); - prepare_configuration(); + let lane_id = prepare_configuration(); // start with bridged relay chain block#0 helpers::initialize_bridge_grandpa_pallet::( @@ -161,8 +138,8 @@ pub fn relayed_incoming_message_works( // to be submitted by relayer to this chain. let (relay_chain_header, grandpa_justification, message_proof) = test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< - RuntimeHelper::MB, - (), + BridgedChainOf, + ThisChainOf, >( lane_id, xcm.into(), @@ -186,7 +163,7 @@ pub fn relayed_incoming_message_works( ( BridgeMessagesCall::::receive_messages_proof { relayer_id_at_bridged_chain, - proof: message_proof, + proof: Box::new(message_proof), messages_count: 1, dispatch_weight: Weight::from_parts(1000000000, 0), }.into(), @@ -218,11 +195,9 @@ pub fn free_relay_extrinsic_works( collator_session_key: CollatorSessionKeys, slot_durations: SlotDurations, runtime_para_id: u32, - bridged_chain_id: bp_runtime::ChainId, sibling_parachain_id: u32, local_relay_chain_id: NetworkId, - lane_id: LaneId, - prepare_configuration: impl Fn(), + prepare_configuration: impl Fn() -> LaneId, construct_and_apply_extrinsic: fn( sp_keyring::AccountKeyring, RuntimeCallOf, @@ -233,13 +208,7 @@ pub fn free_relay_extrinsic_works( AccountIdOf: From, RuntimeCallOf: From> + From>, - UnderlyingChainOf>: ChainWithGrandpa, - >::SourceHeaderChain: - SourceHeaderChain< - MessagesProof = FromBridgedChainMessagesProof< - HashOf>, - >, - >, + BridgedChainOf: ChainWithGrandpa, { // ensure that the runtime allows free header submissions let free_headers_interval = ( relayer_id_at_bridged_chain, message_destination, message_nonce, - xcm| { - prepare_configuration(); + xcm, + bridged_chain_id| { + let lane_id = prepare_configuration(); // start with bridged relay chain block#0 let initial_block_number = 0; @@ -291,8 +261,8 @@ pub fn free_relay_extrinsic_works( // to be submitted by relayer to this chain. let (relay_chain_header, grandpa_justification, message_proof) = test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< - RuntimeHelper::MB, - (), + BridgedChainOf, + ThisChainOf, >( lane_id, xcm.into(), @@ -322,7 +292,7 @@ pub fn free_relay_extrinsic_works( ( BridgeMessagesCall::::receive_messages_proof { relayer_id_at_bridged_chain, - proof: message_proof, + proof: Box::new(message_proof), messages_count: 1, dispatch_weight: Weight::from_parts(1000000000, 0), }.into(), @@ -354,10 +324,8 @@ pub fn complex_relay_extrinsic_works( slot_durations: SlotDurations, runtime_para_id: u32, sibling_parachain_id: u32, - bridged_chain_id: bp_runtime::ChainId, local_relay_chain_id: NetworkId, - lane_id: LaneId, - prepare_configuration: impl Fn(), + prepare_configuration: impl Fn() -> LaneId, construct_and_apply_extrinsic: fn( sp_keyring::AccountKeyring, RuntimeCallOf, @@ -370,13 +338,7 @@ pub fn complex_relay_extrinsic_works( RuntimeCallOf: From> + From> + From>, - UnderlyingChainOf>: ChainWithGrandpa, - >::SourceHeaderChain: - SourceHeaderChain< - MessagesProof = FromBridgedChainMessagesProof< - HashOf>, - >, - >, + BridgedChainOf: ChainWithGrandpa, { helpers::relayed_incoming_message_works::< RuntimeHelper::Runtime, @@ -393,10 +355,11 @@ pub fn complex_relay_extrinsic_works( relayer_id_at_bridged_chain, message_destination, message_nonce, - xcm| { + xcm, + bridged_chain_id| { let relay_header_number = 1u32.into(); - prepare_configuration(); + let lane_id = prepare_configuration(); // start with bridged relay chain block#0 helpers::initialize_bridge_grandpa_pallet::( @@ -407,8 +370,8 @@ pub fn complex_relay_extrinsic_works( // to be submitted by relayer to this chain. let (relay_chain_header, grandpa_justification, message_proof) = test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< - RuntimeHelper::MB, - (), + BridgedChainOf, + ThisChainOf, >( lane_id, xcm.into(), @@ -428,7 +391,7 @@ pub fn complex_relay_extrinsic_works( }.into(), BridgeMessagesCall::::receive_messages_proof { relayer_id_at_bridged_chain, - proof: message_proof, + proof: Box::new(message_proof), messages_count: 1, dispatch_weight: Weight::from_parts(1000000000, 0), }.into(), @@ -470,13 +433,7 @@ where pallet_utility::Config>, RuntimeCallOf: From> + From>, - UnderlyingChainOf>: ChainWithGrandpa, - >::SourceHeaderChain: - SourceHeaderChain< - MessagesProof = FromBridgedChainMessagesProof< - HashOf>, - >, - >, + BridgedChainOf: ChainWithGrandpa, { run_test::(collator_session_key, 1000, vec![], || { // generate bridged relay chain finality, parachain heads and message proofs, @@ -487,8 +444,8 @@ where // the message additionally let (relay_chain_header, grandpa_justification, message_proof) = test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< - RuntimeHelper::MB, - (), + BridgedChainOf, + ThisChainOf, >( LaneId::default(), vec![Instruction::<()>::ClearOrigin; 1_024].into(), @@ -526,19 +483,11 @@ where AccountIdOf: From, RuntimeHelper::Runtime: pallet_utility::Config>, - MessageThisChain: + ThisChainOf: bp_runtime::Chain>, RuntimeCallOf: From> + From>, - UnderlyingChainOf>: ChainWithGrandpa, - >::TargetHeaderChain: - TargetHeaderChain< - XcmAsPlainPayload, - AccountIdOf, - MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof< - HashOf>>, - >, - >, + BridgedChainOf: ChainWithGrandpa, { run_test::(collator_session_key, 1000, vec![], || { // generate bridged relay chain finality, parachain heads and message proofs, @@ -550,7 +499,8 @@ where }; let (relay_chain_header, grandpa_justification, message_delivery_proof) = test_data::from_grandpa_chain::make_complex_relayer_confirmation_proofs::< - RuntimeHelper::MB, + BridgedChainOf, + ThisChainOf, (), >( LaneId::default(), @@ -587,13 +537,7 @@ where RuntimeHelper: WithRemoteGrandpaChainHelper, RuntimeCallOf: From>, - UnderlyingChainOf>: ChainWithGrandpa, - >::SourceHeaderChain: - SourceHeaderChain< - MessagesProof = FromBridgedChainMessagesProof< - HashOf>, - >, - >, + BridgedChainOf: ChainWithGrandpa, { run_test::(collator_session_key, 1000, vec![], || { // generate bridged relay chain finality, parachain heads and message proofs, @@ -604,8 +548,8 @@ where // the message additionally let (_, _, message_proof) = test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< - RuntimeHelper::MB, - (), + BridgedChainOf, + ThisChainOf, >( LaneId::default(), vec![Instruction::<()>::ClearOrigin; 1_024].into(), @@ -639,19 +583,11 @@ pub fn can_calculate_fee_for_standalone_message_confirmation_transaction: From, - MessageThisChain: + ThisChainOf: bp_runtime::Chain>, RuntimeCallOf: From>, - UnderlyingChainOf>: ChainWithGrandpa, - >::TargetHeaderChain: - TargetHeaderChain< - XcmAsPlainPayload, - AccountIdOf, - MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof< - HashOf>>, - >, - >, + BridgedChainOf: ChainWithGrandpa, { run_test::(collator_session_key, 1000, vec![], || { // generate bridged relay chain finality, parachain heads and message proofs, @@ -663,7 +599,8 @@ where }; let (_, _, message_delivery_proof) = test_data::from_grandpa_chain::make_complex_relayer_confirmation_proofs::< - RuntimeHelper::MB, + BridgedChainOf, + ThisChainOf, (), >( LaneId::default(), diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs index 12ab382d9e0f6518afb93f118199170acb5f8cc6..0988528c3f2a0ae867d188d745a3b1e923ab0060 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs @@ -22,23 +22,16 @@ use crate::{ test_data, }; +use alloc::{boxed::Box, vec}; use bp_header_chain::ChainWithGrandpa; -use bp_messages::{ - source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, LaneId, - UnrewardedRelayersState, -}; +use bp_messages::{LaneId, UnrewardedRelayersState}; use bp_polkadot_core::parachains::ParaHash; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; -use bp_runtime::{HashOf, Parachain, UnderlyingChainOf}; -use bridge_runtime_common::{ - messages::{ - source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, - BridgedChain as MessageBridgedChain, MessageBridge, ThisChain as MessageThisChain, - }, - messages_xcm_extension::XcmAsPlainPayload, -}; +use bp_runtime::{Chain, Parachain}; +use bridge_runtime_common::messages_xcm_extension::XcmAsPlainPayload; use frame_support::traits::{OnFinalize, OnInitialize}; use frame_system::pallet_prelude::BlockNumberFor; +use pallet_bridge_messages::{BridgedChainOf, ThisChainOf}; use parachains_runtimes_test_utils::{ AccountIdOf, BasicParachainRuntime, CollatorSessionKeys, RuntimeCallOf, SlotDurations, }; @@ -59,7 +52,6 @@ pub trait WithRemoteParachainHelper { + BridgeMessagesConfig< Self::MPI, InboundPayload = XcmAsPlainPayload, - InboundRelayer = bp_runtime::AccountIdOf>, OutboundPayload = XcmAsPlainPayload, > + pallet_bridge_relayers::Config; /// All pallets of this chain, excluding system pallet. @@ -71,17 +63,15 @@ pub trait WithRemoteParachainHelper { type PPI: 'static; /// Instance of the `pallet-bridge-messages`, used to bridge with remote parachain. type MPI: 'static; - /// Messages bridge definition. - type MB: MessageBridge; } /// Adapter struct that implements `WithRemoteParachainHelper`. -pub struct WithRemoteParachainHelperAdapter( - sp_std::marker::PhantomData<(Runtime, AllPalletsWithoutSystem, GPI, PPI, MPI, MB)>, +pub struct WithRemoteParachainHelperAdapter( + core::marker::PhantomData<(Runtime, AllPalletsWithoutSystem, GPI, PPI, MPI)>, ); -impl WithRemoteParachainHelper - for WithRemoteParachainHelperAdapter +impl WithRemoteParachainHelper + for WithRemoteParachainHelperAdapter where Runtime: BasicParachainRuntime + cumulus_pallet_xcmp_queue::Config @@ -90,7 +80,6 @@ where + BridgeMessagesConfig< MPI, InboundPayload = XcmAsPlainPayload, - InboundRelayer = bp_runtime::AccountIdOf>, OutboundPayload = XcmAsPlainPayload, > + pallet_bridge_relayers::Config, AllPalletsWithoutSystem: @@ -98,14 +87,13 @@ where GPI: 'static, PPI: 'static, MPI: 'static, - MB: MessageBridge, + // MB: MessageBridge, { type Runtime = Runtime; type AllPalletsWithoutSystem = AllPalletsWithoutSystem; type GPI = GPI; type PPI = PPI; type MPI = MPI; - type MB = MB; } /// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer, @@ -116,11 +104,9 @@ pub fn relayed_incoming_message_works( slot_durations: SlotDurations, runtime_para_id: u32, bridged_para_id: u32, - bridged_chain_id: bp_runtime::ChainId, sibling_parachain_id: u32, local_relay_chain_id: NetworkId, - lane_id: LaneId, - prepare_configuration: impl Fn(), + prepare_configuration: impl Fn() -> LaneId, construct_and_apply_extrinsic: fn( sp_keyring::AccountKeyring, ::RuntimeCall, @@ -131,16 +117,9 @@ pub fn relayed_incoming_message_works( RuntimeCallOf: From> + From> + From>, - UnderlyingChainOf>: - bp_runtime::Chain + Parachain, + BridgedChainOf: Chain + Parachain, >::BridgedChain: bp_runtime::Chain + ChainWithGrandpa, - >::SourceHeaderChain: - SourceHeaderChain< - MessagesProof = FromBridgedChainMessagesProof< - HashOf>, - >, - >, { helpers::relayed_incoming_message_works::< RuntimeHelper::Runtime, @@ -157,11 +136,12 @@ pub fn relayed_incoming_message_works( relayer_id_at_bridged_chain, message_destination, message_nonce, - xcm| { + xcm, + bridged_chain_id| { let para_header_number = 5; let relay_header_number = 1; - prepare_configuration(); + let lane_id = prepare_configuration(); // start with bridged relay chain block#0 helpers::initialize_bridge_grandpa_pallet::( @@ -179,8 +159,8 @@ pub fn relayed_incoming_message_works( message_proof, ) = test_data::from_parachain::make_complex_relayer_delivery_proofs::< >::BridgedChain, - RuntimeHelper::MB, - (), + BridgedChainOf, + ThisChainOf, >( lane_id, xcm.into(), @@ -219,7 +199,7 @@ pub fn relayed_incoming_message_works( ( BridgeMessagesCall::::receive_messages_proof { relayer_id_at_bridged_chain, - proof: message_proof, + proof: Box::new(message_proof), messages_count: 1, dispatch_weight: Weight::from_parts(1000000000, 0), }.into(), @@ -252,11 +232,9 @@ pub fn free_relay_extrinsic_works( slot_durations: SlotDurations, runtime_para_id: u32, bridged_para_id: u32, - bridged_chain_id: bp_runtime::ChainId, sibling_parachain_id: u32, local_relay_chain_id: NetworkId, - lane_id: LaneId, - prepare_configuration: impl Fn(), + prepare_configuration: impl Fn() -> LaneId, construct_and_apply_extrinsic: fn( sp_keyring::AccountKeyring, ::RuntimeCall, @@ -268,16 +246,9 @@ pub fn free_relay_extrinsic_works( RuntimeCallOf: From> + From> + From>, - UnderlyingChainOf>: - bp_runtime::Chain + Parachain, + BridgedChainOf: Chain + Parachain, >::BridgedChain: bp_runtime::Chain + ChainWithGrandpa, - >::SourceHeaderChain: - SourceHeaderChain< - MessagesProof = FromBridgedChainMessagesProof< - HashOf>, - >, - >, { // ensure that the runtime allows free header submissions let free_headers_interval = ( relayer_id_at_bridged_chain, message_destination, message_nonce, - xcm| { - prepare_configuration(); + xcm, + bridged_chain_id| { + let lane_id = prepare_configuration(); // start with bridged relay chain block#0 let initial_block_number = 0; @@ -338,8 +310,8 @@ pub fn free_relay_extrinsic_works( message_proof, ) = test_data::from_parachain::make_complex_relayer_delivery_proofs::< >::BridgedChain, - RuntimeHelper::MB, - (), + BridgedChainOf, + ThisChainOf, >( lane_id, xcm.into(), @@ -390,7 +362,7 @@ pub fn free_relay_extrinsic_works( ( BridgeMessagesCall::::receive_messages_proof { relayer_id_at_bridged_chain, - proof: message_proof, + proof: Box::new(message_proof), messages_count: 1, dispatch_weight: Weight::from_parts(1000000000, 0), }.into(), @@ -423,10 +395,8 @@ pub fn complex_relay_extrinsic_works( runtime_para_id: u32, bridged_para_id: u32, sibling_parachain_id: u32, - bridged_chain_id: bp_runtime::ChainId, local_relay_chain_id: NetworkId, - lane_id: LaneId, - prepare_configuration: impl Fn(), + prepare_configuration: impl Fn() -> LaneId, construct_and_apply_extrinsic: fn( sp_keyring::AccountKeyring, ::RuntimeCall, @@ -440,16 +410,9 @@ pub fn complex_relay_extrinsic_works( + From> + From> + From>, - UnderlyingChainOf>: - bp_runtime::Chain + Parachain, + BridgedChainOf: Chain + Parachain, >::BridgedChain: bp_runtime::Chain + ChainWithGrandpa, - >::SourceHeaderChain: - SourceHeaderChain< - MessagesProof = FromBridgedChainMessagesProof< - HashOf>, - >, - >, { helpers::relayed_incoming_message_works::< RuntimeHelper::Runtime, @@ -466,11 +429,12 @@ pub fn complex_relay_extrinsic_works( relayer_id_at_bridged_chain, message_destination, message_nonce, - xcm| { + xcm, + bridged_chain_id| { let para_header_number = 5; let relay_header_number = 1; - prepare_configuration(); + let lane_id = prepare_configuration(); // start with bridged relay chain block#0 helpers::initialize_bridge_grandpa_pallet::( @@ -488,8 +452,8 @@ pub fn complex_relay_extrinsic_works( message_proof, ) = test_data::from_parachain::make_complex_relayer_delivery_proofs::< >::BridgedChain, - RuntimeHelper::MB, - (), + BridgedChainOf, + ThisChainOf, >( lane_id, xcm.into(), @@ -518,7 +482,7 @@ pub fn complex_relay_extrinsic_works( }.into(), BridgeMessagesCall::::receive_messages_proof { relayer_id_at_bridged_chain, - proof: message_proof, + proof: Box::new(message_proof), messages_count: 1, dispatch_weight: Weight::from_parts(1000000000, 0), }.into(), @@ -565,16 +529,9 @@ where RuntimeCallOf: From> + From> + From>, - UnderlyingChainOf>: - bp_runtime::Chain + Parachain, + BridgedChainOf: Chain + Parachain, >::BridgedChain: bp_runtime::Chain + ChainWithGrandpa, - >::SourceHeaderChain: - SourceHeaderChain< - MessagesProof = FromBridgedChainMessagesProof< - HashOf>, - >, - >, { run_test::(collator_session_key, 1000, vec![], || { // generate bridged relay chain finality, parachain heads and message proofs, @@ -592,8 +549,8 @@ where message_proof, ) = test_data::from_parachain::make_complex_relayer_delivery_proofs::< >::BridgedChain, - RuntimeHelper::MB, - (), + BridgedChainOf, + ThisChainOf, >( LaneId::default(), vec![Instruction::<()>::ClearOrigin; 1_024].into(), @@ -612,7 +569,6 @@ where RuntimeHelper::GPI, RuntimeHelper::PPI, RuntimeHelper::MPI, - _, >( relay_chain_header, grandpa_justification, @@ -637,23 +593,14 @@ where AccountIdOf: From, RuntimeHelper::Runtime: pallet_utility::Config>, - MessageThisChain: - bp_runtime::Chain>, + ThisChainOf: + Chain>, RuntimeCallOf: From> + From> + From>, - UnderlyingChainOf>: - bp_runtime::Chain + Parachain, + BridgedChainOf: Chain + Parachain, >::BridgedChain: bp_runtime::Chain + ChainWithGrandpa, - >::TargetHeaderChain: - TargetHeaderChain< - XcmAsPlainPayload, - AccountIdOf, - MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof< - HashOf>>, - >, - >, { run_test::(collator_session_key, 1000, vec![], || { // generate bridged relay chain finality, parachain heads and message proofs, @@ -672,8 +619,8 @@ where message_delivery_proof, ) = test_data::from_parachain::make_complex_relayer_confirmation_proofs::< >::BridgedChain, - RuntimeHelper::MB, - (), + BridgedChainOf, + ThisChainOf, >( LaneId::default(), 1, @@ -714,16 +661,9 @@ where RuntimeHelper: WithRemoteParachainHelper, RuntimeCallOf: From>, - UnderlyingChainOf>: - bp_runtime::Chain + Parachain, + BridgedChainOf: Chain + Parachain, >::BridgedChain: bp_runtime::Chain + ChainWithGrandpa, - >::SourceHeaderChain: - SourceHeaderChain< - MessagesProof = FromBridgedChainMessagesProof< - HashOf>, - >, - >, { run_test::(collator_session_key, 1000, vec![], || { // generate bridged relay chain finality, parachain heads and message proofs, @@ -741,8 +681,8 @@ where message_proof, ) = test_data::from_parachain::make_complex_relayer_delivery_proofs::< >::BridgedChain, - RuntimeHelper::MB, - (), + BridgedChainOf, + ThisChainOf, >( LaneId::default(), vec![Instruction::<()>::ClearOrigin; 1_024].into(), @@ -757,7 +697,6 @@ where let call = test_data::from_parachain::make_standalone_relayer_delivery_call::< RuntimeHelper::Runtime, RuntimeHelper::MPI, - _, >( message_proof, helpers::relayer_id_at_bridged_chain::(), @@ -778,22 +717,13 @@ pub fn can_calculate_fee_for_standalone_message_confirmation_transaction: From, - MessageThisChain: - bp_runtime::Chain>, + ThisChainOf: + Chain>, RuntimeCallOf: From>, - UnderlyingChainOf>: - bp_runtime::Chain + Parachain, + BridgedChainOf: Chain + Parachain, >::BridgedChain: bp_runtime::Chain + ChainWithGrandpa, - >::TargetHeaderChain: - TargetHeaderChain< - XcmAsPlainPayload, - AccountIdOf, - MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof< - HashOf>>, - >, - >, { run_test::(collator_session_key, 1000, vec![], || { // generate bridged relay chain finality, parachain heads and message proofs, @@ -806,8 +736,8 @@ where let (_, _, _, _, _, message_delivery_proof) = test_data::from_parachain::make_complex_relayer_confirmation_proofs::< >::BridgedChain, - RuntimeHelper::MB, - (), + BridgedChainOf, + ThisChainOf, >( LaneId::default(), 1, diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs index 0ce049cd1c4630c55c244afbc8a72213cb83d6b9..c4b5e5583baa0d9a22307e7f1fcb52ca5e95b0e9 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs @@ -22,13 +22,16 @@ use asset_test_utils::BasicParachainRuntime; use bp_messages::{LaneId, MessageNonce}; use bp_polkadot_core::parachains::{ParaHash, ParaId}; use bp_relayers::RewardsAccountParams; +use bp_runtime::Chain; use codec::Decode; +use core::marker::PhantomData; use frame_support::{ assert_ok, traits::{OnFinalize, OnInitialize, PalletInfoAccess}, }; use frame_system::pallet_prelude::BlockNumberFor; use pallet_bridge_grandpa::{BridgedBlockHash, BridgedHeader}; +use pallet_bridge_messages::BridgedChainOf; use parachains_common::AccountId; use parachains_runtimes_test_utils::{ mock_open_hrmp_channel, AccountIdOf, CollatorSessionKeys, RuntimeCallOf, SlotDurations, @@ -36,7 +39,6 @@ use parachains_runtimes_test_utils::{ use sp_core::Get; use sp_keyring::AccountKeyring::*; use sp_runtime::{traits::TrailingZeroInput, AccountId32}; -use sp_std::marker::PhantomData; use xcm::latest::prelude::*; /// Verify that the transaction has succeeded. @@ -240,10 +242,12 @@ pub(crate) fn initialize_bridge_grandpa_pallet( pub type CallsAndVerifiers = Vec<(RuntimeCallOf, Box)>; +pub type InboundRelayerId = bp_runtime::AccountIdOf>; + /// Returns relayer id at the bridged chain. pub fn relayer_id_at_bridged_chain, MPI>( -) -> Runtime::InboundRelayer { - Runtime::InboundRelayer::decode(&mut TrailingZeroInput::zeroes()).unwrap() +) -> InboundRelayerId { + Decode::decode(&mut TrailingZeroInput::zeroes()).unwrap() } /// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer, @@ -260,10 +264,11 @@ pub fn relayed_incoming_message_works( ) -> sp_runtime::DispatchOutcome, prepare_message_proof_import: impl FnOnce( Runtime::AccountId, - Runtime::InboundRelayer, + InboundRelayerId, InteriorLocation, MessageNonce, Xcm<()>, + bp_runtime::ChainId, ) -> CallsAndVerifiers, ) where Runtime: BasicParachainRuntime + cumulus_pallet_xcmp_queue::Config + BridgeMessagesConfig, @@ -275,6 +280,7 @@ pub fn relayed_incoming_message_works( let relayer_at_target = Bob; let relayer_id_on_target: AccountId32 = relayer_at_target.public().into(); let relayer_id_on_source = relayer_id_at_bridged_chain::(); + let bridged_chain_id = Runtime::BridgedChain::ID; assert_ne!(runtime_para_id, sibling_parachain_id); @@ -287,7 +293,7 @@ pub fn relayed_incoming_message_works( // value here is tricky - there are several transaction payment pallets and we don't // want to introduce additional bounds and traits here just for that, so let's just // select some presumably large value - sp_std::cmp::max::(Runtime::ExistentialDeposit::get(), 1u32.into()) * + core::cmp::max::(Runtime::ExistentialDeposit::get(), 1u32.into()) * 100_000_000u32.into(), )], || { @@ -336,6 +342,7 @@ pub fn relayed_incoming_message_works( message_destination, message_nonce, xcm.clone().into(), + bridged_chain_id, ), ); diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs index bc1c7ec5e032c08fb36b3005d4abcaf24bb43ff4..a36a74dbbbc3ab4ec8413f1b92ede16289600413 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs @@ -320,10 +320,9 @@ pub fn handle_export_message_from_system_parachain_to_outbound_queue_works< dyn Fn(Vec) -> Option>, >, export_message_instruction: fn() -> Instruction, - expected_lane_id: LaneId, existential_deposit: Option, maybe_paid_export_message: Option, - prepare_configuration: impl Fn(), + prepare_configuration: impl Fn() -> LaneId, ) where Runtime: BasicParachainRuntime + BridgeMessagesConfig, XcmConfig: xcm_executor::Config, @@ -333,7 +332,7 @@ pub fn handle_export_message_from_system_parachain_to_outbound_queue_works< let sibling_parachain_location = Location::new(1, [Parachain(sibling_parachain_id)]); run_test::(collator_session_key, runtime_para_id, vec![], || { - prepare_configuration(); + let expected_lane_id = prepare_configuration(); // check queue before assert_eq!( @@ -430,8 +429,7 @@ pub fn message_dispatch_routing_works< unwrap_cumulus_pallet_xcmp_queue_event: Box< dyn Fn(Vec) -> Option>, >, - expected_lane_id: LaneId, - prepare_configuration: impl Fn(), + prepare_configuration: impl Fn() -> LaneId, ) where Runtime: BasicParachainRuntime + cumulus_pallet_xcmp_queue::Config @@ -459,7 +457,7 @@ pub fn message_dispatch_routing_works< assert_ne!(runtime_para_id, sibling_parachain_id); run_test::(collator_session_key, runtime_para_id, vec![], || { - prepare_configuration(); + let expected_lane_id = prepare_configuration(); let mut alice = [0u8; 32]; alice[0] = 1; diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs index e5d5e7cac96ba14f6abfdae792908352f40d3e31..5c1dc492a9d2999e6473ca98ece70ffd4d7de905 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs @@ -19,30 +19,29 @@ use crate::test_data::prepare_inbound_xcm; use bp_messages::{ - source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, LaneId, MessageNonce, + source_chain::FromBridgedChainMessagesDeliveryProof, + target_chain::FromBridgedChainMessagesProof, ChainWithMessages, LaneId, MessageNonce, UnrewardedRelayersState, }; -use bp_runtime::{AccountIdOf, BlockNumberOf, HeaderOf, StorageProofSize, UnderlyingChainOf}; +use bp_runtime::{AccountIdOf, BlockNumberOf, Chain, HeaderOf, UnverifiedStorageProofParams}; use bp_test_utils::make_default_justification; -use bridge_runtime_common::{ - messages::{ - source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, - BridgedChain as MessageBridgedChain, MessageBridge, ThisChain as MessageThisChain, - }, - messages_generation::{ - encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof, - prepare_messages_storage_proof, - }, - messages_xcm_extension::XcmAsPlainPayload, -}; +use bridge_runtime_common::messages_xcm_extension::XcmAsPlainPayload; use codec::Encode; use pallet_bridge_grandpa::{BridgedChain, BridgedHeader}; use sp_runtime::traits::Header as HeaderT; use xcm::latest::prelude::*; +use crate::test_cases::helpers::InboundRelayerId; use bp_header_chain::{justification::GrandpaJustification, ChainWithGrandpa}; use bp_messages::{DeliveredMessages, InboundLaneData, UnrewardedRelayer}; use bp_runtime::HashOf; +use pallet_bridge_messages::{ + messages_generation::{ + encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof, + prepare_messages_storage_proof, + }, + BridgedChainOf, +}; use sp_runtime::DigestItem; /// Prepare a batch call with bridged GRANDPA finality and message proof. @@ -50,22 +49,17 @@ pub fn make_complex_relayer_delivery_batch( bridged_header: BridgedHeader, bridged_justification: GrandpaJustification>, message_proof: FromBridgedChainMessagesProof>>, - relayer_id_at_bridged_chain: AccountIdOf>, + relayer_id_at_bridged_chain: InboundRelayerId, ) -> pallet_utility::Call where Runtime: pallet_bridge_grandpa::Config - + pallet_bridge_messages::Config< - MPI, - InboundPayload = XcmAsPlainPayload, - InboundRelayer = AccountIdOf>, - > + pallet_utility::Config, + + pallet_bridge_messages::Config + + pallet_utility::Config, GPI: 'static, MPI: 'static, - >::SourceHeaderChain: SourceHeaderChain< - MessagesProof = FromBridgedChainMessagesProof>>, - >, ::RuntimeCall: From> + From>, + BridgedChainOf: Chain>>, { let submit_grandpa = pallet_bridge_grandpa::Call::::submit_finality_proof { finality_target: Box::new(bridged_header), @@ -73,7 +67,7 @@ where }; let submit_message = pallet_bridge_messages::Call::::receive_messages_proof { relayer_id_at_bridged_chain, - proof: message_proof, + proof: Box::new(message_proof), messages_count: 1, dispatch_weight: Weight::from_parts(1000000000, 0), }; @@ -97,15 +91,9 @@ where + pallet_utility::Config, GPI: 'static, MPI: 'static, - >::TargetHeaderChain: TargetHeaderChain< - XcmAsPlainPayload, - Runtime::AccountId, - MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof< - HashOf>, - >, - >, ::RuntimeCall: From> + From>, + BridgedChainOf: Chain>>, { let submit_grandpa = pallet_bridge_grandpa::Call::::submit_finality_proof { finality_target: Box::new(bridged_header), @@ -124,24 +112,18 @@ where /// Prepare a call with message proof. pub fn make_standalone_relayer_delivery_call( message_proof: FromBridgedChainMessagesProof>>, - relayer_id_at_bridged_chain: AccountIdOf>, + relayer_id_at_bridged_chain: InboundRelayerId, ) -> Runtime::RuntimeCall where Runtime: pallet_bridge_grandpa::Config - + pallet_bridge_messages::Config< - MPI, - InboundPayload = XcmAsPlainPayload, - InboundRelayer = AccountIdOf>, - >, + + pallet_bridge_messages::Config, MPI: 'static, - >::SourceHeaderChain: SourceHeaderChain< - MessagesProof = FromBridgedChainMessagesProof>>, - >, Runtime::RuntimeCall: From>, + BridgedChainOf: Chain>>, { pallet_bridge_messages::Call::::receive_messages_proof { relayer_id_at_bridged_chain, - proof: message_proof, + proof: Box::new(message_proof), messages_count: 1, dispatch_weight: Weight::from_parts(1000000000, 0), } @@ -159,14 +141,8 @@ where Runtime: pallet_bridge_grandpa::Config + pallet_bridge_messages::Config, MPI: 'static, - >::TargetHeaderChain: TargetHeaderChain< - XcmAsPlainPayload, - Runtime::AccountId, - MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof< - HashOf>, - >, - >, Runtime::RuntimeCall: From>, + BridgedChainOf: Chain>>, { pallet_bridge_messages::Call::::receive_messages_delivery_proof { proof: message_delivery_proof, @@ -176,39 +152,43 @@ where } /// Prepare storage proofs of messages, stored at the (bridged) source GRANDPA chain. -pub fn make_complex_relayer_delivery_proofs( +pub fn make_complex_relayer_delivery_proofs( lane_id: LaneId, - xcm_message: Xcm, + xcm_message: Xcm<()>, message_nonce: MessageNonce, message_destination: Junctions, - header_number: BlockNumberOf>, + header_number: BlockNumberOf, is_minimal_call: bool, ) -> ( - HeaderOf>, - GrandpaJustification>>, - FromBridgedChainMessagesProof>>, + HeaderOf, + GrandpaJustification>, + FromBridgedChainMessagesProof>, ) where - MB: MessageBridge, - MessageBridgedChain: Send + Sync + 'static, - UnderlyingChainOf>: ChainWithGrandpa, + BridgedChain: ChainWithGrandpa, + ThisChainWithMessages: ChainWithMessages, { + // prepare message let message_payload = prepare_inbound_xcm(xcm_message, message_destination); - let message_size = StorageProofSize::Minimal(message_payload.len() as u32); - // prepare para storage proof containing message - let (state_root, storage_proof) = prepare_messages_storage_proof::( - lane_id, - message_nonce..=message_nonce, - None, - message_size, - message_payload, - encode_all_messages, - encode_lane_data, - ); + // prepare storage proof containing message + let (state_root, storage_proof) = + prepare_messages_storage_proof::( + lane_id, + message_nonce..=message_nonce, + None, + UnverifiedStorageProofParams::from_db_size(message_payload.len() as u32), + |_| message_payload.clone(), + encode_all_messages, + encode_lane_data, + false, + false, + ); - let (header, justification) = make_complex_bridged_grandpa_header_proof::< - MessageBridgedChain, - >(state_root, header_number, is_minimal_call); + let (header, justification) = make_complex_bridged_grandpa_header_proof::( + state_root, + header_number, + is_minimal_call, + ); let message_proof = FromBridgedChainMessagesProof { bridged_header_hash: header.hash(), @@ -222,44 +202,44 @@ where } /// Prepare storage proofs of message confirmations, stored at the (bridged) target GRANDPA chain. -pub fn make_complex_relayer_confirmation_proofs( +pub fn make_complex_relayer_confirmation_proofs< + BridgedChain, + ThisChainWithMessages, + InnerXcmRuntimeCall, +>( lane_id: LaneId, - header_number: BlockNumberOf>, - relayer_id_at_this_chain: AccountIdOf>, + header_number: BlockNumberOf, + relayer_id_at_this_chain: AccountIdOf, relayers_state: UnrewardedRelayersState, ) -> ( - HeaderOf>, - GrandpaJustification>>, - FromBridgedChainMessagesDeliveryProof>>, + HeaderOf, + GrandpaJustification>, + FromBridgedChainMessagesDeliveryProof>, ) where - MB: MessageBridge, - MessageBridgedChain: Send + Sync + 'static, - MessageThisChain: Send + Sync + 'static, - UnderlyingChainOf>: ChainWithGrandpa, + BridgedChain: ChainWithGrandpa, + ThisChainWithMessages: ChainWithMessages, { // prepare storage proof containing message delivery proof - let (state_root, storage_proof) = prepare_message_delivery_storage_proof::( - lane_id, - InboundLaneData { - relayers: vec![ - UnrewardedRelayer { - relayer: relayer_id_at_this_chain, - messages: DeliveredMessages::new(1) - }; - relayers_state.unrewarded_relayer_entries as usize - ] - .into(), - last_confirmed_nonce: 1, - }, - StorageProofSize::Minimal(0), - ); + let (state_root, storage_proof) = + prepare_message_delivery_storage_proof::( + lane_id, + InboundLaneData { + relayers: vec![ + UnrewardedRelayer { + relayer: relayer_id_at_this_chain, + messages: DeliveredMessages::new(1) + }; + relayers_state.unrewarded_relayer_entries as usize + ] + .into(), + last_confirmed_nonce: 1, + }, + UnverifiedStorageProofParams::default(), + ); - let (header, justification) = make_complex_bridged_grandpa_header_proof::( - state_root, - header_number, - false, - ); + let (header, justification) = + make_complex_bridged_grandpa_header_proof::(state_root, header_number, false); let message_delivery_proof = FromBridgedChainMessagesDeliveryProof { bridged_header_hash: header.hash(), diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs index 5d3cba4e53b5ec7ec9cd2e6141e6e95aa8928970..b99c275bd0df94856eedcc1cc008c1d7a0b1a673 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs @@ -19,61 +19,58 @@ use super::{from_grandpa_chain::make_complex_bridged_grandpa_header_proof, prepare_inbound_xcm}; use bp_messages::{ - source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, LaneId, + source_chain::FromBridgedChainMessagesDeliveryProof, + target_chain::FromBridgedChainMessagesProof, ChainWithMessages, LaneId, UnrewardedRelayersState, Weight, }; use bp_runtime::{ - AccountIdOf, BlockNumberOf, HeaderOf, Parachain, StorageProofSize, UnderlyingChainOf, + AccountIdOf, BlockNumberOf, Chain, HeaderOf, Parachain, UnverifiedStorageProofParams, }; use bp_test_utils::prepare_parachain_heads_proof; -use bridge_runtime_common::{ - messages::{ - source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, - BridgedChain as MessageBridgedChain, MessageBridge, ThisChain as MessageThisChain, - }, - messages_generation::{ - encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof, - prepare_messages_storage_proof, - }, - messages_xcm_extension::XcmAsPlainPayload, -}; +use bridge_runtime_common::messages_xcm_extension::XcmAsPlainPayload; use codec::Encode; use pallet_bridge_grandpa::BridgedHeader; use pallet_bridge_parachains::{RelayBlockHash, RelayBlockNumber}; use sp_runtime::traits::Header as HeaderT; use xcm::latest::prelude::*; +use crate::test_cases::helpers::InboundRelayerId; use bp_header_chain::{justification::GrandpaJustification, ChainWithGrandpa}; use bp_messages::{DeliveredMessages, InboundLaneData, MessageNonce, UnrewardedRelayer}; use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}; +use pallet_bridge_messages::{ + messages_generation::{ + encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof, + prepare_messages_storage_proof, + }, + BridgedChainOf, +}; use sp_runtime::SaturatedConversion; /// Prepare a batch call with relay finality proof, parachain head proof and message proof. -pub fn make_complex_relayer_delivery_batch( +pub fn make_complex_relayer_delivery_batch( relay_chain_header: BridgedHeader, grandpa_justification: GrandpaJustification>, parachain_heads: Vec<(ParaId, ParaHash)>, para_heads_proof: ParaHeadsProof, message_proof: FromBridgedChainMessagesProof, - relayer_id_at_bridged_chain: InboundRelayer, -) -> pallet_utility::Call where - Runtime:pallet_bridge_grandpa::Config + relayer_id_at_bridged_chain: InboundRelayerId, +) -> pallet_utility::Call +where + Runtime: pallet_bridge_grandpa::Config + pallet_bridge_parachains::Config - + pallet_bridge_messages::Config< - MPI, - InboundPayload = XcmAsPlainPayload, - InboundRelayer = InboundRelayer, - > + + pallet_bridge_messages::Config + pallet_utility::Config, GPI: 'static, PPI: 'static, MPI: 'static, - ParaHash: From<<>::BridgedChain as bp_runtime::Chain>::Hash>, - <>::BridgedChain as bp_runtime::Chain>::Hash: From, - <>::SourceHeaderChain as SourceHeaderChain>::MessagesProof: - From>, - ::RuntimeCall: - From> + ParaHash: From< + <>::BridgedChain as bp_runtime::Chain>::Hash, + >, + <>::BridgedChain as bp_runtime::Chain>::Hash: + From, + BridgedChainOf: Chain + Parachain, + ::RuntimeCall: From> + From> + From>, { @@ -93,7 +90,7 @@ pub fn make_complex_relayer_delivery_batch::receive_messages_proof { relayer_id_at_bridged_chain: relayer_id_at_bridged_chain.into(), - proof: message_proof.into(), + proof: Box::new(message_proof), messages_count: 1, dispatch_weight: Weight::from_parts(1000000000, 0), }; @@ -122,11 +119,7 @@ where MPI: 'static, >::BridgedChain: bp_runtime::Chain + ChainWithGrandpa, - >::TargetHeaderChain: TargetHeaderChain< - XcmAsPlainPayload, - Runtime::AccountId, - MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof, - >, + BridgedChainOf: Chain + Parachain, ::RuntimeCall: From> + From> + From>, @@ -160,23 +153,19 @@ where } /// Prepare a call with message proof. -pub fn make_standalone_relayer_delivery_call( +pub fn make_standalone_relayer_delivery_call( message_proof: FromBridgedChainMessagesProof, - relayer_id_at_bridged_chain: InboundRelayer, -) -> Runtime::RuntimeCall where - Runtime: pallet_bridge_messages::Config< - MPI, - InboundPayload = XcmAsPlainPayload, - InboundRelayer = InboundRelayer, - >, + relayer_id_at_bridged_chain: InboundRelayerId, +) -> Runtime::RuntimeCall +where + Runtime: pallet_bridge_messages::Config, MPI: 'static, - Runtime::RuntimeCall: From>, - <>::SourceHeaderChain as SourceHeaderChain>::MessagesProof: - From>, + Runtime::RuntimeCall: From>, + BridgedChainOf: Chain + Parachain, { pallet_bridge_messages::Call::::receive_messages_proof { relayer_id_at_bridged_chain: relayer_id_at_bridged_chain.into(), - proof: message_proof.into(), + proof: Box::new(message_proof), messages_count: 1, dispatch_weight: Weight::from_parts(1000000000, 0), } @@ -192,11 +181,7 @@ where Runtime: pallet_bridge_messages::Config, MPI: 'static, Runtime::RuntimeCall: From>, - >::TargetHeaderChain: TargetHeaderChain< - XcmAsPlainPayload, - Runtime::AccountId, - MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof, - >, + BridgedChainOf: Chain + Parachain, { pallet_bridge_messages::Call::::receive_messages_delivery_proof { proof: message_delivery_proof, @@ -206,9 +191,13 @@ where } /// Prepare storage proofs of messages, stored at the source chain. -pub fn make_complex_relayer_delivery_proofs( +pub fn make_complex_relayer_delivery_proofs< + BridgedRelayChain, + BridgedParachain, + ThisChainWithMessages, +>( lane_id: LaneId, - xcm_message: Xcm, + xcm_message: Xcm<()>, message_nonce: MessageNonce, message_destination: Junctions, para_header_number: u32, @@ -226,24 +215,27 @@ pub fn make_complex_relayer_delivery_proofs + ChainWithGrandpa, - MB: MessageBridge, - UnderlyingChainOf>: bp_runtime::Chain + Parachain, + BridgedParachain: bp_runtime::Chain + Parachain, + ThisChainWithMessages: ChainWithMessages, { + // prepare message let message_payload = prepare_inbound_xcm(xcm_message, message_destination); - let message_size = StorageProofSize::Minimal(message_payload.len() as u32); // prepare para storage proof containing message - let (para_state_root, para_storage_proof) = prepare_messages_storage_proof::( - lane_id, - message_nonce..=message_nonce, - None, - message_size, - message_payload, - encode_all_messages, - encode_lane_data, - ); + let (para_state_root, para_storage_proof) = + prepare_messages_storage_proof::( + lane_id, + message_nonce..=message_nonce, + None, + UnverifiedStorageProofParams::from_db_size(message_payload.len() as u32), + |_| message_payload.clone(), + encode_all_messages, + encode_lane_data, + false, + false, + ); let (relay_chain_header, justification, bridged_para_head, parachain_heads, para_heads_proof) = - make_complex_bridged_parachain_heads_proof::( + make_complex_bridged_parachain_heads_proof::( para_state_root, para_header_number, relay_header_number, @@ -270,12 +262,16 @@ where } /// Prepare storage proofs of message confirmations, stored at the target parachain. -pub fn make_complex_relayer_confirmation_proofs( +pub fn make_complex_relayer_confirmation_proofs< + BridgedRelayChain, + BridgedParachain, + ThisChainWithMessages, +>( lane_id: LaneId, para_header_number: u32, relay_header_number: u32, bridged_para_id: u32, - relayer_id_at_this_chain: AccountIdOf>, + relayer_id_at_this_chain: AccountIdOf, relayers_state: UnrewardedRelayersState, ) -> ( HeaderOf, @@ -288,28 +284,29 @@ pub fn make_complex_relayer_confirmation_proofs + ChainWithGrandpa, - MB: MessageBridge, - UnderlyingChainOf>: bp_runtime::Chain + Parachain, + BridgedParachain: bp_runtime::Chain + Parachain, + ThisChainWithMessages: ChainWithMessages, { // prepare para storage proof containing message delivery proof - let (para_state_root, para_storage_proof) = prepare_message_delivery_storage_proof::( - lane_id, - InboundLaneData { - relayers: vec![ - UnrewardedRelayer { - relayer: relayer_id_at_this_chain.into(), - messages: DeliveredMessages::new(1) - }; - relayers_state.unrewarded_relayer_entries as usize - ] - .into(), - last_confirmed_nonce: 1, - }, - StorageProofSize::Minimal(0), - ); + let (para_state_root, para_storage_proof) = + prepare_message_delivery_storage_proof::( + lane_id, + InboundLaneData { + relayers: vec![ + UnrewardedRelayer { + relayer: relayer_id_at_this_chain.into(), + messages: DeliveredMessages::new(1) + }; + relayers_state.unrewarded_relayer_entries as usize + ] + .into(), + last_confirmed_nonce: 1, + }, + UnverifiedStorageProofParams::default(), + ); let (relay_chain_header, justification, bridged_para_head, parachain_heads, para_heads_proof) = - make_complex_bridged_parachain_heads_proof::( + make_complex_bridged_parachain_heads_proof::( para_state_root, para_header_number, relay_header_number, @@ -334,7 +331,7 @@ where } /// Make bridged parachain header with given state root and relay header that is finalizing it. -pub fn make_complex_bridged_parachain_heads_proof( +pub fn make_complex_bridged_parachain_heads_proof( para_state_root: ParaHash, para_header_number: u32, relay_header_number: BlockNumberOf, @@ -350,20 +347,17 @@ pub fn make_complex_bridged_parachain_heads_proof( where BridgedRelayChain: bp_runtime::Chain + ChainWithGrandpa, - MB: MessageBridge, - ::BridgedChain: Send + Sync + 'static, - ::ThisChain: Send + Sync + 'static, - UnderlyingChainOf>: bp_runtime::Chain + Parachain, + BridgedParachain: bp_runtime::Chain + Parachain, { let bridged_para_head = ParaHead( - bp_test_utils::test_header_with_root::>( + bp_test_utils::test_header_with_root::>( para_header_number.into(), para_state_root, ) .encode(), ); let (relay_state_root, para_heads_proof, parachain_heads) = - prepare_parachain_heads_proof::>(vec![( + prepare_parachain_heads_proof::>(vec![( bridged_para_id, bridged_para_head.clone(), )]); diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/mod.rs index ee3fc1ed2c41f1ff2a729dcf784f832a5a563a58..106eacd799ca3aee1daea2769423976154d50337 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/mod.rs @@ -32,20 +32,16 @@ use bp_messages::MessageNonce; use bp_runtime::BasicOperatingMode; use bp_test_utils::authority_list; use xcm::GetVersion; -use xcm_builder::{HaulBlob, HaulBlobError, HaulBlobExporter}; +use xcm_builder::{BridgeMessage, HaulBlob, HaulBlobError, HaulBlobExporter}; use xcm_executor::traits::{validate_export, ExportXcm}; -pub fn prepare_inbound_xcm( - xcm_message: Xcm, - destination: InteriorLocation, -) -> Vec { +pub fn prepare_inbound_xcm(xcm_message: Xcm<()>, destination: InteriorLocation) -> Vec { let location = xcm::VersionedInteriorLocation::from(destination); - let xcm = xcm::VersionedXcm::::from(xcm_message); - // this is the `BridgeMessage` from polkadot xcm builder, but it has no constructor - // or public fields, so just tuple - // (double encoding, because `.encode()` is called on original Xcm BLOB when it is pushed - // to the storage) - (location, xcm).encode().encode() + let xcm = xcm::VersionedXcm::<()>::from(xcm_message); + + // (double encoding, because `.encode()` is called on original Xcm BLOB when it is pushed to the + // storage) + BridgeMessage { universal_dest: location, message: xcm }.encode().encode() } /// Helper that creates InitializationData mock data, that can be used to initialize bridge diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index fe4de3114be0d0b92643946f0deafe030a8b88f8..43fc9083937c351d0df2190c7593bf1e8126e800 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -10,88 +10,87 @@ description = "Westend Collectives Parachain Runtime" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } -hex-literal = { version = "0.4.1" } +codec = { features = ["derive", "max-encoded-len"], workspace = true } +hex-literal = { workspace = true, default-features = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } # Substrate -frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../../substrate/frame/system", default-features = false } -frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true } -frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false } -frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } -pallet-asset-rate = { path = "../../../../../substrate/frame/asset-rate", default-features = false } -pallet-alliance = { path = "../../../../../substrate/frame/alliance", default-features = false } -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } -pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false } -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } -pallet-collective = { path = "../../../../../substrate/frame/collective", default-features = false } -pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false } -pallet-preimage = { path = "../../../../../substrate/frame/preimage", default-features = false } -pallet-proxy = { path = "../../../../../substrate/frame/proxy", default-features = false } -pallet-scheduler = { path = "../../../../../substrate/frame/scheduler", default-features = false } -pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } -pallet-state-trie-migration = { path = "../../../../../substrate/frame/state-trie-migration", default-features = false } -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } -pallet-treasury = { path = "../../../../../substrate/frame/treasury", default-features = false } -pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false } -pallet-referenda = { path = "../../../../../substrate/frame/referenda", default-features = false } -pallet-ranked-collective = { path = "../../../../../substrate/frame/ranked-collective", default-features = false } -pallet-core-fellowship = { path = "../../../../../substrate/frame/core-fellowship", default-features = false } -pallet-salary = { path = "../../../../../substrate/frame/salary", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } -sp-arithmetic = { path = "../../../../../substrate/primitives/arithmetic", default-features = false } -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false } -sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } -sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false } -sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -sp-session = { path = "../../../../../substrate/primitives/session", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-storage = { path = "../../../../../substrate/primitives/storage", default-features = false } -sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } -sp-version = { path = "../../../../../substrate/primitives/version", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-executive = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-benchmarking = { optional = true, workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +frame-try-runtime = { optional = true, workspace = true } +pallet-asset-rate = { workspace = true } +pallet-alliance = { workspace = true } +pallet-aura = { workspace = true } +pallet-authorship = { workspace = true } +pallet-balances = { workspace = true } +pallet-collective = { workspace = true } +pallet-multisig = { workspace = true } +pallet-preimage = { workspace = true } +pallet-proxy = { workspace = true } +pallet-scheduler = { workspace = true } +pallet-session = { workspace = true } +pallet-state-trie-migration = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-treasury = { workspace = true } +pallet-utility = { workspace = true } +pallet-referenda = { workspace = true } +pallet-ranked-collective = { workspace = true } +pallet-core-fellowship = { workspace = true } +pallet-salary = { workspace = true } +sp-api = { workspace = true } +sp-arithmetic = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-core = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-storage = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } # Polkadot -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } -polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false } -polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } -xcm-fee-payment-runtime-api = { path = "../../../../../polkadot/xcm/xcm-fee-payment-runtime-api", default-features = false } -westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants", default-features = false } +pallet-xcm = { workspace = true } +polkadot-parachain-primitives = { workspace = true } +polkadot-runtime-common = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +westend-runtime-constants = { workspace = true } +xcm-runtime-apis = { workspace = true } # Cumulus -cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } -cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false } -cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } -cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } -cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } -cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } +cumulus-pallet-aura-ext = { workspace = true } +pallet-message-queue = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-session-benchmarking = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +cumulus-primitives-aura = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-utility = { workspace = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true } -pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } -pallet-collective-content = { path = "../../../pallets/collective-content", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } -testnet-parachains-constants = { path = "../../constants", default-features = false, features = ["westend"] } +pallet-collator-selection = { workspace = true } +pallet-collective-content = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } +testnet-parachains-constants = { features = ["westend"], workspace = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [dev-dependencies] -sp-io = { path = "../../../../../substrate/primitives/io", features = ["std"] } +sp-io = { features = ["std"], workspace = true, default-features = true } [features] default = ["std"] @@ -131,7 +130,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", - "xcm-fee-payment-runtime-api/runtime-benchmarks", + "xcm-runtime-apis/runtime-benchmarks", ] try-runtime = [ "cumulus-pallet-aura-ext/try-runtime", @@ -229,7 +228,6 @@ std = [ "sp-offchain/std", "sp-runtime/std", "sp-session/std", - "sp-std/std", "sp-storage/std", "sp-transaction-pool/std", "sp-version/std", @@ -238,7 +236,7 @@ std = [ "westend-runtime-constants/std", "xcm-builder/std", "xcm-executor/std", - "xcm-fee-payment-runtime-api/std", + "xcm-runtime-apis/std", "xcm/std", ] diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/mod.rs index ceef6de6b7435e453e9622a3d318669e1a3a9307..a052a9d3800cc6880ccee84358883194cb46eb80 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/mod.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/mod.rs @@ -117,6 +117,7 @@ impl pallet_ranked_collective::Config for Runtime type MinRankOfClass = sp_runtime::traits::Identity; type MemberSwappedHandler = (crate::AmbassadorCore, crate::AmbassadorSalary); type VoteWeight = pallet_ranked_collective::Linear; + type MaxMemberCount = (); #[cfg(feature = "runtime-benchmarks")] type BenchmarkSetup = (crate::AmbassadorCore, crate::AmbassadorSalary); } @@ -219,6 +220,7 @@ impl pallet_core_fellowship::Config for Runtime { >; type ApproveOrigin = PromoteOrigin; type PromoteOrigin = PromoteOrigin; + type FastPromoteOrigin = Self::PromoteOrigin; type EvidenceSize = ConstU32<65536>; type MaxRank = ConstU32<9>; } diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs index 6f13c3d9d5dec23021ce5207b42993a29319f23e..942e0c294dd022c7c4dacf4febaf99b6ac686dbf 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs @@ -30,7 +30,7 @@ use frame_support::{ parameter_types, traits::{ tokens::UnityOrOuterConversion, EitherOf, EitherOfDiverse, FromContains, MapSuccess, - NeverEnsureOrigin, OriginTrait, TryWithMorphedArg, + OriginTrait, TryWithMorphedArg, }, PalletId, }; @@ -150,6 +150,7 @@ impl pallet_ranked_collective::Config for Runtime type MinRankOfClass = tracks::MinRankOfClass; type MemberSwappedHandler = (crate::FellowshipCore, crate::FellowshipSalary); type VoteWeight = pallet_ranked_collective::Geometric; + type MaxMemberCount = (); #[cfg(feature = "runtime-benchmarks")] type BenchmarkSetup = (crate::FellowshipCore, crate::FellowshipSalary); } @@ -207,6 +208,7 @@ impl pallet_core_fellowship::Config for Runtime { >, EnsureCanPromoteTo, >; + type FastPromoteOrigin = Self::PromoteOrigin; type EvidenceSize = ConstU32<65536>; type MaxRank = ConstU32<9>; } @@ -283,14 +285,6 @@ pub type FellowshipTreasuryPaymaster = PayOverXcm< pub type FellowshipTreasuryInstance = pallet_treasury::Instance1; impl pallet_treasury::Config for Runtime { - // The creation of proposals via the treasury pallet is deprecated and should not be utilized. - // Instead, public or fellowship referenda should be used to propose and command the treasury - // spend or spend_local dispatchables. The parameters below have been configured accordingly to - // discourage its use. - // TODO: replace with `NeverEnsure` once polkadot-sdk 1.5 is released. - type ApproveOrigin = NeverEnsureOrigin<()>; - type OnSlash = (); - type WeightInfo = weights::pallet_treasury::WeightInfo; type PalletId = FellowshipTreasuryPalletId; type Currency = Balances; diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/impls.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/impls.rs index e5b176fc77873805fb0e4ed6dba74d720ea3479a..ed5d4870e4a6d1722e1587a650395c6dd2c742dd 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/impls.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/impls.rs @@ -14,6 +14,8 @@ // limitations under the License. use crate::OriginCaller; +use alloc::boxed::Box; +use core::{cmp::Ordering, marker::PhantomData}; use frame_support::{ dispatch::DispatchResultWithPostInfo, traits::{Currency, PrivilegeCmp}, @@ -21,7 +23,6 @@ use frame_support::{ }; use pallet_alliance::{ProposalIndex, ProposalProvider}; use sp_runtime::DispatchError; -use sp_std::{cmp::Ordering, marker::PhantomData, prelude::*}; type AccountIdOf = ::AccountId; diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index 1d3b8c4581a834dca11013e20e7c4fecadb5e61c..d843d6f6f776e0c4eadec44c72925a19402423df 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -42,8 +42,12 @@ mod weights; pub mod xcm_config; // Fellowship configurations. pub mod fellowship; + +extern crate alloc; + pub use ambassador::pallet_ambassador_origins; +use alloc::{vec, vec::Vec}; use ambassador::AmbassadorCoreInstance; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use fellowship::{pallet_fellowship_origins, Fellows, FellowshipCoreInstance}; @@ -57,7 +61,6 @@ use sp_runtime::{ ApplyExtrinsicResult, Perbill, }; -use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -70,8 +73,8 @@ use frame_support::{ genesis_builder_helper::{build_state, get_preset}, parameter_types, traits::{ - fungible::HoldConsideration, ConstBool, ConstU16, ConstU32, ConstU64, ConstU8, - EitherOfDiverse, InstanceFilter, LinearStoragePrice, TransformOrigin, + fungible::HoldConsideration, ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, + InstanceFilter, LinearStoragePrice, TransformOrigin, }, weights::{ConstantMultiplier, Weight, WeightToFee as _}, PalletId, @@ -104,7 +107,7 @@ use polkadot_runtime_common::{ impls::VersionedLocatableAsset, BlockHashCount, SlowAdjustingFeeUpdate, }; use xcm::prelude::*; -use xcm_fee_payment_runtime_api::{ +use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, }; @@ -122,7 +125,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("collectives-westend"), impl_name: create_runtime_str!("collectives-westend"), authoring_version: 1, - spec_version: 1_013_000, + spec_version: 1_014_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, @@ -163,6 +166,7 @@ parameter_types! { }) .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) .build_or_panic(); + pub const SS58Prefix: u8 = 42; } // Configure FRAME pallets to include in runtime. @@ -180,7 +184,7 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; - type SS58Prefix = ConstU16<0>; + type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = frame_support::traits::ConstU32<16>; } @@ -836,7 +840,7 @@ impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { Runtime::metadata_versions() } } @@ -940,7 +944,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { let acceptable_assets = vec![AssetId(xcm_config::WndLocation::get())]; PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) @@ -953,11 +957,11 @@ impl_runtime_apis! { Ok(WeightToFee::weight_to_fee(&weight)) }, Ok(asset_id) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); Err(XcmPaymentApiError::AssetNotFound) }, Err(_) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); Err(XcmPaymentApiError::VersionedConversionFailed) } } @@ -972,7 +976,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + impl xcm_runtime_apis::dry_run::DryRunApi for Runtime { fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { PolkadotXcm::dry_run_call::(origin, call) } @@ -982,6 +986,18 @@ impl_runtime_apis! { } } + impl xcm_runtime_apis::conversions::LocationToAccountApi for Runtime { + fn convert_location(location: VersionedLocation) -> Result< + AccountId, + xcm_runtime_apis::conversions::Error + > { + xcm_runtime_apis::conversions::LocationToAccountHelper::< + AccountId, + LocationToAccountId, + >::convert_location(location) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) @@ -1034,7 +1050,7 @@ impl_runtime_apis! { use frame_system_benchmarking::Pallet as SystemBench; impl frame_system_benchmarking::Config for Runtime { - fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { + fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); Ok(()) } @@ -1083,7 +1099,7 @@ impl_runtime_apis! { } fn set_up_complex_asset_transfer( - ) -> Option<(Assets, u32, Location, Box)> { + ) -> Option<(Assets, u32, Location, alloc::boxed::Box)> { // Collectives only supports teleports to system parachain. // Relay/native token can be teleported between Collectives and Relay. let native_location = Parent.into(); diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_parachain_system.rs index 0b7a2fc21cde4f12c821a0e89982db4813f3f832..92c8c88b515474ed5335f306c487ca1217a938b6 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_parachain_system.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_parachain_system.rs @@ -47,7 +47,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `cumulus_pallet_parachain_system`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_core_fellowship_ambassador_core.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_core_fellowship_ambassador_core.rs index dbe681f51bb2a8a1f61f9e923e16914dd2eb2fd8..6bedfcc7e012383657a059b87942517644057d8a 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_core_fellowship_ambassador_core.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_core_fellowship_ambassador_core.rs @@ -171,6 +171,20 @@ impl pallet_core_fellowship::WeightInfo for WeightInfo< .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(6)) } + fn promote_fast(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `16844` + // Estimated: `19894 + r * (2489 ยฑ0)` + // Minimum execution time: 45_065_000 picoseconds. + Weight::from_parts(34_090_392, 19894) + // Standard Error: 18_620 + .saturating_add(Weight::from_parts(13_578_046, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 2489).saturating_mul(r.into())) + } /// Storage: `AmbassadorCollective::Members` (r:1 w:0) /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) /// Storage: `AmbassadorCore::Member` (r:1 w:1) diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_core_fellowship_fellowship_core.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_core_fellowship_fellowship_core.rs index 7e6264c0c10d708f1a089cb861094e121f0c5604..05014e273f0009bf212969ba8705879747eedd75 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_core_fellowship_fellowship_core.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_core_fellowship_fellowship_core.rs @@ -170,6 +170,20 @@ impl pallet_core_fellowship::WeightInfo for WeightInfo< .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(6)) } + fn promote_fast(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `16844` + // Estimated: `19894 + r * (2489 ยฑ0)` + // Minimum execution time: 45_065_000 picoseconds. + Weight::from_parts(34_090_392, 19894) + // Standard Error: 18_620 + .saturating_add(Weight::from_parts(13_578_046, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 2489).saturating_mul(r.into())) + } /// Storage: `FellowshipCollective::Members` (r:1 w:0) /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) /// Storage: `FellowshipCore::Member` (r:1 w:1) diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_message_queue.rs index 4bd71c4e7d497b84f9a5b910015e439b69e41ef9..0bb6d3d0f1c451e6fd9bde07cced236845d380a6 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_message_queue.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_message_queue.rs @@ -43,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `pallet_message_queue`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs index c68f230a16dc3d35b861df5aa7667d61d4cf53cf..ae4fe9e84337b833c5188452ceea3e2769048d02 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs @@ -40,10 +40,10 @@ use xcm_builder::{ DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, IsConcrete, LocatableAssetId, OriginToPluralityVoice, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, - XcmFeeToAccount, + SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; @@ -209,7 +209,7 @@ impl xcm_executor::Config for XcmConfig { type AssetExchanger = (); type FeeManager = XcmFeeManagerFromComponents< WaivedLocations, - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = Nothing; diff --git a/cumulus/parachains/runtimes/constants/Cargo.toml b/cumulus/parachains/runtimes/constants/Cargo.toml index 561e8276b5f0543001e10fd21345ea5d3a65fee5..d54f1e7db6c167480858758bf56ed07941fb06c2 100644 --- a/cumulus/parachains/runtimes/constants/Cargo.toml +++ b/cumulus/parachains/runtimes/constants/Cargo.toml @@ -13,20 +13,20 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -smallvec = "1.11.0" +smallvec = { workspace = true, default-features = true } # Substrate -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } +frame-support = { workspace = true } +sp-runtime = { workspace = true } # Polkadot -polkadot-core-primitives = { path = "../../../../polkadot/core-primitives", default-features = false } -rococo-runtime-constants = { path = "../../../../polkadot/runtime/rococo/constants", default-features = false, optional = true } -westend-runtime-constants = { path = "../../../../polkadot/runtime/westend/constants", default-features = false, optional = true } -xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false } +polkadot-core-primitives = { workspace = true } +rococo-runtime-constants = { optional = true, workspace = true } +westend-runtime-constants = { optional = true, workspace = true } +xcm = { workspace = true } # Cumulus -cumulus-primitives-core = { path = "../../../primitives/core", default-features = false } +cumulus-primitives-core = { workspace = true } [features] default = ["std"] diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index e43a69482c79f1d67e30d6c65ea67840a7893816..1fcebb3f16a96d2db051ab1d0108d44abc394f4f 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -13,74 +13,73 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -hex-literal = { version = "0.4.1", optional = true } +codec = { features = ["derive"], workspace = true } +hex-literal = { optional = true, workspace = true, default-features = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } # Substrate -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false } -sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } -sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false } -sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -sp-session = { path = "../../../../../substrate/primitives/session", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-storage = { path = "../../../../../substrate/primitives/storage", default-features = false } -sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } -sp-version = { path = "../../../../../substrate/primitives/version", default-features = false } -frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } -frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../../substrate/frame/system", default-features = false } -frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true } -frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false } -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } -pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false } -pallet-insecure-randomness-collective-flip = { path = "../../../../../substrate/frame/insecure-randomness-collective-flip", default-features = false } -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } -pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false } -pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } -pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false } -pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false } -pallet-contracts = { path = "../../../../../substrate/frame/contracts", default-features = false } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-core = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-storage = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } +frame-benchmarking = { optional = true, workspace = true } +frame-try-runtime = { optional = true, workspace = true } +frame-executive = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-benchmarking = { optional = true, workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +pallet-aura = { workspace = true } +pallet-authorship = { workspace = true } +pallet-insecure-randomness-collective-flip = { workspace = true } +pallet-balances = { workspace = true } +pallet-multisig = { workspace = true } +pallet-session = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-utility = { workspace = true } +pallet-sudo = { workspace = true } +pallet-contracts = { workspace = true } # Polkadot -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } -polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false } -polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false } -rococo-runtime-constants = { path = "../../../../../polkadot/runtime/rococo/constants", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } -xcm-fee-payment-runtime-api = { path = "../../../../../polkadot/xcm/xcm-fee-payment-runtime-api", default-features = false } +pallet-xcm = { workspace = true } +polkadot-parachain-primitives = { workspace = true } +polkadot-runtime-common = { workspace = true } +rococo-runtime-constants = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm-runtime-apis = { workspace = true } # Cumulus -cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } -cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false } -cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } -cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } -cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } -cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } +cumulus-pallet-aura-ext = { workspace = true } +pallet-message-queue = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-session-benchmarking = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +cumulus-primitives-aura = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-utility = { workspace = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true } -pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } -testnet-parachains-constants = { path = "../../constants", default-features = false, features = ["rococo"] } +pallet-collator-selection = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } +testnet-parachains-constants = { features = ["rococo"], workspace = true } [features] default = ["std"] @@ -133,7 +132,6 @@ std = [ "sp-offchain/std", "sp-runtime/std", "sp-session/std", - "sp-std/std", "sp-storage/std", "sp-transaction-pool/std", "sp-version/std", @@ -141,7 +139,7 @@ std = [ "testnet-parachains-constants/std", "xcm-builder/std", "xcm-executor/std", - "xcm-fee-payment-runtime-api/std", + "xcm-runtime-apis/std", "xcm/std", ] @@ -171,7 +169,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", - "xcm-fee-payment-runtime-api/runtime-benchmarks", + "xcm-runtime-apis/runtime-benchmarks", ] try-runtime = [ diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs index fcd786711bbe90096f2ef5b8d427cec23879027b..e8cc9d02fb0e4c6ac2db7ada26a641fea055ea76 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs @@ -65,6 +65,7 @@ impl Config for Runtime { type AddressGenerator = DefaultAddressGenerator; type MaxCodeLen = ConstU32<{ 123 * 1024 }>; type MaxStorageKeyLen = ConstU32<128>; + type MaxTransientStorageSize = ConstU32<{ 1 * 1024 * 1024 }>; type UnsafeUnstableInterface = ConstBool; type UploadOrigin = EnsureSigned; type InstantiateOrigin = EnsureSigned; diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 59aae99d6a16169e7df72ff1fa9c8570fc56f855..47ce6f3628ecdd6a426ccbed9f503258d3c6171a 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -29,6 +29,9 @@ mod contracts; mod weights; mod xcm_config; +extern crate alloc; + +use alloc::{vec, vec::Vec}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use cumulus_primitives_core::AggregateMessageOrigin; use sp_api::impl_runtime_apis; @@ -40,7 +43,6 @@ use sp_runtime::{ ApplyExtrinsicResult, Perbill, }; -use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -50,7 +52,7 @@ use frame_support::{ dispatch::DispatchClass, genesis_builder_helper::{build_state, get_preset}, parameter_types, - traits::{ConstBool, ConstU16, ConstU32, ConstU64, ConstU8}, + traits::{ConstBool, ConstU32, ConstU64, ConstU8}, weights::{ConstantMultiplier, Weight, WeightToFee as _}, PalletId, }; @@ -64,7 +66,7 @@ pub use parachains_common::{AuraId, Balance}; use testnet_parachains_constants::rococo::{consensus::*, currency::*, fee::WeightToFee, time::*}; use xcm::prelude::*; use xcm_config::CollatorSelectionUpdateOrigin; -use xcm_fee_payment_runtime_api::{ +use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, }; @@ -142,7 +144,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("contracts-rococo"), impl_name: create_runtime_str!("contracts-rococo"), authoring_version: 1, - spec_version: 1_013_000, + spec_version: 1_014_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 7, @@ -177,6 +179,7 @@ parameter_types! { }) .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) .build_or_panic(); + pub const SS58Prefix: u8 = 42; } // Configure FRAME pallets to include in runtime. @@ -193,7 +196,7 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = frame_system::weights::SubstrateWeight; - type SS58Prefix = ConstU16<42>; + type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = ConstU32<16>; } @@ -486,7 +489,7 @@ impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { Runtime::metadata_versions() } } @@ -590,7 +593,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { let acceptable_assets = vec![AssetId(xcm_config::RelayLocation::get())]; PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) @@ -603,11 +606,11 @@ impl_runtime_apis! { Ok(WeightToFee::weight_to_fee(&weight)) }, Ok(asset_id) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); Err(XcmPaymentApiError::AssetNotFound) }, Err(_) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); Err(XcmPaymentApiError::VersionedConversionFailed) } } @@ -622,7 +625,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + impl xcm_runtime_apis::dry_run::DryRunApi for Runtime { fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { PolkadotXcm::dry_run_call::(origin, call) } @@ -632,6 +635,18 @@ impl_runtime_apis! { } } + impl xcm_runtime_apis::conversions::LocationToAccountApi for Runtime { + fn convert_location(location: VersionedLocation) -> Result< + AccountId, + xcm_runtime_apis::conversions::Error + > { + xcm_runtime_apis::conversions::LocationToAccountHelper::< + AccountId, + xcm_config::LocationToAccountId + >::convert_location(location) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) @@ -752,7 +767,7 @@ impl_runtime_apis! { use frame_system_benchmarking::Pallet as SystemBench; impl frame_system_benchmarking::Config for Runtime { - fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { + fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); Ok(()) } @@ -802,7 +817,7 @@ impl_runtime_apis! { } fn set_up_complex_asset_transfer( - ) -> Option<(Assets, u32, Location, Box)> { + ) -> Option<(Assets, u32, Location, alloc::boxed::Box)> { // Contracts-System-Para only supports teleports to system parachain. // Relay/native token can be teleported between Contracts-System-Para and Relay. let native_location = Parent.into(); diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs index ef5ded1731d0d9f3ff60e1e8cb71cd1fe18ca81b..6a41cf75d354693d232b9719289b8edefe1ec835 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -42,10 +42,10 @@ use xcm_builder::{ AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NativeAsset, ParentAsSuperuser, - ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; @@ -191,7 +191,7 @@ impl xcm_executor::Config for XcmConfig { type AssetExchanger = (); type FeeManager = XcmFeeManagerFromComponents< WaivedLocations, - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = Nothing; diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml index dc99fe331f78671b0b43842e0762db8bd96a840b..2920bc428d90b202d1035cb3cbe309dd99097013 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml @@ -10,74 +10,74 @@ license = "Apache-2.0" workspace = true [build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -hex-literal = "0.4.1" +codec = { features = ["derive"], workspace = true } +hex-literal = { workspace = true, default-features = true } log = { workspace = true } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Substrate -frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../../substrate/frame/system", default-features = false } -frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true } -frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false } -frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } -pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false } -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } -pallet-broker = { path = "../../../../../substrate/frame/broker", default-features = false } -pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false } -pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } -pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false } -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } -pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false } -sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false } -sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } -sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -sp-session = { path = "../../../../../substrate/primitives/session", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-storage = { path = "../../../../../substrate/primitives/storage", default-features = false } -sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } -sp-version = { path = "../../../../../substrate/primitives/version", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-executive = { workspace = true } +frame-metadata-hash-extension = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-benchmarking = { optional = true, workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +frame-try-runtime = { optional = true, workspace = true } +pallet-aura = { workspace = true } +pallet-authorship = { workspace = true } +pallet-balances = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-broker = { workspace = true } +pallet-multisig = { workspace = true } +pallet-session = { workspace = true } +pallet-sudo = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-utility = { workspace = true } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-core = { workspace = true } +sp-inherents = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-storage = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } # Polkadot -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } -pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } -polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false } -polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false } -rococo-runtime-constants = { path = "../../../../../polkadot/runtime/rococo/constants", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } -xcm-fee-payment-runtime-api = { path = "../../../../../polkadot/xcm/xcm-fee-payment-runtime-api", default-features = false } +pallet-xcm = { workspace = true } +pallet-xcm-benchmarks = { optional = true, workspace = true } +polkadot-parachain-primitives = { workspace = true } +polkadot-runtime-common = { workspace = true } +rococo-runtime-constants = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm-runtime-apis = { workspace = true } # Cumulus -cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } -cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false } -cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } -cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } -cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } -cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } -pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } -testnet-parachains-constants = { path = "../../constants", default-features = false, features = ["rococo"] } +cumulus-pallet-aura-ext = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-session-benchmarking = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +cumulus-primitives-aura = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-utility = { workspace = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true } +pallet-collator-selection = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } +testnet-parachains-constants = { features = ["rococo"], workspace = true } [features] default = ["std"] @@ -94,6 +94,7 @@ std = [ "cumulus-primitives-utility/std", "frame-benchmarking?/std", "frame-executive/std", + "frame-metadata-hash-extension/std", "frame-support/std", "frame-system-benchmarking?/std", "frame-system-rpc-runtime-api/std", @@ -131,7 +132,6 @@ std = [ "sp-offchain/std", "sp-runtime/std", "sp-session/std", - "sp-std/std", "sp-storage/std", "sp-transaction-pool/std", "sp-version/std", @@ -139,7 +139,7 @@ std = [ "testnet-parachains-constants/std", "xcm-builder/std", "xcm-executor/std", - "xcm-fee-payment-runtime-api/std", + "xcm-runtime-apis/std", "xcm/std", ] @@ -169,7 +169,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", - "xcm-fee-payment-runtime-api/runtime-benchmarks", + "xcm-runtime-apis/runtime-benchmarks", ] try-runtime = [ @@ -199,4 +199,14 @@ try-runtime = [ "sp-runtime/try-runtime", ] -fast-runtime = [] +fast-runtime = [ + "rococo-runtime-constants/fast-runtime", +] + +# Enable the metadata hash generation in the wasm builder. +metadata-hash = ["substrate-wasm-builder/metadata-hash"] + +# A feature that should be enabled when the runtime should be built for on-chain +# deployment. This will disable stuff that shouldn't be part of the on-chain wasm +# to make it smaller, like logging for example. +on-chain-release-build = ["metadata-hash", "sp-api/disable-logging"] diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/build.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/build.rs index 28dacd20cf305ebdbc57eb2a30e3c98e4f8853d9..368a1e427aaafe9e45ad4370dbbaba16f5a31b06 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/build.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/build.rs @@ -13,20 +13,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[cfg(feature = "std")] +#[cfg(all(not(feature = "metadata-hash"), feature = "std"))] fn main() { - substrate_wasm_builder::WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() + substrate_wasm_builder::WasmBuilder::build_using_defaults(); + + substrate_wasm_builder::WasmBuilder::init_with_defaults() + .set_file_name("fast_runtime_binary.rs") + .enable_feature("fast-runtime") + .build(); +} + +#[cfg(all(feature = "metadata-hash", feature = "std"))] +fn main() { + substrate_wasm_builder::WasmBuilder::init_with_defaults() + .enable_metadata_hash("ROC", 12) .build(); - substrate_wasm_builder::WasmBuilder::new() - .with_current_project() + substrate_wasm_builder::WasmBuilder::init_with_defaults() .set_file_name("fast_runtime_binary.rs") .enable_feature("fast-runtime") - .import_memory() - .export_heap_base() + .enable_metadata_hash("ROC", 12) .build(); } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs index ec3a4f31202fd5f5333a1057bb06ca5dde247619..fa0c2644421e7ebc3f34a562e6aa2ea0b255df12 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs @@ -21,22 +21,65 @@ use cumulus_primitives_core::relay_chain; use frame_support::{ parameter_types, traits::{ - fungible::{Balanced, Credit}, - OnUnbalanced, + fungible::{Balanced, Credit, Inspect}, + tokens::{Fortitude, Preservation}, + DefensiveResult, OnUnbalanced, }, }; +use frame_system::Pallet as System; use pallet_broker::{CoreAssignment, CoreIndex, CoretimeInterface, PartsOf57600, RCBlockNumberOf}; -use parachains_common::{AccountId, Balance, BlockNumber}; +use parachains_common::{AccountId, Balance}; +use rococo_runtime_constants::system_parachain::coretime; +use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; +use xcm_executor::traits::TransactAsset; -pub struct CreditToCollatorPot; -impl OnUnbalanced> for CreditToCollatorPot { - fn on_nonzero_unbalanced(credit: Credit) { - let staking_pot = CollatorSelection::account_id(); - let _ = >::resolve(&staking_pot, credit); +pub struct BurnCoretimeRevenue; +impl OnUnbalanced> for BurnCoretimeRevenue { + fn on_nonzero_unbalanced(amount: Credit) { + let acc = RevenueAccumulationAccount::get(); + if !System::::account_exists(&acc) { + System::::inc_providers(&acc); + } + Balances::resolve(&acc, amount).defensive_ok(); } } +type AssetTransactor = ::AssetTransactor; + +fn burn_at_relay(stash: &AccountId, value: Balance) -> Result<(), XcmError> { + let dest = Location::parent(); + let stash_location = + Junction::AccountId32 { network: None, id: stash.clone().into() }.into_location(); + let asset = Asset { id: AssetId(Location::parent()), fun: Fungible(value) }; + let dummy_xcm_context = XcmContext { origin: None, message_id: [0; 32], topic: None }; + + let withdrawn = AssetTransactor::withdraw_asset(&asset, &stash_location, None)?; + + AssetTransactor::can_check_out(&dest, &asset, &dummy_xcm_context)?; + + let parent_assets = Into::::into(withdrawn) + .reanchored(&dest, &Here.into()) + .defensive_map_err(|_| XcmError::ReanchorFailed)?; + + PolkadotXcm::send_xcm( + Here, + Location::parent(), + Xcm(vec![ + Instruction::UnpaidExecution { + weight_limit: WeightLimit::Unlimited, + check_origin: None, + }, + ReceiveTeleportedAsset(parent_assets.clone()), + BurnAsset(parent_assets), + ]), + )?; + + AssetTransactor::check_out(&dest, &asset, &dummy_xcm_context); + + Ok(()) +} + /// A type containing the encoding of the coretime pallet in the Relay chain runtime. Used to /// construct any remote calls. The codec index must correspond to the index of `Coretime` in the /// `construct_runtime` of the Relay chain. @@ -66,11 +109,7 @@ enum CoretimeProviderCalls { parameter_types! { pub const BrokerPalletId: PalletId = PalletId(*b"py/broke"); -} - -parameter_types! { - pub storage CoreCount: Option = None; - pub storage CoretimeRevenue: Option<(BlockNumber, Balance)> = None; + pub RevenueAccumulationAccount: AccountId = BrokerPalletId::get().into_sub_account_truncating(b"burnstash"); } /// Type that implements the `CoretimeInterface` for the allocation of Coretime. Meant to operate @@ -205,26 +244,30 @@ impl CoretimeInterface for CoretimeAllocator { } } - fn check_notify_revenue_info() -> Option<(RCBlockNumberOf, Self::Balance)> { - let revenue = CoretimeRevenue::get(); - CoretimeRevenue::set(&None); - revenue - } + fn on_new_timeslice(_t: pallet_broker::Timeslice) { + let stash = RevenueAccumulationAccount::get(); + let value = + Balances::reducible_balance(&stash, Preservation::Expendable, Fortitude::Polite); - #[cfg(feature = "runtime-benchmarks")] - fn ensure_notify_revenue_info(when: RCBlockNumberOf, revenue: Self::Balance) { - CoretimeRevenue::set(&Some((when, revenue))); + if value > 0 { + log::debug!(target: "runtime::coretime", "Going to burn {value} stashed tokens at RC"); + match burn_at_relay(&stash, value) { + Ok(()) => { + log::debug!(target: "runtime::coretime", "Succesfully burnt {value} tokens"); + }, + Err(err) => { + log::error!(target: "runtime::coretime", "burn_at_relay failed: {err:?}"); + }, + } + } } } impl pallet_broker::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type OnRevenue = CreditToCollatorPot; - #[cfg(feature = "fast-runtime")] - type TimeslicePeriod = ConstU32<10>; - #[cfg(not(feature = "fast-runtime"))] - type TimeslicePeriod = ConstU32<80>; + type OnRevenue = BurnCoretimeRevenue; + type TimeslicePeriod = ConstU32<{ coretime::TIMESLICE_PERIOD }>; type MaxLeasedCores = ConstU32<50>; type MaxReservedCores = ConstU32<10>; type Coretime = CoretimeAllocator; diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index 522ee574176a2733b357100599cedd1f3ce986b2..9fd0093840d3fb7008a8fd0f67cb55b858d8600a 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -33,6 +33,9 @@ mod coretime; mod weights; pub mod xcm_config; +extern crate alloc; + +use alloc::{vec, vec::Vec}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::{ @@ -66,7 +69,6 @@ use sp_runtime::{ transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, DispatchError, MultiAddress, Perbill, }; -use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -76,7 +78,7 @@ use xcm::prelude::*; use xcm_config::{ FellowshipLocation, GovernanceLocation, RocRelayLocation, XcmOriginToTransactDispatchOrigin, }; -use xcm_fee_payment_runtime_api::{ +use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, }; @@ -104,6 +106,7 @@ pub type SignedExtra = ( frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, + frame_metadata_hash_extension::CheckMetadataHash, ); /// Unchecked extrinsic type as expected by this runtime. @@ -117,6 +120,7 @@ pub type Migrations = ( cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, pallet_broker::migration::MigrateV0ToV1, pallet_broker::migration::MigrateV1ToV2, + pallet_broker::migration::MigrateV2ToV3, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -142,10 +146,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("coretime-rococo"), impl_name: create_runtime_str!("coretime-rococo"), authoring_version: 1, - spec_version: 1_013_000, + spec_version: 1_014_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 1, + transaction_version: 2, state_version: 1, }; @@ -550,7 +554,7 @@ impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { Runtime::metadata_versions() } } @@ -660,7 +664,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { let acceptable_assets = vec![AssetId(xcm_config::RocRelayLocation::get())]; PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) @@ -673,11 +677,11 @@ impl_runtime_apis! { Ok(WeightToFee::weight_to_fee(&weight)) }, Ok(asset_id) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); Err(XcmPaymentApiError::AssetNotFound) }, Err(_) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); Err(XcmPaymentApiError::VersionedConversionFailed) } } @@ -692,7 +696,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + impl xcm_runtime_apis::dry_run::DryRunApi for Runtime { fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { PolkadotXcm::dry_run_call::(origin, call) } @@ -702,6 +706,18 @@ impl_runtime_apis! { } } + impl xcm_runtime_apis::conversions::LocationToAccountApi for Runtime { + fn convert_location(location: VersionedLocation) -> Result< + AccountId, + xcm_runtime_apis::conversions::Error + > { + xcm_runtime_apis::conversions::LocationToAccountHelper::< + AccountId, + xcm_config::LocationToAccountId, + >::convert_location(location) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) @@ -760,7 +776,7 @@ impl_runtime_apis! { use frame_system_benchmarking::Pallet as SystemBench; impl frame_system_benchmarking::Config for Runtime { - fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { + fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); Ok(()) } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_broker.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_broker.rs index 5c9175a18d98a0b6c0c791945dcd9f2cd1892cc4..83e80e2e91e737827fce0b90fad0ec3d70ce3c33 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_broker.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_broker.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_broker` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-06-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-x5tnzzy-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_918_000 picoseconds. - Weight::from_parts(2_092_000, 0) + // Minimum execution time: 2_024_000 picoseconds. + Weight::from_parts(2_121_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `10888` // Estimated: `13506` - // Minimum execution time: 21_943_000 picoseconds. - Weight::from_parts(22_570_000, 0) + // Minimum execution time: 21_654_000 picoseconds. + Weight::from_parts(22_591_000, 0) .saturating_add(Weight::from_parts(0, 13506)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -77,8 +77,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `12090` // Estimated: `13506` - // Minimum execution time: 20_923_000 picoseconds. - Weight::from_parts(21_354_000, 0) + // Minimum execution time: 20_769_000 picoseconds. + Weight::from_parts(21_328_000, 0) .saturating_add(Weight::from_parts(0, 13506)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -93,24 +93,34 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `466` // Estimated: `1951` - // Minimum execution time: 10_687_000 picoseconds. - Weight::from_parts(11_409_000, 0) + // Minimum execution time: 10_404_000 picoseconds. + Weight::from_parts(10_941_000, 0) .saturating_add(Weight::from_parts(0, 1951)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Broker::Configuration` (r:1 w:0) /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Storage: `Broker::Leases` (r:1 w:1) + /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(401), added: 896, mode: `MaxEncodedLen`) + /// Storage: `Broker::Reservations` (r:1 w:0) + /// Proof: `Broker::Reservations` (`max_values`: Some(1), `max_size`: Some(12021), added: 12516, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::LastRelayChainBlockNumber` (r:1 w:0) /// Proof: `ParachainSystem::LastRelayChainBlockNumber` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Broker::InstaPoolIo` (r:3 w:3) /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `Broker::Reservations` (r:1 w:0) - /// Proof: `Broker::Reservations` (`max_values`: Some(1), `max_size`: Some(12021), added: 12516, mode: `MaxEncodedLen`) - /// Storage: `Broker::Leases` (r:1 w:1) - /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(401), added: 896, mode: `MaxEncodedLen`) /// Storage: `Broker::SaleInfo` (r:0 w:1) /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) /// Storage: `Broker::Status` (r:0 w:1) @@ -120,33 +130,34 @@ impl pallet_broker::WeightInfo for WeightInfo { /// The range of component `n` is `[0, 1000]`. fn start_sales(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `12567` - // Estimated: `14052` - // Minimum execution time: 111_288_000 picoseconds. - Weight::from_parts(117_804_282, 0) - .saturating_add(Weight::from_parts(0, 14052)) - // Standard Error: 391 - .saturating_add(Weight::from_parts(1_243, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(66)) + // Measured: `12599` + // Estimated: `15065 + n * (1 ยฑ0)` + // Minimum execution time: 44_085_000 picoseconds. + Weight::from_parts(127_668_002, 0) + .saturating_add(Weight::from_parts(0, 15065)) + // Standard Error: 2_231 + .saturating_add(Weight::from_parts(20_604, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(13)) + .saturating_add(T::DbWeight::get().writes(59)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: `Broker::Status` (r:1 w:0) /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `Broker::SaleInfo` (r:1 w:1) /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:0) + /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Broker::Regions` (r:0 w:1) - /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) fn purchase() -> Weight { // Proof Size summary in bytes: - // Measured: `316` + // Measured: `332` // Estimated: `3593` - // Minimum execution time: 33_006_000 picoseconds. - Weight::from_parts(34_256_000, 0) + // Minimum execution time: 45_100_000 picoseconds. + Weight::from_parts(46_263_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Broker::Configuration` (r:1 w:0) /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) @@ -156,53 +167,53 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) /// Storage: `Broker::PotentialRenewals` (r:1 w:2) /// Proof: `Broker::PotentialRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:0) + /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Broker::Workplan` (r:0 w:1) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) fn renew() -> Weight { // Proof Size summary in bytes: - // Measured: `434` + // Measured: `553` // Estimated: `4698` - // Minimum execution time: 61_473_000 picoseconds. - Weight::from_parts(66_476_000, 0) + // Minimum execution time: 65_944_000 picoseconds. + Weight::from_parts(68_666_000, 0) .saturating_add(Weight::from_parts(0, 4698)) .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `Broker::Regions` (r:1 w:1) - /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `357` - // Estimated: `3550` - // Minimum execution time: 13_771_000 picoseconds. - Weight::from_parts(14_374_000, 0) - .saturating_add(Weight::from_parts(0, 3550)) + // Measured: `358` + // Estimated: `3551` + // Minimum execution time: 13_794_000 picoseconds. + Weight::from_parts(14_450_000, 0) + .saturating_add(Weight::from_parts(0, 3551)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Broker::Regions` (r:1 w:2) - /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) fn partition() -> Weight { // Proof Size summary in bytes: - // Measured: `357` - // Estimated: `3550` - // Minimum execution time: 15_162_000 picoseconds. - Weight::from_parts(15_742_000, 0) - .saturating_add(Weight::from_parts(0, 3550)) + // Measured: `358` + // Estimated: `3551` + // Minimum execution time: 15_316_000 picoseconds. + Weight::from_parts(15_787_000, 0) + .saturating_add(Weight::from_parts(0, 3551)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Broker::Regions` (r:1 w:3) - /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) fn interlace() -> Weight { // Proof Size summary in bytes: - // Measured: `357` - // Estimated: `3550` - // Minimum execution time: 16_196_000 picoseconds. - Weight::from_parts(16_796_000, 0) - .saturating_add(Weight::from_parts(0, 3550)) + // Measured: `358` + // Estimated: `3551` + // Minimum execution time: 16_375_000 picoseconds. + Weight::from_parts(17_113_000, 0) + .saturating_add(Weight::from_parts(0, 3551)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -211,15 +222,15 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Storage: `Broker::Status` (r:1 w:0) /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `Broker::Regions` (r:1 w:1) - /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) /// Storage: `Broker::Workplan` (r:1 w:1) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) fn assign() -> Weight { // Proof Size summary in bytes: - // Measured: `936` + // Measured: `937` // Estimated: `4681` - // Minimum execution time: 25_653_000 picoseconds. - Weight::from_parts(27_006_000, 0) + // Minimum execution time: 25_952_000 picoseconds. + Weight::from_parts(27_198_000, 0) .saturating_add(Weight::from_parts(0, 4681)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -227,7 +238,7 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Storage: `Broker::Status` (r:1 w:0) /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `Broker::Regions` (r:1 w:1) - /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) /// Storage: `Broker::Workplan` (r:1 w:1) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// Storage: `Broker::InstaPoolIo` (r:2 w:2) @@ -236,10 +247,10 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `Broker::InstaPoolContribution` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn pool() -> Weight { // Proof Size summary in bytes: - // Measured: `1002` + // Measured: `1003` // Estimated: `5996` - // Minimum execution time: 31_114_000 picoseconds. - Weight::from_parts(32_235_000, 0) + // Minimum execution time: 31_790_000 picoseconds. + Weight::from_parts(32_920_000, 0) .saturating_add(Weight::from_parts(0, 5996)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(5)) @@ -255,11 +266,11 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `652` // Estimated: `6196 + m * (2520 ยฑ0)` - // Minimum execution time: 57_280_000 picoseconds. - Weight::from_parts(58_127_480, 0) + // Minimum execution time: 56_286_000 picoseconds. + Weight::from_parts(56_946_240, 0) .saturating_add(Weight::from_parts(0, 6196)) - // Standard Error: 41_670 - .saturating_add(Weight::from_parts(1_203_066, 0).saturating_mul(m.into())) + // Standard Error: 44_472 + .saturating_add(Weight::from_parts(1_684_838, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes(5)) @@ -279,25 +290,25 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn purchase_credit() -> Weight { // Proof Size summary in bytes: - // Measured: `215` - // Estimated: `3680` - // Minimum execution time: 59_968_000 picoseconds. - Weight::from_parts(62_315_000, 0) - .saturating_add(Weight::from_parts(0, 3680)) + // Measured: `322` + // Estimated: `3787` + // Minimum execution time: 64_967_000 picoseconds. + Weight::from_parts(66_504_000, 0) + .saturating_add(Weight::from_parts(0, 3787)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Broker::Status` (r:1 w:0) /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `Broker::Regions` (r:1 w:1) - /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) fn drop_region() -> Weight { // Proof Size summary in bytes: - // Measured: `465` - // Estimated: `3550` - // Minimum execution time: 50_887_000 picoseconds. - Weight::from_parts(57_366_000, 0) - .saturating_add(Weight::from_parts(0, 3550)) + // Measured: `466` + // Estimated: `3551` + // Minimum execution time: 37_552_000 picoseconds. + Weight::from_parts(46_263_000, 0) + .saturating_add(Weight::from_parts(0, 3551)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -311,8 +322,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `463` // Estimated: `3533` - // Minimum execution time: 84_472_000 picoseconds. - Weight::from_parts(96_536_000, 0) + // Minimum execution time: 79_625_000 picoseconds. + Weight::from_parts(86_227_000, 0) .saturating_add(Weight::from_parts(0, 3533)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -329,8 +340,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `857` // Estimated: `3593` - // Minimum execution time: 96_371_000 picoseconds. - Weight::from_parts(104_659_000, 0) + // Minimum execution time: 88_005_000 picoseconds. + Weight::from_parts(92_984_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) @@ -343,8 +354,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `957` // Estimated: `4698` - // Minimum execution time: 51_741_000 picoseconds. - Weight::from_parts(54_461_000, 0) + // Minimum execution time: 38_877_000 picoseconds. + Weight::from_parts(40_408_000, 0) .saturating_add(Weight::from_parts(0, 4698)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -360,13 +371,15 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `n` is `[0, 1000]`. - fn request_core_count(_n: u32, ) -> Weight { + fn request_core_count(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 19_901_000 picoseconds. - Weight::from_parts(21_028_116, 0) + // Minimum execution time: 20_581_000 picoseconds. + Weight::from_parts(21_610_297, 0) .saturating_add(Weight::from_parts(0, 3539)) + // Standard Error: 119 + .saturating_add(Weight::from_parts(144, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -377,29 +390,29 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `266` // Estimated: `1487` - // Minimum execution time: 5_987_000 picoseconds. - Weight::from_parts(6_412_478, 0) + // Minimum execution time: 6_079_000 picoseconds. + Weight::from_parts(6_540_110, 0) .saturating_add(Weight::from_parts(0, 1487)) - // Standard Error: 16 - .saturating_add(Weight::from_parts(47, 0).saturating_mul(n.into())) + // Standard Error: 14 + .saturating_add(Weight::from_parts(10, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + /// Storage: `Broker::RevenueInbox` (r:1 w:1) + /// Proof: `Broker::RevenueInbox` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) /// Storage: `Broker::InstaPoolHistory` (r:1 w:1) /// Proof: `Broker::InstaPoolHistory` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:1) + /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn process_revenue() -> Weight { // Proof Size summary in bytes: - // Measured: `447` + // Measured: `442` // Estimated: `6196` - // Minimum execution time: 38_623_000 picoseconds. - Weight::from_parts(39_773_000, 0) + // Minimum execution time: 42_947_000 picoseconds. + Weight::from_parts(43_767_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Broker::InstaPoolIo` (r:3 w:3) /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) @@ -412,13 +425,15 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Storage: `Broker::Workplan` (r:0 w:60) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. - fn rotate_sale(_n: u32, ) -> Weight { + fn rotate_sale(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `12514` // Estimated: `13506` - // Minimum execution time: 97_074_000 picoseconds. - Weight::from_parts(101_247_740, 0) + // Minimum execution time: 93_426_000 picoseconds. + Weight::from_parts(96_185_447, 0) .saturating_add(Weight::from_parts(0, 13506)) + // Standard Error: 116 + .saturating_add(Weight::from_parts(4, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(65)) } @@ -430,8 +445,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3493` - // Minimum execution time: 6_317_000 picoseconds. - Weight::from_parts(6_521_000, 0) + // Minimum execution time: 5_842_000 picoseconds. + Weight::from_parts(6_077_000, 0) .saturating_add(Weight::from_parts(0, 3493)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -454,8 +469,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1321` // Estimated: `4786` - // Minimum execution time: 32_575_000 picoseconds. - Weight::from_parts(33_299_000, 0) + // Minimum execution time: 33_278_000 picoseconds. + Weight::from_parts(34_076_000, 0) .saturating_add(Weight::from_parts(0, 4786)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -474,8 +489,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 15_256_000 picoseconds. - Weight::from_parts(15_927_000, 0) + // Minimum execution time: 15_779_000 picoseconds. + Weight::from_parts(16_213_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -486,8 +501,19 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_783_000 picoseconds. - Weight::from_parts(1_904_000, 0) + // Minimum execution time: 1_774_000 picoseconds. + Weight::from_parts(1_873_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Broker::RevenueInbox` (r:0 w:1) + /// Proof: `Broker::RevenueInbox` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) + fn notify_revenue() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_858_000 picoseconds. + Weight::from_parts(1_991_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -497,19 +523,19 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) /// Storage: `Broker::CoreCountInbox` (r:1 w:0) /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + /// Storage: `Broker::RevenueInbox` (r:1 w:0) + /// Proof: `Broker::RevenueInbox` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn do_tick_base() -> Weight { // Proof Size summary in bytes: - // Measured: `398` - // Estimated: `3863` - // Minimum execution time: 12_307_000 picoseconds. - Weight::from_parts(12_967_000, 0) - .saturating_add(Weight::from_parts(0, 3863)) + // Measured: `408` + // Estimated: `1893` + // Minimum execution time: 10_874_000 picoseconds. + Weight::from_parts(11_265_000, 0) + .saturating_add(Weight::from_parts(0, 1893)) .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Broker::Leases` (r:1 w:1) /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(401), added: 896, mode: `MaxEncodedLen`) @@ -517,10 +543,32 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `470` // Estimated: `1886` - // Minimum execution time: 6_597_000 picoseconds. - Weight::from_parts(6_969_000, 0) + // Minimum execution time: 6_525_000 picoseconds. + Weight::from_parts(6_769_000, 0) .saturating_add(Weight::from_parts(0, 1886)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn on_new_timeslice() -> Weight { + // Proof Size summary in bytes: + // Measured: `322` + // Estimated: `3787` + // Minimum execution time: 45_561_000 picoseconds. + Weight::from_parts(47_306_000, 0) + .saturating_add(Weight::from_parts(0, 3787)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) + } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs index 9f79cea831aed66a0d073109233731751cdf99ed..b8db473f10662d5b1ef045d28f943fe0cb1430b9 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs @@ -18,10 +18,10 @@ mod pallet_xcm_benchmarks_fungible; mod pallet_xcm_benchmarks_generic; use crate::{xcm_config::MaxAssetsIntoHolding, Runtime}; +use alloc::vec::Vec; use frame_support::weights::Weight; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; -use sp_std::prelude::*; use xcm::{latest::prelude::*, DoubleEncoded}; trait WeighAssets { diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 7ff1cce2e072339dccd52c0809aafd59337db7b4..73a71980530707930681ebc82a5cd563372eb24e 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -43,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::fungible`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 16412eb49a5267d3f3f38cdd285e8f3b248a5f99..676048f92ad937e7cb80f268fdc1ca4e90779d42 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -43,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::generic`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs index c16b40b8675fbce2878bca4ba1106b89bbd9e9b1..f56a3c42de0210669f55f0f27feb23b44b055cd6 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs @@ -43,10 +43,10 @@ use xcm_builder::{ AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NonFungibleAdapter, ParentAsSuperuser, ParentIsPreset, - RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + RelayChainAsNative, SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; @@ -213,7 +213,7 @@ impl xcm_executor::Config for XcmConfig { type AssetExchanger = (); type FeeManager = XcmFeeManagerFromComponents< WaivedLocations, - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = Nothing; diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml index 78018537f5d3ce07d75ed8a465d5e17dba157028..07a4332800d7f22451caa43ff6668c57ec4fabd7 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml @@ -10,74 +10,74 @@ license = "Apache-2.0" workspace = true [build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -hex-literal = "0.4.1" +codec = { features = ["derive"], workspace = true } +hex-literal = { workspace = true, default-features = true } log = { workspace = true } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Substrate -frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../../substrate/frame/system", default-features = false } -frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true } -frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false } -frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } -pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false } -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } -pallet-broker = { path = "../../../../../substrate/frame/broker", default-features = false } -pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false } -pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } -pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false } -sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false } -sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } -sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -sp-session = { path = "../../../../../substrate/primitives/session", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-storage = { path = "../../../../../substrate/primitives/storage", default-features = false } -sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } -sp-version = { path = "../../../../../substrate/primitives/version", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-executive = { workspace = true } +frame-metadata-hash-extension = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-benchmarking = { optional = true, workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +frame-try-runtime = { optional = true, workspace = true } +pallet-aura = { workspace = true } +pallet-authorship = { workspace = true } +pallet-balances = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-broker = { workspace = true } +pallet-multisig = { workspace = true } +pallet-session = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-utility = { workspace = true } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-core = { workspace = true } +sp-inherents = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-storage = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } # Polkadot -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } -pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } -polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false } -polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false } -westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } -xcm-fee-payment-runtime-api = { path = "../../../../../polkadot/xcm/xcm-fee-payment-runtime-api", default-features = false } +pallet-xcm = { workspace = true } +pallet-xcm-benchmarks = { optional = true, workspace = true } +polkadot-parachain-primitives = { workspace = true } +polkadot-runtime-common = { workspace = true } +westend-runtime-constants = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm-runtime-apis = { workspace = true } # Cumulus -cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } -cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false } -cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } -cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } -cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } -cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } +cumulus-pallet-aura-ext = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-session-benchmarking = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +cumulus-primitives-aura = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-utility = { workspace = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true } -pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } -testnet-parachains-constants = { path = "../../constants", default-features = false, features = ["westend"] } +pallet-collator-selection = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } +testnet-parachains-constants = { features = ["westend"], workspace = true } [features] default = ["std"] @@ -94,6 +94,7 @@ std = [ "cumulus-primitives-utility/std", "frame-benchmarking?/std", "frame-executive/std", + "frame-metadata-hash-extension/std", "frame-support/std", "frame-system-benchmarking?/std", "frame-system-rpc-runtime-api/std", @@ -129,7 +130,6 @@ std = [ "sp-offchain/std", "sp-runtime/std", "sp-session/std", - "sp-std/std", "sp-storage/std", "sp-transaction-pool/std", "sp-version/std", @@ -138,7 +138,7 @@ std = [ "westend-runtime-constants/std", "xcm-builder/std", "xcm-executor/std", - "xcm-fee-payment-runtime-api/std", + "xcm-runtime-apis/std", "xcm/std", ] @@ -167,7 +167,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", - "xcm-fee-payment-runtime-api/runtime-benchmarks", + "xcm-runtime-apis/runtime-benchmarks", ] try-runtime = [ @@ -196,4 +196,14 @@ try-runtime = [ "sp-runtime/try-runtime", ] -fast-runtime = [] +fast-runtime = [ + "westend-runtime-constants/fast-runtime", +] + +# Enable the metadata hash generation in the wasm builder. +metadata-hash = ["substrate-wasm-builder/metadata-hash"] + +# A feature that should be enabled when the runtime should be built for on-chain +# deployment. This will disable stuff that shouldn't be part of the on-chain wasm +# to make it smaller, like logging for example. +on-chain-release-build = ["metadata-hash", "sp-api/disable-logging"] diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/build.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/build.rs index 28dacd20cf305ebdbc57eb2a30e3c98e4f8853d9..2f10a39d1b2e238e29ab8a726c808c713914a0b7 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/build.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/build.rs @@ -13,20 +13,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[cfg(feature = "std")] +#[cfg(all(not(feature = "metadata-hash"), feature = "std"))] fn main() { - substrate_wasm_builder::WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() + substrate_wasm_builder::WasmBuilder::build_using_defaults(); + + substrate_wasm_builder::WasmBuilder::init_with_defaults() + .set_file_name("fast_runtime_binary.rs") + .enable_feature("fast-runtime") + .build(); +} + +#[cfg(all(feature = "metadata-hash", feature = "std"))] +fn main() { + substrate_wasm_builder::WasmBuilder::init_with_defaults() + .enable_metadata_hash("WND", 12) .build(); - substrate_wasm_builder::WasmBuilder::new() - .with_current_project() + substrate_wasm_builder::WasmBuilder::init_with_defaults() .set_file_name("fast_runtime_binary.rs") .enable_feature("fast-runtime") - .import_memory() - .export_heap_base() + .enable_metadata_hash("WND", 12) .build(); } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs index a5e219b9897e0710e008ffa6b800624710877bcc..4f06e3e3669c8d69fcb990e55eb7c9e83432e96f 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs @@ -21,22 +21,67 @@ use cumulus_primitives_core::relay_chain; use frame_support::{ parameter_types, traits::{ - fungible::{Balanced, Credit}, - OnUnbalanced, + fungible::{Balanced, Credit, Inspect}, + tokens::{Fortitude, Preservation}, + DefensiveResult, OnUnbalanced, }, }; -use pallet_broker::{CoreAssignment, CoreIndex, CoretimeInterface, PartsOf57600, RCBlockNumberOf}; -use parachains_common::{AccountId, Balance, BlockNumber}; +use frame_system::Pallet as System; +use pallet_broker::{ + CoreAssignment, CoreIndex, CoretimeInterface, PartsOf57600, RCBlockNumberOf, Timeslice, +}; +use parachains_common::{AccountId, Balance}; +use sp_runtime::traits::AccountIdConversion; +use westend_runtime_constants::system_parachain::coretime; use xcm::latest::prelude::*; +use xcm_executor::traits::TransactAsset; -pub struct CreditToCollatorPot; -impl OnUnbalanced> for CreditToCollatorPot { - fn on_nonzero_unbalanced(credit: Credit) { - let staking_pot = CollatorSelection::account_id(); - let _ = >::resolve(&staking_pot, credit); +pub struct BurnCoretimeRevenue; +impl OnUnbalanced> for BurnCoretimeRevenue { + fn on_nonzero_unbalanced(amount: Credit) { + let acc = RevenueAccumulationAccount::get(); + if !System::::account_exists(&acc) { + System::::inc_providers(&acc); + } + Balances::resolve(&acc, amount).defensive_ok(); } } +type AssetTransactor = ::AssetTransactor; + +fn burn_at_relay(stash: &AccountId, value: Balance) -> Result<(), XcmError> { + let dest = Location::parent(); + let stash_location = + Junction::AccountId32 { network: None, id: stash.clone().into() }.into_location(); + let asset = Asset { id: AssetId(Location::parent()), fun: Fungible(value) }; + let dummy_xcm_context = XcmContext { origin: None, message_id: [0; 32], topic: None }; + + let withdrawn = AssetTransactor::withdraw_asset(&asset, &stash_location, None)?; + + AssetTransactor::can_check_out(&dest, &asset, &dummy_xcm_context)?; + + let parent_assets = Into::::into(withdrawn) + .reanchored(&dest, &Here.into()) + .defensive_map_err(|_| XcmError::ReanchorFailed)?; + + PolkadotXcm::send_xcm( + Here, + Location::parent(), + Xcm(vec![ + Instruction::UnpaidExecution { + weight_limit: WeightLimit::Unlimited, + check_origin: None, + }, + ReceiveTeleportedAsset(parent_assets.clone()), + BurnAsset(parent_assets), + ]), + )?; + + AssetTransactor::check_out(&dest, &asset, &dummy_xcm_context); + + Ok(()) +} + /// A type containing the encoding of the coretime pallet in the Relay chain runtime. Used to /// construct any remote calls. The codec index must correspond to the index of `Coretime` in the /// `construct_runtime` of the Relay chain. @@ -66,11 +111,7 @@ enum CoretimeProviderCalls { parameter_types! { pub const BrokerPalletId: PalletId = PalletId(*b"py/broke"); -} - -parameter_types! { - pub storage CoreCount: Option = None; - pub storage CoretimeRevenue: Option<(BlockNumber, Balance)> = None; + pub RevenueAccumulationAccount: AccountId = BrokerPalletId::get().into_sub_account_truncating(b"burnstash"); } /// Type that implements the `CoretimeInterface` for the allocation of Coretime. Meant to operate @@ -217,26 +258,30 @@ impl CoretimeInterface for CoretimeAllocator { } } - fn check_notify_revenue_info() -> Option<(RCBlockNumberOf, Self::Balance)> { - let revenue = CoretimeRevenue::get(); - CoretimeRevenue::set(&None); - revenue - } + fn on_new_timeslice(_timeslice: Timeslice) { + let stash = RevenueAccumulationAccount::get(); + let value = + Balances::reducible_balance(&stash, Preservation::Expendable, Fortitude::Polite); - #[cfg(feature = "runtime-benchmarks")] - fn ensure_notify_revenue_info(when: RCBlockNumberOf, revenue: Self::Balance) { - CoretimeRevenue::set(&Some((when, revenue))); + if value > 0 { + log::debug!(target: "runtime::coretime", "Going to burn {value} stashed tokens at RC"); + match burn_at_relay(&stash, value) { + Ok(()) => { + log::debug!(target: "runtime::coretime", "Succesfully burnt {value} tokens"); + }, + Err(err) => { + log::error!(target: "runtime::coretime", "burn_at_relay failed: {err:?}"); + }, + } + } } } impl pallet_broker::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type OnRevenue = CreditToCollatorPot; - #[cfg(feature = "fast-runtime")] - type TimeslicePeriod = ConstU32<10>; - #[cfg(not(feature = "fast-runtime"))] - type TimeslicePeriod = ConstU32<80>; + type OnRevenue = BurnCoretimeRevenue; + type TimeslicePeriod = ConstU32<{ coretime::TIMESLICE_PERIOD }>; // We don't actually need any leases at launch but set to 10 in case we want to sudo some in. type MaxLeasedCores = ConstU32<10>; type MaxReservedCores = ConstU32<10>; diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index 8830f1a42a2a1b30cb8af7ba94d55e48b1536c44..7907f252cf8e47a1d1694c7721f72a81e660dc74 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -33,6 +33,9 @@ mod coretime; mod weights; pub mod xcm_config; +extern crate alloc; + +use alloc::{vec, vec::Vec}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::{ @@ -66,7 +69,6 @@ use sp_runtime::{ transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, DispatchError, MultiAddress, Perbill, }; -use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -76,7 +78,7 @@ use xcm::prelude::*; use xcm_config::{ FellowshipLocation, GovernanceLocation, TokenRelayLocation, XcmOriginToTransactDispatchOrigin, }; -use xcm_fee_payment_runtime_api::{ +use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, }; @@ -104,6 +106,7 @@ pub type SignedExtra = ( frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, + frame_metadata_hash_extension::CheckMetadataHash, ); /// Unchecked extrinsic type as expected by this runtime. @@ -116,6 +119,7 @@ pub type Migrations = ( cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, pallet_broker::migration::MigrateV0ToV1, pallet_broker::migration::MigrateV1ToV2, + pallet_broker::migration::MigrateV2ToV3, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -141,10 +145,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("coretime-westend"), impl_name: create_runtime_str!("coretime-westend"), authoring_version: 1, - spec_version: 1_013_000, + spec_version: 1_014_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 1, + transaction_version: 2, state_version: 1, }; @@ -541,7 +545,7 @@ impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { Runtime::metadata_versions() } } @@ -651,7 +655,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { let acceptable_assets = vec![AssetId(xcm_config::TokenRelayLocation::get())]; PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) @@ -664,11 +668,11 @@ impl_runtime_apis! { Ok(WeightToFee::weight_to_fee(&weight)) }, Ok(asset_id) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); Err(XcmPaymentApiError::AssetNotFound) }, Err(_) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); Err(XcmPaymentApiError::VersionedConversionFailed) } } @@ -683,7 +687,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + impl xcm_runtime_apis::dry_run::DryRunApi for Runtime { fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { PolkadotXcm::dry_run_call::(origin, call) } @@ -693,6 +697,18 @@ impl_runtime_apis! { } } + impl xcm_runtime_apis::conversions::LocationToAccountApi for Runtime { + fn convert_location(location: VersionedLocation) -> Result< + AccountId, + xcm_runtime_apis::conversions::Error + > { + xcm_runtime_apis::conversions::LocationToAccountHelper::< + AccountId, + xcm_config::LocationToAccountId, + >::convert_location(location) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) @@ -751,7 +767,7 @@ impl_runtime_apis! { use frame_system_benchmarking::Pallet as SystemBench; impl frame_system_benchmarking::Config for Runtime { - fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { + fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); Ok(()) } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs index 7e1c832a90924e39c7bc7d7b24d8163ce5d65589..d130b306f7a52b75958db353aea24e9e113c82d5 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_broker` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-06-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-x5tnzzy-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_897_000 picoseconds. - Weight::from_parts(2_053_000, 0) + // Minimum execution time: 1_899_000 picoseconds. + Weight::from_parts(2_051_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `10888` // Estimated: `13506` - // Minimum execution time: 22_550_000 picoseconds. - Weight::from_parts(22_871_000, 0) + // Minimum execution time: 21_965_000 picoseconds. + Weight::from_parts(22_774_000, 0) .saturating_add(Weight::from_parts(0, 13506)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -77,8 +77,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `12090` // Estimated: `13506` - // Minimum execution time: 21_170_000 picoseconds. - Weight::from_parts(21_645_000, 0) + // Minimum execution time: 20_748_000 picoseconds. + Weight::from_parts(21_464_000, 0) .saturating_add(Weight::from_parts(0, 13506)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -93,24 +93,34 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `146` // Estimated: `1631` - // Minimum execution time: 10_494_000 picoseconds. - Weight::from_parts(10_942_000, 0) + // Minimum execution time: 10_269_000 picoseconds. + Weight::from_parts(10_508_000, 0) .saturating_add(Weight::from_parts(0, 1631)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Broker::Configuration` (r:1 w:0) /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Storage: `Broker::Leases` (r:1 w:1) + /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(81), added: 576, mode: `MaxEncodedLen`) + /// Storage: `Broker::Reservations` (r:1 w:0) + /// Proof: `Broker::Reservations` (`max_values`: Some(1), `max_size`: Some(12021), added: 12516, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::LastRelayChainBlockNumber` (r:1 w:0) /// Proof: `ParachainSystem::LastRelayChainBlockNumber` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Broker::InstaPoolIo` (r:3 w:3) /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `Broker::Reservations` (r:1 w:0) - /// Proof: `Broker::Reservations` (`max_values`: Some(1), `max_size`: Some(12021), added: 12516, mode: `MaxEncodedLen`) - /// Storage: `Broker::Leases` (r:1 w:1) - /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(81), added: 576, mode: `MaxEncodedLen`) /// Storage: `Broker::SaleInfo` (r:0 w:1) /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) /// Storage: `Broker::Status` (r:0 w:1) @@ -118,15 +128,18 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Storage: `Broker::Workplan` (r:0 w:20) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. - fn start_sales(_n: u32, ) -> Weight { + fn start_sales(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `12247` - // Estimated: `13732` - // Minimum execution time: 61_014_000 picoseconds. - Weight::from_parts(63_267_651, 0) - .saturating_add(Weight::from_parts(0, 13732)) - .saturating_add(T::DbWeight::get().reads(8)) + // Measured: `12279` + // Estimated: `14805 + n * (1 ยฑ0)` + // Minimum execution time: 41_900_000 picoseconds. + Weight::from_parts(80_392_728, 0) + .saturating_add(Weight::from_parts(0, 14805)) + // Standard Error: 870 + .saturating_add(Weight::from_parts(4_361, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(26)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: `Broker::Status` (r:1 w:0) /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) @@ -135,13 +148,13 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Broker::Regions` (r:0 w:1) - /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) fn purchase() -> Weight { // Proof Size summary in bytes: - // Measured: `316` + // Measured: `332` // Estimated: `3593` - // Minimum execution time: 30_931_000 picoseconds. - Weight::from_parts(31_941_000, 0) + // Minimum execution time: 40_911_000 picoseconds. + Weight::from_parts(43_102_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -160,47 +173,47 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) fn renew() -> Weight { // Proof Size summary in bytes: - // Measured: `434` + // Measured: `450` // Estimated: `4698` - // Minimum execution time: 57_466_000 picoseconds. - Weight::from_parts(65_042_000, 0) + // Minimum execution time: 70_257_000 picoseconds. + Weight::from_parts(73_889_000, 0) .saturating_add(Weight::from_parts(0, 4698)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Broker::Regions` (r:1 w:1) - /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `357` - // Estimated: `3550` - // Minimum execution time: 12_799_000 picoseconds. - Weight::from_parts(13_401_000, 0) - .saturating_add(Weight::from_parts(0, 3550)) + // Measured: `358` + // Estimated: `3551` + // Minimum execution time: 13_302_000 picoseconds. + Weight::from_parts(13_852_000, 0) + .saturating_add(Weight::from_parts(0, 3551)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Broker::Regions` (r:1 w:2) - /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) fn partition() -> Weight { // Proof Size summary in bytes: - // Measured: `357` - // Estimated: `3550` - // Minimum execution time: 14_107_000 picoseconds. - Weight::from_parts(14_630_000, 0) - .saturating_add(Weight::from_parts(0, 3550)) + // Measured: `358` + // Estimated: `3551` + // Minimum execution time: 14_927_000 picoseconds. + Weight::from_parts(15_553_000, 0) + .saturating_add(Weight::from_parts(0, 3551)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Broker::Regions` (r:1 w:3) - /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) fn interlace() -> Weight { // Proof Size summary in bytes: - // Measured: `357` - // Estimated: `3550` - // Minimum execution time: 15_254_000 picoseconds. - Weight::from_parts(16_062_000, 0) - .saturating_add(Weight::from_parts(0, 3550)) + // Measured: `358` + // Estimated: `3551` + // Minimum execution time: 16_237_000 picoseconds. + Weight::from_parts(16_995_000, 0) + .saturating_add(Weight::from_parts(0, 3551)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -209,15 +222,15 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Storage: `Broker::Status` (r:1 w:0) /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `Broker::Regions` (r:1 w:1) - /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) /// Storage: `Broker::Workplan` (r:1 w:1) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) fn assign() -> Weight { // Proof Size summary in bytes: - // Measured: `735` + // Measured: `736` // Estimated: `4681` - // Minimum execution time: 23_557_000 picoseconds. - Weight::from_parts(24_382_000, 0) + // Minimum execution time: 24_621_000 picoseconds. + Weight::from_parts(25_165_000, 0) .saturating_add(Weight::from_parts(0, 4681)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -225,7 +238,7 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Storage: `Broker::Status` (r:1 w:0) /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `Broker::Regions` (r:1 w:1) - /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) /// Storage: `Broker::Workplan` (r:1 w:1) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// Storage: `Broker::InstaPoolIo` (r:2 w:2) @@ -234,10 +247,10 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `Broker::InstaPoolContribution` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn pool() -> Weight { // Proof Size summary in bytes: - // Measured: `801` + // Measured: `802` // Estimated: `5996` - // Minimum execution time: 29_371_000 picoseconds. - Weight::from_parts(30_200_000, 0) + // Minimum execution time: 29_832_000 picoseconds. + Weight::from_parts(30_894_000, 0) .saturating_add(Weight::from_parts(0, 5996)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(5)) @@ -253,11 +266,11 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `652` // Estimated: `6196 + m * (2520 ยฑ0)` - // Minimum execution time: 54_331_000 picoseconds. - Weight::from_parts(55_322_165, 0) + // Minimum execution time: 55_390_000 picoseconds. + Weight::from_parts(56_124_789, 0) .saturating_add(Weight::from_parts(0, 6196)) - // Standard Error: 35_225 - .saturating_add(Weight::from_parts(1_099_614, 0).saturating_mul(m.into())) + // Standard Error: 41_724 + .saturating_add(Weight::from_parts(1_551_266, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes(5)) @@ -277,25 +290,25 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn purchase_credit() -> Weight { // Proof Size summary in bytes: - // Measured: `215` - // Estimated: `3680` - // Minimum execution time: 53_789_000 picoseconds. - Weight::from_parts(55_439_000, 0) - .saturating_add(Weight::from_parts(0, 3680)) + // Measured: `320` + // Estimated: `3785` + // Minimum execution time: 59_759_000 picoseconds. + Weight::from_parts(61_310_000, 0) + .saturating_add(Weight::from_parts(0, 3785)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Broker::Status` (r:1 w:0) /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `Broker::Regions` (r:1 w:1) - /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) fn drop_region() -> Weight { // Proof Size summary in bytes: - // Measured: `465` - // Estimated: `3550` - // Minimum execution time: 43_941_000 picoseconds. - Weight::from_parts(49_776_000, 0) - .saturating_add(Weight::from_parts(0, 3550)) + // Measured: `466` + // Estimated: `3551` + // Minimum execution time: 37_007_000 picoseconds. + Weight::from_parts(51_927_000, 0) + .saturating_add(Weight::from_parts(0, 3551)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -309,8 +322,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `463` // Estimated: `3533` - // Minimum execution time: 64_917_000 picoseconds. - Weight::from_parts(70_403_000, 0) + // Minimum execution time: 86_563_000 picoseconds. + Weight::from_parts(91_274_000, 0) .saturating_add(Weight::from_parts(0, 3533)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -327,8 +340,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `857` // Estimated: `3593` - // Minimum execution time: 72_633_000 picoseconds. - Weight::from_parts(79_305_000, 0) + // Minimum execution time: 93_655_000 picoseconds. + Weight::from_parts(98_160_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) @@ -341,8 +354,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `556` // Estimated: `4698` - // Minimum execution time: 36_643_000 picoseconds. - Weight::from_parts(48_218_000, 0) + // Minimum execution time: 33_985_000 picoseconds. + Weight::from_parts(43_618_000, 0) .saturating_add(Weight::from_parts(0, 4698)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -358,13 +371,15 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `n` is `[0, 1000]`. - fn request_core_count(_n: u32, ) -> Weight { + fn request_core_count(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 17_617_000 picoseconds. - Weight::from_parts(18_904_788, 0) + // Minimum execution time: 18_778_000 picoseconds. + Weight::from_parts(19_543_425, 0) .saturating_add(Weight::from_parts(0, 3539)) + // Standard Error: 41 + .saturating_add(Weight::from_parts(33, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -375,26 +390,26 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `266` // Estimated: `1487` - // Minimum execution time: 5_575_000 picoseconds. - Weight::from_parts(5_887_598, 0) + // Minimum execution time: 5_505_000 picoseconds. + Weight::from_parts(5_982_015, 0) .saturating_add(Weight::from_parts(0, 1487)) - // Standard Error: 16 - .saturating_add(Weight::from_parts(41, 0).saturating_mul(n.into())) + // Standard Error: 13 + .saturating_add(Weight::from_parts(44, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + /// Storage: `Broker::RevenueInbox` (r:1 w:1) + /// Proof: `Broker::RevenueInbox` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) /// Storage: `Broker::InstaPoolHistory` (r:1 w:1) /// Proof: `Broker::InstaPoolHistory` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:2 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn process_revenue() -> Weight { // Proof Size summary in bytes: - // Measured: `447` + // Measured: `442` // Estimated: `6196` - // Minimum execution time: 36_415_000 picoseconds. - Weight::from_parts(37_588_000, 0) + // Minimum execution time: 38_128_000 picoseconds. + Weight::from_parts(40_979_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -414,11 +429,11 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `12194` // Estimated: `13506` - // Minimum execution time: 48_362_000 picoseconds. - Weight::from_parts(49_616_106, 0) + // Minimum execution time: 49_041_000 picoseconds. + Weight::from_parts(50_522_788, 0) .saturating_add(Weight::from_parts(0, 13506)) - // Standard Error: 61 - .saturating_add(Weight::from_parts(59, 0).saturating_mul(n.into())) + // Standard Error: 72 + .saturating_add(Weight::from_parts(78, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(25)) } @@ -430,8 +445,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3493` - // Minimum execution time: 6_148_000 picoseconds. - Weight::from_parts(6_374_000, 0) + // Minimum execution time: 5_903_000 picoseconds. + Weight::from_parts(6_202_000, 0) .saturating_add(Weight::from_parts(0, 3493)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -454,8 +469,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1321` // Estimated: `4786` - // Minimum execution time: 30_267_000 picoseconds. - Weight::from_parts(30_825_000, 0) + // Minimum execution time: 31_412_000 picoseconds. + Weight::from_parts(31_964_000, 0) .saturating_add(Weight::from_parts(0, 4786)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -474,8 +489,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 13_491_000 picoseconds. - Weight::from_parts(13_949_000, 0) + // Minimum execution time: 14_098_000 picoseconds. + Weight::from_parts(14_554_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -486,8 +501,19 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_711_000 picoseconds. - Weight::from_parts(1_913_000, 0) + // Minimum execution time: 1_723_000 picoseconds. + Weight::from_parts(1_822_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Broker::RevenueInbox` (r:0 w:1) + /// Proof: `Broker::RevenueInbox` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) + fn notify_revenue() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_865_000 picoseconds. + Weight::from_parts(1_983_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -497,19 +523,19 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) /// Storage: `Broker::CoreCountInbox` (r:1 w:0) /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + /// Storage: `Broker::RevenueInbox` (r:1 w:0) + /// Proof: `Broker::RevenueInbox` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn do_tick_base() -> Weight { // Proof Size summary in bytes: - // Measured: `398` - // Estimated: `3863` - // Minimum execution time: 12_035_000 picoseconds. - Weight::from_parts(12_383_000, 0) - .saturating_add(Weight::from_parts(0, 3863)) + // Measured: `408` + // Estimated: `1893` + // Minimum execution time: 10_387_000 picoseconds. + Weight::from_parts(10_819_000, 0) + .saturating_add(Weight::from_parts(0, 1893)) .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Broker::Leases` (r:1 w:1) /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(81), added: 576, mode: `MaxEncodedLen`) @@ -517,10 +543,21 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `150` // Estimated: `1566` - // Minimum execution time: 6_142_000 picoseconds. - Weight::from_parts(6_538_000, 0) + // Minimum execution time: 5_996_000 picoseconds. + Weight::from_parts(6_278_000, 0) .saturating_add(Weight::from_parts(0, 1566)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn on_new_timeslice() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 2_187_000 picoseconds. + Weight::from_parts(2_372_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(1)) + } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs index 99af88812da2be05bd9273585ea7d186be9f8b90..f35f7bfc188dce73525b5742345e7eb9ed459385 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs @@ -17,10 +17,10 @@ mod pallet_xcm_benchmarks_fungible; mod pallet_xcm_benchmarks_generic; use crate::{xcm_config::MaxAssetsIntoHolding, Runtime}; +use alloc::vec::Vec; use frame_support::weights::Weight; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; -use sp_std::prelude::*; use xcm::{latest::prelude::*, DoubleEncoded}; trait WeighAssets { diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 8e1461c4a99e2e95dea078280844a157ab4084de..ddfc599fa579dd7ae4b83d0a94b0e7092fbdc9c1 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -43,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::fungible`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 9657fa55c1f2fdd4cf6ffdc4888e13e22a262155..7390f35e3974060abf4efd0e621239fa6a9bead0 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -43,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::generic`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs index b12765870bfdbbc7eb495a52e9ec4e931dc442da..da8aa1c18bdf44e50643fe6b85cd755051e23c0f 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs @@ -43,10 +43,10 @@ use xcm_builder::{ AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NonFungibleAdapter, ParentAsSuperuser, ParentIsPreset, - RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + RelayChainAsNative, SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; @@ -221,7 +221,7 @@ impl xcm_executor::Config for XcmConfig { type AssetExchanger = (); type FeeManager = XcmFeeManagerFromComponents< WaivedLocations, - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = Nothing; diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml index 92a5bbbd1376088909f315371dff6be13ffa69af..d20b62a557b950e080ae7eca38526d6af9846861 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml @@ -10,54 +10,53 @@ description = "Glutton parachain runtime." workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } # Substrate -frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../../substrate/frame/system", default-features = false } -frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false } -frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true } -frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } -pallet-glutton = { path = "../../../../../substrate/frame/glutton", default-features = false } -pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false } -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false } -sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } -sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } -sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -sp-session = { path = "../../../../../substrate/primitives/session", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-storage = { path = "../../../../../substrate/primitives/storage", default-features = false } -sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } -sp-version = { path = "../../../../../substrate/primitives/version", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-executive = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +frame-system-benchmarking = { optional = true, workspace = true } +frame-try-runtime = { optional = true, workspace = true } +pallet-aura = { workspace = true } +pallet-glutton = { workspace = true } +pallet-sudo = { workspace = true } +pallet-timestamp = { workspace = true } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-core = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } +pallet-message-queue = { workspace = true } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-storage = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } # Polkadot -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } # Cumulus -cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } -cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } -cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } -cumulus-primitives-timestamp = { path = "../../../../primitives/timestamp", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } -testnet-parachains-constants = { path = "../../constants", default-features = false, features = ["westend"] } +cumulus-pallet-aura-ext = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-primitives-aura = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-timestamp = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } +testnet-parachains-constants = { features = ["westend"], workspace = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder" } +substrate-wasm-builder = { workspace = true, default-features = true } [features] default = ["std"] @@ -109,7 +108,6 @@ std = [ "sp-offchain/std", "sp-runtime/std", "sp-session/std", - "sp-std/std", "sp-storage/std", "sp-transaction-pool/std", "sp-version/std", diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs index b8a328c3db696100a558e355286463e524f2f931..1b505ad3acbf7aa22a84ce9923a621d826358122 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs @@ -47,6 +47,9 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub mod weights; pub mod xcm_config; +extern crate alloc; + +use alloc::{vec, vec::Vec}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use sp_api::impl_runtime_apis; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; @@ -57,7 +60,6 @@ use sp_runtime::{ transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, }; -use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -100,7 +102,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("glutton-westend"), impl_name: create_runtime_str!("glutton-westend"), authoring_version: 1, - spec_version: 1_013_000, + spec_version: 1_014_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -345,7 +347,7 @@ impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { Runtime::metadata_versions() } } @@ -455,7 +457,7 @@ impl_runtime_apis! { use frame_system_benchmarking::Pallet as SystemBench; impl frame_system_benchmarking::Config for Runtime { - fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { + fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); Ok(()) } diff --git a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml index d4e65da3cd6426f7a21a2c96d03d53d8161410fb..a732bec2352d2dfd6fe7e842cb6a5d3206291d7d 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml @@ -7,74 +7,73 @@ description = "Rococo's People parachain runtime" license = "Apache-2.0" [build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -enumflags2 = { version = "0.7.7" } -hex-literal = { version = "0.4.1" } +codec = { features = ["derive"], workspace = true } +enumflags2 = { workspace = true } +hex-literal = { workspace = true, default-features = true } log = { workspace = true } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Substrate -frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../../substrate/frame/system", default-features = false } -frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true } -frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false } -frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } -pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false } -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } -pallet-identity = { path = "../../../../../substrate/frame/identity", default-features = false } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } -pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false } -pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } -pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false } -sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } -sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false } -sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -sp-session = { path = "../../../../../substrate/primitives/session", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-storage = { path = "../../../../../substrate/primitives/storage", default-features = false } -sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } -sp-version = { path = "../../../../../substrate/primitives/version", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-executive = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-benchmarking = { optional = true, workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +frame-try-runtime = { optional = true, workspace = true } +pallet-aura = { workspace = true } +pallet-authorship = { workspace = true } +pallet-balances = { workspace = true } +pallet-identity = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-multisig = { workspace = true } +pallet-session = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-utility = { workspace = true } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-core = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-storage = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } # Polkadot -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } -pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } -polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false } -polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false } -rococo-runtime-constants = { path = "../../../../../polkadot/runtime/rococo/constants", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } -xcm-fee-payment-runtime-api = { path = "../../../../../polkadot/xcm/xcm-fee-payment-runtime-api", default-features = false } +pallet-xcm = { workspace = true } +pallet-xcm-benchmarks = { optional = true, workspace = true } +polkadot-parachain-primitives = { workspace = true } +polkadot-runtime-common = { workspace = true } +rococo-runtime-constants = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm-runtime-apis = { workspace = true } # Cumulus -cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } -cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false } -cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } -cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } -cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } -cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } -pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } -testnet-parachains-constants = { path = "../../constants", default-features = false, features = ["rococo"] } +cumulus-pallet-aura-ext = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-session-benchmarking = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +cumulus-primitives-aura = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-utility = { workspace = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true } +pallet-collator-selection = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } +testnet-parachains-constants = { features = ["rococo"], workspace = true } [features] default = ["std"] @@ -128,7 +127,6 @@ std = [ "sp-offchain/std", "sp-runtime/std", "sp-session/std", - "sp-std/std", "sp-storage/std", "sp-transaction-pool/std", "sp-version/std", @@ -136,7 +134,7 @@ std = [ "testnet-parachains-constants/std", "xcm-builder/std", "xcm-executor/std", - "xcm-fee-payment-runtime-api/std", + "xcm-runtime-apis/std", "xcm/std", ] @@ -165,7 +163,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", - "xcm-fee-payment-runtime-api/runtime-benchmarks", + "xcm-runtime-apis/runtime-benchmarks", ] try-runtime = [ diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index bd189c31114cbf72551c905defaefaff98c18775..4f007c3fc39db185df12cee525509d9a1433a9d9 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -22,6 +22,9 @@ pub mod people; mod weights; pub mod xcm_config; +extern crate alloc; + +use alloc::{vec, vec::Vec}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::{ @@ -59,7 +62,6 @@ use sp_runtime::{ ApplyExtrinsicResult, }; pub use sp_runtime::{MultiAddress, Perbill, Permill}; -use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -70,7 +72,7 @@ use xcm_config::{ FellowshipLocation, GovernanceLocation, PriceForSiblingParachainDelivery, XcmConfig, XcmOriginToTransactDispatchOrigin, }; -use xcm_fee_payment_runtime_api::{ +use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, }; @@ -132,7 +134,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("people-rococo"), impl_name: create_runtime_str!("people-rococo"), authoring_version: 1, - spec_version: 1_013_000, + spec_version: 1_014_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -521,7 +523,7 @@ impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { Runtime::metadata_versions() } } @@ -625,7 +627,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { let acceptable_assets = vec![AssetId(xcm_config::RelayLocation::get())]; PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) @@ -638,11 +640,11 @@ impl_runtime_apis! { Ok(WeightToFee::weight_to_fee(&weight)) }, Ok(asset_id) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); Err(XcmPaymentApiError::AssetNotFound) }, Err(_) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); Err(XcmPaymentApiError::VersionedConversionFailed) } } @@ -657,7 +659,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + impl xcm_runtime_apis::dry_run::DryRunApi for Runtime { fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { PolkadotXcm::dry_run_call::(origin, call) } @@ -667,6 +669,18 @@ impl_runtime_apis! { } } + impl xcm_runtime_apis::conversions::LocationToAccountApi for Runtime { + fn convert_location(location: VersionedLocation) -> Result< + AccountId, + xcm_runtime_apis::conversions::Error + > { + xcm_runtime_apis::conversions::LocationToAccountHelper::< + AccountId, + xcm_config::LocationToAccountId, + >::convert_location(location) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) @@ -725,7 +739,7 @@ impl_runtime_apis! { use frame_system_benchmarking::Pallet as SystemBench; impl frame_system_benchmarking::Config for Runtime { - fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { + fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); Ok(()) } diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/people.rs b/cumulus/parachains/runtimes/people/people-rococo/src/people.rs index 88a89711019d59436c1ca270bbf19781f6dc77f0..8211447d68c8a5a53457d1651cc95754c125f7fd 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/people.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/people.rs @@ -28,7 +28,6 @@ use sp_runtime::{ traits::{AccountIdConversion, Verify}, RuntimeDebug, }; -use sp_std::prelude::*; parameter_types! { // 27 | Min encoded size of `Registration` @@ -94,8 +93,8 @@ pub enum IdentityField { )] #[codec(mel_bound())] pub struct IdentityInfo { - /// A reasonable display name for the controller of the account. This should be whatever the - /// account is typically known as and should not be confusable with other entities, given + /// A reasonable display name for the controller of the account. This should be whatever the + /// account is typically known as and should not be confusable with other entities, given /// reasonable context. /// /// Stored as UTF-8. @@ -151,7 +150,7 @@ impl IdentityInformationProvider for IdentityInfo { #[cfg(feature = "runtime-benchmarks")] fn create_identity_info() -> Self { - let data = Data::Raw(vec![0; 32].try_into().unwrap()); + let data = Data::Raw(alloc::vec![0; 32].try_into().unwrap()); IdentityInfo { display: data.clone(), diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/cumulus_pallet_parachain_system.rs index fcea5fd1bf679c803509dd4529b45e4994a7438c..5715d56c2186836556973dc6bebbfec77ac99762 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/cumulus_pallet_parachain_system.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/cumulus_pallet_parachain_system.rs @@ -20,7 +20,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `cumulus_pallet_parachain_system`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_message_queue.rs index fe1911b77a72dbfed0309722a1c59f37b56cb40f..47c67901407366a9f07959e2e22ed5bc83c61a76 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_message_queue.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_message_queue.rs @@ -20,7 +20,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `pallet_message_queue`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs index 4afd65bdcfea18208046edb4cfe693207cada3bb..11c1bad9aa17866d882f4410d76065a18ab4ef28 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs @@ -17,10 +17,10 @@ mod pallet_xcm_benchmarks_fungible; mod pallet_xcm_benchmarks_generic; use crate::{xcm_config::MaxAssetsIntoHolding, Runtime}; +use alloc::vec::Vec; use frame_support::weights::Weight; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; -use sp_std::prelude::*; use xcm::{latest::prelude::*, DoubleEncoded}; trait WeighAssets { diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index b279399e7a96b68ac68f7e12ed165efb324fab9b..2364798596d50f396a3a732c1e9dc1ad6c48a5bf 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -42,7 +42,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::fungible`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index e2be324ee2d48c42a8d7340c8cbcd3a52b161f19..a50c8860c48f84197843a9fd4d44ddb39d742095 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -42,7 +42,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::generic`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs index cca964fb2441bbe8bd40d909eb90766907918df2..96ab3eafa785fe0135916d072666d7102e5027c3 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs @@ -40,10 +40,10 @@ use xcm_builder::{ AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, DescribeTerminus, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsConcrete, ParentAsSuperuser, - ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; @@ -219,7 +219,7 @@ impl xcm_executor::Config for XcmConfig { type AssetExchanger = (); type FeeManager = XcmFeeManagerFromComponents< WaivedLocations, - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = Nothing; diff --git a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml index b040613d19e75a51d3008af0f71aa7953e82be29..20c7e691ebc88622dc57b4a026533fae67cf3044 100644 --- a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml @@ -7,74 +7,73 @@ description = "Westend's People parachain runtime" license = "Apache-2.0" [build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -enumflags2 = { version = "0.7.7" } -hex-literal = { version = "0.4.1" } +codec = { features = ["derive"], workspace = true } +enumflags2 = { workspace = true } +hex-literal = { workspace = true, default-features = true } log = { workspace = true } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Substrate -frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../../substrate/frame/system", default-features = false } -frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true } -frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false } -frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } -pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false } -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } -pallet-identity = { path = "../../../../../substrate/frame/identity", default-features = false } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } -pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false } -pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } -pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false } -sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } -sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false } -sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -sp-session = { path = "../../../../../substrate/primitives/session", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-storage = { path = "../../../../../substrate/primitives/storage", default-features = false } -sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } -sp-version = { path = "../../../../../substrate/primitives/version", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-executive = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-benchmarking = { optional = true, workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +frame-try-runtime = { optional = true, workspace = true } +pallet-aura = { workspace = true } +pallet-authorship = { workspace = true } +pallet-balances = { workspace = true } +pallet-identity = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-multisig = { workspace = true } +pallet-session = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-utility = { workspace = true } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-core = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-storage = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } # Polkadot -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } -pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } -polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false } -polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false } -westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } -xcm-fee-payment-runtime-api = { path = "../../../../../polkadot/xcm/xcm-fee-payment-runtime-api", default-features = false } +pallet-xcm = { workspace = true } +pallet-xcm-benchmarks = { optional = true, workspace = true } +polkadot-parachain-primitives = { workspace = true } +polkadot-runtime-common = { workspace = true } +westend-runtime-constants = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm-runtime-apis = { workspace = true } # Cumulus -cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } -cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false } -cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } -cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } -cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } -cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } -pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } -testnet-parachains-constants = { path = "../../constants", default-features = false, features = ["westend"] } +cumulus-pallet-aura-ext = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-session-benchmarking = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +cumulus-primitives-aura = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-utility = { workspace = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true } +pallet-collator-selection = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } +testnet-parachains-constants = { features = ["westend"], workspace = true } [features] default = ["std"] @@ -127,7 +126,6 @@ std = [ "sp-offchain/std", "sp-runtime/std", "sp-session/std", - "sp-std/std", "sp-storage/std", "sp-transaction-pool/std", "sp-version/std", @@ -136,7 +134,7 @@ std = [ "westend-runtime-constants/std", "xcm-builder/std", "xcm-executor/std", - "xcm-fee-payment-runtime-api/std", + "xcm-runtime-apis/std", "xcm/std", ] @@ -165,7 +163,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", - "xcm-fee-payment-runtime-api/runtime-benchmarks", + "xcm-runtime-apis/runtime-benchmarks", ] try-runtime = [ diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index f071a5f0c9b128f25861c641d670b19564c1bc25..1378324ce7b022e306c39ce4d8b1669ef057eb96 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -22,6 +22,9 @@ pub mod people; mod weights; pub mod xcm_config; +extern crate alloc; + +use alloc::{vec, vec::Vec}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::{ @@ -59,7 +62,6 @@ use sp_runtime::{ ApplyExtrinsicResult, }; pub use sp_runtime::{MultiAddress, Perbill, Permill}; -use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -70,7 +72,7 @@ use xcm_config::{ FellowshipLocation, GovernanceLocation, PriceForSiblingParachainDelivery, XcmConfig, XcmOriginToTransactDispatchOrigin, }; -use xcm_fee_payment_runtime_api::{ +use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, }; @@ -132,7 +134,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("people-westend"), impl_name: create_runtime_str!("people-westend"), authoring_version: 1, - spec_version: 1_013_000, + spec_version: 1_014_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -521,7 +523,7 @@ impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { Runtime::metadata_versions() } } @@ -625,7 +627,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { let acceptable_assets = vec![AssetId(xcm_config::RelayLocation::get())]; PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) @@ -638,11 +640,11 @@ impl_runtime_apis! { Ok(WeightToFee::weight_to_fee(&weight)) }, Ok(asset_id) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); Err(XcmPaymentApiError::AssetNotFound) }, Err(_) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); Err(XcmPaymentApiError::VersionedConversionFailed) } } @@ -657,7 +659,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + impl xcm_runtime_apis::dry_run::DryRunApi for Runtime { fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { PolkadotXcm::dry_run_call::(origin, call) } @@ -667,6 +669,18 @@ impl_runtime_apis! { } } + impl xcm_runtime_apis::conversions::LocationToAccountApi for Runtime { + fn convert_location(location: VersionedLocation) -> Result< + AccountId, + xcm_runtime_apis::conversions::Error + > { + xcm_runtime_apis::conversions::LocationToAccountHelper::< + AccountId, + xcm_config::LocationToAccountId, + >::convert_location(location) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) @@ -725,7 +739,7 @@ impl_runtime_apis! { use frame_system_benchmarking::Pallet as SystemBench; impl frame_system_benchmarking::Config for Runtime { - fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { + fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); Ok(()) } diff --git a/cumulus/parachains/runtimes/people/people-westend/src/people.rs b/cumulus/parachains/runtimes/people/people-westend/src/people.rs index a5c0e66a3f882df14cbbd8dba51572834738015e..0255fd074b1119cf6432a2f9b0346e6523c181f8 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/people.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/people.rs @@ -28,7 +28,6 @@ use sp_runtime::{ traits::{AccountIdConversion, Verify}, RuntimeDebug, }; -use sp_std::prelude::*; parameter_types! { // 27 | Min encoded size of `Registration` @@ -151,7 +150,7 @@ impl IdentityInformationProvider for IdentityInfo { #[cfg(feature = "runtime-benchmarks")] fn create_identity_info() -> Self { - let data = Data::Raw(vec![0; 32].try_into().unwrap()); + let data = Data::Raw(alloc::vec![0; 32].try_into().unwrap()); IdentityInfo { display: data.clone(), diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/cumulus_pallet_parachain_system.rs index fcea5fd1bf679c803509dd4529b45e4994a7438c..5715d56c2186836556973dc6bebbfec77ac99762 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/cumulus_pallet_parachain_system.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/cumulus_pallet_parachain_system.rs @@ -20,7 +20,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `cumulus_pallet_parachain_system`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_message_queue.rs index fe1911b77a72dbfed0309722a1c59f37b56cb40f..47c67901407366a9f07959e2e22ed5bc83c61a76 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_message_queue.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_message_queue.rs @@ -20,7 +20,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `pallet_message_queue`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs index b2579230c9ed7afaf9d187a9e783992723444b3a..b1fc7ad8ed832ec6aa9a65c5e4ad3334ff3225d1 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs @@ -17,10 +17,10 @@ mod pallet_xcm_benchmarks_fungible; mod pallet_xcm_benchmarks_generic; use crate::{xcm_config::MaxAssetsIntoHolding, Runtime}; +use alloc::vec::Vec; use frame_support::weights::Weight; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; -use sp_std::prelude::*; use xcm::{latest::prelude::*, DoubleEncoded}; trait WeighAssets { diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index efffd318817106baf4e2f7661f4cd0a8c333b722..92d08a24618075d21614ae53ed17e3618fc2f8ea 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -42,7 +42,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::fungible`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index d7b10f95c792a9874bd98ccf4eb20bdf87e20bb0..861f038199596ef9813275e58914f252d8842a87 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -42,7 +42,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::generic`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs index 3926ddcf21efe09933e85552b3fc31f368d69e9b..f35e920d7cb752a4e6e8e427294726f1854e5bb4 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs @@ -40,10 +40,10 @@ use xcm_builder::{ AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, DescribeTerminus, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsConcrete, ParentAsSuperuser, - ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; @@ -227,7 +227,7 @@ impl xcm_executor::Config for XcmConfig { type AssetExchanger = (); type FeeManager = XcmFeeManagerFromComponents< WaivedLocations, - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = Nothing; diff --git a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml index 910944f54a5ff3433f11fab1d33aa0e88abc35b2..c76c09a31234e6077f97e38c7e38fe4fbddeae86 100644 --- a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml @@ -10,41 +10,40 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } # Substrate -frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../../substrate/frame/system", default-features = false } -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } -pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false } -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false } -sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } -sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false } -sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -sp-session = { path = "../../../../../substrate/primitives/session", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } -sp-version = { path = "../../../../../substrate/primitives/version", default-features = false } +frame-executive = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-aura = { workspace = true } +pallet-balances = { workspace = true } +pallet-sudo = { workspace = true } +pallet-timestamp = { workspace = true } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-core = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } # Cumulus -cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } -cumulus-pallet-solo-to-para = { path = "../../../../pallets/solo-to-para", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } -cumulus-primitives-timestamp = { path = "../../../../primitives/timestamp", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } +cumulus-pallet-aura-ext = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-solo-to-para = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-timestamp = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [features] default = ["std"] @@ -74,7 +73,6 @@ std = [ "sp-offchain/std", "sp-runtime/std", "sp-session/std", - "sp-std/std", "sp-transaction-pool/std", "sp-version/std", "substrate-wasm-builder", diff --git a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs index 461133f6cfc06ad8cea140ea19d6df6c8aebb520..1fe72604d3731eed1dee3d27477e0e829cccfba0 100644 --- a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs @@ -27,6 +27,9 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +extern crate alloc; + +use alloc::{vec, vec::Vec}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use sp_api::impl_runtime_apis; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; @@ -37,7 +40,6 @@ use sp_runtime::{ transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, }; -use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -310,7 +312,7 @@ impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { Runtime::metadata_versions() } } diff --git a/cumulus/parachains/runtimes/starters/shell/Cargo.toml b/cumulus/parachains/runtimes/starters/shell/Cargo.toml index 7a7fad537ac302a9e71889c949a04aacc79df3f3..8f3b2204cfe34b8bb73c6a9062c9a91df262a8e4 100644 --- a/cumulus/parachains/runtimes/starters/shell/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/shell/Cargo.toml @@ -10,45 +10,44 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } # Substrate -frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../../substrate/frame/system", default-features = false } -frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false } -sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } -sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false } -sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -sp-session = { path = "../../../../../substrate/primitives/session", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } -sp-version = { path = "../../../../../substrate/primitives/version", default-features = false } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } +frame-executive = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-try-runtime = { optional = true, workspace = true } +pallet-aura = { workspace = true } +pallet-timestamp = { workspace = true } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-core = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } +pallet-message-queue = { workspace = true } # Polkadot -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } # Cumulus -cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } -cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } +cumulus-pallet-aura-ext = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-primitives-core = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [features] default = ["std"] @@ -77,7 +76,6 @@ std = [ "sp-offchain/std", "sp-runtime/std", "sp-session/std", - "sp-std/std", "sp-transaction-pool/std", "sp-version/std", "substrate-wasm-builder", diff --git a/cumulus/parachains/runtimes/starters/shell/src/lib.rs b/cumulus/parachains/runtimes/starters/shell/src/lib.rs index 7422b580cc3e08c1df8af5e9dce23d79d0c4e1a8..1dfbe2b6c41c840846e1d64a4d87e7c9c1b0c7cf 100644 --- a/cumulus/parachains/runtimes/starters/shell/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/shell/src/lib.rs @@ -31,6 +31,9 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub mod xcm_config; +extern crate alloc; + +use alloc::{vec, vec::Vec}; use codec::{Decode, Encode}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use cumulus_primitives_core::AggregateMessageOrigin; @@ -45,7 +48,6 @@ use sp_runtime::{ transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, }; -use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -280,7 +282,7 @@ impl sp_runtime::traits::SignedExtension for DisallowSigned { type Pre = (); fn additional_signed( &self, - ) -> sp_std::result::Result<(), sp_runtime::transaction_validity::TransactionValidityError> { + ) -> core::result::Result<(), sp_runtime::transaction_validity::TransactionValidityError> { Ok(()) } fn pre_dispatch( @@ -368,7 +370,7 @@ impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { Runtime::metadata_versions() } } diff --git a/cumulus/parachains/runtimes/test-utils/Cargo.toml b/cumulus/parachains/runtimes/test-utils/Cargo.toml index c081bac4babe87413c40869917715d03c0c71a86..01d7fcc2b5c8b77c7daa90d807634193545e95ec 100644 --- a/cumulus/parachains/runtimes/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/test-utils/Cargo.toml @@ -10,41 +10,40 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { features = ["derive", "max-encoded-len"], workspace = true } # Substrate -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../substrate/frame/system", default-features = false } -pallet-balances = { path = "../../../../substrate/frame/balances", default-features = false } -pallet-session = { path = "../../../../substrate/frame/session", default-features = false } -pallet-timestamp = { path = "../../../../substrate/frame/timestamp", default-features = false } -sp-consensus-aura = { path = "../../../../substrate/primitives/consensus/aura", default-features = false } -sp-io = { path = "../../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } -sp-tracing = { path = "../../../../substrate/primitives/tracing" } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-balances = { workspace = true } +pallet-session = { workspace = true } +pallet-timestamp = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +sp-tracing = { workspace = true, default-features = true } +sp-core = { workspace = true } # Cumulus -cumulus-pallet-parachain-system = { path = "../../../pallets/parachain-system", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../../pallets/xcmp-queue", default-features = false } -pallet-collator-selection = { path = "../../../pallets/collator-selection", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../pallets/parachain-info", default-features = false } -cumulus-primitives-core = { path = "../../../primitives/core", default-features = false } -cumulus-primitives-parachain-inherent = { path = "../../../primitives/parachain-inherent", default-features = false } -cumulus-test-relay-sproof-builder = { path = "../../../test/relay-sproof-builder", default-features = false } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +pallet-collator-selection = { workspace = true } +parachain-info = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-parachain-inherent = { workspace = true } +cumulus-test-relay-sproof-builder = { workspace = true } # Polkadot -xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../polkadot/xcm/xcm-executor", default-features = false } -pallet-xcm = { path = "../../../../polkadot/xcm/pallet-xcm", default-features = false } -polkadot-parachain-primitives = { path = "../../../../polkadot/parachain", default-features = false } +xcm = { workspace = true } +xcm-executor = { workspace = true } +pallet-xcm = { workspace = true } +polkadot-parachain-primitives = { workspace = true } [dev-dependencies] -hex-literal = "0.4.1" +hex-literal = { workspace = true, default-features = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../../substrate/utils/wasm-builder" } +substrate-wasm-builder = { workspace = true, default-features = true } [features] default = ["std"] @@ -68,7 +67,6 @@ std = [ "sp-core/std", "sp-io/std", "sp-runtime/std", - "sp-std/std", "xcm-executor/std", "xcm/std", ] diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index 3c84243306fbe518dd00ee78411d9ec032e90446..3fc3822a63eb9a2c98bc273814854ee2d56035bf 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use sp_std::marker::PhantomData; +use core::marker::PhantomData; use codec::{Decode, DecodeLimit}; use cumulus_primitives_core::{ diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index 3262233053e7e130c230adbc0aef857572756b1d..1a2737f3aa224c1dbf016173a259aafb0224341a 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -15,70 +15,69 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -hex-literal = { version = "0.4.1", optional = true } +codec = { features = ["derive"], workspace = true } +hex-literal = { optional = true, workspace = true, default-features = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } -smallvec = "1.11.0" +scale-info = { features = ["derive"], workspace = true } +smallvec = { workspace = true, default-features = true } # Substrate -frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../../substrate/frame/system", default-features = false } -frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true } -frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false } -frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } -pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false } -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } -pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } -pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false } -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } -pallet-asset-tx-payment = { path = "../../../../../substrate/frame/transaction-payment/asset-tx-payment", default-features = false } -pallet-assets = { path = "../../../../../substrate/frame/assets", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false } -sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } -sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false } -sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -sp-session = { path = "../../../../../substrate/primitives/session", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-storage = { path = "../../../../../substrate/primitives/storage", default-features = false } -sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } -sp-version = { path = "../../../../../substrate/primitives/version", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-executive = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-benchmarking = { optional = true, workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +frame-try-runtime = { optional = true, workspace = true } +pallet-aura = { workspace = true } +pallet-authorship = { workspace = true } +pallet-balances = { workspace = true } +pallet-session = { workspace = true } +pallet-sudo = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-asset-tx-payment = { workspace = true } +pallet-assets = { workspace = true } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-core = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-storage = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } # Polkadot -polkadot-primitives = { path = "../../../../../polkadot/primitives", default-features = false } -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } -polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false } -polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } -xcm-fee-payment-runtime-api = { path = "../../../../../polkadot/xcm/xcm-fee-payment-runtime-api", default-features = false } +polkadot-primitives = { workspace = true } +pallet-xcm = { workspace = true } +polkadot-parachain-primitives = { workspace = true } +polkadot-runtime-common = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm-runtime-apis = { workspace = true } # Cumulus -cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } -cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false } -cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } -cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } -pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } -parachains-common = { path = "../../../common", default-features = false } -assets-common = { path = "../../assets/common", default-features = false } +cumulus-pallet-aura-ext = { workspace = true } +pallet-message-queue = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-session-benchmarking = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-utility = { workspace = true } +pallet-collator-selection = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } +assets-common = { workspace = true } [features] default = ["std"] @@ -128,14 +127,13 @@ std = [ "sp-offchain/std", "sp-runtime/std", "sp-session/std", - "sp-std/std", "sp-storage/std", "sp-transaction-pool/std", "sp-version/std", "substrate-wasm-builder", "xcm-builder/std", "xcm-executor/std", - "xcm-fee-payment-runtime-api/std", + "xcm-runtime-apis/std", "xcm/std", ] @@ -166,7 +164,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", - "xcm-fee-payment-runtime-api/runtime-benchmarks", + "xcm-runtime-apis/runtime-benchmarks", ] try-runtime = [ diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index e77416e6cd5b681a83b3d8b0571401ef1543004b..bf39c02a3f59460156c37e6c652bc69fa7237a2d 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -32,6 +32,9 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); mod weights; pub mod xcm_config; +extern crate alloc; + +use alloc::{vec, vec::Vec}; use codec::Encode; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; @@ -69,7 +72,6 @@ use sp_runtime::{ ApplyExtrinsicResult, }; pub use sp_runtime::{traits::ConvertInto, MultiAddress, Perbill, Permill}; -use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -85,7 +87,7 @@ use xcm::{ latest::prelude::{AssetId as AssetLocationId, BodyId}, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, }; -use xcm_fee_payment_runtime_api::{ +use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, }; @@ -737,7 +739,7 @@ impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { Runtime::metadata_versions() } } @@ -847,7 +849,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { let acceptable_assets = vec![AssetLocationId(xcm_config::RelayLocation::get())]; PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) @@ -860,11 +862,11 @@ impl_runtime_apis! { Ok(WeightToFee::weight_to_fee(&weight)) }, Ok(asset_id) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); Err(XcmPaymentApiError::AssetNotFound) }, Err(_) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); Err(XcmPaymentApiError::VersionedConversionFailed) } } @@ -879,7 +881,7 @@ impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + impl xcm_runtime_apis::dry_run::DryRunApi for Runtime { fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { use xcm_builder::InspectMessageQueues; use xcm_executor::RecordXcm; diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 08a2da260c57e67b17eecf55f3845049e371b996..eca7c7bbc3c2daa4291ba84a11e67b335377e4df 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -47,11 +47,11 @@ use xcm_builder::{ AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex, ConvertedConcreteId, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, NoChecking, - ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, StartsWith, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, - XcmFeeToAccount, + ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, StartsWith, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, }; use xcm_executor::{traits::JustTry, XcmExecutor}; @@ -351,7 +351,7 @@ impl xcm_executor::Config for XcmConfig { type AssetExchanger = (); type FeeManager = XcmFeeManagerFromComponents< (), - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = Nothing; diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index cf734345a976f027ae31f2f38735b9b7aac59f7d..a0ad248bb7048f9a19cec45f97ad4242c9455f83 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -10,60 +10,59 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } # Substrate -frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } -frame-support = { path = "../../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../../substrate/frame/system", default-features = false } -frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false } -pallet-assets = { path = "../../../../../substrate/frame/assets", default-features = false } -pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } -pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false } -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } -sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } -sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false } -sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } -sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false } -sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } -sp-session = { path = "../../../../../substrate/primitives/session", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false } -sp-version = { path = "../../../../../substrate/primitives/version", default-features = false } +frame-benchmarking = { optional = true, workspace = true } +frame-executive = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +pallet-assets = { workspace = true } +pallet-aura = { workspace = true } +pallet-balances = { workspace = true } +pallet-sudo = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-core = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } # Polkadot -pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } -polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false } -xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } -polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false } +pallet-xcm = { workspace = true } +polkadot-parachain-primitives = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +polkadot-runtime-common = { workspace = true } # Cumulus -cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } -pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } -cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } -cumulus-ping = { path = "../../../pallets/ping", default-features = false } -cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } -cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } -cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } -cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } -parachains-common = { path = "../../../common", default-features = false } -testnet-parachains-constants = { path = "../../constants", default-features = false, features = ["rococo"] } -parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } +cumulus-pallet-aura-ext = { workspace = true } +pallet-message-queue = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +cumulus-ping = { workspace = true } +cumulus-primitives-aura = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true } +cumulus-primitives-utility = { workspace = true } +parachains-common = { workspace = true } +testnet-parachains-constants = { features = ["rococo"], workspace = true } +parachain-info = { workspace = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [features] default = ["std"] @@ -106,7 +105,6 @@ std = [ "sp-offchain/std", "sp-runtime/std", "sp-session/std", - "sp-std/std", "sp-transaction-pool/std", "sp-version/std", "substrate-wasm-builder", diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index bf45b437f8bb0bba641ee1d622709ee4ed65732d..dff7046f1972614d30210b6ac6d21c24e0350aea 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -22,6 +22,9 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +extern crate alloc; + +use alloc::{vec, vec::Vec}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use sp_api::impl_runtime_apis; @@ -32,7 +35,6 @@ use sp_runtime::{ transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, }; -use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -107,7 +109,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("test-parachain"), impl_name: create_runtime_str!("test-parachain"), authoring_version: 1, - spec_version: 1_013_000, + spec_version: 1_014_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, @@ -711,7 +713,7 @@ impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { Runtime::metadata_versions() } } diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 890cf51991699d559f0d416dd91e4347e506bff8..b20d2a28fa7f3be2b6517dab5fc422c68d1ec787 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -15,113 +15,114 @@ name = "polkadot-parachain" path = "src/main.rs" [dependencies] -async-trait = "0.1.79" -clap = { version = "4.5.3", features = ["derive"] } -codec = { package = "parity-scale-codec", version = "3.6.12" } -color-print = "0.3.4" -futures = "0.3.28" -hex-literal = "0.4.1" +async-trait = { workspace = true } +clap = { features = ["derive"], workspace = true } +codec = { workspace = true, default-features = true } +color-print = { workspace = true } +futures = { workspace = true } +hex-literal = { workspace = true, default-features = true } log = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } +docify = { workspace = true } # Local -rococo-parachain-runtime = { path = "../parachains/runtimes/testing/rococo-parachain" } -shell-runtime = { path = "../parachains/runtimes/starters/shell" } -glutton-westend-runtime = { path = "../parachains/runtimes/glutton/glutton-westend" } -seedling-runtime = { path = "../parachains/runtimes/starters/seedling" } -asset-hub-rococo-runtime = { path = "../parachains/runtimes/assets/asset-hub-rococo" } -asset-hub-westend-runtime = { path = "../parachains/runtimes/assets/asset-hub-westend" } -collectives-westend-runtime = { path = "../parachains/runtimes/collectives/collectives-westend" } -contracts-rococo-runtime = { path = "../parachains/runtimes/contracts/contracts-rococo" } -bridge-hub-rococo-runtime = { path = "../parachains/runtimes/bridge-hubs/bridge-hub-rococo" } -coretime-rococo-runtime = { path = "../parachains/runtimes/coretime/coretime-rococo" } -coretime-westend-runtime = { path = "../parachains/runtimes/coretime/coretime-westend" } -bridge-hub-westend-runtime = { path = "../parachains/runtimes/bridge-hubs/bridge-hub-westend" } -penpal-runtime = { path = "../parachains/runtimes/testing/penpal" } -jsonrpsee = { version = "0.22", features = ["server"] } -people-rococo-runtime = { path = "../parachains/runtimes/people/people-rococo" } -people-westend-runtime = { path = "../parachains/runtimes/people/people-westend" } -parachains-common = { path = "../parachains/common" } -testnet-parachains-constants = { path = "../parachains/runtimes/constants", default-features = false, features = [ +rococo-parachain-runtime = { workspace = true } +shell-runtime = { workspace = true } +glutton-westend-runtime = { workspace = true } +seedling-runtime = { workspace = true } +asset-hub-rococo-runtime = { workspace = true, default-features = true } +asset-hub-westend-runtime = { workspace = true } +collectives-westend-runtime = { workspace = true } +contracts-rococo-runtime = { workspace = true } +bridge-hub-rococo-runtime = { workspace = true, default-features = true } +coretime-rococo-runtime = { workspace = true } +coretime-westend-runtime = { workspace = true } +bridge-hub-westend-runtime = { workspace = true, default-features = true } +penpal-runtime = { workspace = true } +jsonrpsee = { features = ["server"], workspace = true } +people-rococo-runtime = { workspace = true } +people-westend-runtime = { workspace = true } +parachains-common = { workspace = true, default-features = true } +testnet-parachains-constants = { features = [ "rococo", "westend", -] } +], workspace = true } # Substrate -frame-benchmarking = { path = "../../substrate/frame/benchmarking" } -frame-benchmarking-cli = { path = "../../substrate/utils/frame/benchmarking-cli" } -sp-runtime = { path = "../../substrate/primitives/runtime", default-features = false } -sp-io = { path = "../../substrate/primitives/io" } -sp-core = { path = "../../substrate/primitives/core" } -sp-session = { path = "../../substrate/primitives/session" } -frame-try-runtime = { path = "../../substrate/frame/try-runtime", optional = true } -sc-consensus = { path = "../../substrate/client/consensus/common" } -sp-tracing = { path = "../../substrate/primitives/tracing" } -frame-support = { path = "../../substrate/frame/support" } -sc-cli = { path = "../../substrate/client/cli" } -sc-client-api = { path = "../../substrate/client/api" } -sc-executor = { path = "../../substrate/client/executor" } -sc-service = { path = "../../substrate/client/service" } -sc-telemetry = { path = "../../substrate/client/telemetry" } -sc-transaction-pool = { path = "../../substrate/client/transaction-pool" } -sp-transaction-pool = { path = "../../substrate/primitives/transaction-pool" } -sc-network = { path = "../../substrate/client/network" } -sc-network-sync = { path = "../../substrate/client/network/sync" } -sc-basic-authorship = { path = "../../substrate/client/basic-authorship" } -sp-timestamp = { path = "../../substrate/primitives/timestamp" } -sp-blockchain = { path = "../../substrate/primitives/blockchain" } -sp-genesis-builder = { path = "../../substrate/primitives/genesis-builder", default-features = false } -sp-block-builder = { path = "../../substrate/primitives/block-builder" } -sp-keystore = { path = "../../substrate/primitives/keystore" } -sc-chain-spec = { path = "../../substrate/client/chain-spec" } -sc-rpc = { path = "../../substrate/client/rpc" } -sp-version = { path = "../../substrate/primitives/version" } -sc-tracing = { path = "../../substrate/client/tracing" } -sp-offchain = { path = "../../substrate/primitives/offchain" } -frame-system-rpc-runtime-api = { path = "../../substrate/frame/system/rpc/runtime-api" } -pallet-transaction-payment = { path = "../../substrate/frame/transaction-payment" } -pallet-transaction-payment-rpc-runtime-api = { path = "../../substrate/frame/transaction-payment/rpc/runtime-api" } -sp-std = { path = "../../substrate/primitives/std" } -sp-inherents = { path = "../../substrate/primitives/inherents" } -sp-api = { path = "../../substrate/primitives/api" } -sp-consensus-aura = { path = "../../substrate/primitives/consensus/aura" } -sc-sysinfo = { path = "../../substrate/client/sysinfo" } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../substrate/utils/prometheus" } -sc-transaction-pool-api = { path = "../../substrate/client/transaction-pool/api" } -substrate-frame-rpc-system = { path = "../../substrate/utils/frame/rpc/system" } -pallet-transaction-payment-rpc = { path = "../../substrate/frame/transaction-payment/rpc" } -substrate-state-trie-migration-rpc = { path = "../../substrate/utils/frame/rpc/state-trie-migration-rpc" } +frame-benchmarking = { workspace = true, default-features = true } +frame-benchmarking-cli = { workspace = true, default-features = true } +sp-runtime = { workspace = true } +sp-io = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-session = { workspace = true, default-features = true } +frame-try-runtime = { optional = true, workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +frame-support = { workspace = true, default-features = true } +sc-cli = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-executor = { workspace = true, default-features = true } +sc-service = { workspace = true, default-features = true } +sc-telemetry = { workspace = true, default-features = true } +sc-transaction-pool = { workspace = true, default-features = true } +sp-transaction-pool = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-network-sync = { workspace = true, default-features = true } +sc-basic-authorship = { workspace = true, default-features = true } +sp-timestamp = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-genesis-builder = { workspace = true } +sp-block-builder = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sc-chain-spec = { workspace = true, default-features = true } +sc-rpc = { workspace = true, default-features = true } +sp-version = { workspace = true, default-features = true } +sc-tracing = { workspace = true, default-features = true } +sp-offchain = { workspace = true, default-features = true } +frame-system-rpc-runtime-api = { workspace = true, default-features = true } +pallet-transaction-payment = { workspace = true, default-features = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-consensus-aura = { workspace = true, default-features = true } +sc-sysinfo = { workspace = true, default-features = true } +prometheus-endpoint = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } +substrate-frame-rpc-system = { workspace = true, default-features = true } +pallet-transaction-payment-rpc = { workspace = true, default-features = true } +substrate-state-trie-migration-rpc = { workspace = true, default-features = true } # Polkadot # Use rococo-native as this is currently the default "local" relay chain -polkadot-cli = { path = "../../polkadot/cli", features = ["rococo-native"] } -polkadot-primitives = { path = "../../polkadot/primitives" } -polkadot-service = { path = "../../polkadot/node/service" } -xcm = { package = "staging-xcm", path = "../../polkadot/xcm" } +polkadot-cli = { features = ["rococo-native", "westend-native"], workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-service = { workspace = true, default-features = true } +xcm = { workspace = true, default-features = true } # Cumulus -cumulus-client-cli = { path = "../client/cli" } -cumulus-client-collator = { path = "../client/collator" } -cumulus-client-consensus-aura = { path = "../client/consensus/aura" } -cumulus-client-consensus-relay-chain = { path = "../client/consensus/relay-chain" } -cumulus-client-consensus-common = { path = "../client/consensus/common" } -cumulus-client-consensus-proposer = { path = "../client/consensus/proposer" } -cumulus-client-parachain-inherent = { path = "../client/parachain-inherent" } -cumulus-client-service = { path = "../client/service" } -cumulus-primitives-aura = { path = "../primitives/aura" } -cumulus-primitives-core = { path = "../primitives/core" } -cumulus-relay-chain-interface = { path = "../client/relay-chain-interface" } +cumulus-client-cli = { workspace = true, default-features = true } +cumulus-client-collator = { workspace = true, default-features = true } +cumulus-client-consensus-aura = { workspace = true, default-features = true } +cumulus-client-consensus-relay-chain = { workspace = true, default-features = true } +cumulus-client-consensus-common = { workspace = true, default-features = true } +cumulus-client-consensus-proposer = { workspace = true, default-features = true } +cumulus-client-parachain-inherent = { workspace = true, default-features = true } +cumulus-client-service = { workspace = true, default-features = true } +cumulus-primitives-aura = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true, default-features = true } +cumulus-relay-chain-interface = { workspace = true, default-features = true } [build-dependencies] -substrate-build-script-utils = { path = "../../substrate/utils/build-script-utils" } +substrate-build-script-utils = { workspace = true, default-features = true } [dev-dependencies] -assert_cmd = "2.0" -nix = { version = "0.28.0", features = ["signal"] } -tempfile = "3.8.0" +assert_cmd = { workspace = true } +nix = { features = ["signal"], workspace = true } +tempfile = { workspace = true } tokio = { version = "1.32.0", features = ["macros", "parking_lot", "time"] } -wait-timeout = "0.2" +wait-timeout = { workspace = true } [features] default = [] @@ -171,4 +172,8 @@ try-runtime = [ "shell-runtime/try-runtime", "sp-runtime/try-runtime", ] -fast-runtime = ["bridge-hub-rococo-runtime/fast-runtime"] +fast-runtime = [ + "bridge-hub-rococo-runtime/fast-runtime", + "coretime-rococo-runtime/fast-runtime", + "coretime-westend-runtime/fast-runtime", +] diff --git a/cumulus/polkadot-parachain/chain-specs/people-polkadot.json b/cumulus/polkadot-parachain/chain-specs/people-polkadot.json new file mode 120000 index 0000000000000000000000000000000000000000..44fead1c49e05610ad5f5eac76e6e7ee8b862587 --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/people-polkadot.json @@ -0,0 +1 @@ +../../parachains/chain-specs/people-polkadot.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/src/chain_spec/people.rs b/cumulus/polkadot-parachain/src/chain_spec/people.rs index db8756e68819b3f7abaeeea9e8b684f75beda5dc..6100a15018cb17e82401924f6c210e9481815480 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/people.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/people.rs @@ -63,8 +63,9 @@ impl PeopleRuntimeType { PeopleRuntimeType::Kusama => Ok(Box::new(GenericChainSpec::from_json_bytes( &include_bytes!("../../chain-specs/people-kusama.json")[..], )?)), - PeopleRuntimeType::Polkadot => - todo!("Generate chain-spec: ../../chain-specs/people-polkadot.json"), + PeopleRuntimeType::Polkadot => Ok(Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../../chain-specs/people-polkadot.json")[..], + )?)), PeopleRuntimeType::Rococo => Ok(Box::new(GenericChainSpec::from_json_bytes( &include_bytes!("../../chain-specs/people-rococo.json")[..], )?)), diff --git a/cumulus/polkadot-parachain/src/cli.rs b/cumulus/polkadot-parachain/src/cli.rs index fa4b4da1ba9cadcd2d2d16c772e9d1ceed26f486..a5fe33dffc9672682e0585194981e42141803de6 100644 --- a/cumulus/polkadot-parachain/src/cli.rs +++ b/cumulus/polkadot-parachain/src/cli.rs @@ -14,7 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use clap::{CommandFactory, FromArgMatches}; +use crate::common::NodeExtraArgs; +use clap::{Command, CommandFactory, FromArgMatches}; +use sc_cli::SubstrateCli; use std::path::PathBuf; /// Sub-commands supported by the collator. @@ -58,22 +60,13 @@ pub enum Subcommand { Benchmark(frame_benchmarking_cli::BenchmarkCmd), } -const AFTER_HELP_EXAMPLE: &str = color_print::cstr!( - r#"Examples: - polkadot-parachain --chain asset-hub-polkadot --sync warp -- --chain polkadot --sync warp - Launch a warp-syncing full node of the Asset Hub parachain on the Polkadot Relay Chain. - polkadot-parachain --chain asset-hub-polkadot --sync warp --relay-chain-rpc-url ws://rpc.example.com -- --chain polkadot - Launch a warp-syncing full node of the Asset Hub parachain on the Polkadot Relay Chain. - Uses ws://rpc.example.com as remote relay chain node. - "# -); #[derive(Debug, clap::Parser)] #[command( propagate_version = true, args_conflicts_with_subcommands = true, - subcommand_negates_reqs = true + subcommand_negates_reqs = true, + after_help = crate::examples(Self::executable_name()) )] -#[clap(after_help = AFTER_HELP_EXAMPLE)] pub struct Cli { #[command(subcommand)] pub subcommand: Option, @@ -81,6 +74,12 @@ pub struct Cli { #[command(flatten)] pub run: cumulus_client_cli::RunCmd, + /// EXPERIMENTAL: Use slot-based collator which can handle elastic scaling. + /// + /// Use with care, this flag is unstable and subject to change. + #[arg(long)] + pub experimental_use_slot_based: bool, + /// Disable automatic hardware benchmarks. /// /// By default these benchmarks are automatically ran at startup and measure @@ -91,9 +90,25 @@ pub struct Cli { #[arg(long)] pub no_hardware_benchmarks: bool, + /// Export all `PoVs` build by this collator to the given folder. + /// + /// This is useful for debugging issues that are occurring while validating these `PoVs` on the + /// relay chain. + #[arg(long)] + pub export_pov_to_path: Option, + /// Relay chain arguments #[arg(raw = true)] - pub relaychain_args: Vec, + pub relay_chain_args: Vec, +} + +impl Cli { + pub(crate) fn node_extra_args(&self) -> NodeExtraArgs { + NodeExtraArgs { + use_slot_based_consensus: self.experimental_use_slot_based, + export_pov: self.export_pov_to_path.clone(), + } + } } #[derive(Debug)] @@ -109,12 +124,25 @@ pub struct RelayChainCli { } impl RelayChainCli { + fn polkadot_cmd() -> Command { + let help_template = color_print::cformat!( + "The arguments that are passed to the relay chain node. \n\ + \n\ + RELAY_CHAIN_ARGS: \n\ + {{options}}", + ); + + polkadot_cli::RunCmd::command() + .no_binary_name(true) + .help_template(help_template) + } + /// Parse the relay chain CLI parameters using the parachain `Configuration`. pub fn new<'a>( para_config: &sc_service::Configuration, relay_chain_args: impl Iterator, ) -> Self { - let polkadot_cmd = polkadot_cli::RunCmd::command().no_binary_name(true); + let polkadot_cmd = Self::polkadot_cmd(); let matches = polkadot_cmd.get_matches_from(relay_chain_args); let base = FromArgMatches::from_arg_matches(&matches).unwrap_or_else(|e| e.exit()); diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index 6b3f4b4cd0a7f462da66a219e4180c4132464bd2..e867a41bee2b807852ddf8dbb47379a9afb1cc9c 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -14,15 +14,19 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . +#[cfg(feature = "runtime-benchmarks")] +use crate::service::Block; use crate::{ - chain_spec, - chain_spec::GenericChainSpec, + chain_spec::{self, GenericChainSpec}, cli::{Cli, RelayChainCli, Subcommand}, + common::NodeExtraArgs, fake_runtime_api::{ - asset_hub_polkadot_aura::RuntimeApi as AssetHubPolkadotRuntimeApi, aura::RuntimeApi, + asset_hub_polkadot_aura::RuntimeApi as AssetHubPolkadotRuntimeApi, + aura::RuntimeApi as AuraRuntimeApi, }, - service::{new_partial, Block, Hash}, + service::{new_aura_node_spec, DynNodeSpec, ShellNode}, }; +#[cfg(feature = "runtime-benchmarks")] use cumulus_client_service::storage_proof_size::HostFunctions as ReclaimHostFunctions; use cumulus_primitives_core::ParaId; use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; @@ -34,27 +38,39 @@ use sc_cli::{ }; use sc_service::config::{BasePath, PrometheusConfig}; use sp_runtime::traits::AccountIdConversion; +#[cfg(feature = "runtime-benchmarks")] +use sp_runtime::traits::HashingFor; use std::{net::SocketAddr, path::PathBuf}; +/// The choice of consensus for the parachain omni-node. +#[derive(PartialEq, Eq, Debug, Default)] +pub enum Consensus { + /// Aura consensus. + #[default] + Aura, + /// Use the relay chain consensus. + // TODO: atm this is just a demonstration, not really reach-able. We can add it to the CLI, + // env, or the chain spec. Or, just don't, and when we properly refactor this mess we will + // re-introduce it. + #[allow(unused)] + Relay, +} + /// Helper enum that is used for better distinction of different parachain/runtime configuration /// (it is based/calculated on ChainSpec's ID attribute) -#[derive(Debug, PartialEq, Default)] +#[derive(Debug, PartialEq)] enum Runtime { - /// This is the default runtime (actually based on rococo) - #[default] - Default, + /// None of the system-chain runtimes, rather the node will act agnostic to the runtime ie. be + /// an omni-node, and simply run a node with the given consensus algorithm. + Omni(Consensus), Shell, Seedling, AssetHubPolkadot, - AssetHubKusama, - AssetHubRococo, - AssetHubWestend, + AssetHub, Penpal(ParaId), ContractsRococo, - CollectivesPolkadot, - CollectivesWestend, + Collectives, Glutton, - GluttonWestend, BridgeHub(chain_spec::bridge_hubs::BridgeHubRuntimeType), Coretime(chain_spec::coretime::CoretimeRuntimeType), People(chain_spec::people::PeopleRuntimeType), @@ -97,20 +113,20 @@ fn runtime(id: &str) -> Runtime { Runtime::Seedling } else if id.starts_with("asset-hub-polkadot") | id.starts_with("statemint") { Runtime::AssetHubPolkadot - } else if id.starts_with("asset-hub-kusama") | id.starts_with("statemine") { - Runtime::AssetHubKusama - } else if id.starts_with("asset-hub-rococo") { - Runtime::AssetHubRococo - } else if id.starts_with("asset-hub-westend") | id.starts_with("westmint") { - Runtime::AssetHubWestend + } else if id.starts_with("asset-hub-kusama") | + id.starts_with("statemine") | + id.starts_with("asset-hub-rococo") | + id.starts_with("rockmine") | + id.starts_with("asset-hub-westend") | + id.starts_with("westmint") + { + Runtime::AssetHub } else if id.starts_with("penpal") { Runtime::Penpal(para_id.unwrap_or(ParaId::new(0))) } else if id.starts_with("contracts-rococo") { Runtime::ContractsRococo - } else if id.starts_with("collectives-polkadot") { - Runtime::CollectivesPolkadot - } else if id.starts_with("collectives-westend") { - Runtime::CollectivesWestend + } else if id.starts_with("collectives-polkadot") || id.starts_with("collectives-westend") { + Runtime::Collectives } else if id.starts_with(chain_spec::bridge_hubs::BridgeHubRuntimeType::ID_PREFIX) { Runtime::BridgeHub( id.parse::() @@ -120,15 +136,17 @@ fn runtime(id: &str) -> Runtime { Runtime::Coretime( id.parse::().expect("Invalid value"), ) - } else if id.starts_with("glutton-westend") { - Runtime::GluttonWestend } else if id.starts_with("glutton") { Runtime::Glutton } else if id.starts_with(chain_spec::people::PeopleRuntimeType::ID_PREFIX) { Runtime::People(id.parse::().expect("Invalid value")) } else { - log::warn!("No specific runtime was recognized for ChainSpec's id: '{}', so Runtime::default() will be used", id); - Runtime::default() + log::warn!( + "No specific runtime was recognized for ChainSpec's id: '{}', \ + so Runtime::Omni(Consensus::Aura) will be used", + id + ); + Runtime::Omni(Consensus::Aura) } } @@ -274,55 +292,34 @@ fn load_spec(id: &str) -> std::result::Result, String> { /// (H/T to Phala for the idea) /// E.g. "penpal-kusama-2004" yields ("penpal-kusama", Some(2004)) fn extract_parachain_id(id: &str) -> (&str, &str, Option) { - const ROCOCO_TEST_PARA_PREFIX: &str = "penpal-rococo-"; - const KUSAMA_TEST_PARA_PREFIX: &str = "penpal-kusama-"; - const POLKADOT_TEST_PARA_PREFIX: &str = "penpal-polkadot-"; - - const GLUTTON_PARA_DEV_PREFIX: &str = "glutton-kusama-dev-"; - const GLUTTON_PARA_LOCAL_PREFIX: &str = "glutton-kusama-local-"; - const GLUTTON_PARA_GENESIS_PREFIX: &str = "glutton-kusama-genesis-"; - - const GLUTTON_WESTEND_PARA_DEV_PREFIX: &str = "glutton-westend-dev-"; - const GLUTTON_WESTEND_PARA_LOCAL_PREFIX: &str = "glutton-westend-local-"; - const GLUTTON_WESTEND_PARA_GENESIS_PREFIX: &str = "glutton-westend-genesis-"; - - let (norm_id, orig_id, para) = if let Some(suffix) = id.strip_prefix(ROCOCO_TEST_PARA_PREFIX) { - let para_id: u32 = suffix.parse().expect("Invalid parachain-id suffix"); - (&id[..ROCOCO_TEST_PARA_PREFIX.len() - 1], id, Some(para_id)) - } else if let Some(suffix) = id.strip_prefix(KUSAMA_TEST_PARA_PREFIX) { - let para_id: u32 = suffix.parse().expect("Invalid parachain-id suffix"); - (&id[..KUSAMA_TEST_PARA_PREFIX.len() - 1], id, Some(para_id)) - } else if let Some(suffix) = id.strip_prefix(POLKADOT_TEST_PARA_PREFIX) { - let para_id: u32 = suffix.parse().expect("Invalid parachain-id suffix"); - (&id[..POLKADOT_TEST_PARA_PREFIX.len() - 1], id, Some(para_id)) - } else if let Some(suffix) = id.strip_prefix(GLUTTON_PARA_DEV_PREFIX) { - let para_id: u32 = suffix.parse().expect("Invalid parachain-id suffix"); - (&id[..GLUTTON_PARA_DEV_PREFIX.len() - 1], id, Some(para_id)) - } else if let Some(suffix) = id.strip_prefix(GLUTTON_PARA_LOCAL_PREFIX) { - let para_id: u32 = suffix.parse().expect("Invalid parachain-id suffix"); - (&id[..GLUTTON_PARA_LOCAL_PREFIX.len() - 1], id, Some(para_id)) - } else if let Some(suffix) = id.strip_prefix(GLUTTON_PARA_GENESIS_PREFIX) { - let para_id: u32 = suffix.parse().expect("Invalid parachain-id suffix"); - (&id[..GLUTTON_PARA_GENESIS_PREFIX.len() - 1], id, Some(para_id)) - } else if let Some(suffix) = id.strip_prefix(GLUTTON_WESTEND_PARA_DEV_PREFIX) { - let para_id: u32 = suffix.parse().expect("Invalid parachain-id suffix"); - (&id[..GLUTTON_WESTEND_PARA_DEV_PREFIX.len() - 1], id, Some(para_id)) - } else if let Some(suffix) = id.strip_prefix(GLUTTON_WESTEND_PARA_LOCAL_PREFIX) { - let para_id: u32 = suffix.parse().expect("Invalid parachain-id suffix"); - (&id[..GLUTTON_WESTEND_PARA_LOCAL_PREFIX.len() - 1], id, Some(para_id)) - } else if let Some(suffix) = id.strip_prefix(GLUTTON_WESTEND_PARA_GENESIS_PREFIX) { - let para_id: u32 = suffix.parse().expect("Invalid parachain-id suffix"); - (&id[..GLUTTON_WESTEND_PARA_GENESIS_PREFIX.len() - 1], id, Some(para_id)) - } else { - (id, id, None) - }; + let para_prefixes = [ + // Penpal + "penpal-rococo-", + "penpal-kusama-", + "penpal-polkadot-", + // Glutton Kusama + "glutton-kusama-dev-", + "glutton-kusama-local-", + "glutton-kusama-genesis-", + // Glutton Westend + "glutton-westend-dev-", + "glutton-westend-local-", + "glutton-westend-genesis-", + ]; + + for para_prefix in para_prefixes { + if let Some(suffix) = id.strip_prefix(para_prefix) { + let para_id: u32 = suffix.parse().expect("Invalid parachain-id suffix"); + return (&id[..para_prefix.len() - 1], id, Some(para_id.into())) + } + } - (norm_id, orig_id, para.map(Into::into)) + (id, id, None) } impl SubstrateCli for Cli { fn impl_name() -> String { - "Polkadot parachain".into() + Self::executable_name() } fn impl_version() -> String { @@ -331,10 +328,12 @@ impl SubstrateCli for Cli { fn description() -> String { format!( - "Polkadot parachain\n\nThe command-line arguments provided first will be \ - passed to the parachain node, while the arguments provided after -- will be passed \ - to the relaychain node.\n\n\ - {} [parachain-args] -- [relaychain-args]", + "The command-line arguments provided first will be passed to the parachain node, \n\ + and the arguments provided after -- will be passed to the relay chain node. \n\ + \n\ + Example: \n\ + \n\ + {} [parachain-args] -- [relay-chain-args]", Self::executable_name() ) } @@ -358,33 +357,27 @@ impl SubstrateCli for Cli { impl SubstrateCli for RelayChainCli { fn impl_name() -> String { - "Polkadot parachain".into() + Cli::impl_name() } fn impl_version() -> String { - env!("SUBSTRATE_CLI_IMPL_VERSION").into() + Cli::impl_version() } fn description() -> String { - format!( - "Polkadot parachain\n\nThe command-line arguments provided first will be \ - passed to the parachain node, while the arguments provided after -- will be passed \ - to the relay chain node.\n\n\ - {} [parachain-args] -- [relay_chain-args]", - Self::executable_name() - ) + Cli::description() } fn author() -> String { - env!("CARGO_PKG_AUTHORS").into() + Cli::author() } fn support_url() -> String { - "https://github.com/paritytech/polkadot-sdk/issues/new".into() + Cli::support_url() } fn copyright_start_year() -> i32 { - 2017 + Cli::copyright_start_year() } fn load_spec(&self, id: &str) -> std::result::Result, String> { @@ -392,108 +385,27 @@ impl SubstrateCli for RelayChainCli { } } -/// Creates partial components for the runtimes that are supported by the benchmarks. -macro_rules! construct_partials { - ($config:expr, |$partials:ident| $code:expr) => { - match $config.chain_spec.runtime()? { - Runtime::AssetHubPolkadot => { - let $partials = new_partial::( - &$config, - crate::service::build_relay_to_aura_import_queue::<_, AssetHubPolkadotAuraId>, - )?; - $code - }, - Runtime::AssetHubKusama | - Runtime::AssetHubRococo | - Runtime::AssetHubWestend | - Runtime::BridgeHub(_) | - Runtime::CollectivesPolkadot | - Runtime::CollectivesWestend | - Runtime::Coretime(_) | - Runtime::People(_) => { - let $partials = new_partial::( - &$config, - crate::service::build_relay_to_aura_import_queue::<_, AuraId>, - )?; - $code - }, - Runtime::GluttonWestend | Runtime::Glutton | Runtime::Shell | Runtime::Seedling => { - let $partials = new_partial::( - &$config, - crate::service::build_shell_import_queue, - )?; - $code - }, - Runtime::ContractsRococo | Runtime::Penpal(_) | Runtime::Default => { - let $partials = new_partial::( - &$config, - crate::service::build_aura_import_queue, - )?; - $code - }, - } - }; -} - -macro_rules! construct_async_run { - (|$components:ident, $cli:ident, $cmd:ident, $config:ident| $( $code:tt )* ) => {{ - let runner = $cli.create_runner($cmd)?; - match runner.config().chain_spec.runtime()? { - Runtime::AssetHubPolkadot => { - runner.async_run(|$config| { - let $components = new_partial::( - &$config, - crate::service::build_relay_to_aura_import_queue::<_, AssetHubPolkadotAuraId>, - )?; - let task_manager = $components.task_manager; - { $( $code )* }.map(|v| (v, task_manager)) - }) - }, - Runtime::AssetHubKusama | - Runtime::AssetHubRococo | - Runtime::AssetHubWestend | - Runtime::BridgeHub(_) | - Runtime::CollectivesPolkadot | - Runtime::CollectivesWestend | - Runtime::Coretime(_) | - Runtime::People(_) => { - runner.async_run(|$config| { - let $components = new_partial::( - &$config, - crate::service::build_relay_to_aura_import_queue::<_, AuraId>, - )?; - let task_manager = $components.task_manager; - { $( $code )* }.map(|v| (v, task_manager)) - }) - }, - Runtime::Shell | - Runtime::Seedling | - Runtime::GluttonWestend | - Runtime::Glutton => { - runner.async_run(|$config| { - let $components = new_partial::( - &$config, - crate::service::build_shell_import_queue, - )?; - let task_manager = $components.task_manager; - { $( $code )* }.map(|v| (v, task_manager)) - }) - } - Runtime::ContractsRococo | Runtime::Penpal(_) | Runtime::Default => { - runner.async_run(|$config| { - let $components = new_partial::< - RuntimeApi, - _, - >( - &$config, - crate::service::build_aura_import_queue, - )?; - let task_manager = $components.task_manager; - { $( $code )* }.map(|v| (v, task_manager)) - }) - }, - } - }} +fn new_node_spec( + config: &sc_service::Configuration, + extra_args: &NodeExtraArgs, +) -> std::result::Result, sc_cli::Error> { + Ok(match config.chain_spec.runtime()? { + Runtime::AssetHubPolkadot => + new_aura_node_spec::(extra_args), + Runtime::AssetHub | + Runtime::BridgeHub(_) | + Runtime::Collectives | + Runtime::Coretime(_) | + Runtime::People(_) | + Runtime::ContractsRococo | + Runtime::Glutton | + Runtime::Penpal(_) => new_aura_node_spec::(extra_args), + Runtime::Shell | Runtime::Seedling => Box::new(ShellNode), + Runtime::Omni(consensus) => match consensus { + Consensus::Aura => new_aura_node_spec::(extra_args), + Consensus::Relay => Box::new(ShellNode), + }, + }) } /// Parse command line arguments into service configuration. @@ -506,31 +418,43 @@ pub fn run() -> Result<()> { runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) }, Some(Subcommand::CheckBlock(cmd)) => { - construct_async_run!(|components, cli, cmd, config| { - Ok(cmd.run(components.client, components.import_queue)) + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let node = new_node_spec(&config, &cli.node_extra_args())?; + node.prepare_check_block_cmd(config, cmd) }) }, Some(Subcommand::ExportBlocks(cmd)) => { - construct_async_run!(|components, cli, cmd, config| { - Ok(cmd.run(components.client, config.database)) + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let node = new_node_spec(&config, &cli.node_extra_args())?; + node.prepare_export_blocks_cmd(config, cmd) }) }, Some(Subcommand::ExportState(cmd)) => { - construct_async_run!(|components, cli, cmd, config| { - Ok(cmd.run(components.client, config.chain_spec)) + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let node = new_node_spec(&config, &cli.node_extra_args())?; + node.prepare_export_state_cmd(config, cmd) }) }, Some(Subcommand::ImportBlocks(cmd)) => { - construct_async_run!(|components, cli, cmd, config| { - Ok(cmd.run(components.client, components.import_queue)) + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let node = new_node_spec(&config, &cli.node_extra_args())?; + node.prepare_import_blocks_cmd(config, cmd) + }) + }, + Some(Subcommand::Revert(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let node = new_node_spec(&config, &cli.node_extra_args())?; + node.prepare_revert_cmd(config, cmd) }) }, - Some(Subcommand::Revert(cmd)) => construct_async_run!(|components, cli, cmd, config| { - Ok(cmd.run(components.client, components.backend, None)) - }), Some(Subcommand::PurgeChain(cmd)) => { let runner = cli.create_runner(cmd)?; - let polkadot_cli = RelayChainCli::new(runner.config(), cli.relaychain_args.iter()); + let polkadot_cli = RelayChainCli::new(runner.config(), cli.relay_chain_args.iter()); runner.sync_run(|config| { let polkadot_config = SubstrateCli::create_configuration( @@ -545,8 +469,10 @@ pub fn run() -> Result<()> { }, Some(Subcommand::ExportGenesisHead(cmd)) => { let runner = cli.create_runner(cmd)?; - runner - .sync_run(|config| construct_partials!(config, |partials| cmd.run(partials.client))) + runner.sync_run(|config| { + let node = new_node_spec(&config, &cli.node_extra_args())?; + node.run_export_genesis_head_cmd(config, cmd) + }) }, Some(Subcommand::ExportGenesisWasm(cmd)) => { let runner = cli.create_runner(cmd)?; @@ -560,46 +486,34 @@ pub fn run() -> Result<()> { // Switch on the concrete benchmark sub-command- match cmd { - BenchmarkCmd::Pallet(cmd) => - if cfg!(feature = "runtime-benchmarks") { - runner.sync_run(|config| cmd.run_with_spec::, ReclaimHostFunctions>(Some(config.chain_spec))) - } else { - Err("Benchmarking wasn't enabled when building the node. \ - You can enable it with `--features runtime-benchmarks`." - .into()) - }, + #[cfg(feature = "runtime-benchmarks")] + BenchmarkCmd::Pallet(cmd) => runner.sync_run(|config| { + cmd.run_with_spec::, ReclaimHostFunctions>(Some( + config.chain_spec, + )) + }), BenchmarkCmd::Block(cmd) => runner.sync_run(|config| { - construct_partials!(config, |partials| cmd.run(partials.client)) + let node = new_node_spec(&config, &cli.node_extra_args())?; + node.run_benchmark_block_cmd(config, cmd) }), - #[cfg(not(feature = "runtime-benchmarks"))] - BenchmarkCmd::Storage(_) => - return Err(sc_cli::Error::Input( - "Compile with --features=runtime-benchmarks \ - to enable storage benchmarks." - .into(), - ) - .into()), #[cfg(feature = "runtime-benchmarks")] BenchmarkCmd::Storage(cmd) => runner.sync_run(|config| { - construct_partials!(config, |partials| { - let db = partials.backend.expose_db(); - let storage = partials.backend.expose_storage(); - - cmd.run(config, partials.client.clone(), db, storage) - }) + let node = new_node_spec(&config, &cli.node_extra_args())?; + node.run_benchmark_storage_cmd(config, cmd) }), BenchmarkCmd::Machine(cmd) => runner.sync_run(|config| cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone())), - // NOTE: this allows the Client to leniently implement - // new benchmark commands without requiring a companion MR. #[allow(unreachable_patterns)] - _ => Err("Benchmarking sub-command unsupported".into()), + _ => Err("Benchmarking sub-command unsupported or compilation feature missing. \ + Make sure to compile with --features=runtime-benchmarks \ + to enable all supported benchmarks." + .into()), } }, Some(Subcommand::Key(cmd)) => Ok(cmd.run(&cli)?), None => { let runner = cli.create_runner(&cli.run.normalize())?; - let polkadot_cli = RelayChainCli::new(runner.config(), cli.relaychain_args.iter()); + let polkadot_cli = RelayChainCli::new(runner.config(), cli.relay_chain_args.iter()); let collator_options = cli.run.collator_options(); runner.run_node_until_exit(|config| async move { @@ -621,25 +535,33 @@ pub fn run() -> Result<()> { if old_path.exists() && new_path.exists() { return Err(format!( - "Found legacy {} path {} and new asset-hub path {}. Delete one path such that only one exists.", - old_name, old_path.display(), new_path.display() - ).into()) + "Found legacy {} path {} and new Asset Hub path {}. \ + Delete one path such that only one exists.", + old_name, + old_path.display(), + new_path.display() + ) + .into()) } if old_path.exists() { std::fs::rename(old_path.clone(), new_path.clone())?; info!( - "Statemint renamed to Asset Hub. The filepath with associated data on disk has been renamed from {} to {}.", - old_path.display(), new_path.display() + "{} was renamed to Asset Hub. The filepath with associated data on disk \ + has been renamed from {} to {}.", + old_name, + old_path.display(), + new_path.display() ); } } - let hwbench = (!cli.no_hardware_benchmarks).then_some( - config.database.path().map(|database_path| { + let hwbench = (!cli.no_hardware_benchmarks) + .then_some(config.database.path().map(|database_path| { let _ = std::fs::create_dir_all(database_path); sc_sysinfo::gather_hwbench(Some(database_path)) - })).flatten(); + })) + .flatten(); let para_id = chain_spec::Extensions::try_get(&*config.chain_spec) .map(|e| e.para_id) @@ -648,198 +570,47 @@ pub fn run() -> Result<()> { let id = ParaId::from(para_id); let parachain_account = - AccountIdConversion::::into_account_truncating(&id); + AccountIdConversion::::into_account_truncating( + &id, + ); let tokio_handle = config.tokio_handle.clone(); let polkadot_config = SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle) .map_err(|err| format!("Relay chain argument error: {}", err))?; - info!("Parachain id: {:?}", id); - info!("Parachain Account: {}", parachain_account); - info!("Is collating: {}", if config.role.is_authority() { "yes" } else { "no" }); - - match config.network.network_backend { - sc_network::config::NetworkBackendType::Libp2p => - start_node::>( - config, - polkadot_config, - collator_options, - id, - hwbench, - ) - .await, - sc_network::config::NetworkBackendType::Litep2p => - start_node::( - config, - polkadot_config, - collator_options, - id, - hwbench, - ) - .await, - } + info!("๐Ÿชช Parachain id: {:?}", id); + info!("๐Ÿงพ Parachain Account: {}", parachain_account); + info!("โœ๏ธ Is collating: {}", if config.role.is_authority() { "yes" } else { "no" }); + + start_node( + config, + polkadot_config, + collator_options, + id, + cli.node_extra_args(), + hwbench, + ) + .await }) }, } } -async fn start_node>( +#[sc_tracing::logging::prefix_logs_with("Parachain")] +async fn start_node( config: sc_service::Configuration, polkadot_config: sc_service::Configuration, collator_options: cumulus_client_cli::CollatorOptions, id: ParaId, + extra_args: NodeExtraArgs, hwbench: Option, ) -> Result { - match config.chain_spec.runtime()? { - Runtime::AssetHubPolkadot => crate::service::start_asset_hub_lookahead_node::< - AssetHubPolkadotRuntimeApi, - AssetHubPolkadotAuraId, - Network, - >(config, polkadot_config, collator_options, id, hwbench) - .await - .map(|r| r.0) - .map_err(Into::into), - - Runtime::AssetHubRococo | Runtime::AssetHubWestend | Runtime::AssetHubKusama => - crate::service::start_asset_hub_lookahead_node::( - config, - polkadot_config, - collator_options, - id, - hwbench, - ) - .await - .map(|r| r.0) - .map_err(Into::into), - - Runtime::CollectivesWestend | Runtime::CollectivesPolkadot => - crate::service::start_generic_aura_lookahead_node::( - config, - polkadot_config, - collator_options, - id, - hwbench, - ) - .await - .map(|r| r.0) - .map_err(Into::into), - - Runtime::Seedling | Runtime::Shell => crate::service::start_shell_node::( - config, - polkadot_config, - collator_options, - id, - hwbench, - ) - .await - .map(|r| r.0) - .map_err(Into::into), - - Runtime::ContractsRococo => crate::service::start_contracts_rococo_node::( - config, - polkadot_config, - collator_options, - id, - hwbench, - ) + let node_spec = new_node_spec(&config, &extra_args)?; + node_spec + .start_node(config, polkadot_config, collator_options, id, hwbench, extra_args) .await - .map(|r| r.0) - .map_err(Into::into), - - Runtime::BridgeHub(bridge_hub_runtime_type) => match bridge_hub_runtime_type { - chain_spec::bridge_hubs::BridgeHubRuntimeType::Polkadot | - chain_spec::bridge_hubs::BridgeHubRuntimeType::PolkadotLocal | - chain_spec::bridge_hubs::BridgeHubRuntimeType::Kusama | - chain_spec::bridge_hubs::BridgeHubRuntimeType::KusamaLocal | - chain_spec::bridge_hubs::BridgeHubRuntimeType::Westend | - chain_spec::bridge_hubs::BridgeHubRuntimeType::WestendLocal | - chain_spec::bridge_hubs::BridgeHubRuntimeType::WestendDevelopment | - chain_spec::bridge_hubs::BridgeHubRuntimeType::Rococo | - chain_spec::bridge_hubs::BridgeHubRuntimeType::RococoLocal | - chain_spec::bridge_hubs::BridgeHubRuntimeType::RococoDevelopment => - crate::service::start_generic_aura_lookahead_node::( - config, - polkadot_config, - collator_options, - id, - hwbench, - ) - .await - .map(|r| r.0), - } - .map_err(Into::into), - - Runtime::Coretime(coretime_runtime_type) => match coretime_runtime_type { - chain_spec::coretime::CoretimeRuntimeType::Kusama | - chain_spec::coretime::CoretimeRuntimeType::KusamaLocal | - chain_spec::coretime::CoretimeRuntimeType::Polkadot | - chain_spec::coretime::CoretimeRuntimeType::PolkadotLocal | - chain_spec::coretime::CoretimeRuntimeType::Rococo | - chain_spec::coretime::CoretimeRuntimeType::RococoLocal | - chain_spec::coretime::CoretimeRuntimeType::RococoDevelopment | - chain_spec::coretime::CoretimeRuntimeType::Westend | - chain_spec::coretime::CoretimeRuntimeType::WestendLocal | - chain_spec::coretime::CoretimeRuntimeType::WestendDevelopment => - crate::service::start_generic_aura_lookahead_node::( - config, - polkadot_config, - collator_options, - id, - hwbench, - ) - .await - .map(|r| r.0), - } - .map_err(Into::into), - - Runtime::Penpal(_) | Runtime::Default => - crate::service::start_rococo_parachain_node::( - config, - polkadot_config, - collator_options, - id, - hwbench, - ) - .await - .map(|r| r.0) - .map_err(Into::into), - - Runtime::Glutton | Runtime::GluttonWestend => - crate::service::start_basic_lookahead_node::( - config, - polkadot_config, - collator_options, - id, - hwbench, - ) - .await - .map(|r| r.0) - .map_err(Into::into), - - Runtime::People(people_runtime_type) => match people_runtime_type { - chain_spec::people::PeopleRuntimeType::Kusama | - chain_spec::people::PeopleRuntimeType::KusamaLocal | - chain_spec::people::PeopleRuntimeType::Polkadot | - chain_spec::people::PeopleRuntimeType::PolkadotLocal | - chain_spec::people::PeopleRuntimeType::Rococo | - chain_spec::people::PeopleRuntimeType::RococoLocal | - chain_spec::people::PeopleRuntimeType::RococoDevelopment | - chain_spec::people::PeopleRuntimeType::Westend | - chain_spec::people::PeopleRuntimeType::WestendLocal | - chain_spec::people::PeopleRuntimeType::WestendDevelopment => - crate::service::start_generic_aura_lookahead_node::( - config, - polkadot_config, - collator_options, - id, - hwbench, - ) - .await - .map(|r| r.0), - } - .map_err(Into::into), - } + .map_err(Into::into) } impl DefaultConfigurationValues for RelayChainCli { @@ -971,7 +742,7 @@ impl CliConfiguration for RelayChainCli { mod tests { use crate::{ chain_spec::{get_account_id_from_seed, get_from_seed}, - command::{Runtime, RuntimeResolver}, + command::{Consensus, Runtime, RuntimeResolver}, }; use sc_chain_spec::{ChainSpec, ChainSpecExtension, ChainSpecGroup, ChainType, Extension}; use serde::{Deserialize, Serialize}; @@ -998,9 +769,9 @@ mod tests { pub attribute_z: u32, } - fn store_configuration(dir: &TempDir, spec: Box) -> PathBuf { + fn store_configuration(dir: &TempDir, spec: &dyn ChainSpec) -> PathBuf { let raw_output = true; - let json = sc_service::chain_ops::build_spec(&*spec, raw_output) + let json = sc_service::chain_ops::build_spec(spec, raw_output) .expect("Failed to build json string"); let mut cfg_file_path = dir.path().to_path_buf(); cfg_file_path.push(spec.id()); @@ -1041,32 +812,44 @@ mod tests { let path = store_configuration( &temp_dir, - Box::new(create_default_with_extensions("shell-1", Extensions1::default())), + &create_default_with_extensions("shell-1", Extensions1::default()), ); assert_eq!(Runtime::Shell, path.runtime().unwrap()); let path = store_configuration( &temp_dir, - Box::new(create_default_with_extensions("shell-2", Extensions2::default())), + &create_default_with_extensions("shell-2", Extensions2::default()), ); assert_eq!(Runtime::Shell, path.runtime().unwrap()); let path = store_configuration( &temp_dir, - Box::new(create_default_with_extensions("seedling", Extensions2::default())), + &create_default_with_extensions("seedling", Extensions2::default()), ); assert_eq!(Runtime::Seedling, path.runtime().unwrap()); let path = store_configuration( &temp_dir, - Box::new(crate::chain_spec::rococo_parachain::rococo_parachain_local_config()), + &create_default_with_extensions("penpal-rococo-1000", Extensions2::default()), ); - assert_eq!(Runtime::Default, path.runtime().unwrap()); + assert_eq!(Runtime::Penpal(1000.into()), path.runtime().unwrap()); let path = store_configuration( &temp_dir, - Box::new(crate::chain_spec::contracts::contracts_rococo_local_config()), + &create_default_with_extensions("penpal-polkadot-2000", Extensions2::default()), + ); + assert_eq!(Runtime::Penpal(2000.into()), path.runtime().unwrap()); + + let path = store_configuration( + &temp_dir, + &crate::chain_spec::contracts::contracts_rococo_local_config(), ); assert_eq!(Runtime::ContractsRococo, path.runtime().unwrap()); + + let path = store_configuration( + &temp_dir, + &crate::chain_spec::rococo_parachain::rococo_parachain_local_config(), + ); + assert_eq!(Runtime::Omni(Consensus::Aura), path.runtime().unwrap()); } } diff --git a/cumulus/polkadot-parachain/src/common/mod.rs b/cumulus/polkadot-parachain/src/common/mod.rs index 5adbb4137cd3da4070dc7f271cf2ac1c826e395c..d7718931b8726af15f9348c22596df9406f99c75 100644 --- a/cumulus/polkadot-parachain/src/common/mod.rs +++ b/cumulus/polkadot-parachain/src/common/mod.rs @@ -26,6 +26,7 @@ use sp_block_builder::BlockBuilder; use sp_runtime::traits::Block as BlockT; use sp_session::SessionKeys; use sp_transaction_pool::runtime_api::TaggedTransactionQueue; +use std::path::PathBuf; /// Convenience trait that defines the basic bounds for the `RuntimeApi` of a parachain node. pub trait NodeRuntimeApi: @@ -65,3 +66,11 @@ where { type BoundedRuntimeApi = T::RuntimeApi; } + +/// Extra args that are passed when creating a new node spec. +pub struct NodeExtraArgs { + pub use_slot_based_consensus: bool, + + /// If set, each `PoV` build by the node will be exported to this folder. + pub export_pov: Option, +} diff --git a/cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs b/cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs index 0b79d338c16813238e70a29d454e91882113128f..7d54e9b4be04304f612916efc292b6a2b2fd6ed7 100644 --- a/cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs +++ b/cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs @@ -53,7 +53,7 @@ sp_api::impl_runtime_apis! { unimplemented!() } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> Vec { unimplemented!() } } diff --git a/cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs b/cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs index 823eb9ab584a06ea1370d6b4c03ce124c426f9fe..ca5fc8bdf119b586d1d34f39122af2b6c9801831 100644 --- a/cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs +++ b/cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs @@ -53,7 +53,7 @@ sp_api::impl_runtime_apis! { unimplemented!() } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> Vec { unimplemented!() } } diff --git a/cumulus/polkadot-parachain/src/main.rs b/cumulus/polkadot-parachain/src/main.rs index 2bf659228bc6020276858fcd2b154e5c0e37f82b..cbb76fa214cbedf761975888e63f7ef67910d5fa 100644 --- a/cumulus/polkadot-parachain/src/main.rs +++ b/cumulus/polkadot-parachain/src/main.rs @@ -14,11 +14,34 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -//! Cumulus test parachain collator +//! Polkadot parachain node. #![warn(missing_docs)] #![warn(unused_extern_crates)] +pub(crate) fn examples(executable_name: String) -> String { + color_print::cformat!( + r#"Examples: + + {0} --chain para.json --sync warp -- --chain relay.json --sync warp + Launch a warp-syncing full node of a given para's chain-spec, and a given relay's chain-spec. + + The above approach is the most flexible, and the most forward-compatible way to spawn an omni-node. + + You can find the chain-spec of some networks in: + https://paritytech.github.io/chainspecs + + {0} --chain asset-hub-polkadot --sync warp -- --chain polkadot --sync warp + Launch a warp-syncing full node of the Asset Hub parachain on the Polkadot Relay Chain. + + {0} --chain asset-hub-kusama --sync warp --relay-chain-rpc-url ws://rpc.example.com -- --chain kusama + Launch a warp-syncing full node of the Asset Hub parachain on the Kusama Relay Chain. + Uses ws://rpc.example.com as remote relay chain node. + "#, + executable_name, + ) +} + mod chain_spec; mod cli; mod command; diff --git a/cumulus/polkadot-parachain/src/rpc.rs b/cumulus/polkadot-parachain/src/rpc.rs index 7437bb1f4b9372f2454cbe6d491d302056606571..283a73d931d769fbd7b521c6f8a4a7558fc48be0 100644 --- a/cumulus/polkadot-parachain/src/rpc.rs +++ b/cumulus/polkadot-parachain/src/rpc.rs @@ -18,91 +18,82 @@ #![warn(missing_docs)] -use std::sync::Arc; - +use crate::{ + common::ConstructNodeRuntimeApi, + service::{ParachainBackend, ParachainClient}, +}; +use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; use parachains_common::{AccountId, Balance, Block, Nonce}; -use sc_client_api::AuxStore; -pub use sc_rpc::DenyUnsafe; -use sc_transaction_pool_api::TransactionPool; -use sp_api::ProvideRuntimeApi; -use sp_block_builder::BlockBuilder; -use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; +use sc_rpc::{ + dev::{Dev, DevApiServer}, + DenyUnsafe, +}; +use std::{marker::PhantomData, sync::Arc}; +use substrate_frame_rpc_system::{System, SystemApiServer}; +use substrate_state_trie_migration_rpc::{StateMigration, StateMigrationApiServer}; /// A type representing all RPC extensions. pub type RpcExtension = jsonrpsee::RpcModule<()>; -/// Full client dependencies -pub struct FullDeps { - /// The client instance to use. - pub client: Arc, - /// Transaction pool instance. - pub pool: Arc

, - /// Whether to deny unsafe calls - pub deny_unsafe: DenyUnsafe, +pub(crate) trait BuildRpcExtensions { + fn build_rpc_extensions( + deny_unsafe: DenyUnsafe, + client: Arc, + backend: Arc, + pool: Arc, + ) -> sc_service::error::Result; } -/// Instantiate all RPC extensions. -pub fn create_full( - deps: FullDeps, - backend: Arc, -) -> Result> +pub(crate) struct BuildEmptyRpcExtensions(PhantomData); + +impl + BuildRpcExtensions< + ParachainClient, + ParachainBackend, + sc_transaction_pool::FullPool>, + > for BuildEmptyRpcExtensions where - C: ProvideRuntimeApi - + HeaderBackend - + AuxStore - + HeaderMetadata - + Send - + Sync - + 'static, - C::Api: substrate_frame_rpc_system::AccountNonceApi, - C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, - C::Api: BlockBuilder, - P: TransactionPool + Sync + Send + 'static, - B: sc_client_api::Backend + Send + Sync + 'static, - B::State: sc_client_api::backend::StateBackend>, + RuntimeApi: ConstructNodeRuntimeApi> + Send + Sync + 'static, { - use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; - use substrate_frame_rpc_system::{System, SystemApiServer}; - use substrate_state_trie_migration_rpc::{StateMigration, StateMigrationApiServer}; - - let mut module = RpcExtension::new(()); - let FullDeps { client, pool, deny_unsafe } = deps; - - module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?; - module.merge(TransactionPayment::new(client.clone()).into_rpc())?; - module.merge(StateMigration::new(client, backend, deny_unsafe).into_rpc())?; - - Ok(module) + fn build_rpc_extensions( + _deny_unsafe: DenyUnsafe, + _client: Arc>, + _backend: Arc, + _pool: Arc>>, + ) -> sc_service::error::Result { + Ok(RpcExtension::new(())) + } } -/// Instantiate all RPCs we want at the contracts-rococo chain. -pub fn create_contracts_rococo( - deps: FullDeps, -) -> Result> +pub(crate) struct BuildParachainRpcExtensions(PhantomData); + +impl + BuildRpcExtensions< + ParachainClient, + ParachainBackend, + sc_transaction_pool::FullPool>, + > for BuildParachainRpcExtensions where - C: ProvideRuntimeApi - + sc_client_api::BlockBackend - + HeaderBackend - + AuxStore - + HeaderMetadata - + Send - + Sync - + 'static, - C::Api: substrate_frame_rpc_system::AccountNonceApi, - C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, - C::Api: BlockBuilder, - P: TransactionPool + Sync + Send + 'static, + RuntimeApi: ConstructNodeRuntimeApi> + Send + Sync + 'static, + RuntimeApi::RuntimeApi: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + + substrate_frame_rpc_system::AccountNonceApi, { - use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; - use sc_rpc::dev::{Dev, DevApiServer}; - use substrate_frame_rpc_system::{System, SystemApiServer}; - - let mut module = RpcExtension::new(()); - let FullDeps { client, pool, deny_unsafe } = deps; - - module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?; - module.merge(TransactionPayment::new(client.clone()).into_rpc())?; - module.merge(Dev::new(client, deny_unsafe).into_rpc())?; - - Ok(module) + fn build_rpc_extensions( + deny_unsafe: DenyUnsafe, + client: Arc>, + backend: Arc, + pool: Arc>>, + ) -> sc_service::error::Result { + let build = || -> Result> { + let mut module = RpcExtension::new(()); + + module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?; + module.merge(TransactionPayment::new(client.clone()).into_rpc())?; + module.merge(StateMigration::new(client.clone(), backend, deny_unsafe).into_rpc())?; + module.merge(Dev::new(client, deny_unsafe).into_rpc())?; + + Ok(module) + }; + build().map_err(Into::into) + } } diff --git a/cumulus/polkadot-parachain/src/service.rs b/cumulus/polkadot-parachain/src/service.rs index 9cd3a0037223d6dd4241e5c1b6d3c61f5dff3d3f..80698a2d71154bf08091226a446329afc9bcef1a 100644 --- a/cumulus/polkadot-parachain/src/service.rs +++ b/cumulus/polkadot-parachain/src/service.rs @@ -14,12 +14,18 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use codec::Decode; -use cumulus_client_cli::CollatorOptions; -use cumulus_client_collator::service::CollatorService; +use cumulus_client_cli::{CollatorOptions, ExportGenesisHeadCommand}; +use cumulus_client_collator::service::{ + CollatorService, ServiceInterface as CollatorServiceInterface, +}; use cumulus_client_consensus_aura::collators::lookahead::{self as aura, Params as AuraParams}; +#[docify::export(slot_based_colator_import)] +use cumulus_client_consensus_aura::collators::slot_based::{ + self as slot_based, Params as SlotBasedParams, +}; use cumulus_client_consensus_common::ParachainBlockImport as TParachainBlockImport; -use cumulus_client_consensus_proposer::Proposer; +use cumulus_client_consensus_proposer::{Proposer, ProposerInterface}; +use cumulus_client_consensus_relay_chain::Verifier as RelayChainVerifier; #[allow(deprecated)] use cumulus_client_service::old_consensus; use cumulus_client_service::{ @@ -28,44 +34,41 @@ use cumulus_client_service::{ }; use cumulus_primitives_core::{relay_chain::ValidationCode, ParaId}; use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface}; -use sc_rpc::DenyUnsafe; - -use jsonrpsee::RpcModule; use crate::{ common::{ aura::{AuraIdT, AuraRuntimeApi}, - ConstructNodeRuntimeApi, + ConstructNodeRuntimeApi, NodeExtraArgs, }, fake_runtime_api::aura::RuntimeApi as FakeRuntimeApi, - rpc, + rpc::BuildRpcExtensions, }; -pub use parachains_common::{AccountId, AuraId, Balance, Block, Hash, Nonce}; +pub use parachains_common::{AccountId, Balance, Block, Hash, Nonce}; -use cumulus_client_consensus_relay_chain::Verifier as RelayChainVerifier; +use crate::rpc::{BuildEmptyRpcExtensions, BuildParachainRpcExtensions}; +use frame_benchmarking_cli::BlockCmd; +#[cfg(any(feature = "runtime-benchmarks"))] +use frame_benchmarking_cli::StorageCmd; use futures::prelude::*; +use polkadot_primitives::CollatorPair; use prometheus_endpoint::Registry; -use sc_client_api::Backend as ClientApiBackend; +use sc_cli::{CheckBlockCmd, ExportBlocksCmd, ExportStateCmd, ImportBlocksCmd, RevertCmd}; +use sc_client_api::BlockchainEvents; use sc_consensus::{ import_queue::{BasicQueue, Verifier as VerifierT}, - BlockImportParams, ImportQueue, + BlockImportParams, DefaultImportQueue, ImportQueue, }; use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY}; use sc_network::{config::FullNetworkConfiguration, service::traits::NetworkBackend, NetworkBlock}; -use sc_network_sync::SyncingService; -use sc_service::{Configuration, PartialComponents, TFullBackend, TFullClient, TaskManager}; +use sc_service::{Configuration, Error, PartialComponents, TFullBackend, TFullClient, TaskManager}; +use sc_sysinfo::HwBench; use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle}; -use sp_api::{ConstructRuntimeApi, ProvideRuntimeApi}; -use sp_blockchain::HeaderBackend; -use sp_core::traits::SpawnEssentialNamed; +use sc_transaction_pool::FullPool; +use sp_api::ProvideRuntimeApi; +use sp_inherents::CreateInherentDataProviders; use sp_keystore::KeystorePtr; -use sp_runtime::{ - app_crypto::AppCrypto, - traits::{Block as BlockT, Header as HeaderT}, -}; -use std::{marker::PhantomData, sync::Arc, time::Duration}; - -use polkadot_primitives::CollatorPair; +use sp_runtime::{app_crypto::AppCrypto, traits::Header as HeaderT}; +use std::{marker::PhantomData, pin::Pin, sync::Arc, time::Duration}; #[cfg(not(feature = "runtime-benchmarks"))] type HostFunctions = cumulus_client_service::ParachainHostFunctions; @@ -76,9 +79,9 @@ type HostFunctions = ( frame_benchmarking::benchmarking::HostFunctions, ); -type ParachainClient = TFullClient>; +pub type ParachainClient = TFullClient>; -type ParachainBackend = TFullBackend; +pub type ParachainBackend = TFullBackend; type ParachainBlockImport = TParachainBlockImport>, ParachainBackend>; @@ -93,448 +96,340 @@ pub type Service = PartialComponents< (ParachainBlockImport, Option, Option), >; -/// Starts a `ServiceBuilder` for a full service. -/// -/// Use this macro if you don't actually need the full service, but just the builder in order to -/// be able to perform chain operations. -pub fn new_partial( - config: &Configuration, - build_import_queue: BIQ, -) -> Result, sc_service::Error> -where - RuntimeApi: ConstructNodeRuntimeApi>, - BIQ: FnOnce( - Arc>, - ParachainBlockImport, - &Configuration, - Option, - &TaskManager, - ) -> Result, sc_service::Error>, -{ - let telemetry = config - .telemetry_endpoints - .clone() - .filter(|x| !x.is_empty()) - .map(|endpoints| -> Result<_, sc_telemetry::Error> { - let worker = TelemetryWorker::new(16)?; - let telemetry = worker.handle().new_telemetry(endpoints); - Ok((worker, telemetry)) - }) - .transpose()?; - - let heap_pages = config - .default_heap_pages - .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static { extra_pages: h as _ }); - - let executor = sc_executor::WasmExecutor::::builder() - .with_execution_method(config.wasm_method) - .with_max_runtime_instances(config.max_runtime_instances) - .with_runtime_cache_size(config.runtime_cache_size) - .with_onchain_heap_alloc_strategy(heap_pages) - .with_offchain_heap_alloc_strategy(heap_pages) - .build(); - - let (client, backend, keystore_container, task_manager) = - sc_service::new_full_parts_record_import::( - config, - telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), - executor, - true, - )?; - let client = Arc::new(client); - - let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle()); - - let telemetry = telemetry.map(|(worker, telemetry)| { - task_manager.spawn_handle().spawn("telemetry", None, worker.run()); - telemetry - }); - - let transaction_pool = sc_transaction_pool::BasicPool::new_full( - config.transaction_pool.clone(), - config.role.is_authority().into(), - config.prometheus_registry(), - task_manager.spawn_essential_handle(), - client.clone(), - ); - - let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); - - let import_queue = build_import_queue( - client.clone(), - block_import.clone(), - config, - telemetry.as_ref().map(|telemetry| telemetry.handle()), - &task_manager, - )?; - - Ok(PartialComponents { - backend, - client, - import_queue, - keystore_container, - task_manager, - transaction_pool, - select_chain: (), - other: (block_import, telemetry, telemetry_worker_handle), - }) +pub(crate) trait BuildImportQueue { + fn build_import_queue( + client: Arc>, + block_import: ParachainBlockImport, + config: &Configuration, + telemetry_handle: Option, + task_manager: &TaskManager, + ) -> sc_service::error::Result>; } -/// Start a node with the given parachain `Configuration` and relay chain `Configuration`. -/// -/// This is the actual implementation that is abstract over the executor and the runtime api. -#[sc_tracing::logging::prefix_logs_with("Parachain")] -async fn start_node_impl( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - sybil_resistance_level: CollatorSybilResistance, - para_id: ParaId, - rpc_ext_builder: RB, - build_import_queue: BIQ, - start_consensus: SC, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> +pub(crate) trait StartConsensus where RuntimeApi: ConstructNodeRuntimeApi>, - RB: Fn( - DenyUnsafe, - Arc>, - Arc, - Arc>>, - ) -> Result, sc_service::Error> - + 'static, - BIQ: FnOnce( - Arc>, - ParachainBlockImport, - &Configuration, - Option, - &TaskManager, - ) -> Result, sc_service::Error>, - SC: FnOnce( - Arc>, - ParachainBlockImport, - Option<&Registry>, - Option, - &TaskManager, - Arc, - Arc>>, - Arc>, - KeystorePtr, - Duration, - ParaId, - CollatorPair, - OverseerHandle, - Arc>) + Send + Sync>, - Arc, - ) -> Result<(), sc_service::Error>, - Net: NetworkBackend, { - let parachain_config = prepare_node_config(parachain_config); - - let params = new_partial::(¶chain_config, build_import_queue)?; - let (block_import, mut telemetry, telemetry_worker_handle) = params.other; - - let client = params.client.clone(); - let backend = params.backend.clone(); - - let mut task_manager = params.task_manager; - let (relay_chain_interface, collator_key) = build_relay_chain_interface( - polkadot_config, - ¶chain_config, - telemetry_worker_handle, - &mut task_manager, - collator_options.clone(), - hwbench.clone(), - ) - .await - .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; - - let validator = parachain_config.role.is_authority(); - let prometheus_registry = parachain_config.prometheus_registry().cloned(); - let transaction_pool = params.transaction_pool.clone(); - let import_queue_service = params.import_queue.service(); - let net_config = FullNetworkConfiguration::<_, _, Net>::new(¶chain_config.network); - - let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = - build_network(BuildNetworkParams { - parachain_config: ¶chain_config, - net_config, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - para_id, - spawn_handle: task_manager.spawn_handle(), - relay_chain_interface: relay_chain_interface.clone(), - import_queue: params.import_queue, - sybil_resistance_level, - }) - .await?; - - let rpc_builder = { - let client = client.clone(); - let transaction_pool = transaction_pool.clone(); - let backend_for_rpc = backend.clone(); - - Box::new(move |deny_unsafe, _| { - rpc_ext_builder( - deny_unsafe, - client.clone(), - backend_for_rpc.clone(), - transaction_pool.clone(), - ) - }) - }; - - sc_service::spawn_tasks(sc_service::SpawnTasksParams { - rpc_builder, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - task_manager: &mut task_manager, - config: parachain_config, - keystore: params.keystore_container.keystore(), - backend: backend.clone(), - network: network.clone(), - sync_service: sync_service.clone(), - system_rpc_tx, - tx_handler_controller, - telemetry: telemetry.as_mut(), - })?; - - if let Some(hwbench) = hwbench { - sc_sysinfo::print_hwbench(&hwbench); - if validator { - warn_if_slow_hardware(&hwbench); - } - - if let Some(ref mut telemetry) = telemetry { - let telemetry_handle = telemetry.handle(); - task_manager.spawn_handle().spawn( - "telemetry_hwbench", - None, - sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), - ); - } - } - - let announce_block = { - let sync_service = sync_service.clone(); - Arc::new(move |hash, data| sync_service.announce_block(hash, data)) - }; + fn start_consensus( + client: Arc>, + block_import: ParachainBlockImport, + prometheus_registry: Option<&Registry>, + telemetry: Option, + task_manager: &TaskManager, + relay_chain_interface: Arc, + transaction_pool: Arc>>, + keystore: KeystorePtr, + relay_chain_slot_duration: Duration, + para_id: ParaId, + collator_key: CollatorPair, + overseer_handle: OverseerHandle, + announce_block: Arc>) + Send + Sync>, + backend: Arc, + node_extra_args: NodeExtraArgs, + ) -> Result<(), sc_service::Error>; +} - let relay_chain_slot_duration = Duration::from_secs(6); +pub(crate) trait NodeSpec { + type RuntimeApi: ConstructNodeRuntimeApi>; + + type BuildImportQueue: BuildImportQueue + 'static; + + type BuildRpcExtensions: BuildRpcExtensions< + ParachainClient, + ParachainBackend, + sc_transaction_pool::FullPool>, + > + 'static; + + type StartConsensus: StartConsensus + 'static; + + const SYBIL_RESISTANCE: CollatorSybilResistance; + + /// Starts a `ServiceBuilder` for a full service. + /// + /// Use this macro if you don't actually need the full service, but just the builder in order to + /// be able to perform chain operations. + fn new_partial(config: &Configuration) -> sc_service::error::Result> { + let telemetry = config + .telemetry_endpoints + .clone() + .filter(|x| !x.is_empty()) + .map(|endpoints| -> Result<_, sc_telemetry::Error> { + let worker = TelemetryWorker::new(16)?; + let telemetry = worker.handle().new_telemetry(endpoints); + Ok((worker, telemetry)) + }) + .transpose()?; + + let heap_pages = config.default_heap_pages.map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| { + HeapAllocStrategy::Static { extra_pages: h as _ } + }); + + let executor = sc_executor::WasmExecutor::::builder() + .with_execution_method(config.wasm_method) + .with_max_runtime_instances(config.max_runtime_instances) + .with_runtime_cache_size(config.runtime_cache_size) + .with_onchain_heap_alloc_strategy(heap_pages) + .with_offchain_heap_alloc_strategy(heap_pages) + .build(); + + let (client, backend, keystore_container, task_manager) = + sc_service::new_full_parts_record_import::( + config, + telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), + executor, + true, + )?; + let client = Arc::new(client); + + let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle()); + + let telemetry = telemetry.map(|(worker, telemetry)| { + task_manager.spawn_handle().spawn("telemetry", None, worker.run()); + telemetry + }); + + let transaction_pool = sc_transaction_pool::BasicPool::new_full( + config.transaction_pool.clone(), + config.role.is_authority().into(), + config.prometheus_registry(), + task_manager.spawn_essential_handle(), + client.clone(), + ); - let overseer_handle = relay_chain_interface - .overseer_handle() - .map_err(|e| sc_service::Error::Application(Box::new(e)))?; + let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); - start_relay_chain_tasks(StartRelayChainTasksParams { - client: client.clone(), - announce_block: announce_block.clone(), - para_id, - relay_chain_interface: relay_chain_interface.clone(), - task_manager: &mut task_manager, - da_recovery_profile: if validator { - DARecoveryProfile::Collator - } else { - DARecoveryProfile::FullNode - }, - import_queue: import_queue_service, - relay_chain_slot_duration, - recovery_handle: Box::new(overseer_handle.clone()), - sync_service: sync_service.clone(), - })?; - - if validator { - start_consensus( + let import_queue = Self::BuildImportQueue::build_import_queue( client.clone(), - block_import, - prometheus_registry.as_ref(), - telemetry.as_ref().map(|t| t.handle()), + block_import.clone(), + config, + telemetry.as_ref().map(|telemetry| telemetry.handle()), &task_manager, - relay_chain_interface.clone(), - transaction_pool, - sync_service.clone(), - params.keystore_container.keystore(), - relay_chain_slot_duration, - para_id, - collator_key.expect("Command line arguments do not allow this. qed"), - overseer_handle, - announce_block, - backend.clone(), )?; - } - start_network.start_network(); + Ok(PartialComponents { + backend, + client, + import_queue, + keystore_container, + task_manager, + transaction_pool, + select_chain: (), + other: (block_import, telemetry, telemetry_worker_handle), + }) + } - Ok((task_manager, client)) -} + /// Start a node with the given parachain spec. + /// + /// This is the actual implementation that is abstract over the executor and the runtime api. + fn start_node( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, + node_extra_args: NodeExtraArgs, + ) -> Pin>>> + where + Net: NetworkBackend, + { + Box::pin(async move { + let parachain_config = prepare_node_config(parachain_config); + + let params = Self::new_partial(¶chain_config)?; + let (block_import, mut telemetry, telemetry_worker_handle) = params.other; + + let client = params.client.clone(); + let backend = params.backend.clone(); + + let mut task_manager = params.task_manager; + let (relay_chain_interface, collator_key) = build_relay_chain_interface( + polkadot_config, + ¶chain_config, + telemetry_worker_handle, + &mut task_manager, + collator_options.clone(), + hwbench.clone(), + ) + .await + .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; + + let validator = parachain_config.role.is_authority(); + let prometheus_registry = parachain_config.prometheus_registry().cloned(); + let transaction_pool = params.transaction_pool.clone(); + let import_queue_service = params.import_queue.service(); + let net_config = FullNetworkConfiguration::<_, _, Net>::new( + ¶chain_config.network, + prometheus_registry.clone(), + ); -/// Build the import queue for Aura-based runtimes. -pub fn build_aura_import_queue( - client: Arc>, - block_import: ParachainBlockImport, - config: &Configuration, - telemetry: Option, - task_manager: &TaskManager, -) -> Result, sc_service::Error> { - let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; - - cumulus_client_consensus_aura::import_queue::< - sp_consensus_aura::sr25519::AuthorityPair, - _, - _, - _, - _, - _, - >(cumulus_client_consensus_aura::ImportQueueParams { - block_import, - client, - create_inherent_data_providers: move |_, _| async move { - let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); - - let slot = - sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, - slot_duration, - ); - - Ok((slot, timestamp)) - }, - registry: config.prometheus_registry(), - spawner: &task_manager.spawn_essential_handle(), - telemetry, - }) - .map_err(Into::into) -} + let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = + build_network(BuildNetworkParams { + parachain_config: ¶chain_config, + net_config, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + para_id, + spawn_handle: task_manager.spawn_handle(), + relay_chain_interface: relay_chain_interface.clone(), + import_queue: params.import_queue, + sybil_resistance_level: Self::SYBIL_RESISTANCE, + }) + .await?; + + let rpc_builder = { + let client = client.clone(); + let transaction_pool = transaction_pool.clone(); + let backend_for_rpc = backend.clone(); + + Box::new(move |deny_unsafe, _| { + Self::BuildRpcExtensions::build_rpc_extensions( + deny_unsafe, + client.clone(), + backend_for_rpc.clone(), + transaction_pool.clone(), + ) + }) + }; + + sc_service::spawn_tasks(sc_service::SpawnTasksParams { + rpc_builder, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + task_manager: &mut task_manager, + config: parachain_config, + keystore: params.keystore_container.keystore(), + backend: backend.clone(), + network: network.clone(), + sync_service: sync_service.clone(), + system_rpc_tx, + tx_handler_controller, + telemetry: telemetry.as_mut(), + })?; + + if let Some(hwbench) = hwbench { + sc_sysinfo::print_hwbench(&hwbench); + if validator { + warn_if_slow_hardware(&hwbench); + } -/// Start a rococo parachain node. -pub async fn start_rococo_parachain_node>( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> { - start_node_impl::( - parachain_config, - polkadot_config, - collator_options, - CollatorSybilResistance::Resistant, // Aura - para_id, - build_parachain_rpc_extensions::, - build_aura_import_queue, - start_lookahead_aura_consensus, - hwbench, - ) - .await -} + if let Some(ref mut telemetry) = telemetry { + let telemetry_handle = telemetry.handle(); + task_manager.spawn_handle().spawn( + "telemetry_hwbench", + None, + sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), + ); + } + } -/// Build the import queue for the shell runtime. -pub fn build_shell_import_queue( - client: Arc>, - block_import: ParachainBlockImport, - config: &Configuration, - _: Option, - task_manager: &TaskManager, -) -> Result, sc_service::Error> { - cumulus_client_consensus_relay_chain::import_queue( - client, - block_import, - |_, _| async { Ok(()) }, - &task_manager.spawn_essential_handle(), - config.prometheus_registry(), - ) - .map_err(Into::into) -} + let announce_block = { + let sync_service = sync_service.clone(); + Arc::new(move |hash, data| sync_service.announce_block(hash, data)) + }; + + let relay_chain_slot_duration = Duration::from_secs(6); + + let overseer_handle = relay_chain_interface + .overseer_handle() + .map_err(|e| sc_service::Error::Application(Box::new(e)))?; + + start_relay_chain_tasks(StartRelayChainTasksParams { + client: client.clone(), + announce_block: announce_block.clone(), + para_id, + relay_chain_interface: relay_chain_interface.clone(), + task_manager: &mut task_manager, + da_recovery_profile: if validator { + DARecoveryProfile::Collator + } else { + DARecoveryProfile::FullNode + }, + import_queue: import_queue_service, + relay_chain_slot_duration, + recovery_handle: Box::new(overseer_handle.clone()), + sync_service, + })?; + + if validator { + Self::StartConsensus::start_consensus( + client.clone(), + block_import, + prometheus_registry.as_ref(), + telemetry.as_ref().map(|t| t.handle()), + &task_manager, + relay_chain_interface.clone(), + transaction_pool, + params.keystore_container.keystore(), + relay_chain_slot_duration, + para_id, + collator_key.expect("Command line arguments do not allow this. qed"), + overseer_handle, + announce_block, + backend.clone(), + node_extra_args, + )?; + } -fn build_parachain_rpc_extensions( - deny_unsafe: sc_rpc::DenyUnsafe, - client: Arc>, - backend: Arc, - pool: Arc>>, -) -> Result, sc_service::Error> -where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_block_builder::BlockBuilder - + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi - + substrate_frame_rpc_system::AccountNonceApi, -{ - let deps = rpc::FullDeps { client, pool, deny_unsafe }; + start_network.start_network(); - rpc::create_full(deps, backend).map_err(Into::into) + Ok(task_manager) + }) + } } -fn build_contracts_rpc_extensions( - deny_unsafe: sc_rpc::DenyUnsafe, - client: Arc>, - _backend: Arc, - pool: Arc>>, -) -> Result, sc_service::Error> { - let deps = crate::rpc::FullDeps { client: client.clone(), pool: pool.clone(), deny_unsafe }; - - crate::rpc::create_contracts_rococo(deps).map_err(Into::into) +/// Build the import queue for the shell runtime. +pub(crate) struct BuildShellImportQueue(PhantomData); + +impl BuildImportQueue for BuildShellImportQueue { + fn build_import_queue( + client: Arc>, + block_import: ParachainBlockImport, + config: &Configuration, + _telemetry_handle: Option, + task_manager: &TaskManager, + ) -> sc_service::error::Result> { + cumulus_client_consensus_relay_chain::import_queue( + client, + block_import, + |_, _| async { Ok(()) }, + &task_manager.spawn_essential_handle(), + config.prometheus_registry(), + ) + .map_err(Into::into) + } } -/// Start a polkadot-shell parachain node. -pub async fn start_shell_node>( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> { - start_node_impl::( - parachain_config, - polkadot_config, - collator_options, - CollatorSybilResistance::Unresistant, // free-for-all consensus - para_id, - |_, _, _, _| Ok(RpcModule::new(())), - build_shell_import_queue, - start_relay_chain_consensus, - hwbench, - ) - .await -} +pub(crate) struct ShellNode; -enum BuildOnAccess { - Uninitialized(Option R + Send + Sync>>), - Initialized(R), -} +impl NodeSpec for ShellNode { + type RuntimeApi = FakeRuntimeApi; + type BuildImportQueue = BuildShellImportQueue; + type BuildRpcExtensions = BuildEmptyRpcExtensions; + type StartConsensus = StartRelayChainConsensus; -impl BuildOnAccess { - fn get_mut(&mut self) -> &mut R { - loop { - match self { - Self::Uninitialized(f) => { - *self = Self::Initialized((f.take().unwrap())()); - }, - Self::Initialized(ref mut r) => return r, - } - } - } + const SYBIL_RESISTANCE: CollatorSybilResistance = CollatorSybilResistance::Unresistant; } struct Verifier { client: Arc, - aura_verifier: BuildOnAccess>>, + aura_verifier: Box>, relay_chain_verifier: Box>, _phantom: PhantomData, } #[async_trait::async_trait] -impl VerifierT for Verifier +impl VerifierT for Verifier where - Client: sp_api::ProvideRuntimeApi + Send + Sync, + Client: ProvideRuntimeApi + Send + Sync, Client::Api: AuraRuntimeApi, + AuraId: AuraIdT + Sync, { async fn verify( - &mut self, + &self, block_import: BlockImportParams, ) -> Result, String> { if self.client.runtime_api().has_aura_api(*block_import.header.parent_hash()) { - self.aura_verifier.get_mut().verify(block_import).await + self.aura_verifier.verify(block_import).await } else { self.relay_chain_verifier.verify(block_import).await } @@ -543,405 +438,414 @@ where /// Build the import queue for parachain runtimes that started with relay chain consensus and /// switched to aura. -pub fn build_relay_to_aura_import_queue( - client: Arc>, - block_import: ParachainBlockImport, - config: &Configuration, - telemetry_handle: Option, - task_manager: &TaskManager, -) -> Result, sc_service::Error> +pub(crate) struct BuildRelayToAuraImportQueue( + PhantomData<(RuntimeApi, AuraId)>, +); + +impl BuildImportQueue + for BuildRelayToAuraImportQueue where RuntimeApi: ConstructNodeRuntimeApi>, RuntimeApi::RuntimeApi: AuraRuntimeApi, + AuraId: AuraIdT + Sync, { - let verifier_client = client.clone(); - - let aura_verifier = move || { - Box::new(cumulus_client_consensus_aura::build_verifier::< - ::Pair, - _, - _, - _, - >(cumulus_client_consensus_aura::BuildVerifierParams { - client: verifier_client.clone(), - create_inherent_data_providers: move |parent_hash, _| { - let cidp_client = verifier_client.clone(); - async move { - let slot_duration = cumulus_client_consensus_aura::slot_duration_at( - &*cidp_client, - parent_hash, - )?; - let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); - - let slot = - sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, - slot_duration, - ); - - Ok((slot, timestamp)) - } - }, - telemetry: telemetry_handle, - })) as Box<_> - }; + fn build_import_queue( + client: Arc>, + block_import: ParachainBlockImport, + config: &Configuration, + telemetry_handle: Option, + task_manager: &TaskManager, + ) -> sc_service::error::Result> { + let verifier_client = client.clone(); + + let aura_verifier = + cumulus_client_consensus_aura::build_verifier::<::Pair, _, _, _>( + cumulus_client_consensus_aura::BuildVerifierParams { + client: verifier_client.clone(), + create_inherent_data_providers: move |parent_hash, _| { + let cidp_client = verifier_client.clone(); + async move { + let slot_duration = cumulus_client_consensus_aura::slot_duration_at( + &*cidp_client, + parent_hash, + )?; + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *timestamp, + slot_duration, + ); + + Ok((slot, timestamp)) + } + }, + telemetry: telemetry_handle, + }, + ); - let relay_chain_verifier = - Box::new(RelayChainVerifier::new(client.clone(), |_, _| async { Ok(()) })) as Box<_>; + let relay_chain_verifier = + Box::new(RelayChainVerifier::new(client.clone(), |_, _| async { Ok(()) })); - let verifier = Verifier { - client, - relay_chain_verifier, - aura_verifier: BuildOnAccess::Uninitialized(Some(Box::new(aura_verifier))), - _phantom: PhantomData, - }; + let verifier = Verifier { + client, + relay_chain_verifier, + aura_verifier: Box::new(aura_verifier), + _phantom: PhantomData, + }; - let registry = config.prometheus_registry(); - let spawner = task_manager.spawn_essential_handle(); + let registry = config.prometheus_registry(); + let spawner = task_manager.spawn_essential_handle(); - Ok(BasicQueue::new(verifier, Box::new(block_import), None, &spawner, registry)) + Ok(BasicQueue::new(verifier, Box::new(block_import), None, &spawner, registry)) + } } /// Uses the lookahead collator to support async backing. /// /// Start an aura powered parachain node. Some system chains use this. -pub async fn start_generic_aura_lookahead_node>( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> { - start_node_impl::( - parachain_config, - polkadot_config, - collator_options, - CollatorSybilResistance::Resistant, // Aura - para_id, - build_parachain_rpc_extensions::, - build_relay_to_aura_import_queue::<_, AuraId>, - start_lookahead_aura_consensus, - hwbench, - ) - .await +pub(crate) struct AuraNode( + pub PhantomData<(RuntimeApi, AuraId, StartConsensus)>, +); + +impl Default for AuraNode { + fn default() -> Self { + Self(Default::default()) + } } -/// Start a shell node which should later transition into an Aura powered parachain node. Asset Hub -/// uses this because at genesis, Asset Hub was on the `shell` runtime which didn't have Aura and -/// needs to sync and upgrade before it can run `AuraApi` functions. -/// -/// Uses the lookahead collator to support async backing. -#[sc_tracing::logging::prefix_logs_with("Parachain")] -pub async fn start_asset_hub_lookahead_node( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> +impl NodeSpec for AuraNode where RuntimeApi: ConstructNodeRuntimeApi>, RuntimeApi::RuntimeApi: AuraRuntimeApi + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + substrate_frame_rpc_system::AccountNonceApi, - Net: NetworkBackend, + AuraId: AuraIdT + Sync, + StartConsensus: self::StartConsensus + 'static, { - start_node_impl::( - parachain_config, - polkadot_config, - collator_options, - CollatorSybilResistance::Resistant, // Aura - para_id, - build_parachain_rpc_extensions::, - build_relay_to_aura_import_queue::<_, AuraId>, - |client, - block_import, - prometheus_registry, - telemetry, - task_manager, - relay_chain_interface, - transaction_pool, - sync_oracle, - keystore, - relay_chain_slot_duration, - para_id, - collator_key, - overseer_handle, - announce_block, - backend| { - let relay_chain_interface2 = relay_chain_interface.clone(); - - let collator_service = CollatorService::new( - client.clone(), - Arc::new(task_manager.spawn_handle()), - announce_block, - client.clone(), - ); - - let spawner = task_manager.spawn_handle(); - - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - spawner, - client.clone(), - transaction_pool, - prometheus_registry, - telemetry.clone(), - ); - - let collation_future = Box::pin(async move { - // Start collating with the `shell` runtime while waiting for an upgrade to an Aura - // compatible runtime. - let mut request_stream = cumulus_client_collator::relay_chain_driven::init( - collator_key.clone(), - para_id, - overseer_handle.clone(), - ) - .await; - while let Some(request) = request_stream.next().await { - let pvd = request.persisted_validation_data().clone(); - let last_head_hash = - match ::Header::decode(&mut &pvd.parent_head.0[..]) { - Ok(header) => header.hash(), - Err(e) => { - log::error!("Could not decode the head data: {e}"); - request.complete(None); - continue - }, - }; - - // Check if we have upgraded to an Aura compatible runtime and transition if - // necessary. - if client.runtime_api().has_aura_api(last_head_hash) { - // Respond to this request before transitioning to Aura. - request.complete(None); - break - } - } - - // Move to Aura consensus. - let proposer = Proposer::new(proposer_factory); + type RuntimeApi = RuntimeApi; + type BuildImportQueue = BuildRelayToAuraImportQueue; + type BuildRpcExtensions = BuildParachainRpcExtensions; + type StartConsensus = StartConsensus; + const SYBIL_RESISTANCE: CollatorSybilResistance = CollatorSybilResistance::Resistant; +} - let params = AuraParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client.clone(), - para_backend: backend, - relay_client: relay_chain_interface2, - code_hash_provider: move |block_hash| { - client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) - }, - sync_oracle, - keystore, - collator_key, - para_id, - overseer_handle, - relay_chain_slot_duration, - proposer, - collator_service, - authoring_duration: Duration::from_millis(1500), - reinitialize: true, /* we need to always re-initialize for asset-hub moving - * to aura */ - }; - - aura::run::::Pair, _, _, _, _, _, _, _, _, _>(params) - .await - }); - - let spawner = task_manager.spawn_essential_handle(); - spawner.spawn_essential("cumulus-asset-hub-collator", None, collation_future); - - Ok(()) - }, - hwbench, - ) - .await +pub fn new_aura_node_spec(extra_args: &NodeExtraArgs) -> Box +where + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi + + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + + substrate_frame_rpc_system::AccountNonceApi, + AuraId: AuraIdT + Sync, +{ + if extra_args.use_slot_based_consensus { + Box::new(AuraNode::< + RuntimeApi, + AuraId, + StartSlotBasedAuraConsensus, + >::default()) + } else { + Box::new(AuraNode::< + RuntimeApi, + AuraId, + StartLookaheadAuraConsensus, + >::default()) + } } /// Start relay-chain consensus that is free for all. Everyone can submit a block, the relay-chain /// decides what is backed and included. -fn start_relay_chain_consensus( - client: Arc>, - block_import: ParachainBlockImport, - prometheus_registry: Option<&Registry>, - telemetry: Option, - task_manager: &TaskManager, - relay_chain_interface: Arc, - transaction_pool: Arc>>, - _sync_oracle: Arc>, - _keystore: KeystorePtr, - _relay_chain_slot_duration: Duration, - para_id: ParaId, - collator_key: CollatorPair, - overseer_handle: OverseerHandle, - announce_block: Arc>) + Send + Sync>, - _backend: Arc, -) -> Result<(), sc_service::Error> { - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - task_manager.spawn_handle(), - client.clone(), - transaction_pool, - prometheus_registry, - telemetry, - ); - - let free_for_all = cumulus_client_consensus_relay_chain::build_relay_chain_consensus( - cumulus_client_consensus_relay_chain::BuildRelayChainConsensusParams { - para_id, - proposer_factory, - block_import, - relay_chain_interface: relay_chain_interface.clone(), - create_inherent_data_providers: move |_, (relay_parent, validation_data)| { - let relay_chain_interface = relay_chain_interface.clone(); - async move { - let parachain_inherent = +pub(crate) struct StartRelayChainConsensus; + +impl StartConsensus for StartRelayChainConsensus { + fn start_consensus( + client: Arc>, + block_import: ParachainBlockImport, + prometheus_registry: Option<&Registry>, + telemetry: Option, + task_manager: &TaskManager, + relay_chain_interface: Arc, + transaction_pool: Arc>>, + _keystore: KeystorePtr, + _relay_chain_slot_duration: Duration, + para_id: ParaId, + collator_key: CollatorPair, + overseer_handle: OverseerHandle, + announce_block: Arc>) + Send + Sync>, + _backend: Arc, + _node_extra_args: NodeExtraArgs, + ) -> Result<(), Error> { + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( + task_manager.spawn_handle(), + client.clone(), + transaction_pool, + prometheus_registry, + telemetry, + ); + + let free_for_all = cumulus_client_consensus_relay_chain::build_relay_chain_consensus( + cumulus_client_consensus_relay_chain::BuildRelayChainConsensusParams { + para_id, + proposer_factory, + block_import, + relay_chain_interface: relay_chain_interface.clone(), + create_inherent_data_providers: move |_, (relay_parent, validation_data)| { + let relay_chain_interface = relay_chain_interface.clone(); + async move { + let parachain_inherent = cumulus_client_parachain_inherent::ParachainInherentDataProvider::create_at( relay_parent, &relay_chain_interface, &validation_data, para_id, ).await; - let parachain_inherent = parachain_inherent.ok_or_else(|| { - Box::::from( - "Failed to create parachain inherent", - ) - })?; - Ok(parachain_inherent) - } + let parachain_inherent = parachain_inherent.ok_or_else(|| { + Box::::from( + "Failed to create parachain inherent", + ) + })?; + Ok(parachain_inherent) + } + }, }, - }, - ); - - let spawner = task_manager.spawn_handle(); - - // Required for free-for-all consensus - #[allow(deprecated)] - old_consensus::start_collator_sync(old_consensus::StartCollatorParams { - para_id, - block_status: client.clone(), - announce_block, - overseer_handle, - spawner, - key: collator_key, - parachain_consensus: free_for_all, - runtime_api: client.clone(), - }); - - Ok(()) + ); + + let spawner = task_manager.spawn_handle(); + + // Required for free-for-all consensus + #[allow(deprecated)] + old_consensus::start_collator_sync(old_consensus::StartCollatorParams { + para_id, + block_status: client.clone(), + announce_block, + overseer_handle, + spawner, + key: collator_key, + parachain_consensus: free_for_all, + runtime_api: client.clone(), + }); + + Ok(()) + } } /// Start consensus using the lookahead aura collator. -fn start_lookahead_aura_consensus( - client: Arc>, - block_import: ParachainBlockImport, - prometheus_registry: Option<&Registry>, - telemetry: Option, - task_manager: &TaskManager, - relay_chain_interface: Arc, - transaction_pool: Arc>>, - sync_oracle: Arc>, - keystore: KeystorePtr, - relay_chain_slot_duration: Duration, - para_id: ParaId, - collator_key: CollatorPair, - overseer_handle: OverseerHandle, - announce_block: Arc>) + Send + Sync>, - backend: Arc, -) -> Result<(), sc_service::Error> +pub(crate) struct StartSlotBasedAuraConsensus( + PhantomData<(RuntimeApi, AuraId)>, +); + +impl StartSlotBasedAuraConsensus where RuntimeApi: ConstructNodeRuntimeApi>, RuntimeApi::RuntimeApi: AuraRuntimeApi, + AuraId: AuraIdT + Sync, { - let info = backend.blockchain().info(); - if !client.runtime_api().has_aura_api(info.finalized_hash) { - return Err(sc_service::error::Error::Other("Missing aura runtime APIs".to_string())); + #[docify::export_content] + fn launch_slot_based_collator( + params: SlotBasedParams< + ParachainBlockImport, + CIDP, + ParachainClient, + ParachainBackend, + Arc, + CHP, + Proposer, + CS, + >, + task_manager: &TaskManager, + ) where + CIDP: CreateInherentDataProviders + 'static, + CIDP::InherentDataProviders: Send, + CHP: cumulus_client_consensus_common::ValidationCodeHashProvider + Send + 'static, + Proposer: ProposerInterface + Send + Sync + 'static, + CS: CollatorServiceInterface + Send + Sync + Clone + 'static, + { + let (collation_future, block_builder_future) = + slot_based::run::::Pair, _, _, _, _, _, _, _, _>(params); + + task_manager.spawn_essential_handle().spawn( + "collation-task", + Some("parachain-block-authoring"), + collation_future, + ); + task_manager.spawn_essential_handle().spawn( + "block-builder-task", + Some("parachain-block-authoring"), + block_builder_future, + ); } +} - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - task_manager.spawn_handle(), - client.clone(), - transaction_pool, - prometheus_registry, - telemetry.clone(), - ); - - let collator_service = CollatorService::new( - client.clone(), - Arc::new(task_manager.spawn_handle()), - announce_block, - client.clone(), - ); - - let params = AuraParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client.clone(), - para_backend: backend, - relay_client: relay_chain_interface, - code_hash_provider: move |block_hash| { - client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) - }, - sync_oracle, - keystore, - collator_key, - para_id, - overseer_handle, - relay_chain_slot_duration, - proposer: Proposer::new(proposer_factory), - collator_service, - authoring_duration: Duration::from_millis(1500), - reinitialize: false, - }; +impl StartConsensus + for StartSlotBasedAuraConsensus +where + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi, + AuraId: AuraIdT + Sync, +{ + fn start_consensus( + client: Arc>, + block_import: ParachainBlockImport, + prometheus_registry: Option<&Registry>, + telemetry: Option, + task_manager: &TaskManager, + relay_chain_interface: Arc, + transaction_pool: Arc>>, + keystore: KeystorePtr, + relay_chain_slot_duration: Duration, + para_id: ParaId, + collator_key: CollatorPair, + _overseer_handle: OverseerHandle, + announce_block: Arc>) + Send + Sync>, + backend: Arc, + _node_extra_args: NodeExtraArgs, + ) -> Result<(), Error> { + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( + task_manager.spawn_handle(), + client.clone(), + transaction_pool, + prometheus_registry, + telemetry.clone(), + ); - let fut = aura::run::::Pair, _, _, _, _, _, _, _, _, _>(params); - task_manager.spawn_essential_handle().spawn("aura", None, fut); + let proposer = Proposer::new(proposer_factory); + let collator_service = CollatorService::new( + client.clone(), + Arc::new(task_manager.spawn_handle()), + announce_block, + client.clone(), + ); - Ok(()) + let client_for_aura = client.clone(); + let params = SlotBasedParams { + create_inherent_data_providers: move |_, ()| async move { Ok(()) }, + block_import, + para_client: client.clone(), + para_backend: backend.clone(), + relay_client: relay_chain_interface, + code_hash_provider: move |block_hash| { + client_for_aura.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) + }, + keystore, + collator_key, + para_id, + relay_chain_slot_duration, + proposer, + collator_service, + authoring_duration: Duration::from_millis(2000), + reinitialize: false, + slot_drift: Duration::from_secs(1), + }; + + // We have a separate function only to be able to use `docify::export` on this piece of + // code. + Self::launch_slot_based_collator(params, task_manager); + + Ok(()) + } } -/// Start an aura powered parachain node which uses the lookahead collator to support async backing. -/// This node is basic in the sense that its runtime api doesn't include common contents such as -/// transaction payment. Used for aura glutton. -pub async fn start_basic_lookahead_node>( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> { - start_node_impl::( - parachain_config, - polkadot_config, - collator_options, - CollatorSybilResistance::Resistant, // Aura - para_id, - |_, _, _, _| Ok(RpcModule::new(())), - build_relay_to_aura_import_queue::<_, AuraId>, - start_lookahead_aura_consensus, - hwbench, - ) - .await +/// Wait for the Aura runtime API to appear on chain. +/// This is useful for chains that started out without Aura. Components that +/// are depending on Aura functionality will wait until Aura appears in the runtime. +async fn wait_for_aura(client: Arc>) +where + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi, + AuraId: AuraIdT + Sync, +{ + let finalized_hash = client.chain_info().finalized_hash; + if client.runtime_api().has_aura_api(finalized_hash) { + return; + }; + + let mut stream = client.finality_notification_stream(); + while let Some(notification) = stream.next().await { + if client.runtime_api().has_aura_api(notification.hash) { + return; + } + } } -/// Start a parachain node for Rococo Contracts. -pub async fn start_contracts_rococo_node>( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> { - start_node_impl::( - parachain_config, - polkadot_config, - collator_options, - CollatorSybilResistance::Resistant, // Aura - para_id, - build_contracts_rpc_extensions, - build_aura_import_queue, - start_lookahead_aura_consensus, - hwbench, - ) - .await +/// Start consensus using the lookahead aura collator. +pub(crate) struct StartLookaheadAuraConsensus( + PhantomData<(RuntimeApi, AuraId)>, +); + +impl StartConsensus + for StartLookaheadAuraConsensus +where + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi, + AuraId: AuraIdT + Sync, +{ + fn start_consensus( + client: Arc>, + block_import: ParachainBlockImport, + prometheus_registry: Option<&Registry>, + telemetry: Option, + task_manager: &TaskManager, + relay_chain_interface: Arc, + transaction_pool: Arc>>, + keystore: KeystorePtr, + relay_chain_slot_duration: Duration, + para_id: ParaId, + collator_key: CollatorPair, + overseer_handle: OverseerHandle, + announce_block: Arc>) + Send + Sync>, + backend: Arc, + node_extra_args: NodeExtraArgs, + ) -> Result<(), Error> { + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( + task_manager.spawn_handle(), + client.clone(), + transaction_pool, + prometheus_registry, + telemetry.clone(), + ); + + let collator_service = CollatorService::new( + client.clone(), + Arc::new(task_manager.spawn_handle()), + announce_block, + client.clone(), + ); + + let params = aura::ParamsWithExport { + export_pov: node_extra_args.export_pov, + params: AuraParams { + create_inherent_data_providers: move |_, ()| async move { Ok(()) }, + block_import, + para_client: client.clone(), + para_backend: backend, + relay_client: relay_chain_interface, + code_hash_provider: { + let client = client.clone(); + move |block_hash| { + client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) + } + }, + keystore, + collator_key, + para_id, + overseer_handle, + relay_chain_slot_duration, + proposer: Proposer::new(proposer_factory), + collator_service, + authoring_duration: Duration::from_millis(1500), + reinitialize: false, + }, + }; + + let fut = + async move { + wait_for_aura(client).await; + aura::run_with_export::::Pair, _, _, _, _, _, _, _, _>(params).await; + }; + task_manager.spawn_essential_handle().spawn("aura", None, fut); + + Ok(()) + } } /// Checks that the hardware meets the requirements and print a warning otherwise. @@ -956,3 +860,181 @@ fn warn_if_slow_hardware(hwbench: &sc_sysinfo::HwBench) { ); } } + +type SyncCmdResult = sc_cli::Result<()>; + +type AsyncCmdResult<'a> = + sc_cli::Result<(Pin + 'a>>, TaskManager)>; + +pub(crate) trait DynNodeSpec { + fn prepare_check_block_cmd( + self: Box, + config: Configuration, + cmd: &CheckBlockCmd, + ) -> AsyncCmdResult<'_>; + + fn prepare_export_blocks_cmd( + self: Box, + config: Configuration, + cmd: &ExportBlocksCmd, + ) -> AsyncCmdResult<'_>; + + fn prepare_export_state_cmd( + self: Box, + config: Configuration, + cmd: &ExportStateCmd, + ) -> AsyncCmdResult<'_>; + + fn prepare_import_blocks_cmd( + self: Box, + config: Configuration, + cmd: &ImportBlocksCmd, + ) -> AsyncCmdResult<'_>; + + fn prepare_revert_cmd( + self: Box, + config: Configuration, + cmd: &RevertCmd, + ) -> AsyncCmdResult<'_>; + + fn run_export_genesis_head_cmd( + self: Box, + config: Configuration, + cmd: &ExportGenesisHeadCommand, + ) -> SyncCmdResult; + + fn run_benchmark_block_cmd( + self: Box, + config: Configuration, + cmd: &BlockCmd, + ) -> SyncCmdResult; + + #[cfg(any(feature = "runtime-benchmarks"))] + fn run_benchmark_storage_cmd( + self: Box, + config: Configuration, + cmd: &StorageCmd, + ) -> SyncCmdResult; + + fn start_node( + self: Box, + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, + node_extra_args: NodeExtraArgs, + ) -> Pin>>>; +} + +impl DynNodeSpec for T +where + T: NodeSpec, +{ + fn prepare_check_block_cmd( + self: Box, + config: Configuration, + cmd: &CheckBlockCmd, + ) -> AsyncCmdResult<'_> { + let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, partial.import_queue)), partial.task_manager)) + } + + fn prepare_export_blocks_cmd( + self: Box, + config: Configuration, + cmd: &ExportBlocksCmd, + ) -> AsyncCmdResult<'_> { + let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, config.database)), partial.task_manager)) + } + + fn prepare_export_state_cmd( + self: Box, + config: Configuration, + cmd: &ExportStateCmd, + ) -> AsyncCmdResult<'_> { + let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, config.chain_spec)), partial.task_manager)) + } + + fn prepare_import_blocks_cmd( + self: Box, + config: Configuration, + cmd: &ImportBlocksCmd, + ) -> AsyncCmdResult<'_> { + let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, partial.import_queue)), partial.task_manager)) + } + + fn prepare_revert_cmd( + self: Box, + config: Configuration, + cmd: &RevertCmd, + ) -> AsyncCmdResult<'_> { + let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, partial.backend, None)), partial.task_manager)) + } + + fn run_export_genesis_head_cmd( + self: Box, + config: Configuration, + cmd: &ExportGenesisHeadCommand, + ) -> SyncCmdResult { + let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; + cmd.run(partial.client) + } + + fn run_benchmark_block_cmd( + self: Box, + config: Configuration, + cmd: &BlockCmd, + ) -> SyncCmdResult { + let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; + cmd.run(partial.client) + } + + #[cfg(any(feature = "runtime-benchmarks"))] + fn run_benchmark_storage_cmd( + self: Box, + config: Configuration, + cmd: &StorageCmd, + ) -> SyncCmdResult { + let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; + let db = partial.backend.expose_db(); + let storage = partial.backend.expose_storage(); + + cmd.run(config, partial.client, db, storage) + } + + fn start_node( + self: Box, + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, + node_extra_args: NodeExtraArgs, + ) -> Pin>>> { + match parachain_config.network.network_backend { + sc_network::config::NetworkBackendType::Libp2p => + ::start_node::>( + parachain_config, + polkadot_config, + collator_options, + para_id, + hwbench, + node_extra_args, + ), + sc_network::config::NetworkBackendType::Litep2p => + ::start_node::( + parachain_config, + polkadot_config, + collator_options, + para_id, + hwbench, + node_extra_args, + ), + } + } +} diff --git a/cumulus/primitives/aura/Cargo.toml b/cumulus/primitives/aura/Cargo.toml index ef96f334d63753c73de669ddcd98b6868a88389b..062b9ce736e7f7b9d36f23908bf94437a06f22cb 100644 --- a/cumulus/primitives/aura/Cargo.toml +++ b/cumulus/primitives/aura/Cargo.toml @@ -10,17 +10,16 @@ description = "Core primitives for Aura in Cumulus" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } # Substrate -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-consensus-aura = { path = "../../../substrate/primitives/consensus/aura", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +sp-api = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-runtime = { workspace = true } # Polkadot -polkadot-core-primitives = { path = "../../../polkadot/core-primitives", default-features = false } -polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false } +polkadot-core-primitives = { workspace = true } +polkadot-primitives = { workspace = true } [features] default = ["std"] @@ -31,5 +30,4 @@ std = [ "sp-api/std", "sp-consensus-aura/std", "sp-runtime/std", - "sp-std/std", ] diff --git a/cumulus/primitives/core/Cargo.toml b/cumulus/primitives/core/Cargo.toml index 595aa5f72bf2453edea23e372865de95e9e46699..533d368d3b00ed883b1996d376a80f4d5d970570 100644 --- a/cumulus/primitives/core/Cargo.toml +++ b/cumulus/primitives/core/Cargo.toml @@ -10,20 +10,19 @@ description = "Cumulus related core primitive types and traits" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } # Substrate -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } +sp-api = { workspace = true } +sp-runtime = { workspace = true } +sp-trie = { workspace = true } # Polkadot -polkadot-core-primitives = { path = "../../../polkadot/core-primitives", default-features = false } -polkadot-parachain-primitives = { path = "../../../polkadot/parachain", default-features = false } -polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false } -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } +polkadot-core-primitives = { workspace = true } +polkadot-parachain-primitives = { workspace = true } +polkadot-primitives = { workspace = true } +xcm = { workspace = true } [features] default = ["std"] @@ -35,7 +34,6 @@ std = [ "scale-info/std", "sp-api/std", "sp-runtime/std", - "sp-std/std", "sp-trie/std", "xcm/std", ] diff --git a/cumulus/primitives/core/src/lib.rs b/cumulus/primitives/core/src/lib.rs index 29216d513465160eb94db76faedb6e7fd992b461..6eafecfc3ff574689b5dd3125b97c0e5bade844a 100644 --- a/cumulus/primitives/core/src/lib.rs +++ b/cumulus/primitives/core/src/lib.rs @@ -18,11 +18,13 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + +use alloc::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; use polkadot_parachain_primitives::primitives::HeadData; use scale_info::TypeInfo; use sp_runtime::RuntimeDebug; -use sp_std::prelude::*; pub use polkadot_core_primitives::InboundDownwardMessage; pub use polkadot_parachain_primitives::primitives::{ @@ -202,7 +204,7 @@ pub struct ParachainBlockData { /// The header of the parachain block. header: B::Header, /// The extrinsics of the parachain block. - extrinsics: sp_std::vec::Vec, + extrinsics: alloc::vec::Vec, /// The data that is required to emulate the storage accesses executed by all extrinsics. storage_proof: sp_trie::CompactProof, } @@ -211,7 +213,7 @@ impl ParachainBlockData { /// Creates a new instance of `Self`. pub fn new( header: ::Header, - extrinsics: sp_std::vec::Vec<::Extrinsic>, + extrinsics: alloc::vec::Vec<::Extrinsic>, storage_proof: sp_trie::CompactProof, ) -> Self { Self { header, extrinsics, storage_proof } @@ -243,7 +245,7 @@ impl ParachainBlockData { } /// Deconstruct into the inner parts. - pub fn deconstruct(self) -> (B::Header, sp_std::vec::Vec, sp_trie::CompactProof) { + pub fn deconstruct(self) -> (B::Header, alloc::vec::Vec, sp_trie::CompactProof) { (self.header, self.extrinsics, self.storage_proof) } } diff --git a/cumulus/primitives/parachain-inherent/Cargo.toml b/cumulus/primitives/parachain-inherent/Cargo.toml index 0156eb02e2b4aaa9ee02e4e237f305c20792569d..172af4b9ec63e0843fdf59cdf90f21c842d60b41 100644 --- a/cumulus/primitives/parachain-inherent/Cargo.toml +++ b/cumulus/primitives/parachain-inherent/Cargo.toml @@ -10,20 +10,19 @@ license = "Apache-2.0" workspace = true [dependencies] -async-trait = { version = "0.1.79", optional = true } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +async-trait = { optional = true, workspace = true } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } # Substrate -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", optional = true, default-features = false } -sp-state-machine = { path = "../../../substrate/primitives/state-machine", optional = true, default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } +sp-core = { workspace = true } +sp-inherents = { workspace = true } +sp-runtime = { optional = true, workspace = true } +sp-state-machine = { optional = true, workspace = true } +sp-trie = { workspace = true } # Cumulus -cumulus-primitives-core = { path = "../core", default-features = false } +cumulus-primitives-core = { workspace = true } [features] default = ["std"] @@ -36,6 +35,5 @@ std = [ "sp-inherents/std", "sp-runtime?/std", "sp-state-machine?/std", - "sp-std/std", "sp-trie/std", ] diff --git a/cumulus/primitives/parachain-inherent/src/lib.rs b/cumulus/primitives/parachain-inherent/src/lib.rs index 75a56693958e6a982e21851384535217157b9c82..ad4b39b547c5f24f123e8abfd5a352dd1008adae 100644 --- a/cumulus/primitives/parachain-inherent/src/lib.rs +++ b/cumulus/primitives/parachain-inherent/src/lib.rs @@ -27,14 +27,16 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + use cumulus_primitives_core::{ relay_chain::{BlakeTwo256, Hash as RelayHash, HashT as _}, InboundDownwardMessage, InboundHrmpMessage, ParaId, PersistedValidationData, }; +use alloc::{collections::btree_map::BTreeMap, vec::Vec}; use scale_info::TypeInfo; use sp_inherents::InherentIdentifier; -use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; /// The identifier for the parachain inherent. pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"sysi1337"; diff --git a/cumulus/primitives/proof-size-hostfunction/Cargo.toml b/cumulus/primitives/proof-size-hostfunction/Cargo.toml index dd584ce86b2e3172563848f028730709e1b1600d..e61c865d05fb07aaff931f0ecd59a09c2592a0fa 100644 --- a/cumulus/primitives/proof-size-hostfunction/Cargo.toml +++ b/cumulus/primitives/proof-size-hostfunction/Cargo.toml @@ -10,14 +10,14 @@ license = "Apache-2.0" workspace = true [dependencies] -sp-runtime-interface = { path = "../../../substrate/primitives/runtime-interface", default-features = false } -sp-externalities = { path = "../../../substrate/primitives/externalities", default-features = false } -sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } +sp-runtime-interface = { workspace = true } +sp-externalities = { workspace = true } +sp-trie = { workspace = true } [dev-dependencies] -sp-state-machine = { path = "../../../substrate/primitives/state-machine" } -sp-core = { path = "../../../substrate/primitives/core" } -sp-io = { path = "../../../substrate/primitives/io" } +sp-state-machine = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/cumulus/primitives/storage-weight-reclaim/Cargo.toml b/cumulus/primitives/storage-weight-reclaim/Cargo.toml index bdfb83ad72a96930c1dae2d2c054a2c19c5cfcb2..3a98fdd017aef9b7e411ef59d56fecc89bf0c897 100644 --- a/cumulus/primitives/storage-weight-reclaim/Cargo.toml +++ b/cumulus/primitives/storage-weight-reclaim/Cargo.toml @@ -10,24 +10,23 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +sp-runtime = { workspace = true } -cumulus-primitives-core = { path = "../core", default-features = false } -cumulus-primitives-proof-size-hostfunction = { path = "../proof-size-hostfunction", default-features = false } -docify = "0.2.8" +cumulus-primitives-core = { workspace = true } +cumulus-primitives-proof-size-hostfunction = { workspace = true } +docify = { workspace = true } [dev-dependencies] -sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -cumulus-test-runtime = { path = "../../test/runtime" } +sp-trie = { workspace = true } +sp-io = { workspace = true } +cumulus-test-runtime = { workspace = true } [features] default = ["std"] @@ -41,6 +40,5 @@ std = [ "scale-info/std", "sp-io/std", "sp-runtime/std", - "sp-std/std", "sp-trie/std", ] diff --git a/cumulus/primitives/storage-weight-reclaim/src/lib.rs b/cumulus/primitives/storage-weight-reclaim/src/lib.rs index 35fa334f51c6996c48825cec03a0a90df5b0acbe..f48dd927ee962a23a0d831ec071469bb34e517e3 100644 --- a/cumulus/primitives/storage-weight-reclaim/src/lib.rs +++ b/cumulus/primitives/storage-weight-reclaim/src/lib.rs @@ -18,6 +18,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::{Decode, Encode}; +use core::marker::PhantomData; use cumulus_primitives_core::Weight; use cumulus_primitives_proof_size_hostfunction::{ storage_proof_size::storage_proof_size, PROOF_RECORDING_DISABLED, @@ -33,7 +34,6 @@ use sp_runtime::{ transaction_validity::TransactionValidityError, DispatchResult, }; -use sp_std::marker::PhantomData; const LOG_TARGET: &'static str = "runtime::storage_reclaim"; @@ -199,6 +199,7 @@ where #[cfg(test)] mod tests { use super::*; + use core::marker::PhantomData; use frame_support::{ assert_ok, dispatch::{DispatchClass, PerDispatchClass}, @@ -206,7 +207,6 @@ mod tests { }; use frame_system::{BlockWeight, CheckWeight}; use sp_runtime::{AccountId32, BuildStorage}; - use sp_std::marker::PhantomData; use sp_trie::proof_size_extension::ProofSizeExt; type Test = cumulus_test_runtime::Runtime; diff --git a/cumulus/primitives/timestamp/Cargo.toml b/cumulus/primitives/timestamp/Cargo.toml index 7a6f4787ba3121cf0c9c7eec3b9f3794c870037d..a50011bc3f0e911f2c682fcc02dc8a7693101ffc 100644 --- a/cumulus/primitives/timestamp/Cargo.toml +++ b/cumulus/primitives/timestamp/Cargo.toml @@ -10,16 +10,15 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -futures = "0.3.28" +codec = { features = ["derive"], workspace = true } +futures = { workspace = true } # Substrate -sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-timestamp = { path = "../../../substrate/primitives/timestamp", default-features = false } +sp-inherents = { workspace = true } +sp-timestamp = { workspace = true } # Cumulus -cumulus-primitives-core = { path = "../core", default-features = false } +cumulus-primitives-core = { workspace = true } [features] default = ["std"] @@ -27,6 +26,5 @@ std = [ "codec/std", "cumulus-primitives-core/std", "sp-inherents/std", - "sp-std/std", "sp-timestamp/std", ] diff --git a/cumulus/primitives/timestamp/src/lib.rs b/cumulus/primitives/timestamp/src/lib.rs index e6aba6d0bb74043c134400387d84429cf0a712d1..5365f83efdf1111eaf727a4a8fe87ec4f2065726 100644 --- a/cumulus/primitives/timestamp/src/lib.rs +++ b/cumulus/primitives/timestamp/src/lib.rs @@ -27,9 +27,9 @@ #![cfg_attr(not(feature = "std"), no_std)] +use core::time::Duration; use cumulus_primitives_core::relay_chain::Slot; use sp_inherents::{Error, InherentData}; -use sp_std::time::Duration; pub use sp_timestamp::{InherentType, INHERENT_IDENTIFIER}; diff --git a/cumulus/primitives/utility/Cargo.toml b/cumulus/primitives/utility/Cargo.toml index 85e3ac2f7606c9e12aa4d38f0c44c3fe1818b107..82d18c8c0aac60b98fad565857fff5561a1ac21e 100644 --- a/cumulus/primitives/utility/Cargo.toml +++ b/cumulus/primitives/utility/Cargo.toml @@ -10,25 +10,24 @@ description = "Helper datatypes for Cumulus" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } log = { workspace = true } # Substrate -frame-support = { path = "../../../substrate/frame/support", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -pallet-asset-conversion = { path = "../../../substrate/frame/asset-conversion", default-features = false } +frame-support = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +pallet-asset-conversion = { workspace = true } # Polkadot -polkadot-runtime-common = { path = "../../../polkadot/runtime/common", default-features = false } -polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains", default-features = false } -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false } +polkadot-runtime-common = { workspace = true } +polkadot-runtime-parachains = { workspace = true } +xcm = { workspace = true } +xcm-executor = { workspace = true } +xcm-builder = { workspace = true } # Cumulus -cumulus-primitives-core = { path = "../core", default-features = false } +cumulus-primitives-core = { workspace = true } [features] default = ["std"] @@ -42,7 +41,6 @@ std = [ "polkadot-runtime-parachains/std", "sp-io/std", "sp-runtime/std", - "sp-std/std", "xcm-builder/std", "xcm-executor/std", "xcm/std", diff --git a/cumulus/primitives/utility/src/lib.rs b/cumulus/primitives/utility/src/lib.rs index 64784eb36f846f7b325aaaa5ed72966e3d59a1b8..9d5bf4e231eb0d4893360d107d92079b775db1df 100644 --- a/cumulus/primitives/utility/src/lib.rs +++ b/cumulus/primitives/utility/src/lib.rs @@ -19,7 +19,11 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + +use alloc::{vec, vec::Vec}; use codec::Encode; +use core::marker::PhantomData; use cumulus_primitives_core::{MessageSendError, UpwardMessageSender}; use frame_support::{ defensive, @@ -33,7 +37,6 @@ use sp_runtime::{ traits::{Saturating, Zero}, SaturatedConversion, }; -use sp_std::{marker::PhantomData, prelude::*}; use xcm::{latest::prelude::*, VersionedLocation, VersionedXcm, WrapVersion}; use xcm_builder::{InspectMessageQueues, TakeRevenue}; use xcm_executor::{ @@ -803,7 +806,7 @@ mod test_trader { /// needed. #[cfg(feature = "runtime-benchmarks")] pub struct ToParentDeliveryHelper( - sp_std::marker::PhantomData<(XcmConfig, ExistentialDeposit, PriceForDelivery)>, + core::marker::PhantomData<(XcmConfig, ExistentialDeposit, PriceForDelivery)>, ); #[cfg(feature = "runtime-benchmarks")] diff --git a/cumulus/templates/xcm-bench-template.hbs b/cumulus/templates/xcm-bench-template.hbs index 5d0ded403f63496e93c4b118ea4137830c8a9b0d..119924bca2ee1fc1d4b568a63930bb13128c77e5 100644 --- a/cumulus/templates/xcm-bench-template.hbs +++ b/cumulus/templates/xcm-bench-template.hbs @@ -17,7 +17,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weights for `{{pallet}}`. pub struct WeightInfo(PhantomData); diff --git a/cumulus/test/client/Cargo.toml b/cumulus/test/client/Cargo.toml index 120983eb9390e9007c13b08c763f13446011f98e..fbbaab73ce7695c62cfbe1e6ce62d67ba5a68509 100644 --- a/cumulus/test/client/Cargo.toml +++ b/cumulus/test/client/Cargo.toml @@ -9,43 +9,43 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } # Substrate -sc-service = { path = "../../../substrate/client/service" } -sc-consensus = { path = "../../../substrate/client/consensus/common" } -sc-consensus-aura = { path = "../../../substrate/client/consensus/aura" } -sc-block-builder = { path = "../../../substrate/client/block-builder" } -sc-executor = { path = "../../../substrate/client/executor" } -sc-executor-common = { path = "../../../substrate/client/executor/common" } -substrate-test-client = { path = "../../../substrate/test-utils/client" } -sp-application-crypto = { path = "../../../substrate/primitives/application-crypto" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } -sp-core = { path = "../../../substrate/primitives/core" } -sp-api = { path = "../../../substrate/primitives/api" } -sp-keyring = { path = "../../../substrate/primitives/keyring" } -sp-keystore = { path = "../../../substrate/primitives/keystore" } -sp-consensus-aura = { path = "../../../substrate/primitives/consensus/aura" } -sp-blockchain = { path = "../../../substrate/primitives/blockchain" } -sp-inherents = { path = "../../../substrate/primitives/inherents" } -sp-io = { path = "../../../substrate/primitives/io" } -sp-timestamp = { path = "../../../substrate/primitives/timestamp" } -frame-system = { path = "../../../substrate/frame/system" } -pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment" } -pallet-balances = { path = "../../../substrate/frame/balances" } +sc-service = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sc-consensus-aura = { workspace = true, default-features = true } +sc-block-builder = { workspace = true, default-features = true } +sc-executor = { workspace = true, default-features = true } +sc-executor-common = { workspace = true, default-features = true } +substrate-test-client = { workspace = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-consensus-aura = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-timestamp = { workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } +pallet-transaction-payment = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } # Polkadot -polkadot-primitives = { path = "../../../polkadot/primitives" } -polkadot-parachain-primitives = { path = "../../../polkadot/parachain" } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } # Cumulus -cumulus-test-runtime = { path = "../runtime" } -cumulus-test-service = { path = "../service" } -cumulus-test-relay-sproof-builder = { path = "../relay-sproof-builder" } -cumulus-primitives-core = { path = "../../primitives/core" } -cumulus-primitives-proof-size-hostfunction = { path = "../../primitives/proof-size-hostfunction" } -cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" } -cumulus-primitives-storage-weight-reclaim = { path = "../../primitives/storage-weight-reclaim" } +cumulus-test-runtime = { workspace = true } +cumulus-test-service = { workspace = true } +cumulus-test-relay-sproof-builder = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true, default-features = true } +cumulus-primitives-proof-size-hostfunction = { workspace = true, default-features = true } +cumulus-primitives-parachain-inherent = { workspace = true, default-features = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true, default-features = true } [features] runtime-benchmarks = [ diff --git a/cumulus/test/client/src/lib.rs b/cumulus/test/client/src/lib.rs index d233ad2691768c0c1d563c3a0f4c62b44f4c9b23..f26413e441e72b7fca558043f0507de91db4746f 100644 --- a/cumulus/test/client/src/lib.rs +++ b/cumulus/test/client/src/lib.rs @@ -79,6 +79,7 @@ impl substrate_test_client::GenesisInit for GenesisParameters { cumulus_test_service::chain_spec::get_chain_spec_with_extra_endowed( None, self.endowed_accounts.clone(), + cumulus_test_runtime::WASM_BINARY.expect("WASM binary not compiled!"), ) .build_storage() .expect("Builds test runtime genesis storage") diff --git a/cumulus/test/relay-sproof-builder/Cargo.toml b/cumulus/test/relay-sproof-builder/Cargo.toml index d775c61f7801e98b4c8e8436eb95c1ec86854d77..e266b5807081aa1bc3dd8d5793d1f03342f094fc 100644 --- a/cumulus/test/relay-sproof-builder/Cargo.toml +++ b/cumulus/test/relay-sproof-builder/Cargo.toml @@ -10,19 +10,18 @@ description = "Mocked relay state proof builder for testing Cumulus." workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } # Substrate -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-state-machine = { path = "../../../substrate/primitives/state-machine", default-features = false } -sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +sp-runtime = { workspace = true } +sp-state-machine = { workspace = true } +sp-trie = { workspace = true } # Polkadot -polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false } +polkadot-primitives = { workspace = true } # Cumulus -cumulus-primitives-core = { path = "../../primitives/core", default-features = false } +cumulus-primitives-core = { workspace = true } [features] default = ["std"] @@ -32,6 +31,5 @@ std = [ "polkadot-primitives/std", "sp-runtime/std", "sp-state-machine/std", - "sp-std/std", "sp-trie/std", ] diff --git a/cumulus/test/relay-sproof-builder/src/lib.rs b/cumulus/test/relay-sproof-builder/src/lib.rs index fbd2692a36b466827376e0917adfc93aac10a739..d1016085c8073d67f2b8d50a224dce39711403f3 100644 --- a/cumulus/test/relay-sproof-builder/src/lib.rs +++ b/cumulus/test/relay-sproof-builder/src/lib.rs @@ -14,12 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . +extern crate alloc; + +use alloc::collections::btree_map::BTreeMap; use cumulus_primitives_core::{ relay_chain, AbridgedHostConfiguration, AbridgedHrmpChannel, ParaId, }; use polkadot_primitives::UpgradeGoAhead; use sp_runtime::traits::HashingFor; -use sp_std::collections::btree_map::BTreeMap; use sp_trie::PrefixedMemoryDB; /// Builds a sproof (portmanteau of 'spoof' and 'proof') of the relay chain state. diff --git a/cumulus/test/runtime/Cargo.toml b/cumulus/test/runtime/Cargo.toml index b14e3b7f040e74cfabe834d770859433cdb1553d..54b83e2dfedae35583a7c8baf5308a9d709c1f4a 100644 --- a/cumulus/test/runtime/Cargo.toml +++ b/cumulus/test/runtime/Cargo.toml @@ -9,48 +9,47 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } # Substrate -frame-executive = { path = "../../../substrate/frame/executive", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -frame-system-rpc-runtime-api = { path = "../../../substrate/frame/system/rpc/runtime-api", default-features = false } -pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } -pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } -pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false } -pallet-aura = { path = "../../../substrate/frame/aura", default-features = false } -pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } -pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false } -pallet-glutton = { path = "../../../substrate/frame/glutton", default-features = false } -pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false } -pallet-session = { path = "../../../substrate/frame/session", default-features = false } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-block-builder = { path = "../../../substrate/primitives/block-builder", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-genesis-builder = { path = "../../../substrate/primitives/genesis-builder", default-features = false } -sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -sp-offchain = { path = "../../../substrate/primitives/offchain", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-session = { path = "../../../substrate/primitives/session", default-features = false } -sp-consensus-aura = { path = "../../../substrate/primitives/consensus/aura", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-transaction-pool = { path = "../../../substrate/primitives/transaction-pool", default-features = false } -sp-version = { path = "../../../substrate/primitives/version", default-features = false } +frame-executive = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +pallet-balances = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-sudo = { workspace = true } +pallet-aura = { workspace = true } +pallet-authorship = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-glutton = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-session = { workspace = true } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-core = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } +sp-io = { workspace = true } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } # Cumulus -cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../parachains/pallets/parachain-info", default-features = false } -cumulus-primitives-aura = { path = "../../primitives/aura", default-features = false } -pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false } -cumulus-pallet-aura-ext = { path = "../../pallets/aura-ext", default-features = false } -cumulus-primitives-core = { path = "../../primitives/core", default-features = false } -cumulus-primitives-storage-weight-reclaim = { path = "../../primitives/storage-weight-reclaim", default-features = false } +cumulus-pallet-parachain-system = { workspace = true } +parachain-info = { workspace = true } +cumulus-primitives-aura = { workspace = true } +pallet-collator-selection = { workspace = true } +cumulus-pallet-aura-ext = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [features] default = ["std"] @@ -87,9 +86,9 @@ std = [ "sp-offchain/std", "sp-runtime/std", "sp-session/std", - "sp-std/std", "sp-transaction-pool/std", "sp-version/std", "substrate-wasm-builder", ] increment-spec-version = [] +elastic-scaling = [] diff --git a/cumulus/test/runtime/build.rs b/cumulus/test/runtime/build.rs index ebd5c178cba07e2889b6501a9be490344467d228..bf579f4121e5f6b48fa5ba310c76f7cdd02fa7a0 100644 --- a/cumulus/test/runtime/build.rs +++ b/cumulus/test/runtime/build.rs @@ -24,6 +24,13 @@ fn main() { .enable_feature("increment-spec-version") .set_file_name("wasm_binary_spec_version_incremented.rs") .build(); + + WasmBuilder::new() + .with_current_project() + .enable_feature("elastic-scaling") + .import_memory() + .set_file_name("wasm_binary_elastic_scaling.rs") + .build(); } #[cfg(not(feature = "std"))] diff --git a/cumulus/test/runtime/src/lib.rs b/cumulus/test/runtime/src/lib.rs index 26c6635e1ad3200e1a78fb9f0645bf7ba989ac4b..274f16ab630d6c0f9cff092b0ed79624e2a27a67 100644 --- a/cumulus/test/runtime/src/lib.rs +++ b/cumulus/test/runtime/src/lib.rs @@ -27,7 +27,16 @@ pub mod wasm_spec_version_incremented { include!(concat!(env!("OUT_DIR"), "/wasm_binary_spec_version_incremented.rs")); } +pub mod elastic_scaling { + #[cfg(feature = "std")] + include!(concat!(env!("OUT_DIR"), "/wasm_binary_elastic_scaling.rs")); +} + mod test_pallet; + +extern crate alloc; + +use alloc::{vec, vec::Vec}; use frame_support::{derive_impl, traits::OnRuntimeUpgrade, PalletId}; use sp_api::{decl_runtime_apis, impl_runtime_apis}; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; @@ -39,7 +48,6 @@ use sp_runtime::{ transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, MultiSignature, }; -use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -83,8 +91,23 @@ impl_opaque_keys! { /// The para-id used in this runtime. pub const PARACHAIN_ID: u32 = 100; -const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3; +#[cfg(not(feature = "elastic-scaling"))] +const UNINCLUDED_SEGMENT_CAPACITY: u32 = 4; +#[cfg(not(feature = "elastic-scaling"))] const BLOCK_PROCESSING_VELOCITY: u32 = 1; + +#[cfg(feature = "elastic-scaling")] +const UNINCLUDED_SEGMENT_CAPACITY: u32 = 7; +#[cfg(feature = "elastic-scaling")] +const BLOCK_PROCESSING_VELOCITY: u32 = 4; + +#[cfg(not(feature = "elastic-scaling"))] +pub const MILLISECS_PER_BLOCK: u64 = 6000; +#[cfg(feature = "elastic-scaling")] +pub const MILLISECS_PER_BLOCK: u64 = 2000; + +pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; + const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; // The only difference between the two declarations below is the `spec_version`. With the @@ -126,10 +149,6 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { state_version: 1, }; -pub const MILLISECS_PER_BLOCK: u64 = 6000; - -pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; - pub const EPOCH_DURATION_IN_BLOCKS: u32 = 10 * MINUTES; // These time units are defined in number of blocks. @@ -438,7 +457,7 @@ impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> Vec { Runtime::metadata_versions() } } diff --git a/cumulus/test/runtime/src/test_pallet.rs b/cumulus/test/runtime/src/test_pallet.rs index 7f43f713fadc4c96776adfea90cdd17365a6b1cd..61195386ae79d2501965a8048a08c12143407348 100644 --- a/cumulus/test/runtime/src/test_pallet.rs +++ b/cumulus/test/runtime/src/test_pallet.rs @@ -42,7 +42,7 @@ pub mod pallet { #[pallet::weight(0)] pub fn set_custom_validation_head_data( _: OriginFor, - custom_header: sp_std::vec::Vec, + custom_header: alloc::vec::Vec, ) -> DispatchResult { cumulus_pallet_parachain_system::Pallet::::set_custom_validation_head_data( custom_header, @@ -79,7 +79,7 @@ pub mod pallet { #[pallet::genesis_config] pub struct GenesisConfig { #[serde(skip)] - pub _config: sp_std::marker::PhantomData, + pub _config: core::marker::PhantomData, } #[pallet::genesis_build] diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index 732d884528f8974b4d09b33c118f41b74d22f348..f766d123632096a4af578fcf87bdb0b299008028 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -13,96 +13,94 @@ name = "test-parachain" path = "src/main.rs" [dependencies] -async-trait = "0.1.79" -clap = { version = "4.5.3", features = ["derive"] } -codec = { package = "parity-scale-codec", version = "3.6.12" } -criterion = { version = "0.5.1", features = ["async_tokio"] } -jsonrpsee = { version = "0.22", features = ["server"] } -rand = "0.8.5" +async-trait = { workspace = true } +clap = { features = ["derive"], workspace = true } +codec = { workspace = true, default-features = true } +criterion = { features = ["async_tokio"], workspace = true, default-features = true } +jsonrpsee = { features = ["server"], workspace = true } +rand = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } -tokio = { version = "1.32.0", features = ["macros"] } -tracing = "0.1.37" -url = "2.4.0" -tempfile = "3.8.0" +tokio = { features = ["macros"], workspace = true, default-features = true } +tracing = { workspace = true, default-features = true } +url = { workspace = true } +tempfile = { workspace = true } # Substrate -frame-system = { path = "../../../substrate/frame/system" } -frame-system-rpc-runtime-api = { path = "../../../substrate/frame/system/rpc/runtime-api" } -pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment" } -sc-basic-authorship = { path = "../../../substrate/client/basic-authorship" } -sc-chain-spec = { path = "../../../substrate/client/chain-spec" } -sc-client-api = { path = "../../../substrate/client/api" } -sc-consensus = { path = "../../../substrate/client/consensus/common" } -sc-consensus-aura = { path = "../../../substrate/client/consensus/aura" } -sc-executor = { path = "../../../substrate/client/executor" } -sc-network = { path = "../../../substrate/client/network" } -sc-service = { path = "../../../substrate/client/service" } -sc-tracing = { path = "../../../substrate/client/tracing" } -sc-transaction-pool = { path = "../../../substrate/client/transaction-pool" } -sc-transaction-pool-api = { path = "../../../substrate/client/transaction-pool/api" } -sc-telemetry = { path = "../../../substrate/client/telemetry" } -sp-arithmetic = { path = "../../../substrate/primitives/arithmetic" } -sp-blockchain = { path = "../../../substrate/primitives/blockchain" } -sp-core = { path = "../../../substrate/primitives/core" } -sp-io = { path = "../../../substrate/primitives/io" } -sp-api = { path = "../../../substrate/primitives/api" } -sp-keyring = { path = "../../../substrate/primitives/keyring" } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-state-machine = { path = "../../../substrate/primitives/state-machine" } -sp-tracing = { path = "../../../substrate/primitives/tracing" } -sp-timestamp = { path = "../../../substrate/primitives/timestamp" } -sp-consensus = { path = "../../../substrate/primitives/consensus/common" } -sp-consensus-aura = { path = "../../../substrate/primitives/consensus/aura" } -substrate-test-client = { path = "../../../substrate/test-utils/client" } -sc-cli = { path = "../../../substrate/client/cli" } -sc-block-builder = { path = "../../../substrate/client/block-builder" } -sc-executor-wasmtime = { path = "../../../substrate/client/executor/wasmtime" } -sc-executor-common = { path = "../../../substrate/client/executor/common" } +frame-system = { workspace = true, default-features = true } +frame-system-rpc-runtime-api = { workspace = true, default-features = true } +pallet-transaction-payment = { workspace = true, default-features = true } +sc-basic-authorship = { workspace = true, default-features = true } +sc-chain-spec = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sc-consensus-aura = { workspace = true, default-features = true } +sc-executor = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-service = { workspace = true, default-features = true } +sc-tracing = { workspace = true, default-features = true } +sc-transaction-pool = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } +sc-telemetry = { workspace = true, default-features = true } +sp-arithmetic = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-runtime = { workspace = true } +sp-state-machine = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +sp-timestamp = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-consensus-aura = { workspace = true, default-features = true } +substrate-test-client = { workspace = true } +sc-cli = { workspace = true, default-features = true } +sc-block-builder = { workspace = true, default-features = true } +sc-executor-wasmtime = { workspace = true, default-features = true } +sc-executor-common = { workspace = true, default-features = true } # Polkadot -polkadot-primitives = { path = "../../../polkadot/primitives" } -polkadot-service = { path = "../../../polkadot/node/service" } -polkadot-test-service = { path = "../../../polkadot/node/test/service" } -polkadot-cli = { path = "../../../polkadot/cli" } -polkadot-node-subsystem = { path = "../../../polkadot/node/subsystem" } -polkadot-overseer = { path = "../../../polkadot/node/overseer" } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-service = { workspace = true, default-features = true } +polkadot-test-service = { workspace = true } +polkadot-cli = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-overseer = { workspace = true, default-features = true } # Cumulus -cumulus-client-cli = { path = "../../client/cli" } -parachains-common = { path = "../../parachains/common" } -cumulus-client-consensus-common = { path = "../../client/consensus/common" } -cumulus-client-consensus-proposer = { path = "../../client/consensus/proposer" } -cumulus-client-consensus-aura = { path = "../../client/consensus/aura" } -cumulus-client-consensus-relay-chain = { path = "../../client/consensus/relay-chain" } -cumulus-client-parachain-inherent = { path = "../../client/parachain-inherent" } -cumulus-client-service = { path = "../../client/service" } -cumulus-client-collator = { path = "../../client/collator" } -cumulus-primitives-core = { path = "../../primitives/core" } -cumulus-relay-chain-inprocess-interface = { path = "../../client/relay-chain-inprocess-interface" } -cumulus-relay-chain-interface = { path = "../../client/relay-chain-interface" } -cumulus-test-runtime = { path = "../runtime" } -cumulus-relay-chain-minimal-node = { path = "../../client/relay-chain-minimal-node" } -cumulus-client-pov-recovery = { path = "../../client/pov-recovery" } -cumulus-test-relay-sproof-builder = { path = "../relay-sproof-builder" } -cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false } -cumulus-primitives-storage-weight-reclaim = { path = "../../primitives/storage-weight-reclaim" } -pallet-timestamp = { path = "../../../substrate/frame/timestamp" } +cumulus-client-cli = { workspace = true, default-features = true } +parachains-common = { workspace = true, default-features = true } +cumulus-client-consensus-common = { workspace = true, default-features = true } +cumulus-client-consensus-proposer = { workspace = true, default-features = true } +cumulus-client-consensus-aura = { workspace = true, default-features = true } +cumulus-client-consensus-relay-chain = { workspace = true, default-features = true } +cumulus-client-parachain-inherent = { workspace = true, default-features = true } +cumulus-client-service = { workspace = true, default-features = true } +cumulus-client-collator = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true, default-features = true } +cumulus-relay-chain-inprocess-interface = { workspace = true, default-features = true } +cumulus-relay-chain-interface = { workspace = true, default-features = true } +cumulus-test-runtime = { workspace = true } +cumulus-relay-chain-minimal-node = { workspace = true, default-features = true } +cumulus-client-pov-recovery = { workspace = true, default-features = true } +cumulus-test-relay-sproof-builder = { workspace = true, default-features = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true, default-features = true } +pallet-timestamp = { workspace = true, default-features = true } [dev-dependencies] -futures = "0.3.28" -portpicker = "0.1.1" -rococo-parachain-runtime = { path = "../../parachains/runtimes/testing/rococo-parachain" } -sp-consensus-grandpa = { path = "../../../substrate/primitives/consensus/grandpa" } -sp-authority-discovery = { path = "../../../substrate/primitives/authority-discovery" } -cumulus-test-client = { path = "../client" } +futures = { workspace = true } +portpicker = { workspace = true } +sp-authority-discovery = { workspace = true, default-features = true } +cumulus-test-client = { workspace = true } # Polkadot dependencies -polkadot-test-service = { path = "../../../polkadot/node/test/service" } +polkadot-test-service = { workspace = true } # Substrate dependencies -sc-cli = { path = "../../../substrate/client/cli" } -substrate-test-utils = { path = "../../../substrate/test-utils" } +sc-cli = { workspace = true, default-features = true } +substrate-test-utils = { workspace = true } [features] runtime-benchmarks = [ @@ -116,7 +114,6 @@ runtime-benchmarks = [ "polkadot-primitives/runtime-benchmarks", "polkadot-service/runtime-benchmarks", "polkadot-test-service/runtime-benchmarks", - "rococo-parachain-runtime/runtime-benchmarks", "sc-service/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] diff --git a/cumulus/test/service/src/chain_spec.rs b/cumulus/test/service/src/chain_spec.rs index 174d478f2575caae3f6afe14810c8fe7f6719cb8..ae71028ad486a46f32347f925e645ff0980bd652 100644 --- a/cumulus/test/service/src/chain_spec.rs +++ b/cumulus/test/service/src/chain_spec.rs @@ -66,9 +66,10 @@ where pub fn get_chain_spec_with_extra_endowed( id: Option, extra_endowed_accounts: Vec, + code: &[u8], ) -> ChainSpec { ChainSpec::builder( - cumulus_test_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), + code, Extensions { para_id: id.unwrap_or(cumulus_test_runtime::PARACHAIN_ID.into()).into() }, ) .with_name("Local Testnet") @@ -83,7 +84,21 @@ pub fn get_chain_spec_with_extra_endowed( /// Get the chain spec for a specific parachain ID. pub fn get_chain_spec(id: Option) -> ChainSpec { - get_chain_spec_with_extra_endowed(id, Default::default()) + get_chain_spec_with_extra_endowed( + id, + Default::default(), + cumulus_test_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), + ) +} + +/// Get the chain spec for a specific parachain ID. +pub fn get_elastic_scaling_chain_spec(id: Option) -> ChainSpec { + get_chain_spec_with_extra_endowed( + id, + Default::default(), + cumulus_test_runtime::elastic_scaling::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + ) } /// Local testnet genesis for testing. diff --git a/cumulus/test/service/src/cli.rs b/cumulus/test/service/src/cli.rs index 87d1d4af8a95e0edf12efc454d5505a6c1ad7544..37ca27542cbfe0cd0d93ba7eb6a6dfb7a05459c0 100644 --- a/cumulus/test/service/src/cli.rs +++ b/cumulus/test/service/src/cli.rs @@ -50,6 +50,12 @@ pub struct TestCollatorCli { #[arg(long)] pub fail_pov_recovery: bool, + + /// EXPERIMENTAL: Use slot-based collator which can handle elastic scaling. + /// + /// Use with care, this flag is unstable and subject to change. + #[arg(long)] + pub experimental_use_slot_based: bool, } #[derive(Debug, clap::Subcommand)] @@ -253,8 +259,16 @@ impl SubstrateCli for TestCollatorCli { fn load_spec(&self, id: &str) -> std::result::Result, String> { Ok(match id { - "" => - Box::new(cumulus_test_service::get_chain_spec(Some(ParaId::from(2000)))) as Box<_>, + "" => { + tracing::info!("Using default test service chain spec."); + Box::new(cumulus_test_service::get_chain_spec(Some(ParaId::from(2000)))) as Box<_> + }, + "elastic-scaling" => { + tracing::info!("Using elastic-scaling chain spec."); + Box::new(cumulus_test_service::get_elastic_scaling_chain_spec(Some(ParaId::from( + 2100, + )))) as Box<_> + }, path => { let chain_spec = cumulus_test_service::chain_spec::ChainSpec::from_json_file(path.into())?; diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index 6f8b9d19bb29ba7445b2b67fdd9b0ac4a3263553..503c2f24fd54941e1ac65b2fdabd0790ac375ca2 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -25,7 +25,10 @@ pub mod chain_spec; use cumulus_client_collator::service::CollatorService; use cumulus_client_consensus_aura::{ - collators::lookahead::{self as aura, Params as AuraParams}, + collators::{ + lookahead::{self as aura, Params as AuraParams}, + slot_based::{self as slot_based, Params as SlotBasedParams}, + }, ImportQueueParams, }; use cumulus_client_consensus_proposer::Proposer; @@ -45,7 +48,7 @@ use cumulus_client_cli::{CollatorOptions, RelayChainMode}; use cumulus_client_consensus_common::{ ParachainBlockImport as TParachainBlockImport, ParachainCandidate, ParachainConsensus, }; -use cumulus_client_pov_recovery::RecoveryHandle; +use cumulus_client_pov_recovery::{RecoveryDelayRange, RecoveryHandle}; #[allow(deprecated)] use cumulus_client_service::old_consensus; use cumulus_client_service::{ @@ -304,7 +307,7 @@ async fn build_relay_chain_interface( /// Start a node with the given parachain `Configuration` and relay chain `Configuration`. /// /// This is the actual implementation that is abstract over the executor and the runtime api. -#[sc_tracing::logging::prefix_logs_with(parachain_config.network.node_name.as_str())] +#[sc_tracing::logging::prefix_logs_with("Parachain")] pub async fn start_node_impl>( parachain_config: Configuration, collator_key: Option, @@ -316,6 +319,7 @@ pub async fn start_node_impl>( consensus: Consensus, collator_options: CollatorOptions, proof_recording_during_import: bool, + use_slot_based_collator: bool, ) -> sc_service::error::Result<( TaskManager, Arc, @@ -349,7 +353,11 @@ where .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; let import_queue_service = params.import_queue.service(); - let net_config = FullNetworkConfiguration::::new(¶chain_config.network); + let prometheus_registry = parachain_config.prometheus_registry().cloned(); + let net_config = FullNetworkConfiguration::::new( + ¶chain_config.network, + prometheus_registry.clone(), + ); let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = build_network(BuildNetworkParams { @@ -368,8 +376,6 @@ where }) .await?; - let prometheus_registry = parachain_config.prometheus_registry().cloned(); - let keystore = params.keystore_container.keystore(); let rpc_builder = { let client = client.clone(); @@ -409,7 +415,6 @@ where } else { Box::new(overseer_handle.clone()) }; - let is_collator = collator_key.is_some(); let relay_chain_slot_duration = Duration::from_secs(6); start_relay_chain_tasks(StartRelayChainTasksParams { @@ -418,11 +423,11 @@ where para_id, relay_chain_interface: relay_chain_interface.clone(), task_manager: &mut task_manager, - da_recovery_profile: if is_collator { - DARecoveryProfile::Collator - } else { - DARecoveryProfile::FullNode - }, + // Increase speed of recovery for testing purposes. + da_recovery_profile: DARecoveryProfile::Other(RecoveryDelayRange { + min: Duration::from_secs(1), + max: Duration::from_secs(5), + }), import_queue: import_queue_service, relay_chain_slot_duration, recovery_handle, @@ -461,29 +466,72 @@ where ); let client_for_aura = client.clone(); - let params = AuraParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client.clone(), - para_backend: backend.clone(), - relay_client: relay_chain_interface, - code_hash_provider: move |block_hash| { - client_for_aura.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) - }, - sync_oracle: sync_service, - keystore, - collator_key, - para_id, - overseer_handle, - relay_chain_slot_duration, - proposer, - collator_service, - authoring_duration: Duration::from_millis(2000), - reinitialize: false, - }; - let fut = aura::run::(params); - task_manager.spawn_essential_handle().spawn("aura", None, fut); + if use_slot_based_collator { + tracing::info!(target: LOG_TARGET, "Starting block authoring with slot based authoring."); + let params = SlotBasedParams { + create_inherent_data_providers: move |_, ()| async move { Ok(()) }, + block_import, + para_client: client.clone(), + para_backend: backend.clone(), + relay_client: relay_chain_interface, + code_hash_provider: move |block_hash| { + client_for_aura + .code_at(block_hash) + .ok() + .map(|c| ValidationCode::from(c).hash()) + }, + keystore, + collator_key, + para_id, + relay_chain_slot_duration, + proposer, + collator_service, + authoring_duration: Duration::from_millis(2000), + reinitialize: false, + slot_drift: Duration::from_secs(1), + }; + + let (collation_future, block_builer_future) = + slot_based::run::(params); + task_manager.spawn_essential_handle().spawn( + "collation-task", + None, + collation_future, + ); + task_manager.spawn_essential_handle().spawn( + "block-builder-task", + None, + block_builer_future, + ); + } else { + tracing::info!(target: LOG_TARGET, "Starting block authoring with lookahead collator."); + let params = AuraParams { + create_inherent_data_providers: move |_, ()| async move { Ok(()) }, + block_import, + para_client: client.clone(), + para_backend: backend.clone(), + relay_client: relay_chain_interface, + code_hash_provider: move |block_hash| { + client_for_aura + .code_at(block_hash) + .ok() + .map(|c| ValidationCode::from(c).hash()) + }, + keystore, + collator_key, + para_id, + overseer_handle, + relay_chain_slot_duration, + proposer, + collator_service, + authoring_duration: Duration::from_millis(2000), + reinitialize: false, + }; + + let fut = aura::run::(params); + task_manager.spawn_essential_handle().spawn("aura", None, fut); + } } } @@ -720,6 +768,7 @@ impl TestNodeBuilder { self.consensus, collator_options, self.record_proof_during_import, + false, ) .await .expect("could not create Cumulus test service"), @@ -735,6 +784,7 @@ impl TestNodeBuilder { self.consensus, collator_options, self.record_proof_during_import, + false, ) .await .expect("could not create Cumulus test service"), @@ -766,8 +816,11 @@ pub fn node_config( let root = base_path.path().join(format!("cumulus_test_service_{}", key)); let role = if is_collator { Role::Authority } else { Role::Full }; let key_seed = key.to_seed(); - let mut spec = - Box::new(chain_spec::get_chain_spec_with_extra_endowed(Some(para_id), endowed_accounts)); + let mut spec = Box::new(chain_spec::get_chain_spec_with_extra_endowed( + Some(para_id), + endowed_accounts, + cumulus_test_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), + )); let mut storage = spec.as_storage_builder().build_storage().expect("could not build storage"); @@ -840,7 +893,6 @@ pub fn node_config( announce_block: true, data_path: root, base_path, - informant_output_format: Default::default(), wasm_runtime_overrides: None, runtime_cache_size: 2, }) diff --git a/cumulus/test/service/src/main.rs b/cumulus/test/service/src/main.rs index 90d37173dd5907ebf1f4a136a284ef50dda816e8..9357978b769a4e8ec6c4f850d37290e3dee1b1e5 100644 --- a/cumulus/test/service/src/main.rs +++ b/cumulus/test/service/src/main.rs @@ -118,6 +118,7 @@ fn main() -> Result<(), sc_cli::Error> { consensus, collator_options, true, + cli.experimental_use_slot_based, ) .await, sc_network::config::NetworkBackendType::Litep2p => @@ -135,6 +136,7 @@ fn main() -> Result<(), sc_cli::Error> { consensus, collator_options, true, + cli.experimental_use_slot_based, ) .await, } diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml index 0ed77bf5b7073bc9e3041388206203ce7c1829a2..ba1097fba075696e9d40dffc3c4753d9956615b1 100644 --- a/cumulus/xcm/xcm-emulator/Cargo.toml +++ b/cumulus/xcm/xcm-emulator/Cargo.toml @@ -10,36 +10,36 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12" } -paste = "1.0.14" +codec = { workspace = true, default-features = true } +paste = { workspace = true, default-features = true } log = { workspace = true } -lazy_static = "1.4.0" -impl-trait-for-tuples = "0.2.2" +lazy_static = { workspace = true } +impl-trait-for-tuples = { workspace = true } # Substrate -frame-support = { path = "../../../substrate/frame/support" } -frame-system = { path = "../../../substrate/frame/system" } -sp-io = { path = "../../../substrate/primitives/io" } -sp-core = { path = "../../../substrate/primitives/core" } -sp-crypto-hashing = { path = "../../../substrate/primitives/crypto/hashing" } -sp-std = { path = "../../../substrate/primitives/std" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } -sp-arithmetic = { path = "../../../substrate/primitives/arithmetic" } -sp-tracing = { path = "../../../substrate/primitives/tracing" } -pallet-balances = { path = "../../../substrate/frame/balances" } -pallet-message-queue = { path = "../../../substrate/frame/message-queue" } +frame-support = { workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-arithmetic = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +pallet-message-queue = { workspace = true, default-features = true } # Cumulus -cumulus-primitives-core = { path = "../../primitives/core" } -cumulus-pallet-xcmp-queue = { path = "../../pallets/xcmp-queue" } -cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system" } -cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" } -cumulus-test-relay-sproof-builder = { path = "../../test/relay-sproof-builder" } -parachains-common = { path = "../../parachains/common" } +cumulus-primitives-core = { workspace = true, default-features = true } +cumulus-pallet-xcmp-queue = { workspace = true, default-features = true } +cumulus-pallet-parachain-system = { workspace = true, default-features = true } +cumulus-primitives-parachain-inherent = { workspace = true, default-features = true } +cumulus-test-relay-sproof-builder = { workspace = true, default-features = true } +parachains-common = { workspace = true, default-features = true } # Polkadot -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm" } -xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor" } -polkadot-primitives = { path = "../../../polkadot/primitives" } -polkadot-parachain-primitives = { path = "../../../polkadot/parachain" } -polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains" } +xcm = { workspace = true, default-features = true } +xcm-executor = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index 1a3f3930cb3478d9e7811c49becbfdd7874bbe48..8de3660c223627155a27f5ecc659a3ea030d7b02 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +extern crate alloc; + pub use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; pub use lazy_static::lazy_static; pub use log; @@ -24,6 +26,8 @@ pub use std::{ }; // Substrate +pub use alloc::collections::vec_deque::VecDeque; +pub use core::{cell::RefCell, fmt::Debug}; pub use cumulus_primitives_core::AggregateMessageOrigin as CumulusAggregateMessageOrigin; pub use frame_support::{ assert_ok, @@ -44,7 +48,6 @@ pub use sp_core::{parameter_types, sr25519, storage::Storage, Pair}; pub use sp_crypto_hashing::blake2_256; pub use sp_io::TestExternalities; pub use sp_runtime::BoundedSlice; -pub use sp_std::{cell::RefCell, collections::vec_deque::VecDeque, fmt::Debug}; pub use sp_tracing; // Cumulus diff --git a/cumulus/zombienet/tests/0002-pov_recovery.zndsl b/cumulus/zombienet/tests/0002-pov_recovery.zndsl index b05285c87bff5a69312552d13b9b652bbd9d1bc1..dc7095ced252de497afd0fcd2cedadf460b412d1 100644 --- a/cumulus/zombienet/tests/0002-pov_recovery.zndsl +++ b/cumulus/zombienet/tests/0002-pov_recovery.zndsl @@ -2,7 +2,9 @@ Description: PoV recovery test Network: ./0002-pov_recovery.toml Creds: config -# wait 20 blocks and register parachain +# Wait 20 blocks and register parachain. This part is important for pov-recovery. +# We need to make sure that the recovering node is able to see all relay-chain +# notifications containing the candidates to recover. validator-3: reports block height is at least 20 within 250 seconds validator-0: js-script ./register-para.js with "2000" within 240 seconds validator-0: parachain 2000 is registered within 300 seconds diff --git a/cumulus/zombienet/tests/0003-full_node_catching_up.zndsl b/cumulus/zombienet/tests/0003-full_node_catching_up.zndsl index 49b6d9e94fd16d73ce7de3cf102fc2bfad1a6e76..e1e8442f30509c72c49673288920e6d5336a8bfb 100644 --- a/cumulus/zombienet/tests/0003-full_node_catching_up.zndsl +++ b/cumulus/zombienet/tests/0003-full_node_catching_up.zndsl @@ -6,3 +6,6 @@ alice: parachain 2000 is registered within 225 seconds dave: reports block height is at least 7 within 250 seconds eve: reports block height is at least 7 within 250 seconds ferdie: reports block height is at least 7 within 250 seconds + +# We want to make sure that none of the consensus hook checks fail, even if the chain makes progress +charlie: count of log lines containing "set_validation_data inherent needs to be present in every block" is 0 within 10 seconds diff --git a/cumulus/zombienet/tests/0006-rpc_collator_builds_blocks.zndsl b/cumulus/zombienet/tests/0006-rpc_collator_builds_blocks.zndsl index 7da8416d0161a23f84184d288cb14fdcd3094fd5..b14c15ed5e5b90f8fed878c5c8c82eefbe71b624 100644 --- a/cumulus/zombienet/tests/0006-rpc_collator_builds_blocks.zndsl +++ b/cumulus/zombienet/tests/0006-rpc_collator_builds_blocks.zndsl @@ -13,3 +13,7 @@ two: restart after 1 seconds three: restart after 20 seconds dave: is up dave: reports block height is at least 30 within 200 seconds + +# We want to make sure that none of the consensus hook checks fail, even if the chain makes progress +dave: count of log lines containing "set_validation_data inherent needs to be present in every block" is 0 within 10 seconds +eve: count of log lines containing "set_validation_data inherent needs to be present in every block" is 0 within 10 seconds diff --git a/cumulus/zombienet/tests/0008-elastic_authoring.toml b/cumulus/zombienet/tests/0008-elastic_authoring.toml new file mode 100644 index 0000000000000000000000000000000000000000..f2e2010a9e4582feefaebdaa355ab96b6a8f7695 --- /dev/null +++ b/cumulus/zombienet/tests/0008-elastic_authoring.toml @@ -0,0 +1,50 @@ +[settings] +timeout = 1000 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.async_backing_params] + max_candidate_depth = 6 + allowed_ancestry_len = 3 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] + max_validators_per_core = 1 + num_cores = 4 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.approval_voting_params] + max_approval_coalesce_count = 5 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" +command = "polkadot" + + [[relaychain.nodes]] + name = "alice" + args = ["" ] + + [[relaychain.node_groups]] + name = "validator" + args = ["-lruntime=debug,parachain=trace" ] + count = 8 + +# Slot based authoring with 3 cores and 2s slot duration +[[parachains]] +id = 2100 +chain = "elastic-scaling" +add_to_genesis = true + + [[parachains.collators]] + name = "collator-elastic" + image = "{{COL_IMAGE}}" + command = "test-parachain" + args = ["-laura=trace,runtime=info,cumulus-consensus=trace,consensus::common=trace,parachain::collation-generation=trace,parachain::collator-protocol=trace,parachain=debug", "--force-authoring", "--experimental-use-slot-based"] + +# Slot based authoring with 1 core and 6s slot duration +[[parachains]] +id = 2000 +add_to_genesis = true + + [[parachains.collators]] + name = "collator-single-core" + image = "{{COL_IMAGE}}" + command = "test-parachain" + args = ["-laura=trace,runtime=info,cumulus-consensus=trace,consensus::common=trace,parachain::collation-generation=trace,parachain::collator-protocol=trace,parachain=debug", "--force-authoring", "--experimental-use-slot-based"] diff --git a/cumulus/zombienet/tests/0008-elastic_authoring.zndsl b/cumulus/zombienet/tests/0008-elastic_authoring.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..a06ffd24fefd2bab46de4c80b210959a62660da1 --- /dev/null +++ b/cumulus/zombienet/tests/0008-elastic_authoring.zndsl @@ -0,0 +1,19 @@ +Description: Slot based authoring for elastic scaling +Network: ./0008-elastic_authoring.toml +Creds: config + +alice: is up +collator-elastic: is up +collator-single-core: is up + + +# configure relay chain +alice: js-script ./assign-core.js with "2100,0" return is 0 within 600 seconds +alice: js-script ./assign-core.js with "2100,1" return is 0 within 600 seconds + +collator-single-core: reports block height is at least 20 within 225 seconds +collator-elastic: reports block height is at least 40 within 225 seconds + +# We want to make sure that none of the consensus hook checks fail, even if the chain makes progress +collator-elastic: count of log lines containing "set_validation_data inherent needs to be present in every block" is 0 within 10 seconds +collator-single-core: count of log lines containing "set_validation_data inherent needs to be present in every block" is 0 within 10 seconds diff --git a/cumulus/zombienet/tests/0009-elastic_pov_recovery.toml b/cumulus/zombienet/tests/0009-elastic_pov_recovery.toml new file mode 100644 index 0000000000000000000000000000000000000000..b695f8aa937653340534d9366a5eab210888e416 --- /dev/null +++ b/cumulus/zombienet/tests/0009-elastic_pov_recovery.toml @@ -0,0 +1,48 @@ +[settings] +timeout = 1000 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.async_backing_params] + max_candidate_depth = 6 + allowed_ancestry_len = 3 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] + max_validators_per_core = 1 + num_cores = 4 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.approval_voting_params] + max_approval_coalesce_count = 5 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" +command = "polkadot" + + [[relaychain.nodes]] + name = "alice" + args = ["" ] + + [[relaychain.node_groups]] + name = "validator" + args = ["-lruntime=debug,parachain=trace", "--reserved-only", "--reserved-nodes {{'alice'|zombie('multiAddress')}}"] + count = 8 + +# Slot based authoring with 3 cores and 2s slot duration +[[parachains]] +id = 2100 +chain = "elastic-scaling" +add_to_genesis = false + + # Slot based authoring with 3 cores and 2s slot duration + [[parachains.collators]] + name = "collator-elastic" + image = "{{COL_IMAGE}}" + command = "test-parachain" + args = ["--disable-block-announcements", "-laura=trace,runtime=info,cumulus-consensus=trace,consensus::common=trace,parachain::collation-generation=trace,parachain::collator-protocol=trace,parachain=debug", "--force-authoring", "--experimental-use-slot-based"] + + # run 'recovery-target' as a parachain full node + [[parachains.collators]] + name = "recovery-target" + validator = false # full node + image = "{{COL_IMAGE}}" + command = "test-parachain" + args = ["-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", "--disable-block-announcements", "--bootnodes {{'collator-elastic'|zombie('multiAddress')}}", "--in-peers 0", "--out-peers 0", "--", "--reserved-only", "--reserved-nodes {{'alice'|zombie('multiAddress')}}"] diff --git a/cumulus/zombienet/tests/0009-elastic_pov_recovery.zndsl b/cumulus/zombienet/tests/0009-elastic_pov_recovery.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..5cca6120ff3a37dbff4d3d93c8ad977e5404f645 --- /dev/null +++ b/cumulus/zombienet/tests/0009-elastic_pov_recovery.zndsl @@ -0,0 +1,24 @@ +Description: Elastic scaling PoV recovery test +Network: ./0009-elastic_pov_recovery.toml +Creds: config + +alice: is up +collator-elastic: is up + +# configure relay chain +alice: js-script ./assign-core.js with "2100,0" return is 0 within 200 seconds +alice: js-script ./assign-core.js with "2100,1" return is 0 within 200 seconds + +# Wait 20 blocks and register parachain. This part is important for pov-recovery. +# We need to make sure that the recovering node is able to see all relay-chain +# notifications containing the candidates to recover. +alice: reports block height is at least 20 within 250 seconds +alice: js-script ./register-para.js with "2100" within 240 seconds +alice: parachain 2100 is registered within 300 seconds + + +# check block production +collator-elastic: reports block height is at least 40 within 225 seconds +collator-elastic: count of log lines containing "set_validation_data inherent needs to be present in every block" is 0 within 10 seconds + +recovery-target: count of log lines containing "Importing block retrieved using pov_recovery" is greater than 35 within 10 seconds diff --git a/cumulus/zombienet/tests/assign-core.js b/cumulus/zombienet/tests/assign-core.js new file mode 100644 index 0000000000000000000000000000000000000000..4179b68b2e3cb139bb48d937b472258e943ddce2 --- /dev/null +++ b/cumulus/zombienet/tests/assign-core.js @@ -0,0 +1,46 @@ +// Assign a parachain to a core. +// +// First argument should be the parachain id. +// Second argument should be the core. +async function run(nodeName, networkInfo, args) { + const { wsUri, userDefinedTypes } = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + + let para = Number(args[0]); + let core = Number(args[1]); + console.log(`Assigning para ${para} to core ${core}`); + + await zombie.util.cryptoWaitReady(); + + // Submit transaction with Alice accoung + const keyring = new zombie.Keyring({ type: "sr25519" }); + const alice = keyring.addFromUri("//Alice"); + + // Wait for this transaction to be finalized in a block. + await new Promise(async (resolve, reject) => { + const unsub = await api.tx.sudo + .sudo(api.tx.coretime.assignCore(core, 0, [[{ task: para }, 57600]], null)) + .signAndSend(alice, ({ status, isError }) => { + if (status.isInBlock) { + console.log( + `Transaction included at blockhash ${status.asInBlock}`, + ); + } else if (status.isFinalized) { + console.log( + `Transaction finalized at blockHash ${status.asFinalized}`, + ); + unsub(); + return resolve(); + } else if (isError) { + console.log(`Transaction error`); + reject(`Transaction error`); + } + }); + }); + + + + return 0; +} + +module.exports = { run }; diff --git a/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile b/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile index e17952ccee804d5ff82339c1770f96f28c1cdab8..60698de1d6addf53385ba6e3f30b36e9a1d7f784 100644 --- a/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile +++ b/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile @@ -1,7 +1,7 @@ # this image is built on top of existing Zombienet image ARG ZOMBIENET_IMAGE # this image uses substrate-relay image built elsewhere -ARG SUBSTRATE_RELAY_IMAGE=docker.io/paritytech/substrate-relay:v1.6.4 +ARG SUBSTRATE_RELAY_IMAGE=docker.io/paritytech/substrate-relay:v1.6.6 # metadata ARG VCS_REF diff --git a/docs/contributor/CONTRIBUTING.md b/docs/contributor/CONTRIBUTING.md index 96dc86e9780561e33e24fbc6f0346572d26598b7..7d54b2681b41329c15ab4e3c25f37943ecf0d6a7 100644 --- a/docs/contributor/CONTRIBUTING.md +++ b/docs/contributor/CONTRIBUTING.md @@ -4,18 +4,16 @@ The `Polkadot SDK` project is an **OPENISH Open Source Project** ## What? -Individuals making significant and valuable contributions are given commit-access to the project. -Contributions are done via pull-requests and need to be approved by the maintainers. +Individuals making significant and valuable contributions are given commit-access to the project. Contributions are done +via pull-requests and need to be approved by the maintainers. ## Rules There are a few basic ground-rules for contributors (including the maintainer(s) of the project): -1. **No `--force` pushes** or modifying the master branch history in any way. - If you need to rebase, ensure you do it in your own repo. No rewriting of the history - after the code has been shared (e.g. through a Pull-Request). -2. **Non-master branches**, prefixed with a short name moniker (e.g. `gav-my-feature`) must be - used for ongoing work. +1. **No `--force` pushes** or modifying the master branch history in any way. If you need to rebase, ensure you do it in + your own repo. No rewriting of the history after the code has been shared (e.g. through a Pull-Request). +2. **Non-master branches**, prefixed with a short name moniker (e.g. `gav-my-feature`) must be used for ongoing work. 3. **All modifications** must be made in a **pull-request** to solicit feedback from other contributors. 4. A pull-request **must not be merged until CI** has finished successfully. 5. Contributors should adhere to the [house coding style](./STYLE_GUIDE.md). @@ -25,12 +23,10 @@ There are a few basic ground-rules for contributors (including the maintainer(s) ### In General -A Pull Request (PR) needs to be reviewed and approved by project maintainers. -If a change does not alter any logic (e.g. comments, dependencies, docs), then it may be tagged -`A1-insubstantial` and merged faster. -If it is an urgent fix with no large change to logic, then it may be merged after a non-author -contributor has reviewed it well and approved the review once CI is complete. -No PR should be merged until all reviews' comments are addressed. +* A Pull Request (PR) needs to be reviewed and approved by project maintainers. +* If a change does not alter any logic (e.g. comments, dependencies, docs), then it may be tagged `A1-insubstantial` and +merged faster. +* No PR should be merged until all reviews' comments are addressed. ### Labels @@ -38,39 +34,26 @@ The set of labels and their description can be found [here](https://paritytech.g ### Process -1. Please use our [Pull Request Template](./PULL_REQUEST_TEMPLATE.md) and make sure all relevant - information is reflected in your PR. -2. Please tag each PR with minimum one `T*` label. The respective `T*` labels should signal the - component that was changed, they are also used by downstream users to track changes and to - include these changes properly into their own releases. -3. If youโ€™re still working on your PR, please submit as โ€œDraftโ€. Once a PR is ready for review change - the status to โ€œOpenโ€, so that the maintainers get to review your PR. Generally PRs should sit for - 48 hours in order to garner feedback. It may be merged before if all relevant parties had a look at it. -4. If youโ€™re introducing a major change, that might impact the documentation please add the label - `T13-documentation`. The docs team will get in touch. -5. If your PR changes files in these paths: - - `polkadot` : `^runtime/polkadot` - `polkadot` : `^runtime/kusama` - `polkadot` : `^primitives/src/` - `polkadot` : `^runtime/common` - `substrate` : `^frame/` - `substrate` : `^primitives/` - - It should be added to the [security audit board](https://github.com/orgs/paritytech/projects/103) - and will need to undergo an audit before merge. -6. PRs will be able to be merged once all reviewers' comments are addressed and CI is successful. - -**Noting breaking changes:** -When breaking APIs, the PR description should mention what was changed alongside some examples on how -to change the code to make it work/compile. -It should also mention potential storage migrations and if they require some special setup aside adding -it to the list of migrations in the runtime. +1. Please use our [Pull Request Template](./PULL_REQUEST_TEMPLATE.md) and make sure all relevant information is + reflected in your PR. +2. Please tag each PR with minimum one `T*` label. The respective `T*` labels should signal the component that was + changed, they are also used by downstream users to track changes and to include these changes properly into their own + releases. +3. If youโ€™re still working on your PR, please submit as โ€œDraftโ€. Once a PR is ready for review change the status to + โ€œOpenโ€, so that the maintainers get to review your PR. Generally PRs should sit for 48 hours in order to garner + feedback. It may be merged before if all relevant parties had a look at it. +4. With respect to auditing, please see [AUDIT.md](../AUDIT.md). In general, merging to master can happen independent of + audit. +5. PRs will be able to be merged once all reviewers' comments are addressed and CI is successful. + +**Noting breaking changes:** When breaking APIs, the PR description should mention what was changed alongside some +examples on how to change the code to make it work/compile. It should also mention potential storage migrations and if +they require some special setup aside adding it to the list of migrations in the runtime. ## Reviewing pull requests -When reviewing a pull request, the end-goal is to suggest useful changes to the author. -Reviews should finish with approval unless there are issues that would result in: +When reviewing a pull request, the end-goal is to suggest useful changes to the author. Reviews should finish with +approval unless there are issues that would result in: 1. Buggy behavior. 2. Undue maintenance burden. 3. Breaking with house coding style. @@ -80,18 +63,17 @@ Reviews should finish with approval unless there are issues that would result in The reviewers are also responsible to check: -1. if a changelog is necessary and attached -1. the quality of information in the changelog file -1. the PR has an impact on docs -1. that the docs team was included in the review process of a docs update +* if the PR description is well written to facilitate integration, in case it contains breaking changes. +* the PR has an impact on docs. **Reviews may not be used as an effective veto for a PR because**: 1. There exists a somewhat cleaner/better/faster way of accomplishing the same feature/fix. 2. It does not fit well with some other contributors' longer-term vision for the project. -## Documentation +## `PRDoc` -All Pull Requests must contain proper title & description. +All Pull Requests must contain proper title & description, as described in [Pull Request +Template](./PULL_REQUEST_TEMPLATE.md). Moreover, all pull requests must have a proper `prdoc` file attached. Some Pull Requests can be exempt of `prdoc` documentation, those must be labelled with [`R0-silent`](https://github.com/paritytech/labels/blob/main/ruled_labels/specs_polkadot-sdk.yaml#L89-L91). @@ -102,46 +84,49 @@ See more about `prdoc` [here](./prdoc.md) ## Helping out -We use [labels](https://github.com/paritytech/polkadot-sdk/labels) to manage PRs and issues and communicate -state of a PR. Please familiarise yourself with them. Best way to get started is to a pick a ticket tagged -[easy](https://github.com/paritytech/polkadot-sdk/issues?q=is%3Aopen+is%3Aissue+label%3AD0-easy) -or [medium](https://github.com/paritytech/polkadot-sdk/issues?q=is%3Aopen+is%3Aissue+label%3AD1-medium) -and get going. Alternatively, look out for issues tagged [mentor](https://github.com/paritytech/polkadot-sdk/issues?q=is%3Aopen+is%3Aissue+label%3AC1-mentor) -and get in contact with the mentor offering their support on that larger task. +We use [labels](https://github.com/paritytech/polkadot-sdk/labels) to manage PRs and issues and communicate state of a +PR. Please familiarise yourself with them. Best way to get started is to a pick a ticket tagged +[easy](https://github.com/paritytech/polkadot-sdk/issues?q=is%3Aopen+is%3Aissue+label%3AD0-easy) or +[medium](https://github.com/paritytech/polkadot-sdk/issues?q=is%3Aopen+is%3Aissue+label%3AD1-medium) and get going. +Alternatively, look out for issues tagged +[mentor](https://github.com/paritytech/polkadot-sdk/issues?q=is%3Aopen+is%3Aissue+label%3AC1-mentor) and get in contact +with the mentor offering their support on that larger task. **** ### Issues If what you are looking for is an answer rather than proposing a new feature or fix, search -[https://substrate.stackexchange.com](https://substrate.stackexchange.com/) to see if an post already -exists, and ask if not. Please do not file support issues here. -Before opening a new issue search to see if a similar one already exists and leave a comment that you -also experienced this issue or add your specifics that are related to an existing issue. -Please label issues with the following labels: +[https://substrate.stackexchange.com](https://substrate.stackexchange.com/) to see if an post already exists, and ask if +not. Please do not file support issues here. + +Before opening a new issue search to see if a similar one already exists and leave a comment that you also experienced +this issue or add your specifics that are related to an existing issue. + +Please label issues with the following labels (only relevant for maintainer): 1. `I*` issue severity and type. EXACTLY ONE REQUIRED. 2. `D*` issue difficulty, suggesting the level of complexity this issue has. AT MOST ONE ALLOWED. 3. `T*` Issue topic. MULTIPLE ALLOWED. ## Releases -Declaring formal releases remains the prerogative of the project maintainer(s). +Declaring formal releases remains the prerogative of the project maintainer(s). See [RELEASE.md](../RELEASE.md). ## UI tests -UI tests are used for macros to ensure that the output of a macro doesnโ€™t change and is in the expected format. -These UI tests are sensible to any changes in the macro generated code or to switching the rust stable version. -The tests are only run when the `RUN_UI_TESTS` environment variable is set. So, when the CI is for example complaining -about failing UI tests and it is expected that they fail these tests need to be executed locally. -To simplify the updating of the UI test output there is a script -- `./scripts/update-ui-tests.sh` to update the tests for a current rust version locally -- `./scripts/update-ui-tests.sh 1.70` # to update the tests for a specific rust version locally +UI tests are used for macros to ensure that the output of a macro doesnโ€™t change and is in the expected format. These UI +tests are sensible to any changes in the macro generated code or to switching the rust stable version. The tests are +only run when the `RUN_UI_TESTS` environment variable is set. So, when the CI is for example complaining about failing +UI tests and it is expected that they fail these tests need to be executed locally. To simplify the updating of the UI +test output there is a script +* `./scripts/update-ui-tests.sh` to update the tests for a current rust version locally +* `./scripts/update-ui-tests.sh 1.70` # to update the tests for a specific rust version locally Or if you have opened PR and you're member of `paritytech` - you can use command-bot to run the tests for you in CI: -- `bot update-ui` - will run the tests for the current rust version -- `bot update-ui latest --rust_version=1.70.0` - will run the tests for the specified rust version -- `bot update-ui latest -v CMD_IMAGE=paritytech/ci-unified:bullseye-1.70.0-2023-05-23 --rust_version=1.70.0` - -will run the tests for the specified rust version and specified image +* `bot update-ui` - will run the tests for the current rust version +* `bot update-ui latest --rust_version=1.70.0` - will run the tests for the specified rust version +* `bot update-ui latest -v CMD_IMAGE=paritytech/ci-unified:bullseye-1.70.0-2023-05-23 --rust_version=1.70.0` - will run +the tests for the specified rust version and specified image ## Feature Propagation @@ -157,4 +142,5 @@ Start with comment in PR: `bot help` to see the list of available commands. ## Deprecating code When deprecating and removing code you need to be mindful of how this could impact downstream developers. In order to -mitigate this impact, it is recommended to adhere to the steps outlined in the [Deprecation Checklist](./DEPRECATION_CHECKLIST.md). +mitigate this impact, it is recommended to adhere to the steps outlined in the [Deprecation +Checklist](./DEPRECATION_CHECKLIST.md). diff --git a/docs/contributor/PULL_REQUEST_TEMPLATE.md b/docs/contributor/PULL_REQUEST_TEMPLATE.md index 79a036a235ad92a2cfceeba9b8fb66a44d163dfd..083b30b4a3567904a62c83dd07a21677b7c0e048 100644 --- a/docs/contributor/PULL_REQUEST_TEMPLATE.md +++ b/docs/contributor/PULL_REQUEST_TEMPLATE.md @@ -2,35 +2,42 @@ โœ„ ----------------------------------------------------------------------------- -Thank you for your Pull Request! ๐Ÿ™ Please make sure it follows the contribution guidelines outlined in -[this document](https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/CONTRIBUTING.md) and fill -out the sections below. Once you're ready to submit your PR for review, please -delete this section and leave only the text under the "Description" heading. +Thank you for your Pull Request! ๐Ÿ™ Please make sure it follows the contribution guidelines outlined in [this +document](https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/CONTRIBUTING.md) and fill out the +sections below. Once you're ready to submit your PR for review, please delete this section and leave only the text under +the "Description" heading. # Description -*Please include a summary of the changes and the related issue. Please also include relevant motivation and context, -including:* +*A concise description of what your PR is doing, and what potential issue it is solving. Use [Github semantic +linking](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) +to link the PR to an issue that must be closed once this is merged.* -- What does this PR do? -- Why are these changes needed? -- How were these changes implemented and what do they affect? +## Integration -*Use [Github semantic -linking](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) -to address any open issues this PR relates to or closes.* +*In depth notes about how this PR should be integrated by downstream projects. This part is mandatory, and should be +reviewed by reviewers, if the PR does NOT have the `R0-Silent` label. In case of a `R0-Silent`, it can be ignored.* + +## Review Notes + +*In depth notes about the **implenentation** details of your PR. This should be the main guide for reviewers to +understand your approach and effectively review it. If too long, use +[`

`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details)*. -Fixes # (issue number, *if applicable*) +*Imagine that someone who is depending on the old code wants to integrate your new code and the only information that +they get is this section. It helps to include example usage and default value here, with a `diff` code-block to show +possibly integration.* -Closes # (issue number, *if applicable*) +*Include your leftover TODOs, if any, here.* # Checklist -- [ ] My PR includes a detailed description as outlined in the "Description" section above -- [ ] My PR follows the [labeling requirements](CONTRIBUTING.md#Process) of this project (at minimum one label for `T` +* [ ] My PR includes a detailed description as outlined in the "Description" and its two subsections above. +* [ ] My PR follows the [labeling requirements](CONTRIBUTING.md#Process) of this project (at minimum one label for `T` required) -- [ ] I have made corresponding changes to the documentation (if applicable) -- [ ] I have added tests that prove my fix is effective or that my feature works (if applicable) + * External contributors: ask maintainers to put the right label on your PR. +* [ ] I have made corresponding changes to the documentation (if applicable) +* [ ] I have added tests that prove my fix is effective or that my feature works (if applicable) You can remove the "Checklist" section once all have been checked. Thank you for your contribution! diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index ee603f8c49465d79040dbc712051960c5696234a..d3e48de5d181911f0686738c6d556e552176fd7a 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -15,101 +15,104 @@ workspace = true [dependencies] # Needed for all FRAME-based code -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -scale-info = { version = "2.6.0", default-features = false } -frame = { package = "polkadot-sdk-frame", path = "../../substrate/frame", features = [ +codec = { workspace = true } +scale-info = { workspace = true } +frame = { features = [ "experimental", "runtime", -] } -pallet-examples = { path = "../../substrate/frame/examples" } -pallet-default-config-example = { path = "../../substrate/frame/examples/default-config" } -pallet-example-offchain-worker = { path = "../../substrate/frame/examples/offchain-worker" } +], workspace = true, default-features = true } +pallet-examples = { workspace = true } +pallet-default-config-example = { workspace = true, default-features = true } +pallet-example-offchain-worker = { workspace = true, default-features = true } # How we build docs in rust-docs simple-mermaid = "0.1.1" -docify = "0.2.8" +docify = { workspace = true } # Polkadot SDK deps, typically all should only be in scope such that we can link to their doc item. -polkadot-sdk = { path = "../../umbrella", features = ["runtime"] } -node-cli = { package = "staging-node-cli", path = "../../substrate/bin/node/cli" } -kitchensink-runtime = { path = "../../substrate/bin/node/runtime" } -chain-spec-builder = { package = "staging-chain-spec-builder", path = "../../substrate/bin/utils/chain-spec-builder" } -subkey = { path = "../../substrate/bin/utils/subkey" } -frame-system = { path = "../../substrate/frame/system", default-features = false } -frame-support = { path = "../../substrate/frame/support", default-features = false } -frame-executive = { path = "../../substrate/frame/executive", default-features = false } -pallet-example-single-block-migrations = { path = "../../substrate/frame/examples/single-block-migrations" } -frame-metadata-hash-extension = { path = "../../substrate/frame/metadata-hash-extension" } +polkadot-sdk = { features = ["runtime"], workspace = true, default-features = true } +node-cli = { workspace = true } +kitchensink-runtime = { workspace = true } +chain-spec-builder = { workspace = true, default-features = true } +subkey = { workspace = true, default-features = true } +frame-system = { workspace = true } +frame-support = { workspace = true } +frame-executive = { workspace = true } +pallet-example-single-block-migrations = { workspace = true, default-features = true } +frame-metadata-hash-extension = { workspace = true, default-features = true } # Substrate Client -sc-network = { path = "../../substrate/client/network" } -sc-rpc-api = { path = "../../substrate/client/rpc-api" } -sc-rpc = { path = "../../substrate/client/rpc" } -sc-client-db = { path = "../../substrate/client/db" } -sc-cli = { path = "../../substrate/client/cli" } -sc-consensus-aura = { path = "../../substrate/client/consensus/aura" } -sc-consensus-babe = { path = "../../substrate/client/consensus/babe" } -sc-consensus-grandpa = { path = "../../substrate/client/consensus/grandpa" } -sc-consensus-beefy = { path = "../../substrate/client/consensus/beefy" } -sc-consensus-manual-seal = { path = "../../substrate/client/consensus/manual-seal" } -sc-consensus-pow = { path = "../../substrate/client/consensus/pow" } -sc-executor = { path = "../../substrate/client/executor" } -sc-service = { path = "../../substrate/client/service" } -sc-chain-spec = { path = "../../substrate/client/chain-spec" } +sc-network = { workspace = true, default-features = true } +sc-rpc-api = { workspace = true, default-features = true } +sc-rpc = { workspace = true, default-features = true } +sc-client-db = { workspace = true, default-features = true } +sc-cli = { workspace = true, default-features = true } +sc-consensus-aura = { workspace = true, default-features = true } +sc-consensus-babe = { workspace = true, default-features = true } +sc-consensus-grandpa = { workspace = true, default-features = true } +sc-consensus-beefy = { workspace = true, default-features = true } +sc-consensus-manual-seal = { workspace = true, default-features = true } +sc-consensus-pow = { workspace = true, default-features = true } +sc-executor = { workspace = true, default-features = true } +sc-service = { workspace = true, default-features = true } +sc-chain-spec = { workspace = true, default-features = true } -substrate-wasm-builder = { path = "../../substrate/utils/wasm-builder" } +substrate-wasm-builder = { workspace = true, default-features = true } # Cumulus -cumulus-pallet-aura-ext = { path = "../../cumulus/pallets/aura-ext" } -cumulus-pallet-parachain-system = { path = "../../cumulus/pallets/parachain-system" } -parachain-info = { package = "staging-parachain-info", path = "../../cumulus/parachains/pallets/parachain-info" } -cumulus-primitives-proof-size-hostfunction = { path = "../../cumulus/primitives/proof-size-hostfunction" } -cumulus-client-service = { path = "../../cumulus/client/service" } -cumulus-primitives-storage-weight-reclaim = { path = "../../cumulus/primitives/storage-weight-reclaim" } +cumulus-pallet-aura-ext = { workspace = true, default-features = true } +cumulus-pallet-parachain-system = { workspace = true, default-features = true } +parachain-info = { workspace = true, default-features = true } +cumulus-primitives-proof-size-hostfunction = { workspace = true, default-features = true } +cumulus-client-service = { workspace = true, default-features = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true, default-features = true } # Pallets and FRAME internals -pallet-aura = { path = "../../substrate/frame/aura" } -pallet-timestamp = { path = "../../substrate/frame/timestamp" } -pallet-balances = { path = "../../substrate/frame/balances" } -pallet-assets = { path = "../../substrate/frame/assets" } -pallet-preimage = { path = "../../substrate/frame/preimage" } -pallet-transaction-payment = { path = "../../substrate/frame/transaction-payment" } -pallet-utility = { path = "../../substrate/frame/utility" } -pallet-multisig = { path = "../../substrate/frame/multisig" } -pallet-proxy = { path = "../../substrate/frame/proxy" } -pallet-authorship = { path = "../../substrate/frame/authorship" } -pallet-collective = { path = "../../substrate/frame/collective" } -pallet-democracy = { path = "../../substrate/frame/democracy" } -pallet-uniques = { path = "../../substrate/frame/uniques" } -pallet-nfts = { path = "../../substrate/frame/nfts" } -pallet-scheduler = { path = "../../substrate/frame/scheduler" } -pallet-referenda = { path = "../../substrate/frame/referenda" } -pallet-broker = { path = "../../substrate/frame/broker" } -pallet-babe = { path = "../../substrate/frame/babe" } +pallet-aura = { workspace = true, default-features = true } +pallet-timestamp = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +pallet-assets = { workspace = true, default-features = true } +pallet-preimage = { workspace = true, default-features = true } +pallet-transaction-payment = { workspace = true, default-features = true } +pallet-asset-tx-payment = { workspace = true, default-features = true } +pallet-skip-feeless-payment = { workspace = true, default-features = true } +pallet-asset-conversion-tx-payment = { workspace = true, default-features = true } +pallet-utility = { workspace = true, default-features = true } +pallet-multisig = { workspace = true, default-features = true } +pallet-proxy = { workspace = true, default-features = true } +pallet-authorship = { workspace = true, default-features = true } +pallet-collective = { workspace = true, default-features = true } +pallet-democracy = { workspace = true, default-features = true } +pallet-uniques = { workspace = true, default-features = true } +pallet-nfts = { workspace = true, default-features = true } +pallet-scheduler = { workspace = true, default-features = true } +pallet-referenda = { workspace = true, default-features = true } +pallet-broker = { workspace = true, default-features = true } +pallet-babe = { workspace = true, default-features = true } # Primitives -sp-io = { path = "../../substrate/primitives/io" } -sp-std = { path = "../../substrate/primitives/std" } -sp-tracing = { path = "../../substrate/primitives/tracing" } -sp-runtime-interface = { path = "../../substrate/primitives/runtime-interface" } -sp-api = { path = "../../substrate/primitives/api" } -sp-core = { path = "../../substrate/primitives/core" } -sp-keyring = { path = "../../substrate/primitives/keyring" } -sp-runtime = { path = "../../substrate/primitives/runtime" } -sp-arithmetic = { path = "../../substrate/primitives/arithmetic" } -sp-genesis-builder = { path = "../../substrate/primitives/genesis-builder" } -sp-offchain = { path = "../../substrate/primitives/offchain" } -sp-version = { path = "../../substrate/primitives/version" } +sp-io = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +sp-runtime-interface = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-arithmetic = { workspace = true, default-features = true } +sp-genesis-builder = { workspace = true, default-features = true } +sp-offchain = { workspace = true, default-features = true } +sp-version = { workspace = true, default-features = true } # XCM -xcm = { package = "staging-xcm", path = "../../polkadot/xcm" } -xcm-docs = { path = "../../polkadot/xcm/docs" } +xcm = { workspace = true, default-features = true } +xcm-docs = { workspace = true } # runtime guides -chain-spec-guide-runtime = { path = "./src/reference_docs/chain_spec_runtime" } +chain-spec-guide-runtime = { workspace = true } # Templates -minimal-template-runtime = { path = "../../templates/minimal/runtime" } -solochain-template-runtime = { path = "../../templates/solochain/runtime" } -parachain-template-runtime = { path = "../../templates/parachain/runtime" } +minimal-template-runtime = { workspace = true } +solochain-template-runtime = { workspace = true } +parachain-template-runtime = { workspace = true } diff --git a/docs/sdk/src/guides/async_backing_guide.rs b/docs/sdk/src/guides/async_backing_guide.rs new file mode 100644 index 0000000000000000000000000000000000000000..f2f4dcabfd29b872de2981cd0a9c5003118c29c0 --- /dev/null +++ b/docs/sdk/src/guides/async_backing_guide.rs @@ -0,0 +1,254 @@ +//! # Upgrade Parachain for Asynchronous Backing Compatibility +//! +//! This guide is relevant for cumulus based parachain projects started in 2023 or before, whose +//! backing process is synchronous where parablocks can only be built on the latest Relay Chain +//! block. Async Backing allows collators to build parablocks on older Relay Chain blocks and create +//! pipelines of multiple pending parablocks. This parallel block generation increases efficiency +//! and throughput. For more information on Async backing and its terminology, refer to the document +//! on [the Polkadot Wiki.](https://wiki.polkadot.network/docs/maintain-guides-async-backing) +//! +//! > If starting a new parachain project, please use an async backing compatible template such as +//! > the +//! > [parachain template](https://github.com/paritytech/polkadot-sdk/tree/master/templates/parachain). +//! The rollout process for Async Backing has three phases. Phases 1 and 2 below put new +//! infrastructure in place. Then we can simply turn on async backing in phase 3. +//! +//! ## Prerequisite +//! +//! The relay chain needs to have async backing enabled so double-check that the relay-chain +//! configuration contains the following three parameters (especially when testing locally e.g. with +//! zombienet): +//! +//! ```json +//! "async_backing_params": { +//! "max_candidate_depth": 3, +//! "allowed_ancestry_len": 2 +//! }, +//! "scheduling_lookahead": 2 +//! ``` +//! +//!
`scheduling_lookahead` must be set to 2, otherwise parachain block times +//! will degrade to worse than with sync backing!
+//! +//! ## Phase 1 - Update Parachain Runtime +//! +//! This phase involves configuring your parachainโ€™s runtime `/runtime/src/lib.rs` to make use of +//! async backing system. +//! +//! 1. Establish and ensure constants for `capacity` and `velocity` are both set to 1 in the +//! runtime. +//! 2. Establish and ensure the constant relay chain slot duration measured in milliseconds equal to +//! `6000` in the runtime. +//! ```rust +//! // Maximum number of blocks simultaneously accepted by the Runtime, not yet included into the +//! // relay chain. +//! pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; +//! // How many parachain blocks are processed by the relay chain per parent. Limits the number of +//! // blocks authored per slot. +//! pub const BLOCK_PROCESSING_VELOCITY: u32 = 1; +//! // Relay chain slot duration, in milliseconds. +//! pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; +//! ``` +//! +//! 3. Establish constants `MILLISECS_PER_BLOCK` and `SLOT_DURATION` if not already present in the +//! runtime. +//! ```ignore +//! // `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked +//! // up by `pallet_aura` to implement `fn slot_duration()`. +//! // +//! // Change this to adjust the block time. +//! pub const MILLISECS_PER_BLOCK: u64 = 12000; +//! pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; +//! ``` +//! +//! 4. Configure `cumulus_pallet_parachain_system` in the runtime. +//! +//! - Define a `FixedVelocityConsensusHook` using our capacity, velocity, and relay slot duration +//! constants. Use this to set the parachain system `ConsensusHook` property. +#![doc = docify::embed!("../../templates/parachain/runtime/src/lib.rs", ConsensusHook)] +//! ```ignore +//! impl cumulus_pallet_parachain_system::Config for Runtime { +//! .. +//! type ConsensusHook = ConsensusHook; +//! .. +//! } +//! ``` +//! - Set the parachain system property `CheckAssociatedRelayNumber` to +//! `RelayNumberMonotonicallyIncreases` +//! ```ignore +//! impl cumulus_pallet_parachain_system::Config for Runtime { +//! .. +//! type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; +//! .. +//! } +//! ``` +//! +//! 5. Configure `pallet_aura` in the runtime. +//! +//! - Set `AllowMultipleBlocksPerSlot` to `false` (don't worry, we will set it to `true` when we +//! activate async backing in phase 3). +//! +//! - Define `pallet_aura::SlotDuration` using our constant `SLOT_DURATION` +//! ```ignore +//! impl pallet_aura::Config for Runtime { +//! .. +//! type AllowMultipleBlocksPerSlot = ConstBool; +//! #[cfg(feature = "experimental")] +//! type SlotDuration = ConstU64; +//! .. +//! } +//! ``` +//! +//! 6. Update `sp_consensus_aura::AuraApi::slot_duration` in `sp_api::impl_runtime_apis` to match +//! the constant `SLOT_DURATION` +#![doc = docify::embed!("../../templates/parachain/runtime/src/apis.rs", impl_slot_duration)] +//! +//! 7. Implement the `AuraUnincludedSegmentApi`, which allows the collator client to query its +//! runtime to determine whether it should author a block. +//! +//! - Add the dependency `cumulus-primitives-aura` to the `runtime/Cargo.toml` file for your +//! runtime +//! ```ignore +//! .. +//! cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } +//! .. +//! ``` +//! +//! - In the same file, add `"cumulus-primitives-aura/std",` to the `std` feature. +//! +//! - Inside the `impl_runtime_apis!` block for your runtime, implement the +//! `cumulus_primitives_aura::AuraUnincludedSegmentApi` as shown below. +#![doc = docify::embed!("../../templates/parachain/runtime/src/apis.rs", impl_can_build_upon)] +//! +//! **Note:** With a capacity of 1 we have an effective velocity of ยฝ even when velocity is +//! configured to some larger value. This is because capacity will be filled after a single block is +//! produced and will only be freed up after that block is included on the relay chain, which takes +//! 2 relay blocks to accomplish. Thus with capacity 1 and velocity 1 we get the customary 12 second +//! parachain block time. +//! +//! 8. If your `runtime/src/lib.rs` provides a `CheckInherents` type to `register_validate_block`, +//! remove it. `FixedVelocityConsensusHook` makes it unnecessary. The following example shows how +//! `register_validate_block` should look after removing `CheckInherents`. +#![doc = docify::embed!("../../templates/parachain/runtime/src/lib.rs", register_validate_block)] +//! +//! +//! ## Phase 2 - Update Parachain Nodes +//! +//! This phase consists of plugging in the new lookahead collator node. +//! +//! 1. Import `cumulus_primitives_core::ValidationCode` to `node/src/service.rs`. +#![doc = docify::embed!("../../templates/parachain/node/src/service.rs", cumulus_primitives)] +//! +//! 2. In `node/src/service.rs`, modify `sc_service::spawn_tasks` to use a clone of `Backend` rather +//! than the original +//! ```ignore +//! sc_service::spawn_tasks(sc_service::SpawnTasksParams { +//! .. +//! backend: backend.clone(), +//! .. +//! })?; +//! ``` +//! +//! 3. Add `backend` as a parameter to `start_consensus()` in `node/src/service.rs` +//! ```text +//! fn start_consensus( +//! .. +//! backend: Arc, +//! .. +//! ``` +//! ```ignore +//! if validator { +//! start_consensus( +//! .. +//! backend.clone(), +//! .. +//! )?; +//! } +//! ``` +//! +//! 4. In `node/src/service.rs` import the lookahead collator rather than the basic collator +#![doc = docify::embed!("../../templates/parachain/node/src/service.rs", lookahead_collator)] +//! +//! 5. In `start_consensus()` replace the `BasicAuraParams` struct with `AuraParams` +//! - Change the struct type from `BasicAuraParams` to `AuraParams` +//! - In the `para_client` field, pass in a cloned para client rather than the original +//! - Add a `para_backend` parameter after `para_client`, passing in our para backend +//! - Provide a `code_hash_provider` closure like that shown below +//! - Increase `authoring_duration` from 500 milliseconds to 1500 +//! ```ignore +//! let params = AuraParams { +//! .. +//! para_client: client.clone(), +//! para_backend: backend.clone(), +//! .. +//! code_hash_provider: move |block_hash| { +//! client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) +//! }, +//! .. +//! authoring_duration: Duration::from_millis(1500), +//! .. +//! }; +//! ``` +//! +//! **Note:** Set `authoring_duration` to whatever you want, taking your own hardware into account. +//! But if the backer who should be slower than you due to reading from disk, times out at two +//! seconds your candidates will be rejected. +//! +//! 6. In `start_consensus()` replace `basic_aura::run` with `aura::run` +//! ```ignore +//! let fut = +//! aura::run::( +//! params, +//! ); +//! task_manager.spawn_essential_handle().spawn("aura", None, fut); +//! ``` +//! +//! ## Phase 3 - Activate Async Backing +//! +//! This phase consists of changes to your parachainโ€™s runtime that activate async backing feature. +//! +//! 1. Configure `pallet_aura`, setting `AllowMultipleBlocksPerSlot` to true in +//! `runtime/src/lib.rs`. +#![doc = docify::embed!("../../templates/parachain/runtime/src/configs/mod.rs", aura_config)] +//! +//! 2. Increase the maximum `UNINCLUDED_SEGMENT_CAPACITY` in `runtime/src/lib.rs`. +#![doc = docify::embed!("../../templates/parachain/runtime/src/lib.rs", async_backing_params)] +//! +//! 3. Decrease `MILLISECS_PER_BLOCK` to 6000. +//! +//! - Note: For a parachain which measures time in terms of its own block number rather than by +//! relay block number it may be preferable to increase velocity. Changing block time may cause +//! complications, requiring additional changes. See the section โ€œTiming by Block Numberโ€. +#![doc = docify::embed!("../../templates/parachain/runtime/src/lib.rs", block_times)] +//! +//! 4. Update `MAXIMUM_BLOCK_WEIGHT` to reflect the increased time available for block production. +#![doc = docify::embed!("../../templates/parachain/runtime/src/lib.rs", max_block_weight)] +//! +//! 5. Add a feature flagged alternative for `MinimumPeriod` in `pallet_timestamp`. The type should +//! be `ConstU64<0>` with the feature flag experimental, and `ConstU64<{SLOT_DURATION / 2}>` +//! without. +//! ```ignore +//! impl pallet_timestamp::Config for Runtime { +//! .. +//! #[cfg(feature = "experimental")] +//! type MinimumPeriod = ConstU64<0>; +//! #[cfg(not(feature = "experimental"))] +//! type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; +//! .. +//! } +//! ``` +//! +//! ## Timing by Block Number +//! +//! With asynchronous backing it will be possible for parachains to opt for a block time of 6 +//! seconds rather than 12 seconds. But modifying block duration isnโ€™t so simple for a parachain +//! which was measuring time in terms of its own block number. It could result in expected and +//! actual time not matching up, stalling the parachain. +//! +//! One strategy to deal with this issue is to instead rely on relay chain block numbers for timing. +//! Relay block number is kept track of by each parachain in `pallet-parachain-system` with the +//! storage value `LastRelayChainBlockNumber`. This value can be obtained and used wherever timing +//! based on block number is needed. + +#![deny(rustdoc::broken_intra_doc_links)] +#![deny(rustdoc::private_intra_doc_links)] diff --git a/docs/sdk/src/guides/enable_elastic_scaling_mvp.rs b/docs/sdk/src/guides/enable_elastic_scaling_mvp.rs new file mode 100644 index 0000000000000000000000000000000000000000..bc4f36c271fe3c063f85c9debb32fd78f7e33efa --- /dev/null +++ b/docs/sdk/src/guides/enable_elastic_scaling_mvp.rs @@ -0,0 +1,142 @@ +//! # Enable elastic scaling MVP for a parachain +//! +//!
This guide assumes full familiarity with Asynchronous Backing and its +//! terminology, as defined in https://wiki.polkadot.network/docs/maintain-guides-async-backing. +//! Furthermore, the parachain should have already been upgraded according to the guide.
+//! +//! ## Quick introduction to elastic scaling +//! +//! [Elastic scaling](https://polkadot.network/blog/elastic-scaling-streamling-growth-on-polkadot) +//! is a feature that will enable parachains to seamlessly scale up/down the number of used cores. +//! This can be desirable in order to increase the compute or storage throughput of a parachain or +//! to lower the latency between a transaction being submitted and it getting built in a parachain +//! block. +//! +//! At present, with Asynchronous Backing enabled, a parachain can only include a block on the relay +//! chain every 6 seconds, irregardless of how many cores the parachain acquires. Elastic scaling +//! builds further on the 10x throughput increase of Async Backing, enabling collators to submit up +//! to 3 parachain blocks per relay chain block, resulting in a further 3x throughput increase. +//! +//! ## Current limitations of the MVP +//! +//! The full implementation of elastic scaling spans across the entire relay/parachain stack and is +//! still [work in progress](https://github.com/paritytech/polkadot-sdk/issues/1829). +//! The MVP is still considered experimental software, so stability is not guaranteed. +//! If you encounter any problems, +//! [please open an issue](https://github.com/paritytech/polkadot-sdk/issues). +//! Below are described the current limitations of the MVP: +//! +//! 1. **Limited core count**. Parachain block authoring is sequential, so the second block will +//! start being built only after the previous block is imported. The current block production is +//! capped at 2 seconds of execution. Therefore, assuming the full 2 seconds are used, a +//! parachain can only utilise at most 3 cores in a relay chain slot of 6 seconds. If the full +//! execution time is not being used, higher core counts can be achieved. +//! 2. **Single collator requirement for consistently scaling beyond a core at full authorship +//! duration of 2 seconds per block.** Using the current implementation with multiple collators +//! adds additional latency to the block production pipeline. Assuming block execution takes +//! about the same as authorship, the additional overhead is equal the duration of the authorship +//! plus the block announcement. Each collator must first import the previous block before +//! authoring a new one, so it is clear that the highest throughput can be achieved using a +//! single collator. Experiments show that the peak performance using more than one collator +//! (measured up to 10 collators) is utilising 2 cores with authorship time of 1.3 seconds per +//! block, which leaves 400ms for networking overhead. This would allow for 2.6 seconds of +//! execution, compared to the 2 seconds async backing enabled. +//! [More experiments](https://github.com/paritytech/polkadot-sdk/issues/4696) are being +//! conducted in this space. +//! 3. **Trusted collator set.** The collator set needs to be trusted until thereโ€™s a mitigation +//! that would prevent or deter multiple collators from submitting the same collation to multiple +//! backing groups. A solution is being discussed +//! [here](https://github.com/polkadot-fellows/RFCs/issues/92). +//! 4. **Fixed scaling.** For true elasticity, the parachain must be able to seamlessly acquire or +//! sell coretime as the user demand grows and shrinks over time, in an automated manner. This is +//! currently lacking - a parachain can only scale up or down by โ€œmanuallyโ€ acquiring coretime. +//! This is not in the scope of the relay chain functionality. Parachains can already start +//! implementing such autoscaling, but we aim to provide a framework/examples for developing +//! autoscaling strategies. +//! +//! Another hard limitation that is not envisioned to ever be lifted is that parachains which create +//! forks will generally not be able to utilise the full number of cores they acquire. +//! +//! ## Using elastic scaling MVP +//! +//! ### Prerequisites +//! +//! - Ensure Asynchronous Backing is enabled on the network and you have enabled it on the parachain +//! using [`crate::guides::async_backing_guide`]. +//! - Ensure the `AsyncBackingParams.max_candidate_depth` value is configured to a value that is at +//! least double the maximum targeted parachain velocity. For example, if the parachain will build +//! at most 3 candidates per relay chain block, the `max_candidate_depth` should be at least 6. +//! - Use a trusted single collator for maximum throughput. +//! - Ensure enough coretime is assigned to the parachain. For maximum throughput the upper bound is +//! 3 cores. +//! +//!
Phase 1 is not needed if using the `polkadot-parachain` binary built +//! from the latest polkadot-sdk release! Simply pass the `--experimental-use-slot-based` parameter +//! to the command line and jump to Phase 2.
+//! +//! The following steps assume using the cumulus parachain template. +//! +//! ### Phase 1 - (For custom parachain node) Update Parachain Node +//! +//! This assumes you are using +//! [the latest parachain template](https://github.com/paritytech/polkadot-sdk/tree/master/templates/parachain). +//! +//! This phase consists of plugging in the new slot-based collator. +//! +//! 1. In `node/src/service.rs` import the slot based collator instead of the lookahead collator. +#![doc = docify::embed!("../../cumulus/polkadot-parachain/src/service.rs", slot_based_colator_import)] +//! +//! 2. In `start_consensus()` +//! - Remove the `overseer_handle` param (also remove the +//! `OverseerHandle` type import if itโ€™s not used elsewhere). +//! - Rename `AuraParams` to `SlotBasedParams`, remove the `overseer_handle` field and add a +//! `slot_drift` field with a value of `Duration::from_secs(1)`. +//! - Replace the single future returned by `aura::run` with the two futures returned by it and +//! spawn them as separate tasks: +#![doc = docify::embed!("../../cumulus/polkadot-parachain/src/service.rs", launch_slot_based_collator)] +//! +//! 3. In `start_parachain_node()` remove the `overseer_handle` param passed to `start_consensus`. +//! +//! ### Phase 2 - Activate fixed factor scaling in the runtime +//! +//! This phase consists of a couple of changes needed to be made to the parachainโ€™s runtime in order +//! to utilise fixed factor scaling. +//! +//! First of all, you need to decide the upper limit to how many parachain blocks you need to +//! produce per relay chain block (in direct correlation with the number of acquired cores). This +//! should be either 1 (no scaling), 2 or 3. This is called the parachain velocity. +//! +//! If you configure a velocity which is different from the number of assigned cores, the measured +//! velocity in practice will be the minimum of these two. +//! +//! The chosen velocity will also be used to compute: +//! - The slot duration, by dividing the 6000 ms duration of the relay chain slot duration by the +//! velocity. +//! - The unincluded segment capacity, by multiplying the velocity with 2 and adding 1 to +//! it. +//! +//! Letโ€™s assume a desired maximum velocity of 3 parachain blocks per relay chain block. The needed +//! changes would all be done in `runtime/src/lib.rs`: +//! +//! 1. Rename `BLOCK_PROCESSING_VELOCITY` to `MAX_BLOCK_PROCESSING_VELOCITY` and increase it to the +//! desired value. In this example, 3. +//! +//! ```ignore +//! const MAX_BLOCK_PROCESSING_VELOCITY: u32 = 3; +//! ``` +//! +//! 2. Set the `MILLISECS_PER_BLOCK` to the desired value. +//! +//! ```ignore +//! const MILLISECS_PER_BLOCK: u32 = +//! RELAY_CHAIN_SLOT_DURATION_MILLIS / MAX_BLOCK_PROCESSING_VELOCITY; +//! ``` +//! Note: for a parachain which measures time in terms of its own block number, changing block +//! time may cause complications, requiring additional changes. See here more information: +//! [`crate::guides::async_backing_guide#timing-by-block-number`]. +//! +//! 3. Increase the `UNINCLUDED_SEGMENT_CAPACITY` to the desired value. +//! +//! ```ignore +//! const UNINCLUDED_SEGMENT_CAPACITY: u32 = 2 * MAX_BLOCK_PROCESSING_VELOCITY + 1; +//! ``` diff --git a/docs/sdk/src/guides/mod.rs b/docs/sdk/src/guides/mod.rs index 485cdc30636f2751145188c5d13a99b7d6fd6726..9384f4c82ab3e37e5d15e0cb853c7d01731b4b41 100644 --- a/docs/sdk/src/guides/mod.rs +++ b/docs/sdk/src/guides/mod.rs @@ -36,5 +36,11 @@ pub mod your_first_runtime; /// How to enable storage weight reclaiming in a parachain node and runtime. pub mod enable_pov_reclaim; +/// How to enable Async Backing on parachain projects that started in 2023 or before. +pub mod async_backing_guide; + /// How to enable metadata hash verification in the runtime. pub mod enable_metadata_hash; + +/// How to enable elastic scaling MVP on a parachain. +pub mod enable_elastic_scaling_mvp; diff --git a/docs/sdk/src/polkadot_sdk/frame_runtime.rs b/docs/sdk/src/polkadot_sdk/frame_runtime.rs index f9b8a381365c4b3675485f3f32cb0cf751138275..39255c8f51ad6e589c22c7a29f08211b50053203 100644 --- a/docs/sdk/src/polkadot_sdk/frame_runtime.rs +++ b/docs/sdk/src/polkadot_sdk/frame_runtime.rs @@ -87,8 +87,6 @@ //! * writing a runtime in pure Rust, as done in [this template](https://github.com/JoshOrndorff/frameless-node-template). //! * writing a runtime in AssemblyScript,as explored in [this project](https://github.com/LimeChain/subsembly). -use frame::prelude::*; - /// A FRAME based pallet. This `mod` is the entry point for everything else. All /// `#[pallet::xxx]` macros must be defined in this `mod`. Although, frame also provides an /// experimental feature to break these parts into different `mod`s. See [`pallet_examples`] for @@ -96,7 +94,7 @@ use frame::prelude::*; #[docify::export] #[frame::pallet(dev_mode)] pub mod pallet { - use super::*; + use frame::prelude::*; /// The configuration trait of a pallet. Mandatory. Allows a pallet to receive types at a /// later point from the runtime that wishes to contain it. It allows the pallet to be diff --git a/docs/sdk/src/reference_docs/blockchain_state_machines.rs b/docs/sdk/src/reference_docs/blockchain_state_machines.rs index 0d1aefcc52770b70baf284335816f013cbfbe5ed..36ab0ce5ed54f448dd56ca28346b40e07b33c491 100644 --- a/docs/sdk/src/reference_docs/blockchain_state_machines.rs +++ b/docs/sdk/src/reference_docs/blockchain_state_machines.rs @@ -21,7 +21,7 @@ #![doc = simple_mermaid::mermaid!("../../../mermaid/stf.mmd")] //! //! In essence, the state of the blockchain at block N is the outcome of applying the state -//! transition function to the the previous state, and the current block as input. This can be +//! transition function to the previous state, and the current block as input. This can be //! mathematically represented as: //! //! ```math diff --git a/docs/sdk/src/reference_docs/chain_spec_runtime/Cargo.toml b/docs/sdk/src/reference_docs/chain_spec_runtime/Cargo.toml index c6dd3af9d90be8039cf2aabbdf04964ff5dc886d..02849571203285d5a9bbc19d4d3aecad8495c214 100644 --- a/docs/sdk/src/reference_docs/chain_spec_runtime/Cargo.toml +++ b/docs/sdk/src/reference_docs/chain_spec_runtime/Cargo.toml @@ -10,44 +10,43 @@ edition.workspace = true publish = false [dependencies] -docify = "0.2.8" -parity-scale-codec = { version = "3.6.12", default-features = false } -scale-info = { version = "2.6.0", default-features = false } -serde = { workspace = true, default-features = false } +docify = { workspace = true } +codec = { workspace = true } +scale-info = { workspace = true } +serde = { workspace = true } serde_json = { workspace = true } # this is a frame-based runtime, thus importing `frame` with runtime feature enabled. -frame = { package = "polkadot-sdk-frame", path = "../../../../../substrate/frame", default-features = false, features = [ +frame = { features = [ "experimental", "runtime", -] } +], workspace = true } # pallets that we want to use -pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } -pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false } -pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } -pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } +pallet-balances = { workspace = true } +pallet-sudo = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } # genesis builder that allows us to interact with runtime genesis config -sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } -sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false, features = ["serde"] } -sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } -sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } -sp-keyring = { path = "../../../../../substrate/primitives/keyring", default-features = false } -sp-application-crypto = { path = "../../../../../substrate/primitives/application-crypto", default-features = false, features = ["serde"] } +sp-genesis-builder = { workspace = true } +sp-runtime = { features = ["serde"], workspace = true } +sp-core = { workspace = true } +sp-keyring = { workspace = true } +sp-application-crypto = { features = ["serde"], workspace = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [dev-dependencies] -chain-spec-builder = { package = "staging-chain-spec-builder", path = "../../../../../substrate/bin/utils/chain-spec-builder" } -sc-chain-spec = { path = "../../../../../substrate/client/chain-spec" } +chain-spec-builder = { workspace = true, default-features = true } +sc-chain-spec = { workspace = true, default-features = true } [features] default = ["std"] std = [ - "parity-scale-codec/std", + "codec/std", "scale-info/std", "frame/std", @@ -63,7 +62,6 @@ std = [ "sp-genesis-builder/std", "sp-keyring/std", "sp-runtime/std", - "sp-std/std", "serde/std", "serde_json/std", diff --git a/docs/sdk/src/reference_docs/chain_spec_runtime/src/lib.rs b/docs/sdk/src/reference_docs/chain_spec_runtime/src/lib.rs index 4606104fb9680628f10dc4ff7738f9c4740ced62..e7effce1bd6697196c3af45bde27e811250d0e5f 100644 --- a/docs/sdk/src/reference_docs/chain_spec_runtime/src/lib.rs +++ b/docs/sdk/src/reference_docs/chain_spec_runtime/src/lib.rs @@ -19,6 +19,8 @@ //! A minimal runtime that shows runtime genesis state. +extern crate alloc; + pub mod pallets; pub mod presets; pub mod runtime; diff --git a/docs/sdk/src/reference_docs/chain_spec_runtime/src/pallets.rs b/docs/sdk/src/reference_docs/chain_spec_runtime/src/pallets.rs index be4455aa21979f8915d32b0a85c84e278ba3b83f..2ff2d9539e2dbdd13997f925474ecbaf5a2836c7 100644 --- a/docs/sdk/src/reference_docs/chain_spec_runtime/src/pallets.rs +++ b/docs/sdk/src/reference_docs/chain_spec_runtime/src/pallets.rs @@ -17,6 +17,7 @@ //! Pallets for the chain-spec demo runtime. +use alloc::vec::Vec; use frame::prelude::*; #[docify::export] diff --git a/docs/sdk/src/reference_docs/chain_spec_runtime/src/presets.rs b/docs/sdk/src/reference_docs/chain_spec_runtime/src/presets.rs index c51947f6cc7cb0c53f8fbf52f2f80a370b1f681c..02c2d90f7c827f51dfe913fd0743109b9f96618a 100644 --- a/docs/sdk/src/reference_docs/chain_spec_runtime/src/presets.rs +++ b/docs/sdk/src/reference_docs/chain_spec_runtime/src/presets.rs @@ -18,10 +18,10 @@ //! Presets for the chain-spec demo runtime. use crate::pallets::{FooEnum, SomeFooData1, SomeFooData2}; +use alloc::vec; use serde_json::{json, to_string, Value}; use sp_application_crypto::Ss58Codec; use sp_keyring::AccountKeyring; -use sp_std::vec; /// A demo preset with strings only. pub const PRESET_1: &str = "preset_1"; @@ -122,7 +122,7 @@ fn preset_invalid() -> Value { /// /// If no preset with given `id` exits `None` is returned. #[docify::export] -pub fn get_builtin_preset(id: &sp_genesis_builder::PresetId) -> Option> { +pub fn get_builtin_preset(id: &sp_genesis_builder::PresetId) -> Option> { let preset = match id.try_into() { Ok(PRESET_1) => preset_1(), Ok(PRESET_2) => preset_2(), diff --git a/docs/sdk/src/reference_docs/chain_spec_runtime/src/runtime.rs b/docs/sdk/src/reference_docs/chain_spec_runtime/src/runtime.rs index 6d9bc1260b11fa79004b40ded4ab20343cf29037..c45f0126337e5a42b83fee6e80c5be04c03c1d73 100644 --- a/docs/sdk/src/reference_docs/chain_spec_runtime/src/runtime.rs +++ b/docs/sdk/src/reference_docs/chain_spec_runtime/src/runtime.rs @@ -25,6 +25,7 @@ use crate::{ pallets::{pallet_bar, pallet_foo}, presets::*, }; +use alloc::{vec, vec::Vec}; use frame::{ deps::frame_support::{ genesis_builder_helper::{build_state, get_preset}, diff --git a/docs/sdk/src/reference_docs/frame_storage_derives.rs b/docs/sdk/src/reference_docs/frame_storage_derives.rs new file mode 100644 index 0000000000000000000000000000000000000000..3d9edef398a072839f82c21be76b74da6cf20ff2 --- /dev/null +++ b/docs/sdk/src/reference_docs/frame_storage_derives.rs @@ -0,0 +1,199 @@ +//!
+//! In all examples, a few lines of boilerplate have been hidden from each snippet for conciseness. +//!
+//! +//! Let's begin by starting to store a `NewType` in a storage item: +//! +//! ```compile_fail +//! #[frame::pallet] +//! pub mod pallet { +//! # use frame::prelude::*; +//! # #[pallet::config] +//! # pub trait Config: frame_system::Config {} +//! # #[pallet::pallet] +//! # pub struct Pallet(_); +//! pub struct NewType(u32); +// +//! #[pallet::storage] +//! pub type Something = StorageValue<_, NewType>; +//! } +//! ``` +//! +//! This raises a number of compiler errors, like: +//! ```text +//! the trait `MaxEncodedLen` is not implemented for `NewType`, which is required by +//! `frame::prelude::StorageValue<_GeneratedPrefixForStorageSomething, NewType>: +//! StorageInfoTrait` +//! ``` +//! +//! This implies the following set of traits that need to be derived for a type to be stored in +//! `frame` storage: +//! ```rust +//! #[frame::pallet] +//! pub mod pallet { +//! # use frame::prelude::*; +//! # #[pallet::config] +//! # pub trait Config: frame_system::Config {} +//! # #[pallet::pallet] +//! # pub struct Pallet(_); +//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)] +//! pub struct NewType(u32); +//! +//! #[pallet::storage] +//! pub type Something = StorageValue<_, NewType>; +//! } +//! ``` +//! +//! Next, let's look at how this will differ if we are to store a type that is derived from `T` in +//! storage, such as [`frame::prelude::BlockNumberFor`]: +//! ```compile_fail +//! #[frame::pallet] +//! pub mod pallet { +//! # use frame::prelude::*; +//! # #[pallet::config] +//! # pub trait Config: frame_system::Config {} +//! # #[pallet::pallet] +//! # pub struct Pallet(_); +//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)] +//! pub struct NewType(BlockNumberFor); +//! +//! #[pallet::storage] +//! pub type Something = StorageValue<_, NewType>; +//! } +//! ``` +//! +//! Surprisingly, this will also raise a number of errors, like: +//! ```text +//! the trait `TypeInfo` is not implemented for `T`, which is required +//! by`frame_support::pallet_prelude::StorageValue, +//! pallet_2::NewType>:StorageEntryMetadataBuilder +//! ``` +//! +//! Why is that? The underlying reason is that the `TypeInfo` `derive` macro will only work for +//! `NewType` if all of `NewType`'s generics also implement `TypeInfo`. This is not the case for `T` +//! in the example above. +//! +//! If you expand an instance of the derive, you will find something along the lines of: +//! `impl TypeInfo for NewType where T: TypeInfo { ... }`. This is the reason why the +//! `TypeInfo` trait is required for `T`. +//! +//! To fix this, we need to add a `#[scale_info(skip_type_params(T))]` +//! attribute to `NewType`. This additional macro will instruct the `derive` to skip the bound on +//! `T`. +//! ```rust +//! #[frame::pallet] +//! pub mod pallet { +//! # use frame::prelude::*; +//! # #[pallet::config] +//! # pub trait Config: frame_system::Config {} +//! # #[pallet::pallet] +//! # pub struct Pallet(_); +//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)] +//! #[scale_info(skip_type_params(T))] +//! pub struct NewType(BlockNumberFor); +//! +//! #[pallet::storage] +//! pub type Something = StorageValue<_, NewType>; +//! } +//! ``` +//! +//! Next, let's say we wish to store `NewType` as [`frame::prelude::ValueQuery`], which means it +//! must also implement `Default`. This should be as simple as adding `derive(Default)` to it, +//! right? +//! ```compile_fail +//! #[frame::pallet] +//! pub mod pallet { +//! # use frame::prelude::*; +//! # #[pallet::config] +//! # pub trait Config: frame_system::Config {} +//! # #[pallet::pallet] +//! # pub struct Pallet(_); +//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo, Default)] +//! #[scale_info(skip_type_params(T))] +//! pub struct NewType(BlockNumberFor); +//! +//! #[pallet::storage] +//! pub type Something = StorageValue<_, NewType, ValueQuery>; +//! } +//! ``` +//! +//! Under the hood, the expansion of the `derive(Default)` will suffer from the same restriction as +//! before: it will only work if `T: Default`, and `T` is not `Default`. Note that this is an +//! expected issue: `T` is merely a wrapper of many other types, such as `BlockNumberFor`. +//! `BlockNumberFor` should indeed implement `Default`, but `T` implementing `Default` is rather +//! meaningless. +//! +//! To fix this, frame provides a set of macros that are analogous to normal rust derive macros, but +//! work nicely on top of structs that are generic over `T: Config`. These macros are: +//! +//! - [`frame::prelude::DefaultNoBound`] +//! - [`frame::prelude::DebugNoBound`] +//! - [`frame::prelude::PartialEqNoBound`] +//! - [`frame::prelude::EqNoBound`] +//! - [`frame::prelude::CloneNoBound`] +//! - [`frame::prelude::PartialOrdNoBound`] +//! - [`frame::prelude::OrdNoBound`] +//! +//! The above traits are almost certainly needed for your tests: To print your type, assert equality +//! or clone it. +//! +//! We can fix the following example by using [`frame::prelude::DefaultNoBound`]. +//! ```rust +//! #[frame::pallet] +//! pub mod pallet { +//! # use frame::prelude::*; +//! # #[pallet::config] +//! # pub trait Config: frame_system::Config {} +//! # #[pallet::pallet] +//! # pub struct Pallet(_); +//! #[derive( +//! codec::Encode, +//! codec::Decode, +//! codec::MaxEncodedLen, +//! scale_info::TypeInfo, +//! DefaultNoBound +//! )] +//! #[scale_info(skip_type_params(T))] +//! pub struct NewType(BlockNumberFor); +//! +//! #[pallet::storage] +//! pub type Something = StorageValue<_, NewType, ValueQuery>; +//! } +//! ``` +//! +//! Finally, if a custom type that is provided through `Config` is to be stored in the storage, it +//! is subject to the same trait requirements. The following does not work: +//! ```compile_fail +//! #[frame::pallet] +//! pub mod pallet { +//! use frame::prelude::*; +//! #[pallet::config] +//! pub trait Config: frame_system::Config { +//! type CustomType; +//! } +//! #[pallet::pallet] +//! pub struct Pallet(_); +//! #[pallet::storage] +//! pub type Something = StorageValue<_, T::CustomType>; +//! } +//! ``` +//! +//! But adding the right trait bounds will fix it. +//! ```rust +//! #[frame::pallet] +//! pub mod pallet { +//! use frame::prelude::*; +//! #[pallet::config] +//! pub trait Config: frame_system::Config { +//! type CustomType: codec::FullCodec +//! + codec::MaxEncodedLen +//! + scale_info::TypeInfo +//! + Debug +//! + Default; +//! } +//! #[pallet::pallet] +//! pub struct Pallet(_); +//! #[pallet::storage] +//! pub type Something = StorageValue<_, T::CustomType>; +//! } +//! ``` diff --git a/docs/sdk/src/reference_docs/mod.rs b/docs/sdk/src/reference_docs/mod.rs index 688339b7e3806c0ed86db5caabc253b0d45e7c41..c69c79365427e25726a95e17913f535a244fe368 100644 --- a/docs/sdk/src/reference_docs/mod.rs +++ b/docs/sdk/src/reference_docs/mod.rs @@ -45,6 +45,10 @@ pub mod signed_extensions; /// Learn about *Origins*, a topic in FRAME that enables complex account abstractions to be built. pub mod frame_origin; +/// Learn about the details of what derives are needed for a type to be store-able in `frame` +/// storage. +pub mod frame_storage_derives; + /// Learn about how to write safe and defensive code in your FRAME runtime. pub mod defensive_programming; diff --git a/docs/sdk/src/reference_docs/signed_extensions.rs b/docs/sdk/src/reference_docs/signed_extensions.rs index 43a6bcc14c5d2f67703864c485264583acb19ea3..c644aeaa41650817cd02b0dcc7a97e80c2b19bd0 100644 --- a/docs/sdk/src/reference_docs/signed_extensions.rs +++ b/docs/sdk/src/reference_docs/signed_extensions.rs @@ -1,7 +1,59 @@ //! Signed extensions are, briefly, a means for different chains to extend the "basic" extrinsic //! format with custom data that can be checked by the runtime. //! -//! # Example +//! # FRAME provided signed extensions +//! +//! FRAME by default already provides the following signed extensions: +//! +//! - [`CheckGenesis`](frame_system::CheckGenesis): Ensures that a transaction was sent for the same +//! network. Determined based on genesis. +//! +//! - [`CheckMortality`](frame_system::CheckMortality): Extends a transaction with a configurable +//! mortality. +//! +//! - [`CheckNonZeroSender`](frame_system::CheckNonZeroSender): Ensures that the sender of a +//! transaction is not the *all zero account* (all bytes of the accountid are zero). +//! +//! - [`CheckNonce`](frame_system::CheckNonce): Extends a transaction with a nonce to prevent replay +//! of transactions and to provide ordering of transactions. +//! +//! - [`CheckSpecVersion`](frame_system::CheckSpecVersion): Ensures that a transaction was built for +//! the currently active runtime. +//! +//! - [`CheckTxVersion`](frame_system::CheckTxVersion): Ensures that the transaction signer used the +//! correct encoding of the call. +//! +//! - [`CheckWeight`](frame_system::CheckWeight): Ensures that the transaction fits into the block +//! before dispatching it. +//! +//! - [`ChargeTransactionPayment`](pallet_transaction_payment::ChargeTransactionPayment): Charges +//! transaction fees from the signer based on the weight of the call using the native token. +//! +//! - [`ChargeAssetTxPayment`](pallet_asset_tx_payment::ChargeAssetTxPayment): Charges transaction +//! fees from the signer based on the weight of the call using any supported asset (including the +//! native token). +//! +//! - [`ChargeAssetTxPayment`(using +//! conversion)](pallet_asset_conversion_tx_payment::ChargeAssetTxPayment): Charges transaction +//! fees from the signer based on the weight of the call using any supported asset (including the +//! native token). The asset is converted to the native token using a pool. +//! +//! - [`SkipCheckIfFeeless`](pallet_skip_feeless_payment::SkipCheckIfFeeless): Allows transactions +//! to be processed without paying any fee. This requires that the `call` that should be +//! dispatched is augmented with the [`feeless_if`](frame_support::pallet_macros::feeless_if) +//! attribute. +//! +//! - [`CheckMetadataHash`](frame_metadata_hash_extension::CheckMetadataHash): Extends transactions +//! to include the so-called metadata hash. This is required by chains to support the generic +//! Ledger application and other similar offline wallets. +//! +//! - [`StorageWeightReclaim`](cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim): A +//! signed extension for parachains that reclaims unused storage weight after executing a +//! transaction. +//! +//! For more information about these extensions, follow the link to the type documentation. +//! +//! # Building a custom signed extension //! //! Defining a couple of very simple signed extensions looks like the following: #![doc = docify::embed!("./src/reference_docs/signed_extensions.rs", signed_extensions_example)] diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index 3aeec8d5961e35133233c35c38f57c2145c7f62c..3a939464868fed72d4bf89f3501dae84769d97b0 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -25,32 +25,32 @@ default-run = "polkadot" workspace = true [dependencies] -color-eyre = { version = "0.6.1", default-features = false } -tikv-jemallocator = { version = "0.5.0", optional = true, features = ["unprefixed_malloc_on_supported_platforms"] } +color-eyre = { workspace = true } +tikv-jemallocator = { optional = true, features = ["unprefixed_malloc_on_supported_platforms"], workspace = true } # Crates in our workspace, defined as dependencies so we can pass them feature flags. -polkadot-cli = { path = "cli", features = ["rococo-native", "westend-native"] } -polkadot-node-core-pvf = { path = "node/core/pvf" } -polkadot-node-core-pvf-prepare-worker = { path = "node/core/pvf/prepare-worker" } -polkadot-overseer = { path = "node/overseer" } +polkadot-cli = { features = ["rococo-native", "westend-native"], workspace = true, default-features = true } +polkadot-node-core-pvf = { workspace = true, default-features = true } +polkadot-node-core-pvf-prepare-worker = { workspace = true, default-features = true } +polkadot-overseer = { workspace = true, default-features = true } # Needed for worker binaries. -polkadot-node-core-pvf-common = { path = "node/core/pvf/common" } -polkadot-node-core-pvf-execute-worker = { path = "node/core/pvf/execute-worker" } +polkadot-node-core-pvf-common = { workspace = true, default-features = true } +polkadot-node-core-pvf-execute-worker = { workspace = true, default-features = true } [target.'cfg(target_os = "linux")'.dependencies] tikv-jemallocator = { version = "0.5.0", features = ["unprefixed_malloc_on_supported_platforms"] } [dev-dependencies] -assert_cmd = "2.0.4" -nix = { version = "0.28.0", features = ["signal"] } -tempfile = "3.2.0" -tokio = "1.37" -substrate-rpc-client = { path = "../substrate/utils/frame/rpc/client" } -polkadot-core-primitives = { path = "core-primitives" } +assert_cmd = { workspace = true } +nix = { features = ["signal"], workspace = true } +tempfile = { workspace = true } +tokio = { workspace = true, default-features = true } +substrate-rpc-client = { workspace = true, default-features = true } +polkadot-core-primitives = { workspace = true, default-features = true } [build-dependencies] -substrate-build-script-utils = { path = "../substrate/utils/build-script-utils" } +substrate-build-script-utils = { workspace = true, default-features = true } [badges] maintenance = { status = "actively-developed" } @@ -68,6 +68,11 @@ jemalloc-allocator = [ "polkadot-overseer/jemalloc-allocator", ] +# Generate the metadata hash needed for CheckMetadataHash +# in the builtin test runtimes (westend and rococo). +metadata-hash = [ + "polkadot-cli/metadata-hash", +] # Enables timeout-based tests supposed to be run only in CI environment as they may be flaky # when run locally depending on system load diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index 1917dcd579c4c6a723acc7f5fcde086f6e8e5e53..da37f6062c5725e9162718c7d49ee50d94617140 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -18,37 +18,38 @@ wasm-opt = false crate-type = ["cdylib", "rlib"] [dependencies] -cfg-if = "1.0" -clap = { version = "4.5.3", features = ["derive"], optional = true } +cfg-if = { workspace = true } +clap = { features = ["derive"], optional = true, workspace = true } log = { workspace = true, default-features = true } thiserror = { workspace = true } -futures = "0.3.30" -pyroscope = { version = "0.5.3", optional = true } -pyroscope_pprofrs = { version = "0.2", optional = true } +futures = { workspace = true } +pyroscope = { optional = true, workspace = true } +pyroscope_pprofrs = { optional = true, workspace = true } -polkadot-service = { path = "../node/service", default-features = false, optional = true } +polkadot-service = { optional = true, workspace = true } -sp-core = { path = "../../substrate/primitives/core" } -sp-io = { path = "../../substrate/primitives/io" } -sp-keyring = { path = "../../substrate/primitives/keyring" } -sp-maybe-compressed-blob = { path = "../../substrate/primitives/maybe-compressed-blob" } -frame-benchmarking-cli = { path = "../../substrate/utils/frame/benchmarking-cli", optional = true } -sc-cli = { path = "../../substrate/client/cli", optional = true } -sc-service = { path = "../../substrate/client/service", optional = true } -polkadot-node-metrics = { path = "../node/metrics" } -polkadot-node-primitives = { path = "../node/primitives" } -sc-tracing = { path = "../../substrate/client/tracing", optional = true } -sc-sysinfo = { path = "../../substrate/client/sysinfo" } -sc-executor = { path = "../../substrate/client/executor" } -sc-storage-monitor = { path = "../../substrate/client/storage-monitor" } -sp-runtime = { path = "../../substrate/primitives/runtime" } +sp-core = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-maybe-compressed-blob = { workspace = true, default-features = true } +frame-benchmarking-cli = { optional = true, workspace = true, default-features = true } +sc-cli = { optional = true, workspace = true, default-features = true } +sc-service = { optional = true, workspace = true, default-features = true } +polkadot-node-metrics = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +sc-tracing = { optional = true, workspace = true, default-features = true } +sc-sysinfo = { workspace = true, default-features = true } +sc-executor = { workspace = true, default-features = true } +sc-storage-monitor = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } [build-dependencies] -substrate-build-script-utils = { path = "../../substrate/utils/build-script-utils" } +substrate-build-script-utils = { workspace = true, default-features = true } [features] default = ["cli", "db", "full-node"] db = ["polkadot-service/db"] +metadata-hash = ["polkadot-service/metadata-hash"] service = ["dep:polkadot-service"] cli = [ "clap", diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs index b89054b4dc32178b0c42b3f365392e5202b88bc5..62d99122c3012701aa46039b13c3c05d3331d8c3 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -192,7 +192,7 @@ where F: FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration), { let runner = cli - .create_runner_with_logger_hook::(&cli.run.base, logger_hook) + .create_runner_with_logger_hook::<_, _, F>(&cli.run.base, logger_hook) .map_err(Error::from)?; let chain_spec = &runner.config().chain_spec; diff --git a/polkadot/core-primitives/Cargo.toml b/polkadot/core-primitives/Cargo.toml index 7d94196fa26dbbe95bfe543243c62099f1b4cb03..42ca27953738e5c06dc5cb904323ee6a5bbc91f2 100644 --- a/polkadot/core-primitives/Cargo.toml +++ b/polkadot/core-primitives/Cargo.toml @@ -10,11 +10,10 @@ license.workspace = true workspace = true [dependencies] -sp-core = { path = "../../substrate/primitives/core", default-features = false } -sp-std = { path = "../../substrate/primitives/std", default-features = false } -sp-runtime = { path = "../../substrate/primitives/runtime", default-features = false } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +codec = { features = ["derive"], workspace = true } [features] default = ["std"] @@ -23,5 +22,4 @@ std = [ "scale-info/std", "sp-core/std", "sp-runtime/std", - "sp-std/std", ] diff --git a/polkadot/core-primitives/src/lib.rs b/polkadot/core-primitives/src/lib.rs index 072c045a8c7039da82e0128d00e1886a7817ec4d..666636def46048ad2d97c48d5b82591df3108fcc 100644 --- a/polkadot/core-primitives/src/lib.rs +++ b/polkadot/core-primitives/src/lib.rs @@ -20,6 +20,8 @@ //! //! These core Polkadot types are used by the relay chain and the Parachains. +extern crate alloc; + use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime::{ @@ -81,8 +83,8 @@ impl std::fmt::Display for CandidateHash { } } -impl sp_std::fmt::Debug for CandidateHash { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { +impl core::fmt::Debug for CandidateHash { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{:?}", self.0) } } @@ -119,7 +121,7 @@ pub type Remark = [u8; 32]; /// A message sent from the relay-chain down to a parachain. /// /// The size of the message is limited by the `config.max_downward_message_size` parameter. -pub type DownwardMessage = sp_std::vec::Vec; +pub type DownwardMessage = alloc::vec::Vec; /// A wrapped version of `DownwardMessage`. The difference is that it has attached the block number /// when the message was sent. @@ -139,7 +141,7 @@ pub struct InboundHrmpMessage { /// enacted. pub sent_at: BlockNumber, /// The message payload. - pub data: sp_std::vec::Vec, + pub data: alloc::vec::Vec, } /// An HRMP message seen from the perspective of a sender. @@ -148,7 +150,7 @@ pub struct OutboundHrmpMessage { /// The para that will get this message in its downward message queue. pub recipient: Id, /// The message payload. - pub data: sp_std::vec::Vec, + pub data: alloc::vec::Vec, } /// `V2` primitives. diff --git a/polkadot/erasure-coding/Cargo.toml b/polkadot/erasure-coding/Cargo.toml index 3c14fd95eee3b29988a87b68047f585c32c5bbc0..969742c5bb0aa792ea81b287f588b1315a48971d 100644 --- a/polkadot/erasure-coding/Cargo.toml +++ b/polkadot/erasure-coding/Cargo.toml @@ -10,17 +10,17 @@ license.workspace = true workspace = true [dependencies] -polkadot-primitives = { path = "../primitives" } -polkadot-node-primitives = { package = "polkadot-node-primitives", path = "../node/primitives" } -novelpoly = { package = "reed-solomon-novelpoly", version = "2.0.0" } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "std"] } -sp-core = { path = "../../substrate/primitives/core" } -sp-trie = { path = "../../substrate/primitives/trie" } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +novelpoly = { workspace = true } +codec = { features = ["derive", "std"], workspace = true } +sp-core = { workspace = true, default-features = true } +sp-trie = { workspace = true, default-features = true } thiserror = { workspace = true } [dev-dependencies] -quickcheck = { version = "1.0.3", default-features = false } -criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } +quickcheck = { workspace = true } +criterion = { features = ["cargo_bench_support"], workspace = true } [[bench]] name = "scaling_with_validators" diff --git a/polkadot/erasure-coding/fuzzer/Cargo.toml b/polkadot/erasure-coding/fuzzer/Cargo.toml index bd254f6d51651d27ac2a992285c80f9e1e272623..6f451f0319b23dee9ebbf08726dd4550f518e95d 100644 --- a/polkadot/erasure-coding/fuzzer/Cargo.toml +++ b/polkadot/erasure-coding/fuzzer/Cargo.toml @@ -10,10 +10,10 @@ publish = false workspace = true [dependencies] -polkadot-erasure-coding = { path = ".." } -honggfuzz = "0.5" -polkadot-primitives = { path = "../../primitives" } -polkadot-node-primitives = { path = "../../node/primitives" } +polkadot-erasure-coding = { workspace = true, default-features = true } +honggfuzz = { workspace = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } [[bin]] name = "reconstruct" diff --git a/polkadot/node/collation-generation/Cargo.toml b/polkadot/node/collation-generation/Cargo.toml index da5d10d7994970dde81b8530888c28c56dffb0b0..4b0a5f7248ab383884365105b164f27f2a090bf1 100644 --- a/polkadot/node/collation-generation/Cargo.toml +++ b/polkadot/node/collation-generation/Cargo.toml @@ -10,21 +10,21 @@ description = "Collator-side subsystem that handles incoming candidate submissio workspace = true [dependencies] -futures = "0.3.30" -gum = { package = "tracing-gum", path = "../gum" } -polkadot-erasure-coding = { path = "../../erasure-coding" } -polkadot-node-primitives = { path = "../primitives" } -polkadot-node-subsystem = { path = "../subsystem" } -polkadot-node-subsystem-util = { path = "../subsystem-util" } -polkadot-primitives = { path = "../../primitives" } -sp-core = { path = "../../../substrate/primitives/core" } -sp-maybe-compressed-blob = { path = "../../../substrate/primitives/maybe-compressed-blob" } +futures = { workspace = true } +gum = { workspace = true, default-features = true } +polkadot-erasure-coding = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-maybe-compressed-blob = { workspace = true, default-features = true } thiserror = { workspace = true } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["bit-vec", "derive"] } +codec = { features = ["bit-vec", "derive"], workspace = true } [dev-dependencies] -polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } -polkadot-primitives-test-helpers = { path = "../../primitives/test-helpers" } -assert_matches = "1.4.0" -rstest = "0.18.2" -sp-keyring = { path = "../../../substrate/primitives/keyring" } +polkadot-node-subsystem-test-helpers = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } +assert_matches = { workspace = true } +rstest = { workspace = true } +sp-keyring = { workspace = true, default-features = true } diff --git a/polkadot/node/collation-generation/src/lib.rs b/polkadot/node/collation-generation/src/lib.rs index 0c2f8ee14a58033dce47947a4e923ea644213831..d38516a4ff713f32c98c4e616155c4cdffb8bfb8 100644 --- a/polkadot/node/collation-generation/src/lib.rs +++ b/polkadot/node/collation-generation/src/lib.rs @@ -147,11 +147,7 @@ impl CollationGenerationSubsystem { Ok(FromOrchestra::Communication { msg: CollationGenerationMessage::Reinitialize(config), }) => { - if self.config.is_none() { - gum::error!(target: LOG_TARGET, "no initial initialization"); - } else { - self.config = Some(Arc::new(config)); - } + self.config = Some(Arc::new(config)); false }, Ok(FromOrchestra::Communication { diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index 7da3d7ddd781485d673b29980b6787b99aea9da6..65985c0a5db930cf94922a6c8fde6e549021e7ef 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -10,51 +10,51 @@ description = "Approval Voting Subsystem of the Polkadot node" workspace = true [dependencies] -futures = "0.3.30" -futures-timer = "3.0.2" -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["bit-vec", "derive"] } -gum = { package = "tracing-gum", path = "../../gum" } -bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } -schnellru = "0.2.1" -merlin = "3.0" -schnorrkel = "0.11.4" -kvdb = "0.13.0" -derive_more = "0.99.17" +futures = { workspace = true } +futures-timer = { workspace = true } +codec = { features = ["bit-vec", "derive"], workspace = true } +gum = { workspace = true, default-features = true } +bitvec = { features = ["alloc"], workspace = true } +schnellru = { workspace = true } +merlin = { workspace = true, default-features = true } +schnorrkel = { workspace = true, default-features = true } +kvdb = { workspace = true } +derive_more = { workspace = true, default-features = true } thiserror = { workspace = true } -itertools = "0.11" +itertools = { workspace = true } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } -polkadot-overseer = { path = "../../overseer" } -polkadot-primitives = { path = "../../../primitives" } -polkadot-node-primitives = { path = "../../primitives" } -polkadot-node-jaeger = { path = "../../jaeger" } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-overseer = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-jaeger = { workspace = true, default-features = true } -sc-keystore = { path = "../../../../substrate/client/keystore", default-features = false } -sp-consensus = { path = "../../../../substrate/primitives/consensus/common", default-features = false } -sp-consensus-slots = { path = "../../../../substrate/primitives/consensus/slots", default-features = false } -sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto", default-features = false, features = ["full_crypto"] } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } +sc-keystore = { workspace = true } +sp-consensus = { workspace = true } +sp-consensus-slots = { workspace = true } +sp-application-crypto = { features = ["full_crypto"], workspace = true } +sp-runtime = { workspace = true } # rand_core should match schnorrkel -rand_core = "0.6.2" -rand_chacha = { version = "0.3.1" } -rand = "0.8.5" +rand_core = { workspace = true } +rand_chacha = { workspace = true, default-features = true } +rand = { workspace = true, default-features = true } [dev-dependencies] -async-trait = "0.1.79" -parking_lot = "0.12.1" -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -sp-keystore = { path = "../../../../substrate/primitives/keystore" } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-consensus-babe = { path = "../../../../substrate/primitives/consensus/babe" } -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -assert_matches = "1.4.0" -kvdb-memorydb = "0.13.0" -polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } +async-trait = { workspace = true } +parking_lot = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +polkadot-node-subsystem-test-helpers = { workspace = true } +assert_matches = { workspace = true } +kvdb-memorydb = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } log = { workspace = true, default-features = true } -env_logger = "0.11" +env_logger = { workspace = true } -polkadot-subsystem-bench = { path = "../../subsystem-bench" } +polkadot-subsystem-bench = { workspace = true } [[bench]] name = "approval-voting-regression-bench" diff --git a/polkadot/node/core/approval-voting/benches/approval-voting-regression-bench.rs b/polkadot/node/core/approval-voting/benches/approval-voting-regression-bench.rs index 687063dd0eb302c4b61b224ee74bb9c4a56fbe5b..a18e667253d08298eb32fd5a65762f80482715a6 100644 --- a/polkadot/node/core/approval-voting/benches/approval-voting-regression-bench.rs +++ b/polkadot/node/core/approval-voting/benches/approval-voting-regression-bench.rs @@ -77,12 +77,12 @@ fn main() -> Result<(), String> { // We expect no variance for received and sent // but use 0.001 because we operate with floats messages.extend(average_usage.check_network_usage(&[ - ("Received from peers", 52942.4600, 0.001), - ("Sent to peers", 63547.0330, 0.001), + ("Received from peers", 52941.6071, 0.001), + ("Sent to peers", 63810.1859, 0.001), ])); messages.extend(average_usage.check_cpu_usage(&[ - ("approval-distribution", 7.4075, 0.1), - ("approval-voting", 9.9873, 0.1), + ("approval-distribution", 6.3912, 0.1), + ("approval-voting", 10.0578, 0.1), ])); if messages.is_empty() { diff --git a/polkadot/node/core/av-store/Cargo.toml b/polkadot/node/core/av-store/Cargo.toml index 62f7ff0b61e64de81fa6b3c34987df042a865cbb..4274c8b576a3dc82cefbc22a7619bfe3206c181d 100644 --- a/polkadot/node/core/av-store/Cargo.toml +++ b/polkadot/node/core/av-store/Cargo.toml @@ -10,32 +10,32 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.30" -futures-timer = "3.0.2" -kvdb = "0.13.0" +futures = { workspace = true } +futures-timer = { workspace = true } +kvdb = { workspace = true } thiserror = { workspace = true } -gum = { package = "tracing-gum", path = "../../gum" } -bitvec = "1.0.0" +gum = { workspace = true, default-features = true } +bitvec = { workspace = true, default-features = true } -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } -polkadot-erasure-coding = { path = "../../../erasure-coding" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } -polkadot-overseer = { path = "../../overseer" } -polkadot-primitives = { path = "../../../primitives" } -polkadot-node-primitives = { path = "../../primitives" } -sp-consensus = { path = "../../../../substrate/primitives/consensus/common", default-features = false } -polkadot-node-jaeger = { path = "../../jaeger" } +codec = { features = ["derive"], workspace = true, default-features = true } +polkadot-erasure-coding = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-overseer = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +sp-consensus = { workspace = true } +polkadot-node-jaeger = { workspace = true, default-features = true } [dev-dependencies] log = { workspace = true, default-features = true } -env_logger = "0.11" -assert_matches = "1.4.0" -kvdb-memorydb = "0.13.0" +env_logger = { workspace = true } +assert_matches = { workspace = true } +kvdb-memorydb = { workspace = true } -sp-core = { path = "../../../../substrate/primitives/core" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -parking_lot = "0.12.1" -polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } +sp-core = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-node-subsystem-test-helpers = { workspace = true } +sp-keyring = { workspace = true, default-features = true } +parking_lot = { workspace = true, default-features = true } +polkadot-primitives-test-helpers = { workspace = true } diff --git a/polkadot/node/core/backing/Cargo.toml b/polkadot/node/core/backing/Cargo.toml index ffd6de076889413e6872e7c765d849798afb338a..1b52afc309bc9e301f879a720d253467a5359f13 100644 --- a/polkadot/node/core/backing/Cargo.toml +++ b/polkadot/node/core/backing/Cargo.toml @@ -10,28 +10,28 @@ description = "The Candidate Backing Subsystem. Tracks parachain candidates that workspace = true [dependencies] -futures = "0.3.30" -sp-keystore = { path = "../../../../substrate/primitives/keystore" } -polkadot-primitives = { path = "../../../primitives" } -polkadot-node-primitives = { path = "../../primitives" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } -polkadot-erasure-coding = { path = "../../../erasure-coding" } -polkadot-statement-table = { path = "../../../statement-table" } -bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } -gum = { package = "tracing-gum", path = "../../gum" } +futures = { workspace = true } +sp-keystore = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-erasure-coding = { workspace = true, default-features = true } +polkadot-statement-table = { workspace = true, default-features = true } +bitvec = { features = ["alloc"], workspace = true } +gum = { workspace = true, default-features = true } thiserror = { workspace = true } -fatality = "0.1.1" -schnellru = "0.2.1" +fatality = { workspace = true } +schnellru = { workspace = true } [dev-dependencies] -sp-core = { path = "../../../../substrate/primitives/core" } -sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto" } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -sc-keystore = { path = "../../../../substrate/client/keystore" } -sp-tracing = { path = "../../../../substrate/primitives/tracing" } -futures = { version = "0.3.30", features = ["thread-pool"] } -assert_matches = "1.4.0" -rstest = "0.18.2" -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } +sp-core = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sc-keystore = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +futures = { features = ["thread-pool"], workspace = true } +assert_matches = { workspace = true } +rstest = { workspace = true } +polkadot-node-subsystem-test-helpers = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs index 1bda81c5197ef32e5659ab8393ef68384a288577..5bcd47a2434c71f3a6dd88e4c0456f467817deb7 100644 --- a/polkadot/node/core/backing/src/lib.rs +++ b/polkadot/node/core/backing/src/lib.rs @@ -827,8 +827,8 @@ async fn handle_communication( CandidateBackingMessage::Statement(relay_parent, statement) => { handle_statement_message(ctx, state, relay_parent, statement, metrics).await?; }, - CandidateBackingMessage::GetBackedCandidates(requested_candidates, tx) => - handle_get_backed_candidates_message(state, requested_candidates, tx, metrics)?, + CandidateBackingMessage::GetBackableCandidates(requested_candidates, tx) => + handle_get_backable_candidates_message(state, requested_candidates, tx, metrics)?, CandidateBackingMessage::CanSecond(request, tx) => handle_can_second_request(ctx, state, request, tx).await, } @@ -2158,7 +2158,7 @@ async fn handle_statement_message( } } -fn handle_get_backed_candidates_message( +fn handle_get_backable_candidates_message( state: &State, requested_candidates: HashMap>, tx: oneshot::Sender>>, diff --git a/polkadot/node/core/backing/src/tests/mod.rs b/polkadot/node/core/backing/src/tests/mod.rs index 5f2bc7e18424390bbd012cdccc268c902820e4e3..10eb45b82d12544be09a188493d7114fc99c6d58 100644 --- a/polkadot/node/core/backing/src/tests/mod.rs +++ b/polkadot/node/core/backing/src/tests/mod.rs @@ -703,7 +703,7 @@ fn backing_works(#[case] elastic_scaling_mvp: bool) { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; let (tx, rx) = oneshot::channel(); - let msg = CandidateBackingMessage::GetBackedCandidates( + let msg = CandidateBackingMessage::GetBackableCandidates( std::iter::once(( test_state.chain_ids[0], vec![(candidate_a_hash, test_state.relay_parent)], @@ -895,7 +895,7 @@ fn get_backed_candidate_preserves_order() { // Happy case, all candidates should be present. let (tx, rx) = oneshot::channel(); - let msg = CandidateBackingMessage::GetBackedCandidates( + let msg = CandidateBackingMessage::GetBackableCandidates( [ ( test_state.chain_ids[0], @@ -946,7 +946,7 @@ fn get_backed_candidate_preserves_order() { ], ] { let (tx, rx) = oneshot::channel(); - let msg = CandidateBackingMessage::GetBackedCandidates( + let msg = CandidateBackingMessage::GetBackableCandidates( [ (test_state.chain_ids[0], candidates), (test_state.chain_ids[1], vec![(candidate_c_hash, test_state.relay_parent)]), @@ -985,7 +985,7 @@ fn get_backed_candidate_preserves_order() { ], ] { let (tx, rx) = oneshot::channel(); - let msg = CandidateBackingMessage::GetBackedCandidates( + let msg = CandidateBackingMessage::GetBackableCandidates( [ (test_state.chain_ids[0], candidates), (test_state.chain_ids[1], vec![(candidate_c_hash, test_state.relay_parent)]), @@ -1030,7 +1030,7 @@ fn get_backed_candidate_preserves_order() { ], ] { let (tx, rx) = oneshot::channel(); - let msg = CandidateBackingMessage::GetBackedCandidates( + let msg = CandidateBackingMessage::GetBackableCandidates( [ (test_state.chain_ids[0], candidates), (test_state.chain_ids[1], vec![(candidate_c_hash, test_state.relay_parent)]), @@ -1321,7 +1321,7 @@ fn backing_works_while_validation_ongoing() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; let (tx, rx) = oneshot::channel(); - let msg = CandidateBackingMessage::GetBackedCandidates( + let msg = CandidateBackingMessage::GetBackableCandidates( std::iter::once(( test_state.chain_ids[0], vec![(candidate_a.hash(), test_state.relay_parent)], @@ -1942,7 +1942,7 @@ fn backing_works_after_failed_validation() { // Try to get a set of backable candidates to trigger _some_ action in the subsystem // and check that it is still alive. let (tx, rx) = oneshot::channel(); - let msg = CandidateBackingMessage::GetBackedCandidates( + let msg = CandidateBackingMessage::GetBackableCandidates( std::iter::once(( test_state.chain_ids[0], vec![(candidate.hash(), test_state.relay_parent)], diff --git a/polkadot/node/core/bitfield-signing/Cargo.toml b/polkadot/node/core/bitfield-signing/Cargo.toml index 335e733987b017c0ee68f85d6dede42e3128b83c..126a18a141661c49411b576d9730e255ca627692 100644 --- a/polkadot/node/core/bitfield-signing/Cargo.toml +++ b/polkadot/node/core/bitfield-signing/Cargo.toml @@ -10,15 +10,15 @@ description = "Bitfield signing subsystem for the Polkadot node" workspace = true [dependencies] -futures = "0.3.30" -gum = { package = "tracing-gum", path = "../../gum" } -polkadot-primitives = { path = "../../../primitives" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } -sp-keystore = { path = "../../../../substrate/primitives/keystore" } -wasm-timer = "0.2.5" +futures = { workspace = true } +gum = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +wasm-timer = { workspace = true } thiserror = { workspace = true } [dev-dependencies] -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } +polkadot-node-subsystem-test-helpers = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } diff --git a/polkadot/node/core/candidate-validation/Cargo.toml b/polkadot/node/core/candidate-validation/Cargo.toml index a0b25e6c25f9ccd3c5ab2e2ddd38b1f0aa0433a5..13ab3e3fba50af4db1dc13497729f6c932ab7348 100644 --- a/polkadot/node/core/candidate-validation/Cargo.toml +++ b/polkadot/node/core/candidate-validation/Cargo.toml @@ -10,29 +10,31 @@ license.workspace = true workspace = true [dependencies] -async-trait = "0.1.79" -futures = "0.3.30" -futures-timer = "3.0.2" -gum = { package = "tracing-gum", path = "../../gum" } +async-trait = { workspace = true } +futures = { workspace = true } +futures-timer = { workspace = true } +gum = { workspace = true, default-features = true } -sp-maybe-compressed-blob = { package = "sp-maybe-compressed-blob", path = "../../../../substrate/primitives/maybe-compressed-blob" } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["bit-vec", "derive"] } +sp-keystore = { workspace = true } +sp-application-crypto = { workspace = true } +sp-maybe-compressed-blob = { workspace = true, default-features = true } +codec = { features = ["bit-vec", "derive"], workspace = true } -polkadot-primitives = { path = "../../../primitives" } -polkadot-parachain-primitives = { path = "../../../parachain" } -polkadot-node-primitives = { path = "../../primitives" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } -polkadot-node-metrics = { path = "../../metrics" } -polkadot-overseer = { path = "../../overseer" } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-node-metrics = { workspace = true, default-features = true } +polkadot-overseer = { workspace = true, default-features = true } [target.'cfg(not(any(target_os = "android", target_os = "unknown")))'.dependencies] -polkadot-node-core-pvf = { path = "../pvf" } +polkadot-node-core-pvf = { workspace = true, default-features = true } [dev-dependencies] -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -futures = { version = "0.3.30", features = ["thread-pool"] } -assert_matches = "1.4.0" -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -sp-core = { path = "../../../../substrate/primitives/core" } -polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } +sp-keyring = { workspace = true, default-features = true } +futures = { features = ["thread-pool"], workspace = true } +assert_matches = { workspace = true } +polkadot-node-subsystem-test-helpers = { workspace = true } +sp-core = { workspace = true, default-features = true } +polkadot-primitives-test-helpers = { workspace = true } diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index 76619bd391f2bbefed07a8b8203a4c1bbcab75e7..1985964ebc512ea8bdb53631896643f9dcb85735 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -39,7 +39,8 @@ use polkadot_node_subsystem::{ overseer, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, SubsystemResult, SubsystemSender, }; -use polkadot_node_subsystem_util::executor_params_at_relay_parent; +use polkadot_node_subsystem_util as util; +use polkadot_overseer::ActiveLeavesUpdate; use polkadot_parachain_primitives::primitives::{ ValidationParams, ValidationResult as WasmValidationResult, }; @@ -48,16 +49,19 @@ use polkadot_primitives::{ DEFAULT_APPROVAL_EXECUTION_TIMEOUT, DEFAULT_BACKING_EXECUTION_TIMEOUT, DEFAULT_LENIENT_PREPARATION_TIMEOUT, DEFAULT_PRECHECK_PREPARATION_TIMEOUT, }, - CandidateCommitments, CandidateDescriptor, CandidateReceipt, ExecutorParams, Hash, - OccupiedCoreAssumption, PersistedValidationData, PvfExecKind, PvfPrepKind, ValidationCode, - ValidationCodeHash, + AuthorityDiscoveryId, CandidateCommitments, CandidateDescriptor, CandidateEvent, + CandidateReceipt, ExecutorParams, Hash, OccupiedCoreAssumption, PersistedValidationData, + PvfExecKind, PvfPrepKind, SessionIndex, ValidationCode, ValidationCodeHash, }; +use sp_application_crypto::{AppCrypto, ByteArray}; +use sp_keystore::KeystorePtr; use codec::Encode; use futures::{channel::oneshot, prelude::*, stream::FuturesUnordered}; use std::{ + collections::HashSet, path::PathBuf, pin::Pin, sync::Arc, @@ -88,7 +92,7 @@ const PVF_APPROVAL_EXECUTION_RETRY_DELAY: Duration = Duration::from_millis(200); const TASK_LIMIT: usize = 30; /// Configuration for the candidate validation subsystem -#[derive(Clone)] +#[derive(Clone, Default)] pub struct Config { /// The path where candidate validation can store compiled artifacts for PVFs. pub artifacts_cache_path: PathBuf, @@ -111,6 +115,7 @@ pub struct Config { /// The candidate validation subsystem. pub struct CandidateValidationSubsystem { + keystore: KeystorePtr, #[allow(missing_docs)] pub metrics: Metrics, #[allow(missing_docs)] @@ -122,10 +127,11 @@ impl CandidateValidationSubsystem { /// Create a new `CandidateValidationSubsystem`. pub fn with_config( config: Option, + keystore: KeystorePtr, metrics: Metrics, pvf_metrics: polkadot_node_core_pvf::Metrics, ) -> Self { - CandidateValidationSubsystem { config, metrics, pvf_metrics } + CandidateValidationSubsystem { keystore, config, metrics, pvf_metrics } } } @@ -133,7 +139,7 @@ impl CandidateValidationSubsystem { impl CandidateValidationSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem { if let Some(config) = self.config { - let future = run(ctx, self.metrics, self.pvf_metrics, config) + let future = run(ctx, self.keystore, self.metrics, self.pvf_metrics, config) .map_err(|e| SubsystemError::with_origin("candidate-validation", e)) .boxed(); SpawnedSubsystem { name: "candidate-validation-subsystem", future } @@ -223,6 +229,7 @@ where #[overseer::contextbounds(CandidateValidation, prefix = self::overseer)] async fn run( mut ctx: Context, + keystore: KeystorePtr, metrics: Metrics, pvf_metrics: polkadot_node_core_pvf::Metrics, Config { @@ -253,13 +260,16 @@ async fn run( ctx.spawn_blocking("pvf-validation-host", task.boxed())?; let mut tasks = FuturesUnordered::new(); + let mut prepare_state = PrepareValidationState::default(); loop { loop { futures::select! { comm = ctx.recv().fuse() => { match comm { - Ok(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(_))) => {}, + Ok(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update))) => { + maybe_prepare_validation(ctx.sender(), keystore.clone(), validation_host.clone(), update, &mut prepare_state).await; + }, Ok(FromOrchestra::Signal(OverseerSignal::BlockFinalized(..))) => {}, Ok(FromOrchestra::Signal(OverseerSignal::Conclude)) => return Ok(()), Ok(FromOrchestra::Communication { msg }) => { @@ -298,6 +308,246 @@ async fn run( } } +struct PrepareValidationState { + session_index: Option, + is_next_session_authority: bool, + // PVF host won't prepare the same code hash twice, so here we just avoid extra communication + already_prepared_code_hashes: HashSet, + // How many PVFs per block we take to prepare themselves for the next session validation + per_block_limit: usize, +} + +impl Default for PrepareValidationState { + fn default() -> Self { + Self { + session_index: None, + is_next_session_authority: false, + already_prepared_code_hashes: HashSet::new(), + per_block_limit: 1, + } + } +} + +async fn maybe_prepare_validation( + sender: &mut Sender, + keystore: KeystorePtr, + validation_backend: impl ValidationBackend, + update: ActiveLeavesUpdate, + state: &mut PrepareValidationState, +) where + Sender: SubsystemSender, +{ + let Some(leaf) = update.activated else { return }; + let new_session_index = new_session_index(sender, state.session_index, leaf.hash).await; + if new_session_index.is_some() { + state.session_index = new_session_index; + state.already_prepared_code_hashes.clear(); + state.is_next_session_authority = check_next_session_authority( + sender, + keystore, + leaf.hash, + state.session_index.expect("qed: just checked above"), + ) + .await; + } + + // On every active leaf check candidates and prepare PVFs our node doesn't have yet. + if state.is_next_session_authority { + let code_hashes = prepare_pvfs_for_backed_candidates( + sender, + validation_backend, + leaf.hash, + &state.already_prepared_code_hashes, + state.per_block_limit, + ) + .await; + state.already_prepared_code_hashes.extend(code_hashes.unwrap_or_default()); + } +} + +// Returns the new session index if it is greater than the current one. +async fn new_session_index( + sender: &mut Sender, + session_index: Option, + relay_parent: Hash, +) -> Option +where + Sender: SubsystemSender, +{ + let Ok(Ok(new_session_index)) = + util::request_session_index_for_child(relay_parent, sender).await.await + else { + gum::warn!( + target: LOG_TARGET, + ?relay_parent, + "cannot fetch session index from runtime API", + ); + return None + }; + + session_index.map_or(Some(new_session_index), |index| { + if new_session_index > index { + Some(new_session_index) + } else { + None + } + }) +} + +// Returns true if the node is an authority in the next session. +async fn check_next_session_authority( + sender: &mut Sender, + keystore: KeystorePtr, + relay_parent: Hash, + session_index: SessionIndex, +) -> bool +where + Sender: SubsystemSender, +{ + // In spite of function name here we request past, present and future authorities. + // It's ok to stil prepare PVFs in other cases, but better to request only future ones. + let Ok(Ok(authorities)) = util::request_authorities(relay_parent, sender).await.await else { + gum::warn!( + target: LOG_TARGET, + ?relay_parent, + "cannot fetch authorities from runtime API", + ); + return false + }; + + // We need to exclude at least current session authority from the previous request + let Ok(Ok(Some(session_info))) = + util::request_session_info(relay_parent, session_index, sender).await.await + else { + gum::warn!( + target: LOG_TARGET, + ?relay_parent, + "cannot fetch session info from runtime API", + ); + return false + }; + + let is_past_present_or_future_authority = authorities + .iter() + .any(|v| keystore.has_keys(&[(v.to_raw_vec(), AuthorityDiscoveryId::ID)])); + + let is_present_authority = session_info + .discovery_keys + .iter() + .any(|v| keystore.has_keys(&[(v.to_raw_vec(), AuthorityDiscoveryId::ID)])); + + // There is still a chance to be a previous session authority, but this extra work does not + // affect the finalization. + is_past_present_or_future_authority && !is_present_authority +} + +// Sends PVF with unknown code hashes to the validation host returning the list of code hashes sent. +async fn prepare_pvfs_for_backed_candidates( + sender: &mut Sender, + mut validation_backend: impl ValidationBackend, + relay_parent: Hash, + already_prepared: &HashSet, + per_block_limit: usize, +) -> Option> +where + Sender: SubsystemSender, +{ + let Ok(Ok(events)) = util::request_candidate_events(relay_parent, sender).await.await else { + gum::warn!( + target: LOG_TARGET, + ?relay_parent, + "cannot fetch candidate events from runtime API", + ); + return None + }; + let code_hashes = events + .into_iter() + .filter_map(|e| match e { + CandidateEvent::CandidateBacked(receipt, ..) => { + let h = receipt.descriptor.validation_code_hash; + if already_prepared.contains(&h) { + None + } else { + Some(h) + } + }, + _ => None, + }) + .take(per_block_limit) + .collect::>(); + + let Ok(executor_params) = util::executor_params_at_relay_parent(relay_parent, sender).await + else { + gum::warn!( + target: LOG_TARGET, + ?relay_parent, + "cannot fetch executor params for the session", + ); + return None + }; + let timeout = pvf_prep_timeout(&executor_params, PvfPrepKind::Prepare); + + let mut active_pvfs = vec![]; + let mut processed_code_hashes = vec![]; + for code_hash in code_hashes { + let Ok(Ok(Some(validation_code))) = + util::request_validation_code_by_hash(relay_parent, code_hash, sender) + .await + .await + else { + gum::warn!( + target: LOG_TARGET, + ?relay_parent, + ?code_hash, + "cannot fetch validation code hash from runtime API", + ); + continue; + }; + + let pvf = match sp_maybe_compressed_blob::decompress( + &validation_code.0, + VALIDATION_CODE_BOMB_LIMIT, + ) { + Ok(code) => PvfPrepData::from_code( + code.into_owned(), + executor_params.clone(), + timeout, + PrepareJobKind::Prechecking, + ), + Err(e) => { + gum::debug!(target: LOG_TARGET, err=?e, "cannot decompress validation code"); + continue + }, + }; + + active_pvfs.push(pvf); + processed_code_hashes.push(code_hash); + } + + if active_pvfs.is_empty() { + return None + } + + if let Err(err) = validation_backend.heads_up(active_pvfs).await { + gum::warn!( + target: LOG_TARGET, + ?relay_parent, + ?err, + "cannot prepare PVF for the next session", + ); + return None + }; + + gum::debug!( + target: LOG_TARGET, + ?relay_parent, + ?processed_code_hashes, + "Prepared PVF for the next session", + ); + + Some(processed_code_hashes) +} + struct RuntimeRequestFailed; async fn runtime_api_request( @@ -378,25 +628,26 @@ where }, }; - let executor_params = - if let Ok(executor_params) = executor_params_at_relay_parent(relay_parent, sender).await { - gum::debug!( - target: LOG_TARGET, - ?relay_parent, - ?validation_code_hash, - "precheck: acquired executor params for the session: {:?}", - executor_params, - ); - executor_params - } else { - gum::warn!( - target: LOG_TARGET, - ?relay_parent, - ?validation_code_hash, - "precheck: failed to acquire executor params for the session, thus voting against.", - ); - return PreCheckOutcome::Invalid - }; + let executor_params = if let Ok(executor_params) = + util::executor_params_at_relay_parent(relay_parent, sender).await + { + gum::debug!( + target: LOG_TARGET, + ?relay_parent, + ?validation_code_hash, + "precheck: acquired executor params for the session: {:?}", + executor_params, + ); + executor_params + } else { + gum::warn!( + target: LOG_TARGET, + ?relay_parent, + ?validation_code_hash, + "precheck: failed to acquire executor params for the session, thus voting against.", + ); + return PreCheckOutcome::Invalid + }; let timeout = pvf_prep_timeout(&executor_params, PvfPrepKind::Precheck); @@ -891,6 +1142,8 @@ trait ValidationBackend { } async fn precheck_pvf(&mut self, pvf: PvfPrepData) -> Result<(), PrepareError>; + + async fn heads_up(&mut self, active_pvfs: Vec) -> Result<(), String>; } #[async_trait] @@ -933,6 +1186,10 @@ impl ValidationBackend for ValidationHost { precheck_result } + + async fn heads_up(&mut self, active_pvfs: Vec) -> Result<(), String> { + self.heads_up(active_pvfs).await + } } /// Does basic checks of a candidate. Provide the encoded PoV-block. Returns `Ok` if basic checks diff --git a/polkadot/node/core/candidate-validation/src/tests.rs b/polkadot/node/core/candidate-validation/src/tests.rs index 491ed7a335d8fb5a8a7531e64267e664e3bf91d3..86d855f78b454dcea2e8ac50fb77ea6ed2afe727 100644 --- a/polkadot/node/core/candidate-validation/src/tests.rs +++ b/polkadot/node/core/candidate-validation/src/tests.rs @@ -14,16 +14,25 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +use std::sync::atomic::{AtomicUsize, Ordering}; + use super::*; use assert_matches::assert_matches; use futures::executor; use polkadot_node_core_pvf::PrepareError; use polkadot_node_subsystem::messages::AllMessages; use polkadot_node_subsystem_util::reexports::SubsystemContext; -use polkadot_primitives::{HeadData, Id as ParaId, UpwardMessage}; -use polkadot_primitives_test_helpers::{dummy_hash, make_valid_candidate_descriptor}; +use polkadot_overseer::ActivatedLeaf; +use polkadot_primitives::{ + CoreIndex, GroupIndex, HeadData, Id as ParaId, IndexedVec, SessionInfo, UpwardMessage, + ValidatorId, ValidatorIndex, +}; +use polkadot_primitives_test_helpers::{ + dummy_collator, dummy_collator_signature, dummy_hash, make_valid_candidate_descriptor, +}; use sp_core::testing::TaskExecutor; use sp_keyring::Sr25519Keyring; +use sp_keystore::{testing::MemoryKeystore, Keystore}; #[test] fn correctly_checks_included_assumption() { @@ -390,6 +399,10 @@ impl ValidationBackend for MockValidateCandidateBackend { async fn precheck_pvf(&mut self, _pvf: PvfPrepData) -> Result<(), PrepareError> { unreachable!() } + + async fn heads_up(&mut self, _active_pvfs: Vec) -> Result<(), String> { + unreachable!() + } } #[test] @@ -1071,6 +1084,10 @@ impl ValidationBackend for MockPreCheckBackend { async fn precheck_pvf(&mut self, _pvf: PvfPrepData) -> Result<(), PrepareError> { self.result.clone() } + + async fn heads_up(&mut self, _active_pvfs: Vec) -> Result<(), String> { + unreachable!() + } } #[test] @@ -1263,3 +1280,628 @@ fn precheck_properly_classifies_outcomes() { inner(Err(PrepareError::TimedOut), PreCheckOutcome::Failed); inner(Err(PrepareError::IoErr("fizz".to_owned())), PreCheckOutcome::Failed); } + +#[derive(Default, Clone)] +struct MockHeadsUp { + heads_up_call_count: Arc, +} + +#[async_trait] +impl ValidationBackend for MockHeadsUp { + async fn validate_candidate( + &mut self, + _pvf: PvfPrepData, + _timeout: Duration, + _encoded_params: Vec, + _prepare_priority: polkadot_node_core_pvf::Priority, + ) -> Result { + unreachable!() + } + + async fn precheck_pvf(&mut self, _pvf: PvfPrepData) -> Result<(), PrepareError> { + unreachable!() + } + + async fn heads_up(&mut self, _active_pvfs: Vec) -> Result<(), String> { + let _ = self.heads_up_call_count.fetch_add(1, Ordering::SeqCst); + Ok(()) + } +} + +fn alice_keystore() -> KeystorePtr { + let keystore: KeystorePtr = Arc::new(MemoryKeystore::new()); + let _ = Keystore::sr25519_generate_new( + &*keystore, + ValidatorId::ID, + Some(&Sr25519Keyring::Alice.to_seed()), + ) + .unwrap(); + let _ = Keystore::sr25519_generate_new( + &*keystore, + AuthorityDiscoveryId::ID, + Some(&Sr25519Keyring::Alice.to_seed()), + ) + .unwrap(); + + keystore +} + +fn dummy_active_leaves_update(hash: Hash) -> ActiveLeavesUpdate { + ActiveLeavesUpdate { + activated: Some(ActivatedLeaf { + hash, + number: 10, + unpin_handle: polkadot_node_subsystem_test_helpers::mock::dummy_unpin_handle(hash), + span: Arc::new(overseer::jaeger::Span::Disabled), + }), + ..Default::default() + } +} + +fn dummy_candidate_backed( + relay_parent: Hash, + validation_code_hash: ValidationCodeHash, +) -> CandidateEvent { + let zeros = dummy_hash(); + let descriptor = CandidateDescriptor { + para_id: ParaId::from(0_u32), + relay_parent, + collator: dummy_collator(), + persisted_validation_data_hash: zeros, + pov_hash: zeros, + erasure_root: zeros, + signature: dummy_collator_signature(), + para_head: zeros, + validation_code_hash, + }; + + CandidateEvent::CandidateBacked( + CandidateReceipt { descriptor, commitments_hash: zeros }, + HeadData(Vec::new()), + CoreIndex(0), + GroupIndex(0), + ) +} + +fn dummy_session_info(discovery_keys: Vec) -> SessionInfo { + SessionInfo { + validators: IndexedVec::::from(vec![]), + discovery_keys, + assignment_keys: vec![], + validator_groups: Default::default(), + n_cores: 4u32, + zeroth_delay_tranche_width: 0u32, + relay_vrf_modulo_samples: 0u32, + n_delay_tranches: 2u32, + no_show_slots: 0u32, + needed_approvals: 1u32, + active_validator_indices: vec![], + dispute_period: 6, + random_seed: [0u8; 32], + } +} + +#[test] +fn maybe_prepare_validation_golden_path() { + let pool = TaskExecutor::new(); + let (mut ctx, mut ctx_handle) = + polkadot_node_subsystem_test_helpers::make_subsystem_context::(pool); + + let keystore = alice_keystore(); + let backend = MockHeadsUp::default(); + let activated_hash = Hash::random(); + let update = dummy_active_leaves_update(activated_hash); + let mut state = PrepareValidationState::default(); + + let check_fut = + maybe_prepare_validation(ctx.sender(), keystore, backend.clone(), update, &mut state); + + let test_fut = async move { + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))) => { + let _ = tx.send(Ok(1)); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::Authorities(tx))) => { + let _ = tx.send(Ok(vec![Sr25519Keyring::Alice.public().into()])); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionInfo(index, tx))) => { + assert_eq!(index, 1); + let _ = tx.send(Ok(Some(dummy_session_info(vec![Sr25519Keyring::Bob.public().into()])))); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::CandidateEvents(tx))) => { + let _ = tx.send(Ok(vec![dummy_candidate_backed(activated_hash, dummy_hash().into())])); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))) => { + let _ = tx.send(Ok(1)); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(index, tx))) => { + assert_eq!(index, 1); + let _ = tx.send(Ok(Some(ExecutorParams::default()))); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx))) => { + assert_eq!(hash, dummy_hash().into()); + let _ = tx.send(Ok(Some(ValidationCode(Vec::new())))); + } + ); + }; + + let test_fut = future::join(test_fut, check_fut); + executor::block_on(test_fut); + + assert_eq!(backend.heads_up_call_count.load(Ordering::SeqCst), 1); + assert!(state.session_index.is_some()); + assert!(state.is_next_session_authority); +} + +#[test] +fn maybe_prepare_validation_checkes_authority_once_per_session() { + let pool = TaskExecutor::new(); + let (mut ctx, mut ctx_handle) = + polkadot_node_subsystem_test_helpers::make_subsystem_context::(pool); + + let keystore = alice_keystore(); + let backend = MockHeadsUp::default(); + let activated_hash = Hash::random(); + let update = dummy_active_leaves_update(activated_hash); + let mut state = PrepareValidationState { + session_index: Some(1), + is_next_session_authority: false, + ..Default::default() + }; + + let check_fut = + maybe_prepare_validation(ctx.sender(), keystore, backend.clone(), update, &mut state); + + let test_fut = async move { + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))) => { + let _ = tx.send(Ok(1)); + } + ); + }; + + let test_fut = future::join(test_fut, check_fut); + executor::block_on(test_fut); + + assert_eq!(backend.heads_up_call_count.load(Ordering::SeqCst), 0); + assert!(state.session_index.is_some()); + assert!(!state.is_next_session_authority); +} + +#[test] +fn maybe_prepare_validation_resets_state_on_a_new_session() { + let pool = TaskExecutor::new(); + let (mut ctx, mut ctx_handle) = + polkadot_node_subsystem_test_helpers::make_subsystem_context::(pool); + + let keystore = alice_keystore(); + let backend = MockHeadsUp::default(); + let activated_hash = Hash::random(); + let update = dummy_active_leaves_update(activated_hash); + let mut state = PrepareValidationState { + session_index: Some(1), + is_next_session_authority: true, + already_prepared_code_hashes: HashSet::from_iter(vec![ValidationCode(vec![0; 16]).hash()]), + ..Default::default() + }; + + let check_fut = + maybe_prepare_validation(ctx.sender(), keystore, backend.clone(), update, &mut state); + + let test_fut = async move { + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))) => { + let _ = tx.send(Ok(2)); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::Authorities(tx))) => { + let _ = tx.send(Ok(vec![Sr25519Keyring::Bob.public().into()])); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionInfo(index, tx))) => { + assert_eq!(index, 2); + let _ = tx.send(Ok(Some(dummy_session_info(vec![Sr25519Keyring::Bob.public().into()])))); + } + ); + }; + + let test_fut = future::join(test_fut, check_fut); + executor::block_on(test_fut); + + assert_eq!(backend.heads_up_call_count.load(Ordering::SeqCst), 0); + assert_eq!(state.session_index.unwrap(), 2); + assert!(!state.is_next_session_authority); + assert!(state.already_prepared_code_hashes.is_empty()); +} + +#[test] +fn maybe_prepare_validation_does_not_prepare_pvfs_if_no_new_session_and_not_a_validator() { + let pool = TaskExecutor::new(); + let (mut ctx, mut ctx_handle) = + polkadot_node_subsystem_test_helpers::make_subsystem_context::(pool); + + let keystore = alice_keystore(); + let backend = MockHeadsUp::default(); + let activated_hash = Hash::random(); + let update = dummy_active_leaves_update(activated_hash); + let mut state = PrepareValidationState { session_index: Some(1), ..Default::default() }; + + let check_fut = + maybe_prepare_validation(ctx.sender(), keystore, backend.clone(), update, &mut state); + + let test_fut = async move { + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))) => { + let _ = tx.send(Ok(1)); + } + ); + }; + + let test_fut = future::join(test_fut, check_fut); + executor::block_on(test_fut); + + assert_eq!(backend.heads_up_call_count.load(Ordering::SeqCst), 0); + assert!(state.session_index.is_some()); + assert!(!state.is_next_session_authority); +} + +#[test] +fn maybe_prepare_validation_does_not_prepare_pvfs_if_no_new_session_but_a_validator() { + let pool = TaskExecutor::new(); + let (mut ctx, mut ctx_handle) = + polkadot_node_subsystem_test_helpers::make_subsystem_context::(pool); + + let keystore = alice_keystore(); + let backend = MockHeadsUp::default(); + let activated_hash = Hash::random(); + let update = dummy_active_leaves_update(activated_hash); + let mut state = PrepareValidationState { + session_index: Some(1), + is_next_session_authority: true, + ..Default::default() + }; + + let check_fut = + maybe_prepare_validation(ctx.sender(), keystore, backend.clone(), update, &mut state); + + let test_fut = async move { + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))) => { + let _ = tx.send(Ok(1)); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::CandidateEvents(tx))) => { + let _ = tx.send(Ok(vec![dummy_candidate_backed(activated_hash, dummy_hash().into())])); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))) => { + let _ = tx.send(Ok(1)); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(index, tx))) => { + assert_eq!(index, 1); + let _ = tx.send(Ok(Some(ExecutorParams::default()))); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx))) => { + assert_eq!(hash, dummy_hash().into()); + let _ = tx.send(Ok(Some(ValidationCode(Vec::new())))); + } + ); + }; + + let test_fut = future::join(test_fut, check_fut); + executor::block_on(test_fut); + + assert_eq!(backend.heads_up_call_count.load(Ordering::SeqCst), 1); + assert!(state.session_index.is_some()); + assert!(state.is_next_session_authority); +} + +#[test] +fn maybe_prepare_validation_does_not_prepare_pvfs_if_not_a_validator_in_the_next_session() { + let pool = TaskExecutor::new(); + let (mut ctx, mut ctx_handle) = + polkadot_node_subsystem_test_helpers::make_subsystem_context::(pool); + + let keystore = alice_keystore(); + let backend = MockHeadsUp::default(); + let activated_hash = Hash::random(); + let update = dummy_active_leaves_update(activated_hash); + let mut state = PrepareValidationState::default(); + + let check_fut = + maybe_prepare_validation(ctx.sender(), keystore, backend.clone(), update, &mut state); + + let test_fut = async move { + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))) => { + let _ = tx.send(Ok(1)); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::Authorities(tx))) => { + let _ = tx.send(Ok(vec![Sr25519Keyring::Bob.public().into()])); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionInfo(index, tx))) => { + assert_eq!(index, 1); + let _ = tx.send(Ok(Some(dummy_session_info(vec![Sr25519Keyring::Bob.public().into()])))); + } + ); + }; + + let test_fut = future::join(test_fut, check_fut); + executor::block_on(test_fut); + + assert_eq!(backend.heads_up_call_count.load(Ordering::SeqCst), 0); + assert!(state.session_index.is_some()); + assert!(!state.is_next_session_authority); +} + +#[test] +fn maybe_prepare_validation_does_not_prepare_pvfs_if_a_validator_in_the_current_session() { + let pool = TaskExecutor::new(); + let (mut ctx, mut ctx_handle) = + polkadot_node_subsystem_test_helpers::make_subsystem_context::(pool); + + let keystore = alice_keystore(); + let backend = MockHeadsUp::default(); + let activated_hash = Hash::random(); + let update = dummy_active_leaves_update(activated_hash); + let mut state = PrepareValidationState::default(); + + let check_fut = + maybe_prepare_validation(ctx.sender(), keystore, backend.clone(), update, &mut state); + + let test_fut = async move { + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))) => { + let _ = tx.send(Ok(1)); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::Authorities(tx))) => { + let _ = tx.send(Ok(vec![Sr25519Keyring::Alice.public().into()])); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionInfo(index, tx))) => { + assert_eq!(index, 1); + let _ = tx.send(Ok(Some(dummy_session_info(vec![Sr25519Keyring::Alice.public().into()])))); + } + ); + }; + + let test_fut = future::join(test_fut, check_fut); + executor::block_on(test_fut); + + assert_eq!(backend.heads_up_call_count.load(Ordering::SeqCst), 0); + assert!(state.session_index.is_some()); + assert!(!state.is_next_session_authority); +} + +#[test] +fn maybe_prepare_validation_prepares_a_limited_number_of_pvfs() { + let pool = TaskExecutor::new(); + let (mut ctx, mut ctx_handle) = + polkadot_node_subsystem_test_helpers::make_subsystem_context::(pool); + + let keystore = alice_keystore(); + let backend = MockHeadsUp::default(); + let activated_hash = Hash::random(); + let update = dummy_active_leaves_update(activated_hash); + let mut state = PrepareValidationState { per_block_limit: 2, ..Default::default() }; + + let check_fut = + maybe_prepare_validation(ctx.sender(), keystore, backend.clone(), update, &mut state); + + let test_fut = async move { + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))) => { + let _ = tx.send(Ok(1)); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::Authorities(tx))) => { + let _ = tx.send(Ok(vec![Sr25519Keyring::Alice.public().into()])); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionInfo(index, tx))) => { + assert_eq!(index, 1); + let _ = tx.send(Ok(Some(dummy_session_info(vec![Sr25519Keyring::Bob.public().into()])))); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::CandidateEvents(tx))) => { + let candidates = vec![ + dummy_candidate_backed(activated_hash, ValidationCode(vec![0; 16]).hash()), + dummy_candidate_backed(activated_hash, ValidationCode(vec![1; 16]).hash()), + dummy_candidate_backed(activated_hash, ValidationCode(vec![2; 16]).hash()), + ]; + let _ = tx.send(Ok(candidates)); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))) => { + let _ = tx.send(Ok(1)); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(index, tx))) => { + assert_eq!(index, 1); + let _ = tx.send(Ok(Some(ExecutorParams::default()))); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx))) => { + assert_eq!(hash, ValidationCode(vec![0; 16]).hash()); + let _ = tx.send(Ok(Some(ValidationCode(Vec::new())))); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx))) => { + assert_eq!(hash, ValidationCode(vec![1; 16]).hash()); + let _ = tx.send(Ok(Some(ValidationCode(Vec::new())))); + } + ); + }; + + let test_fut = future::join(test_fut, check_fut); + executor::block_on(test_fut); + + assert_eq!(backend.heads_up_call_count.load(Ordering::SeqCst), 1); + assert!(state.session_index.is_some()); + assert!(state.is_next_session_authority); + assert_eq!(state.already_prepared_code_hashes.len(), 2); +} + +#[test] +fn maybe_prepare_validation_does_not_prepare_already_prepared_pvfs() { + let pool = TaskExecutor::new(); + let (mut ctx, mut ctx_handle) = + polkadot_node_subsystem_test_helpers::make_subsystem_context::(pool); + + let keystore = alice_keystore(); + let backend = MockHeadsUp::default(); + let activated_hash = Hash::random(); + let update = dummy_active_leaves_update(activated_hash); + let mut state = PrepareValidationState { + session_index: Some(1), + is_next_session_authority: true, + per_block_limit: 2, + already_prepared_code_hashes: HashSet::from_iter(vec![ + ValidationCode(vec![0; 16]).hash(), + ValidationCode(vec![1; 16]).hash(), + ]), + }; + + let check_fut = + maybe_prepare_validation(ctx.sender(), keystore, backend.clone(), update, &mut state); + + let test_fut = async move { + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))) => { + let _ = tx.send(Ok(1)); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::CandidateEvents(tx))) => { + let candidates = vec![ + dummy_candidate_backed(activated_hash, ValidationCode(vec![0; 16]).hash()), + dummy_candidate_backed(activated_hash, ValidationCode(vec![1; 16]).hash()), + dummy_candidate_backed(activated_hash, ValidationCode(vec![2; 16]).hash()), + ]; + let _ = tx.send(Ok(candidates)); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))) => { + let _ = tx.send(Ok(1)); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(index, tx))) => { + assert_eq!(index, 1); + let _ = tx.send(Ok(Some(ExecutorParams::default()))); + } + ); + + assert_matches!( + ctx_handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx))) => { + assert_eq!(hash, ValidationCode(vec![2; 16]).hash()); + let _ = tx.send(Ok(Some(ValidationCode(Vec::new())))); + } + ); + }; + + let test_fut = future::join(test_fut, check_fut); + executor::block_on(test_fut); + + assert_eq!(backend.heads_up_call_count.load(Ordering::SeqCst), 1); + assert!(state.session_index.is_some()); + assert!(state.is_next_session_authority); + assert_eq!(state.already_prepared_code_hashes.len(), 3); +} diff --git a/polkadot/node/core/chain-api/Cargo.toml b/polkadot/node/core/chain-api/Cargo.toml index c58024876b9c77c371b9325c9da922a21211e698..a8e911e0c5c9586c31109462e1a9527c9d8246f2 100644 --- a/polkadot/node/core/chain-api/Cargo.toml +++ b/polkadot/node/core/chain-api/Cargo.toml @@ -10,20 +10,20 @@ description = "The Chain API subsystem provides access to chain related utility workspace = true [dependencies] -futures = "0.3.30" -gum = { package = "tracing-gum", path = "../../gum" } -polkadot-node-metrics = { path = "../../metrics" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-subsystem-types = { path = "../../subsystem-types" } -sc-client-api = { path = "../../../../substrate/client/api" } -sc-consensus-babe = { path = "../../../../substrate/client/consensus/babe" } +futures = { workspace = true } +gum = { workspace = true, default-features = true } +polkadot-node-metrics = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-types = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-consensus-babe = { workspace = true, default-features = true } [dev-dependencies] -futures = { version = "0.3.30", features = ["thread-pool"] } -maplit = "1.0.2" -codec = { package = "parity-scale-codec", version = "3.6.12" } -polkadot-node-primitives = { path = "../../primitives" } -polkadot-primitives = { path = "../../../primitives" } -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-blockchain = { path = "../../../../substrate/primitives/blockchain" } +futures = { features = ["thread-pool"], workspace = true } +maplit = { workspace = true } +codec = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem-test-helpers = { workspace = true } +sp-core = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } diff --git a/polkadot/node/core/chain-selection/Cargo.toml b/polkadot/node/core/chain-selection/Cargo.toml index 2aa929653ccc2a2fa07b16a7ad0a4ada025afb5a..755d5cadeaaf388a4e21eff79699ae06368e8010 100644 --- a/polkadot/node/core/chain-selection/Cargo.toml +++ b/polkadot/node/core/chain-selection/Cargo.toml @@ -10,20 +10,20 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.30" -futures-timer = "3" -gum = { package = "tracing-gum", path = "../../gum" } -polkadot-primitives = { path = "../../../primitives" } -polkadot-node-primitives = { path = "../../primitives" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } -kvdb = "0.13.0" +futures = { workspace = true } +futures-timer = { workspace = true } +gum = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +kvdb = { workspace = true } thiserror = { workspace = true } -codec = { package = "parity-scale-codec", version = "3.6.12" } +codec = { workspace = true, default-features = true } [dev-dependencies] -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -sp-core = { path = "../../../../substrate/primitives/core" } -parking_lot = "0.12.1" -assert_matches = "1" -kvdb-memorydb = "0.13.0" +polkadot-node-subsystem-test-helpers = { workspace = true } +sp-core = { workspace = true, default-features = true } +parking_lot = { workspace = true, default-features = true } +assert_matches = { workspace = true } +kvdb-memorydb = { workspace = true } diff --git a/polkadot/node/core/dispute-coordinator/Cargo.toml b/polkadot/node/core/dispute-coordinator/Cargo.toml index 2c08cfa9b1efa623ae157c6fd60f10c9330d30d2..eb4600b235b9f2cfde8f030ebb3b9626d6ea8869 100644 --- a/polkadot/node/core/dispute-coordinator/Cargo.toml +++ b/polkadot/node/core/dispute-coordinator/Cargo.toml @@ -10,33 +10,33 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.30" -gum = { package = "tracing-gum", path = "../../gum" } -codec = { package = "parity-scale-codec", version = "3.6.12" } -kvdb = "0.13.0" +futures = { workspace = true } +gum = { workspace = true, default-features = true } +codec = { workspace = true, default-features = true } +kvdb = { workspace = true } thiserror = { workspace = true } -schnellru = "0.2.1" -fatality = "0.1.1" +schnellru = { workspace = true } +fatality = { workspace = true } -polkadot-primitives = { path = "../../../primitives" } -polkadot-node-primitives = { path = "../../primitives" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } -sc-keystore = { path = "../../../../substrate/client/keystore" } +sc-keystore = { workspace = true, default-features = true } [dev-dependencies] -kvdb-memorydb = "0.13.0" -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-keystore = { path = "../../../../substrate/primitives/keystore" } -assert_matches = "1.4.0" -polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } -futures-timer = "3.0.2" -sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto" } -sp-tracing = { path = "../../../../substrate/primitives/tracing" } +kvdb-memorydb = { workspace = true } +polkadot-node-subsystem-test-helpers = { workspace = true } +sp-keyring = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +assert_matches = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } +futures-timer = { workspace = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } [features] # If not enabled, the dispute coordinator will do nothing. diff --git a/polkadot/node/core/parachains-inherent/Cargo.toml b/polkadot/node/core/parachains-inherent/Cargo.toml index 4f6090f90e9535a7cee8da2e333d5e66a0dea972..1e4953f40d0bd87bd5ef69bf3b91b66935e90fdc 100644 --- a/polkadot/node/core/parachains-inherent/Cargo.toml +++ b/polkadot/node/core/parachains-inherent/Cargo.toml @@ -10,13 +10,13 @@ description = "Parachains inherent data provider for Polkadot node" workspace = true [dependencies] -futures = "0.3.30" -futures-timer = "3.0.2" -gum = { package = "tracing-gum", path = "../../gum" } +futures = { workspace = true } +futures-timer = { workspace = true } +gum = { workspace = true, default-features = true } thiserror = { workspace = true } -async-trait = "0.1.79" -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-overseer = { path = "../../overseer" } -polkadot-primitives = { path = "../../../primitives" } -sp-blockchain = { path = "../../../../substrate/primitives/blockchain" } -sp-inherents = { path = "../../../../substrate/primitives/inherents" } +async-trait = { workspace = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-overseer = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } diff --git a/polkadot/node/core/prospective-parachains/Cargo.toml b/polkadot/node/core/prospective-parachains/Cargo.toml index b9573ee9851908fdcb77bc44bd21a83566ecaeb5..97da5a1e94a07947765ddc8311b23c8d03cb4f79 100644 --- a/polkadot/node/core/prospective-parachains/Cargo.toml +++ b/polkadot/node/core/prospective-parachains/Cargo.toml @@ -10,26 +10,26 @@ description = "The Prospective Parachains subsystem. Tracks and handles prospect workspace = true [dependencies] -futures = "0.3.30" -gum = { package = "tracing-gum", path = "../../gum" } -codec = { package = "parity-scale-codec", version = "3.6.12" } +futures = { workspace = true } +gum = { workspace = true, default-features = true } +codec = { workspace = true, default-features = true } thiserror = { workspace = true } -fatality = "0.1.1" -bitvec = "1" +fatality = { workspace = true } +bitvec = { workspace = true, default-features = true } -polkadot-primitives = { path = "../../../primitives" } -polkadot-node-primitives = { path = "../../primitives" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } [dev-dependencies] -assert_matches = "1" -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -polkadot-node-subsystem-types = { path = "../../subsystem-types" } -polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } -sp-core = { path = "../../../../substrate/primitives/core" } -sc-keystore = { path = "../../../../substrate/client/keystore" } -sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto" } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -sp-keystore = { path = "../../../../substrate/primitives/keystore" } -rstest = "0.18.2" +assert_matches = { workspace = true } +polkadot-node-subsystem-test-helpers = { workspace = true } +polkadot-node-subsystem-types = { workspace = true, default-features = true } +polkadot-primitives-test-helpers = { workspace = true } +sp-core = { workspace = true, default-features = true } +sc-keystore = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +rstest = { workspace = true } diff --git a/polkadot/node/core/prospective-parachains/src/fragment_chain/mod.rs b/polkadot/node/core/prospective-parachains/src/fragment_chain/mod.rs index f87d4820ff9af242bf28ca7170527ec72d1963b8..b5fe70e7692345c62fd98644f6ecf9570d7a8b67 100644 --- a/polkadot/node/core/prospective-parachains/src/fragment_chain/mod.rs +++ b/polkadot/node/core/prospective-parachains/src/fragment_chain/mod.rs @@ -160,8 +160,6 @@ impl CandidateStorage { state, candidate: Arc::new(ProspectiveCandidate { commitments: candidate.commitments, - collator: candidate.descriptor.collator, - collator_signature: candidate.descriptor.signature, persisted_validation_data, pov_hash: candidate.descriptor.pov_hash, validation_code_hash: candidate.descriptor.validation_code_hash, diff --git a/polkadot/node/core/provisioner/Cargo.toml b/polkadot/node/core/provisioner/Cargo.toml index a81d22c6f82838c2d446a7d8cd0997013f161fa3..5869e494c70ff40365397d3ffa104f5bad6c421e 100644 --- a/polkadot/node/core/provisioner/Cargo.toml +++ b/polkadot/node/core/provisioner/Cargo.toml @@ -10,21 +10,21 @@ license.workspace = true workspace = true [dependencies] -bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } -futures = "0.3.30" -gum = { package = "tracing-gum", path = "../../gum" } +bitvec = { features = ["alloc"], workspace = true } +futures = { workspace = true } +gum = { workspace = true, default-features = true } thiserror = { workspace = true } -polkadot-primitives = { path = "../../../primitives" } -polkadot-node-primitives = { path = "../../primitives" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } -futures-timer = "3.0.2" -fatality = "0.1.1" -schnellru = "0.2.1" +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +futures-timer = { workspace = true } +fatality = { workspace = true } +schnellru = { workspace = true } [dev-dependencies] -sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto" } -sp-keystore = { path = "../../../../substrate/primitives/keystore" } -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } -rstest = "0.18.2" +sp-application-crypto = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +polkadot-node-subsystem-test-helpers = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } +rstest = { workspace = true } diff --git a/polkadot/node/core/provisioner/src/lib.rs b/polkadot/node/core/provisioner/src/lib.rs index fa16b38d28bda4e364c5b6d8b74bb85ca727036d..3f622a60a059bbdb3062a90bd93d2661ad96d326 100644 --- a/polkadot/node/core/provisioner/src/lib.rs +++ b/polkadot/node/core/provisioner/src/lib.rs @@ -822,7 +822,7 @@ async fn select_candidates( // now get the backed candidates corresponding to these candidate receipts let (tx, rx) = oneshot::channel(); - sender.send_unbounded_message(CandidateBackingMessage::GetBackedCandidates( + sender.send_unbounded_message(CandidateBackingMessage::GetBackableCandidates( selected_candidates.clone(), tx, )); diff --git a/polkadot/node/core/provisioner/src/tests.rs b/polkadot/node/core/provisioner/src/tests.rs index 0d3675777cbf4ad0ef6620ae05b1b0bdab11cdb9..b38459302c8f18721b4ceb0515fdeac3d116cea8 100644 --- a/polkadot/node/core/provisioner/src/tests.rs +++ b/polkadot/node/core/provisioner/src/tests.rs @@ -578,7 +578,7 @@ mod select_candidates { )) => tx.send(Ok(Some(Default::default()))).unwrap(), AllMessages::RuntimeApi(Request(_parent_hash, AvailabilityCores(tx))) => tx.send(Ok(mock_availability_cores.clone())).unwrap(), - AllMessages::CandidateBacking(CandidateBackingMessage::GetBackedCandidates( + AllMessages::CandidateBacking(CandidateBackingMessage::GetBackableCandidates( hashes, sender, )) => { diff --git a/polkadot/node/core/pvf-checker/Cargo.toml b/polkadot/node/core/pvf-checker/Cargo.toml index 6dec407e2d2d1f91bcdf72b73b1db376dcdd07d5..73ef17a2843aedcffc40c6456d5519e62265b605 100644 --- a/polkadot/node/core/pvf-checker/Cargo.toml +++ b/polkadot/node/core/pvf-checker/Cargo.toml @@ -10,24 +10,24 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.30" +futures = { workspace = true } thiserror = { workspace = true } -gum = { package = "tracing-gum", path = "../../gum" } +gum = { workspace = true, default-features = true } -polkadot-node-primitives = { path = "../../primitives" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-primitives = { path = "../../../primitives" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } -polkadot-overseer = { path = "../../overseer" } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-overseer = { workspace = true, default-features = true } -sp-keystore = { path = "../../../../substrate/primitives/keystore" } +sp-keystore = { workspace = true, default-features = true } [dev-dependencies] -sp-core = { path = "../../../../substrate/primitives/core" } -sp-runtime = { path = "../../../../substrate/primitives/runtime" } -sc-keystore = { path = "../../../../substrate/client/keystore" } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } -sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto" } -futures-timer = "3.0.2" +sp-core = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sc-keystore = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +polkadot-node-subsystem-test-helpers = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } +sp-application-crypto = { workspace = true, default-features = true } +futures-timer = { workspace = true } diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index 8aebe0b4c3f0c3875781ed537eadd4887ccf856b..d603af04bf061fc16dfb00979e3aaf85b21adb60 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -10,60 +10,60 @@ license.workspace = true workspace = true [dependencies] -always-assert = "0.1" -array-bytes = "6.2.2" -blake3 = "1.5" -cfg-if = "1.0" -futures = "0.3.30" -futures-timer = "3.0.2" -gum = { package = "tracing-gum", path = "../../gum" } -is_executable = { version = "1.0.1", optional = true } -pin-project = "1.0.9" -rand = "0.8.5" -slotmap = "1.0" -tempfile = "3.3.0" +always-assert = { workspace = true } +array-bytes = { workspace = true, default-features = true } +blake3 = { workspace = true } +cfg-if = { workspace = true } +futures = { workspace = true } +futures-timer = { workspace = true } +gum = { workspace = true, default-features = true } +is_executable = { optional = true, workspace = true } +pin-project = { workspace = true } +rand = { workspace = true, default-features = true } +slotmap = { workspace = true } +tempfile = { workspace = true } thiserror = { workspace = true } -tokio = { version = "1.24.2", features = ["fs", "process"] } +tokio = { features = ["fs", "process"], workspace = true, default-features = true } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ +codec = { features = [ "derive", -] } +], workspace = true } -polkadot-parachain-primitives = { path = "../../../parachain" } -polkadot-core-primitives = { path = "../../../core-primitives" } -polkadot-node-core-pvf-common = { path = "common" } -polkadot-node-metrics = { path = "../../metrics" } -polkadot-node-primitives = { path = "../../primitives" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-primitives = { path = "../../../primitives" } +polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-core-primitives = { workspace = true, default-features = true } +polkadot-node-core-pvf-common = { workspace = true, default-features = true } +polkadot-node-metrics = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-maybe-compressed-blob = { path = "../../../../substrate/primitives/maybe-compressed-blob", optional = true } -polkadot-node-core-pvf-prepare-worker = { path = "prepare-worker", optional = true } -polkadot-node-core-pvf-execute-worker = { path = "execute-worker", optional = true } +sp-core = { workspace = true, default-features = true } +sp-maybe-compressed-blob = { optional = true, workspace = true, default-features = true } +polkadot-node-core-pvf-prepare-worker = { optional = true, workspace = true, default-features = true } +polkadot-node-core-pvf-execute-worker = { optional = true, workspace = true, default-features = true } [dev-dependencies] -assert_matches = "1.4.0" -criterion = { version = "0.5.1", default-features = false, features = [ +assert_matches = { workspace = true } +criterion = { features = [ "async_tokio", "cargo_bench_support", -] } -hex-literal = "0.4.1" +], workspace = true } +hex-literal = { workspace = true, default-features = true } -polkadot-node-core-pvf-common = { path = "common", features = ["test-utils"] } +polkadot-node-core-pvf-common = { features = ["test-utils"], workspace = true, default-features = true } # For benches and integration tests, depend on ourselves with the test-utils # feature. -polkadot-node-core-pvf = { path = "", features = ["test-utils"] } -rococo-runtime = { path = "../../../runtime/rococo" } +polkadot-node-core-pvf = { features = ["test-utils"], workspace = true, default-features = true } +rococo-runtime = { workspace = true } -test-parachain-adder = { path = "../../../parachain/test-parachains/adder" } -test-parachain-halt = { path = "../../../parachain/test-parachains/halt" } +test-parachain-adder = { workspace = true } +test-parachain-halt = { workspace = true } [target.'cfg(target_os = "linux")'.dev-dependencies] -libc = "0.2.153" +libc = "0.2.155" procfs = "0.16.0" rusty-fork = "0.3.0" -sc-sysinfo = { path = "../../../../substrate/client/sysinfo" } +sc-sysinfo = { workspace = true, default-features = true } [[bench]] name = "host_prepare_rococo_runtime" diff --git a/polkadot/node/core/pvf/common/Cargo.toml b/polkadot/node/core/pvf/common/Cargo.toml index 491f6cc49642cb3202f87bf189e7467cfb607230..18b3f959c95513763addc9ddf4ff82783e5c1a02 100644 --- a/polkadot/node/core/pvf/common/Cargo.toml +++ b/polkadot/node/core/pvf/common/Cargo.toml @@ -10,29 +10,29 @@ license.workspace = true workspace = true [dependencies] -cpu-time = "1.0.0" -futures = "0.3.30" -gum = { package = "tracing-gum", path = "../../../gum" } -libc = "0.2.152" -nix = { version = "0.28.0", features = ["resource", "sched"] } +cpu-time = { workspace = true } +futures = { workspace = true } +gum = { workspace = true, default-features = true } +libc = { workspace = true } +nix = { features = ["resource", "sched"], workspace = true } thiserror = { workspace = true } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ +codec = { features = [ "derive", -] } +], workspace = true } -polkadot-parachain-primitives = { path = "../../../../parachain" } -polkadot-primitives = { path = "../../../../primitives" } +polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } -sc-executor = { path = "../../../../../substrate/client/executor" } -sc-executor-common = { path = "../../../../../substrate/client/executor/common" } -sc-executor-wasmtime = { path = "../../../../../substrate/client/executor/wasmtime" } +sc-executor = { workspace = true, default-features = true } +sc-executor-common = { workspace = true, default-features = true } +sc-executor-wasmtime = { workspace = true, default-features = true } -sp-core = { path = "../../../../../substrate/primitives/core" } -sp-crypto-hashing = { path = "../../../../../substrate/primitives/crypto/hashing" } -sp-externalities = { path = "../../../../../substrate/primitives/externalities" } -sp-io = { path = "../../../../../substrate/primitives/io" } -sp-tracing = { path = "../../../../../substrate/primitives/tracing" } +sp-core = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true, default-features = true } +sp-externalities = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } [target.'cfg(target_os = "linux")'.dependencies] landlock = "0.3.0" @@ -41,8 +41,8 @@ landlock = "0.3.0" seccompiler = "0.4.0" [dev-dependencies] -assert_matches = "1.4.0" -tempfile = "3.3.0" +assert_matches = { workspace = true } +tempfile = { workspace = true } [features] # This feature is used to export test code to other crates without putting it in the production build. diff --git a/polkadot/node/core/pvf/execute-worker/Cargo.toml b/polkadot/node/core/pvf/execute-worker/Cargo.toml index cf5b873e29d771e3806c8ec3085a7385b0d59b0b..f24b66dc4a0e8ba20f6b7a8205c7092a47c30245 100644 --- a/polkadot/node/core/pvf/execute-worker/Cargo.toml +++ b/polkadot/node/core/pvf/execute-worker/Cargo.toml @@ -10,17 +10,17 @@ license.workspace = true workspace = true [dependencies] -cpu-time = "1.0.0" -gum = { package = "tracing-gum", path = "../../../gum" } -cfg-if = "1.0" -nix = { version = "0.28.0", features = ["process", "resource", "sched"] } -libc = "0.2.152" +cpu-time = { workspace = true } +gum = { workspace = true, default-features = true } +cfg-if = { workspace = true } +nix = { features = ["process", "resource", "sched"], workspace = true } +libc = { workspace = true } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } -polkadot-node-core-pvf-common = { path = "../common" } -polkadot-parachain-primitives = { path = "../../../../parachain" } -polkadot-primitives = { path = "../../../../primitives" } +polkadot-node-core-pvf-common = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } [features] builder = [] diff --git a/polkadot/node/core/pvf/prepare-worker/Cargo.toml b/polkadot/node/core/pvf/prepare-worker/Cargo.toml index f7daa0d7a89c3e65b3e6dee9ad3bcbe1e9ecf60e..9e0d01fc438b0257b87b9bf6791f466d8691049e 100644 --- a/polkadot/node/core/pvf/prepare-worker/Cargo.toml +++ b/polkadot/node/core/pvf/prepare-worker/Cargo.toml @@ -10,23 +10,23 @@ license.workspace = true workspace = true [dependencies] -blake3 = "1.5" -cfg-if = "1.0" -gum = { package = "tracing-gum", path = "../../../gum" } -libc = "0.2.152" -rayon = "1.5.1" -tracking-allocator = { package = "staging-tracking-allocator", path = "../../../tracking-allocator" } -tikv-jemalloc-ctl = { version = "0.5.0", optional = true } -tikv-jemallocator = { version = "0.5.0", optional = true } -nix = { version = "0.28.0", features = ["process", "resource", "sched"] } +blake3 = { workspace = true } +cfg-if = { workspace = true } +gum = { workspace = true, default-features = true } +libc = { workspace = true } +rayon = { workspace = true } +tracking-allocator = { workspace = true, default-features = true } +tikv-jemalloc-ctl = { optional = true, workspace = true } +tikv-jemallocator = { optional = true, workspace = true } +nix = { features = ["process", "resource", "sched"], workspace = true } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } -polkadot-node-core-pvf-common = { path = "../common" } -polkadot-primitives = { path = "../../../../primitives" } +polkadot-node-core-pvf-common = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } -sc-executor-common = { path = "../../../../../substrate/client/executor/common" } -sc-executor-wasmtime = { path = "../../../../../substrate/client/executor/wasmtime" } +sc-executor-common = { workspace = true, default-features = true } +sc-executor-wasmtime = { workspace = true, default-features = true } [target.'cfg(target_os = "linux")'.dependencies] tikv-jemallocator = "0.5.0" @@ -41,9 +41,9 @@ jemalloc-allocator = [ ] [dev-dependencies] -criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } -rococo-runtime = { path = "../../../../runtime/rococo" } -sp-maybe-compressed-blob = { path = "../../../../../substrate/primitives/maybe-compressed-blob" } +criterion = { features = ["cargo_bench_support"], workspace = true } +rococo-runtime = { workspace = true } +sp-maybe-compressed-blob = { workspace = true, default-features = true } [[bench]] name = "prepare_rococo_runtime" diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index d62a1aef230990057c5c408a840f51bc66a5029f..9ad486657512c7a6dda6c3b907500c074aef7433 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -523,20 +523,17 @@ async fn prepare_can_run_serially() { #[cfg(all(feature = "ci-only-tests", target_os = "linux"))] #[tokio::test] async fn all_security_features_work() { - // Landlock is only available starting Linux 5.13, and we may be testing on an old kernel. let can_enable_landlock = { - let sysinfo = sc_sysinfo::gather_sysinfo(); - // The version will look something like "5.15.0-87-generic". - let version = sysinfo.linux_kernel.unwrap(); - let version_split: Vec<&str> = version.split(".").collect(); - let major: u32 = version_split[0].parse().unwrap(); - let minor: u32 = version_split[1].parse().unwrap(); - if major >= 6 { - true - } else if major == 5 { - minor >= 13 + let res = unsafe { libc::syscall(libc::SYS_landlock_create_ruleset, 0usize, 0usize, 1u32) }; + if res == -1 { + let err = std::io::Error::last_os_error().raw_os_error().unwrap(); + if err == libc::ENOSYS { + false + } else { + panic!("Unexpected errno from landlock check: {err}"); + } } else { - false + true } }; diff --git a/polkadot/node/core/runtime-api/Cargo.toml b/polkadot/node/core/runtime-api/Cargo.toml index 5524cc705457e45e18e6ea9919c567bf796225c7..834e4b300b9eba67c4764ac60e00261b66215250 100644 --- a/polkadot/node/core/runtime-api/Cargo.toml +++ b/polkadot/node/core/runtime-api/Cargo.toml @@ -10,23 +10,23 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.30" -gum = { package = "tracing-gum", path = "../../gum" } -schnellru = "0.2.1" +futures = { workspace = true } +gum = { workspace = true, default-features = true } +schnellru = { workspace = true } -sp-consensus-babe = { path = "../../../../substrate/primitives/consensus/babe" } +sp-consensus-babe = { workspace = true, default-features = true } -polkadot-primitives = { path = "../../../primitives" } -polkadot-node-metrics = { path = "../../metrics" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-subsystem-types = { path = "../../subsystem-types" } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-metrics = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-types = { workspace = true, default-features = true } [dev-dependencies] -sp-api = { path = "../../../../substrate/primitives/api" } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -async-trait = "0.1.79" -futures = { version = "0.3.30", features = ["thread-pool"] } -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -polkadot-node-primitives = { path = "../../primitives" } -polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } +sp-api = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +async-trait = { workspace = true } +futures = { features = ["thread-pool"], workspace = true } +polkadot-node-subsystem-test-helpers = { workspace = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-primitives-test-helpers = { workspace = true } diff --git a/polkadot/node/gum/Cargo.toml b/polkadot/node/gum/Cargo.toml index 0d887b9be5394c6b36f882d60f57d4ee2d9bf8eb..9b2df435a06a90e4cb0561e19ce4a85dd281b127 100644 --- a/polkadot/node/gum/Cargo.toml +++ b/polkadot/node/gum/Cargo.toml @@ -10,7 +10,7 @@ description = "Stick logs together with the TraceID as provided by tempo" workspace = true [dependencies] -coarsetime = "0.1.22" -tracing = "0.1.35" -gum-proc-macro = { package = "tracing-gum-proc-macro", path = "proc-macro" } -polkadot-primitives = { path = "../../primitives", features = ["std"] } +coarsetime = { workspace = true } +tracing = { workspace = true, default-features = true } +gum-proc-macro = { workspace = true, default-features = true } +polkadot-primitives = { features = ["std"], workspace = true, default-features = true } diff --git a/polkadot/node/gum/proc-macro/Cargo.toml b/polkadot/node/gum/proc-macro/Cargo.toml index 70126b4f43367ce11a1a23d462392b513ca1c028..da6364977cae25f16e8605f8024dc96aa86f6120 100644 --- a/polkadot/node/gum/proc-macro/Cargo.toml +++ b/polkadot/node/gum/proc-macro/Cargo.toml @@ -18,12 +18,12 @@ proc-macro = true [dependencies] syn = { features = ["extra-traits", "full"], workspace = true } quote = { workspace = true } -proc-macro2 = "1.0.56" -proc-macro-crate = "3.0.0" -expander = "2.0.0" +proc-macro2 = { workspace = true } +proc-macro-crate = { workspace = true } +expander = { workspace = true } [dev-dependencies] -assert_matches = "1.5.0" +assert_matches = { workspace = true } [features] diff --git a/polkadot/node/jaeger/Cargo.toml b/polkadot/node/jaeger/Cargo.toml index 18b0c417aaf3d5798d81b8a2d4b11e4ddcc5f5fc..90a6c80e3d0bd3ab2567933bf94d89b7a00dc1e9 100644 --- a/polkadot/node/jaeger/Cargo.toml +++ b/polkadot/node/jaeger/Cargo.toml @@ -10,15 +10,15 @@ description = "Polkadot Jaeger primitives, but equally useful for Grafana/Tempo" workspace = true [dependencies] -mick-jaeger = "0.1.8" -lazy_static = "1.4" -parking_lot = "0.12.1" -polkadot-primitives = { path = "../../primitives" } -polkadot-node-primitives = { path = "../primitives" } -sc-network = { path = "../../../substrate/client/network" } -sc-network-types = { path = "../../../substrate/client/network/types" } -sp-core = { path = "../../../substrate/primitives/core" } +mick-jaeger = { workspace = true } +lazy_static = { workspace = true } +parking_lot = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-network-types = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } thiserror = { workspace = true } -tokio = "1.37" +tokio = { workspace = true, default-features = true } log = { workspace = true, default-features = true } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } +codec = { workspace = true } diff --git a/polkadot/node/malus/Cargo.toml b/polkadot/node/malus/Cargo.toml index fec148f7d38150936d733dfadf2030f1eea2c76c..49434606a61c8dff08a7c075c06c998cc8395a5b 100644 --- a/polkadot/node/malus/Cargo.toml +++ b/polkadot/node/malus/Cargo.toml @@ -29,40 +29,40 @@ path = "../../src/bin/prepare-worker.rs" doc = false [dependencies] -polkadot-cli = { path = "../../cli", features = ["malus", "rococo-native", "westend-native"] } -polkadot-node-subsystem = { path = "../subsystem" } -polkadot-node-subsystem-util = { path = "../subsystem-util" } -polkadot-node-subsystem-types = { path = "../subsystem-types" } -polkadot-node-core-dispute-coordinator = { path = "../core/dispute-coordinator" } -polkadot-node-core-candidate-validation = { path = "../core/candidate-validation" } -polkadot-node-core-backing = { path = "../core/backing" } -polkadot-node-primitives = { path = "../primitives" } -polkadot-node-network-protocol = { path = "../network/protocol" } -polkadot-primitives = { path = "../../primitives" } -color-eyre = { version = "0.6.1", default-features = false } -assert_matches = "1.5" -async-trait = "0.1.79" -sp-keystore = { path = "../../../substrate/primitives/keystore" } -sp-core = { path = "../../../substrate/primitives/core" } -clap = { version = "4.5.3", features = ["derive"] } -futures = "0.3.30" -futures-timer = "3.0.2" -gum = { package = "tracing-gum", path = "../gum" } -polkadot-erasure-coding = { path = "../../erasure-coding" } -rand = "0.8.5" +polkadot-cli = { features = ["malus", "rococo-native", "westend-native"], workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-node-subsystem-types = { workspace = true, default-features = true } +polkadot-node-core-dispute-coordinator = { workspace = true, default-features = true } +polkadot-node-core-candidate-validation = { workspace = true, default-features = true } +polkadot-node-core-backing = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +color-eyre = { workspace = true } +assert_matches = { workspace = true } +async-trait = { workspace = true } +sp-keystore = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +clap = { features = ["derive"], workspace = true } +futures = { workspace = true } +futures-timer = { workspace = true } +gum = { workspace = true, default-features = true } +polkadot-erasure-coding = { workspace = true, default-features = true } +rand = { workspace = true, default-features = true } # Required for worker binaries to build. -polkadot-node-core-pvf-common = { path = "../core/pvf/common" } -polkadot-node-core-pvf-execute-worker = { path = "../core/pvf/execute-worker" } -polkadot-node-core-pvf-prepare-worker = { path = "../core/pvf/prepare-worker" } +polkadot-node-core-pvf-common = { workspace = true, default-features = true } +polkadot-node-core-pvf-execute-worker = { workspace = true, default-features = true } +polkadot-node-core-pvf-prepare-worker = { workspace = true, default-features = true } [dev-dependencies] -polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } -sp-core = { path = "../../../substrate/primitives/core" } -futures = { version = "0.3.30", features = ["thread-pool"] } +polkadot-node-subsystem-test-helpers = { workspace = true } +sp-core = { workspace = true, default-features = true } +futures = { features = ["thread-pool"], workspace = true } [build-dependencies] -substrate-build-script-utils = { path = "../../../substrate/utils/build-script-utils" } +substrate-build-script-utils = { workspace = true, default-features = true } [features] default = [] diff --git a/polkadot/node/malus/src/interceptor.rs b/polkadot/node/malus/src/interceptor.rs index b44ffc8956b52581f0d27eeb7e794ffacc922fb7..2181118646d568e2b59db6dbf61e24dfac90257b 100644 --- a/polkadot/node/malus/src/interceptor.rs +++ b/polkadot/node/malus/src/interceptor.rs @@ -90,6 +90,10 @@ where >::Error: std::fmt::Debug, { async fn send_message(&mut self, msg: OutgoingMessage) { + self.send_message_with_priority::(msg).await; + } + + async fn send_message_with_priority(&mut self, msg: OutgoingMessage) { let msg = < <>::Message as overseer::AssociateOutgoing >::OutgoingMessages as From>::from(msg); @@ -103,7 +107,14 @@ where } } - fn try_send_message(&mut self, msg: OutgoingMessage) -> Result<(), TrySendError> { + fn try_send_message( + &mut self, + msg: OutgoingMessage, + ) -> Result<(), polkadot_node_subsystem_util::metered::TrySendError> { + self.try_send_message_with_priority::(msg) + } + + fn try_send_message_with_priority(&mut self, msg: OutgoingMessage) -> Result<(), TrySendError> { let msg = < <>::Message as overseer::AssociateOutgoing >::OutgoingMessages as From>::from(msg); diff --git a/polkadot/node/metrics/Cargo.toml b/polkadot/node/metrics/Cargo.toml index 55df8d3daf6d17d142aa7980884c5ad9b4f0e568..41b08b66e9b4881bf93285b02076714bf41dfb0f 100644 --- a/polkadot/node/metrics/Cargo.toml +++ b/polkadot/node/metrics/Cargo.toml @@ -10,32 +10,34 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.30" -futures-timer = "3.0.2" -gum = { package = "tracing-gum", path = "../gum" } +futures = { workspace = true } +futures-timer = { workspace = true } +gum = { workspace = true, default-features = true } -metered = { package = "prioritized-metered-channel", version = "0.6.1", default-features = false, features = ["futures_channel"] } +metered = { features = ["futures_channel"], workspace = true } # Both `sc-service` and `sc-cli` are required by runtime metrics `logger_hook()`. -sc-service = { path = "../../../substrate/client/service" } -sc-cli = { path = "../../../substrate/client/cli" } +sc-service = { workspace = true, default-features = true } +sc-cli = { workspace = true, default-features = true } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../substrate/utils/prometheus" } -sc-tracing = { path = "../../../substrate/client/tracing" } -codec = { package = "parity-scale-codec", version = "3.6.12" } -polkadot-primitives = { path = "../../primitives" } -bs58 = { version = "0.5.0", features = ["alloc"] } +prometheus-endpoint = { workspace = true, default-features = true } +sc-tracing = { workspace = true, default-features = true } +codec = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +bs58 = { features = ["alloc"], workspace = true, default-features = true } log = { workspace = true, default-features = true } [dev-dependencies] -assert_cmd = "2.0.4" -tempfile = "3.2.0" -hyper = { version = "0.14.20", default-features = false, features = ["http1", "tcp"] } -tokio = "1.37" -polkadot-test-service = { path = "../test/service", features = ["runtime-metrics"] } -substrate-test-utils = { path = "../../../substrate/test-utils" } -sc-service = { path = "../../../substrate/client/service" } -sp-keyring = { path = "../../../substrate/primitives/keyring" } -prometheus-parse = { version = "0.2.2" } +assert_cmd = { workspace = true } +tempfile = { workspace = true } +hyper-util = { features = ["client-legacy", "tokio"], workspace = true } +hyper = { workspace = true } +http-body-util = { workspace = true } +tokio = { workspace = true, default-features = true } +polkadot-test-service = { features = ["runtime-metrics"], workspace = true } +substrate-test-utils = { workspace = true } +sc-service = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +prometheus-parse = { workspace = true } [features] default = [] diff --git a/polkadot/node/metrics/src/tests.rs b/polkadot/node/metrics/src/tests.rs index fde7c314413462799f82aa727b0a5a1a68bbd5f6..e720924feb60c6d4ef3828d52312f96521a6f989 100644 --- a/polkadot/node/metrics/src/tests.rs +++ b/polkadot/node/metrics/src/tests.rs @@ -16,7 +16,9 @@ //! Polkadot runtime metrics integration test. -use hyper::{Client, Uri}; +use http_body_util::BodyExt; +use hyper::Uri; +use hyper_util::{client::legacy::Client, rt::TokioExecutor}; use polkadot_primitives::metric_definitions::PARACHAIN_INHERENT_DATA_BITFIELDS_PROCESSED; use polkadot_test_service::{node_config, run_validator_node, test_prometheus_config}; use sp_keyring::AccountKeyring::*; @@ -66,14 +68,20 @@ async fn runtime_can_publish_metrics() { } async fn scrape_prometheus_metrics(metrics_uri: &str) -> HashMap { - let res = Client::new() + let res = Client::builder(TokioExecutor::new()) + .build_http::>() .get(Uri::try_from(metrics_uri).expect("bad URI")) .await .expect("GET request failed"); // Retrieve the `HTTP` response body. let body = String::from_utf8( - hyper::body::to_bytes(res).await.expect("can't get body as bytes").to_vec(), + res.into_body() + .collect() + .await + .expect("can't get body as bytes") + .to_bytes() + .to_vec(), ) .expect("body is not an UTF8 string"); diff --git a/polkadot/node/network/approval-distribution/Cargo.toml b/polkadot/node/network/approval-distribution/Cargo.toml index d80519b9e2e95aa4d958bff5b9a08e3bddb2cf3c..a85cde303b61bfb9281c022b68ea220af18251e6 100644 --- a/polkadot/node/network/approval-distribution/Cargo.toml +++ b/polkadot/node/network/approval-distribution/Cargo.toml @@ -10,32 +10,32 @@ license.workspace = true workspace = true [dependencies] -polkadot-node-metrics = { path = "../../metrics" } -polkadot-node-network-protocol = { path = "../protocol" } -polkadot-node-primitives = { path = "../../primitives" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } -polkadot-primitives = { path = "../../../primitives" } -polkadot-node-jaeger = { path = "../../jaeger" } -rand = "0.8" -itertools = "0.11" +polkadot-node-metrics = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-jaeger = { workspace = true, default-features = true } +rand = { workspace = true, default-features = true } +itertools = { workspace = true } -futures = "0.3.30" -futures-timer = "3.0.2" -gum = { package = "tracing-gum", path = "../../gum" } -bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } +futures = { workspace = true } +futures-timer = { workspace = true } +gum = { workspace = true, default-features = true } +bitvec = { features = ["alloc"], workspace = true } [dev-dependencies] -sp-authority-discovery = { path = "../../../../substrate/primitives/authority-discovery" } -sp-core = { path = "../../../../substrate/primitives/core", features = ["std"] } +sp-authority-discovery = { workspace = true, default-features = true } +sp-core = { features = ["std"], workspace = true, default-features = true } -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } +polkadot-node-subsystem-test-helpers = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } -assert_matches = "1.4.0" -schnorrkel = { version = "0.11.4", default-features = false } +assert_matches = { workspace = true } +schnorrkel = { workspace = true } # rand_core should match schnorrkel -rand_core = "0.6.2" -rand_chacha = "0.3.1" -env_logger = "0.11" +rand_core = { workspace = true } +rand_chacha = { workspace = true, default-features = true } +env_logger = { workspace = true } log = { workspace = true, default-features = true } diff --git a/polkadot/node/network/approval-distribution/src/lib.rs b/polkadot/node/network/approval-distribution/src/lib.rs index 369d82b45b094b30f0b65d72d54d5c14c1e28440..d48fb08a311c7496556eec797cbd2bd751a1472a 100644 --- a/polkadot/node/network/approval-distribution/src/lib.rs +++ b/polkadot/node/network/approval-distribution/src/lib.rs @@ -1431,6 +1431,21 @@ impl State { let required_routing = topology.map_or(RequiredRouting::PendingTopology, |t| { t.local_grid_neighbors().required_routing_by_index(validator_index, local) }); + // Peers that we will send the assignment to. + let mut peers = HashSet::new(); + + let peers_to_route_to = topology + .as_ref() + .map(|t| t.peers_to_route(required_routing)) + .unwrap_or_default(); + + for peer in peers_to_route_to { + if !entry.known_by.contains_key(&peer) { + continue + } + + peers.insert(peer); + } // All the peers that know the relay chain block. let peers_to_filter = entry.known_by(); @@ -1456,20 +1471,13 @@ impl State { let n_peers_total = self.peer_views.len(); let source_peer = source.peer_id(); - // Peers that we will send the assignment to. - let mut peers = Vec::new(); - // Filter destination peers for peer in peers_to_filter.into_iter() { if Some(peer) == source_peer { continue } - if let Some(true) = topology - .as_ref() - .map(|t| t.local_grid_neighbors().route_to_peer(required_routing, &peer)) - { - peers.push(peer); + if peers.contains(&peer) { continue } @@ -1485,7 +1493,11 @@ impl State { if route_random { approval_entry.routing_info_mut().mark_randomly_sent(peer); - peers.push(peer); + peers.insert(peer); + } + + if approval_entry.routing_info().random_routing.is_complete() { + break } } diff --git a/polkadot/node/network/approval-distribution/src/tests.rs b/polkadot/node/network/approval-distribution/src/tests.rs index 5ad034464767efc3757c3812967d88c71a6fbdd3..2d08807f97b60b817657a53af6a351002c04ff73 100644 --- a/polkadot/node/network/approval-distribution/src/tests.rs +++ b/polkadot/node/network/approval-distribution/src/tests.rs @@ -2404,7 +2404,7 @@ fn propagates_locally_generated_assignment_to_both_dimensions() { let assignments = vec![(cert.clone(), candidate_index)]; let approvals = vec![approval.clone()]; - let assignment_sent_peers = assert_matches!( + let mut assignment_sent_peers = assert_matches!( overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( sent_peers, @@ -2428,12 +2428,14 @@ fn propagates_locally_generated_assignment_to_both_dimensions() { assert_matches!( overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - sent_peers, + mut sent_peers, Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( protocol_v1::ApprovalDistributionMessage::Approvals(sent_approvals) )) )) => { // Random sampling is reused from the assignment. + sent_peers.sort(); + assignment_sent_peers.sort(); assert_eq!(sent_peers, assignment_sent_peers); assert_eq!(sent_approvals, approvals); } @@ -2678,7 +2680,7 @@ fn propagates_to_required_after_connect() { let assignments = vec![(cert.clone(), candidate_index)]; let approvals = vec![approval.clone()]; - let assignment_sent_peers = assert_matches!( + let mut assignment_sent_peers = assert_matches!( overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( sent_peers, @@ -2702,12 +2704,14 @@ fn propagates_to_required_after_connect() { assert_matches!( overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - sent_peers, + mut sent_peers, Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( protocol_v1::ApprovalDistributionMessage::Approvals(sent_approvals) )) )) => { // Random sampling is reused from the assignment. + sent_peers.sort(); + assignment_sent_peers.sort(); assert_eq!(sent_peers, assignment_sent_peers); assert_eq!(sent_approvals, approvals); } diff --git a/polkadot/node/network/availability-distribution/Cargo.toml b/polkadot/node/network/availability-distribution/Cargo.toml index db3a0456d9adbe3bc94e5d69b0c3586a78206c8b..8c5574f244e4a0671e807cc46dcb1286bafaf3a2 100644 --- a/polkadot/node/network/availability-distribution/Cargo.toml +++ b/polkadot/node/network/availability-distribution/Cargo.toml @@ -10,35 +10,35 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.30" -gum = { package = "tracing-gum", path = "../../gum" } -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["std"] } -polkadot-primitives = { path = "../../../primitives" } -polkadot-erasure-coding = { path = "../../../erasure-coding" } -polkadot-node-network-protocol = { path = "../protocol" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } -polkadot-node-primitives = { path = "../../primitives" } -sc-network = { path = "../../../../substrate/client/network" } -sp-core = { path = "../../../../substrate/primitives/core", features = ["std"] } -sp-keystore = { path = "../../../../substrate/primitives/keystore" } +futures = { workspace = true } +gum = { workspace = true, default-features = true } +codec = { features = ["std"], workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-erasure-coding = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sp-core = { features = ["std"], workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } thiserror = { workspace = true } -rand = "0.8.5" -derive_more = "0.99.17" -schnellru = "0.2.1" -fatality = "0.1.1" +rand = { workspace = true, default-features = true } +derive_more = { workspace = true, default-features = true } +schnellru = { workspace = true } +fatality = { workspace = true } [dev-dependencies] -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -sp-core = { path = "../../../../substrate/primitives/core", features = ["std"] } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -sp-tracing = { path = "../../../../substrate/primitives/tracing" } -sc-network = { path = "../../../../substrate/client/network" } -futures-timer = "3.0.2" -assert_matches = "1.4.0" -polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } -rstest = "0.18.2" -polkadot-subsystem-bench = { path = "../../subsystem-bench" } +polkadot-node-subsystem-test-helpers = { workspace = true } +sp-core = { features = ["std"], workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +futures-timer = { workspace = true } +assert_matches = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } +rstest = { workspace = true } +polkadot-subsystem-bench = { workspace = true } [[bench]] diff --git a/polkadot/node/network/availability-distribution/src/tests/state.rs b/polkadot/node/network/availability-distribution/src/tests/state.rs index befbff0a2f27efc0f91f1c23f9bdcc1ded704a8f..97e616f79fb759c0800946b762aca03acba9c4bc 100644 --- a/polkadot/node/network/availability-distribution/src/tests/state.rs +++ b/polkadot/node/network/availability-distribution/src/tests/state.rs @@ -216,7 +216,7 @@ impl TestState { // Test will fail if this does not happen until timeout. let mut remaining_stores = self.valid_chunks.len(); - let TestSubsystemContextHandle { tx, mut rx } = harness.virtual_overseer; + let TestSubsystemContextHandle { tx, mut rx, .. } = harness.virtual_overseer; // Spawning necessary as incoming queue can only hold a single item, we don't want to dead // lock ;-) diff --git a/polkadot/node/network/availability-recovery/Cargo.toml b/polkadot/node/network/availability-recovery/Cargo.toml index 1c9c861e6f733ebf7e23ae323d6685c9ce26a66b..41f09b1f7044358697fe923ab56f745bfdce22e7 100644 --- a/polkadot/node/network/availability-recovery/Cargo.toml +++ b/polkadot/node/network/availability-recovery/Cargo.toml @@ -10,39 +10,39 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.30" -tokio = "1.37" -schnellru = "0.2.1" -rand = "0.8.5" -fatality = "0.1.1" +futures = { workspace = true } +tokio = { workspace = true, default-features = true } +schnellru = { workspace = true } +rand = { workspace = true, default-features = true } +fatality = { workspace = true } thiserror = { workspace = true } -async-trait = "0.1.79" -gum = { package = "tracing-gum", path = "../../gum" } - -polkadot-erasure-coding = { path = "../../../erasure-coding" } -polkadot-primitives = { path = "../../../primitives" } -polkadot-node-primitives = { path = "../../primitives" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } -polkadot-node-network-protocol = { path = "../protocol" } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -sc-network = { path = "../../../../substrate/client/network" } +async-trait = { workspace = true } +gum = { workspace = true, default-features = true } + +polkadot-erasure-coding = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } +codec = { features = ["derive"], workspace = true } +sc-network = { workspace = true, default-features = true } [dev-dependencies] -assert_matches = "1.4.0" -futures-timer = "3.0.2" -rstest = "0.18.2" +assert_matches = { workspace = true } +futures-timer = { workspace = true } +rstest = { workspace = true } log = { workspace = true, default-features = true } -sp-tracing = { path = "../../../../substrate/primitives/tracing" } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto" } -sc-network = { path = "../../../../substrate/client/network" } +sp-tracing = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } -polkadot-subsystem-bench = { path = "../../subsystem-bench" } +polkadot-node-subsystem-test-helpers = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } +polkadot-subsystem-bench = { workspace = true } [[bench]] name = "availability-recovery-regression-bench" diff --git a/polkadot/node/network/bitfield-distribution/Cargo.toml b/polkadot/node/network/bitfield-distribution/Cargo.toml index 6b5b784b7fd899713c4ccbce2f9dec649a50f933..b1becaf319d55068a811a6cd97dbbccc9702dcbb 100644 --- a/polkadot/node/network/bitfield-distribution/Cargo.toml +++ b/polkadot/node/network/bitfield-distribution/Cargo.toml @@ -10,26 +10,26 @@ license.workspace = true workspace = true [dependencies] -always-assert = "0.1" -futures = "0.3.30" -futures-timer = "3.0.2" -gum = { package = "tracing-gum", path = "../../gum" } -polkadot-primitives = { path = "../../../primitives" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } -polkadot-node-network-protocol = { path = "../protocol" } -rand = "0.8" +always-assert = { workspace = true } +futures = { workspace = true } +futures-timer = { workspace = true } +gum = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } +rand = { workspace = true, default-features = true } [dev-dependencies] -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto" } -sp-authority-discovery = { path = "../../../../substrate/primitives/authority-discovery" } -sp-keystore = { path = "../../../../substrate/primitives/keystore" } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -maplit = "1.0.2" +polkadot-node-subsystem-test-helpers = { workspace = true } +bitvec = { features = ["alloc"], workspace = true } +sp-core = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-authority-discovery = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +maplit = { workspace = true } log = { workspace = true, default-features = true } -env_logger = "0.11" -assert_matches = "1.4.0" -rand_chacha = "0.3.1" +env_logger = { workspace = true } +assert_matches = { workspace = true } +rand_chacha = { workspace = true, default-features = true } diff --git a/polkadot/node/network/bridge/Cargo.toml b/polkadot/node/network/bridge/Cargo.toml index cd4e00ee1e4c596ed8c9798fd0009c95f6950a93..b4b5743853cd6dc2b43cce5d6b8c4d63bb893c8b 100644 --- a/polkadot/node/network/bridge/Cargo.toml +++ b/polkadot/node/network/bridge/Cargo.toml @@ -10,28 +10,28 @@ license.workspace = true workspace = true [dependencies] -always-assert = "0.1" -async-trait = "0.1.79" -futures = "0.3.30" -gum = { package = "tracing-gum", path = "../../gum" } -polkadot-primitives = { path = "../../../primitives" } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -sc-network = { path = "../../../../substrate/client/network" } -sp-consensus = { path = "../../../../substrate/primitives/consensus/common" } -polkadot-node-metrics = { path = "../../metrics" } -polkadot-node-network-protocol = { path = "../protocol" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-overseer = { path = "../../overseer" } -parking_lot = "0.12.1" -bytes = "1" -fatality = "0.1.1" +always-assert = { workspace = true } +async-trait = { workspace = true } +futures = { workspace = true } +gum = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +codec = { features = ["derive"], workspace = true } +sc-network = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +polkadot-node-metrics = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-overseer = { workspace = true, default-features = true } +parking_lot = { workspace = true, default-features = true } +bytes = { workspace = true, default-features = true } +fatality = { workspace = true } thiserror = { workspace = true } [dev-dependencies] -assert_matches = "1.4.0" -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -futures-timer = "3" -polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } +assert_matches = { workspace = true } +polkadot-node-subsystem-test-helpers = { workspace = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +futures-timer = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } diff --git a/polkadot/node/network/bridge/src/network.rs b/polkadot/node/network/bridge/src/network.rs index b31359f48a56fa01aea1e34bd23f0098d0744739..1f438df2d148cc8ebaffba08d98d2220c8745685 100644 --- a/polkadot/node/network/bridge/src/network.rs +++ b/polkadot/node/network/bridge/src/network.rs @@ -204,6 +204,13 @@ pub trait Network: Clone + Send + 'static { multiaddresses: HashSet, ) -> Result<(), String>; + /// Ask the network to extend the reserved set with these nodes. + async fn add_peers_to_reserved_set( + &mut self, + protocol: ProtocolName, + multiaddresses: HashSet, + ) -> Result<(), String>; + /// Removes the peers for the protocol's peer set (both reserved and non-reserved). async fn remove_from_peers_set( &mut self, @@ -240,6 +247,14 @@ impl Network for Arc { ::set_reserved_peers(&**self, protocol, multiaddresses) } + async fn add_peers_to_reserved_set( + &mut self, + protocol: ProtocolName, + multiaddresses: HashSet, + ) -> Result<(), String> { + ::add_peers_to_reserved_set(&**self, protocol, multiaddresses) + } + async fn remove_from_peers_set( &mut self, protocol: ProtocolName, diff --git a/polkadot/node/network/bridge/src/rx/mod.rs b/polkadot/node/network/bridge/src/rx/mod.rs index 84e935366d0cb7734d5b0aec102032aa0c85edec..56965ce6ba404c2e6fc2b189ce75ac9122cbf67c 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -1135,13 +1135,33 @@ async fn dispatch_validation_events_to_all( I: IntoIterator>, I::IntoIter: Send, { + macro_rules! send_message { + ($event:expr, $message:ident) => { + if let Ok(event) = $event.focus() { + let has_high_priority = matches!( + event, + // NetworkBridgeEvent::OurViewChange(..) must also be here, + // but it is sent via an unbounded channel. + // See https://github.com/paritytech/polkadot-sdk/issues/824 + NetworkBridgeEvent::PeerConnected(..) | + NetworkBridgeEvent::PeerDisconnected(..) | + NetworkBridgeEvent::PeerViewChange(..) + ); + let message = $message::from(event); + if has_high_priority { + sender.send_message_with_priority::(message).await; + } else { + sender.send_message(message).await; + } + } + }; + } + for event in events { - sender - .send_messages(event.focus().map(StatementDistributionMessage::from)) - .await; - sender.send_messages(event.focus().map(BitfieldDistributionMessage::from)).await; - sender.send_messages(event.focus().map(ApprovalDistributionMessage::from)).await; - sender.send_messages(event.focus().map(GossipSupportMessage::from)).await; + send_message!(event, StatementDistributionMessage); + send_message!(event, BitfieldDistributionMessage); + send_message!(event, ApprovalDistributionMessage); + send_message!(event, GossipSupportMessage); } } diff --git a/polkadot/node/network/bridge/src/rx/tests.rs b/polkadot/node/network/bridge/src/rx/tests.rs index 6182bf3d883b5be19231d534babf1c70973da00d..601dca5cb8a3c4db817d2c4681058392b9f7686f 100644 --- a/polkadot/node/network/bridge/src/rx/tests.rs +++ b/polkadot/node/network/bridge/src/rx/tests.rs @@ -124,6 +124,14 @@ impl Network for TestNetwork { Ok(()) } + async fn add_peers_to_reserved_set( + &mut self, + _protocol: ProtocolName, + _: HashSet, + ) -> Result<(), String> { + Ok(()) + } + async fn remove_from_peers_set( &mut self, _protocol: ProtocolName, @@ -880,6 +888,8 @@ fn peer_view_updates_sent_via_overseer() { &mut virtual_overseer, ) .await; + + assert_eq!(virtual_overseer.message_counter.with_high_priority(), 8); } network_handle @@ -895,6 +905,7 @@ fn peer_view_updates_sent_via_overseer() { &mut virtual_overseer, ) .await; + assert_eq!(virtual_overseer.message_counter.with_high_priority(), 12); virtual_overseer }); } @@ -930,6 +941,8 @@ fn peer_messages_sent_via_overseer() { &mut virtual_overseer, ) .await; + + assert_eq!(virtual_overseer.message_counter.with_high_priority(), 8); } let approval_distribution_message = @@ -970,6 +983,7 @@ fn peer_messages_sent_via_overseer() { &mut virtual_overseer, ) .await; + assert_eq!(virtual_overseer.message_counter.with_high_priority(), 12); virtual_overseer }); } @@ -1008,6 +1022,8 @@ fn peer_disconnect_from_just_one_peerset() { &mut virtual_overseer, ) .await; + + assert_eq!(virtual_overseer.message_counter.with_high_priority(), 8); } { @@ -1036,6 +1052,7 @@ fn peer_disconnect_from_just_one_peerset() { &mut virtual_overseer, ) .await; + assert_eq!(virtual_overseer.message_counter.with_high_priority(), 12); // to show that we're still connected on the collation protocol, send a view update. @@ -1094,6 +1111,8 @@ fn relays_collation_protocol_messages() { &mut virtual_overseer, ) .await; + + assert_eq!(virtual_overseer.message_counter.with_high_priority(), 8); } { @@ -1201,6 +1220,8 @@ fn different_views_on_different_peer_sets() { &mut virtual_overseer, ) .await; + + assert_eq!(virtual_overseer.message_counter.with_high_priority(), 8); } { @@ -1247,6 +1268,8 @@ fn different_views_on_different_peer_sets() { ) .await; + assert_eq!(virtual_overseer.message_counter.with_high_priority(), 12); + assert_sends_collation_event_to_all( NetworkBridgeEvent::PeerViewChange(peer, view_b.clone()), &mut virtual_overseer, @@ -1481,6 +1504,8 @@ fn network_protocol_versioning_subsystem_msg() { &mut virtual_overseer, ) .await; + + assert_eq!(virtual_overseer.message_counter.with_high_priority(), 8); } let approval_distribution_message = diff --git a/polkadot/node/network/bridge/src/tx/mod.rs b/polkadot/node/network/bridge/src/tx/mod.rs index 7b6dea748572ba1c24633b047227b92a9890c12c..6c353195d41ada27a579fba83f8d86979b3ca407 100644 --- a/polkadot/node/network/bridge/src/tx/mod.rs +++ b/polkadot/node/network/bridge/src/tx/mod.rs @@ -370,6 +370,22 @@ where .await; return (network_service, authority_discovery_service) }, + + NetworkBridgeTxMessage::AddToResolvedValidators { validator_addrs, peer_set } => { + gum::trace!( + target: LOG_TARGET, + action = "AddToResolvedValidators", + peer_set = ?peer_set, + ?validator_addrs, + "Received a resolved validator connection request", + ); + + let all_addrs = validator_addrs.into_iter().flatten().collect(); + let network_service = validator_discovery + .on_add_to_resolved_request(all_addrs, peer_set, network_service) + .await; + return (network_service, authority_discovery_service) + }, } (network_service, authority_discovery_service) } diff --git a/polkadot/node/network/bridge/src/tx/tests.rs b/polkadot/node/network/bridge/src/tx/tests.rs index 9265358196dbf96d485af6b363ed089cf8efe321..30b2c3421372a44d7e2c3716fdb280ab5ecbf887 100644 --- a/polkadot/node/network/bridge/src/tx/tests.rs +++ b/polkadot/node/network/bridge/src/tx/tests.rs @@ -148,6 +148,14 @@ impl Network for TestNetwork { Ok(()) } + async fn add_peers_to_reserved_set( + &mut self, + _protocol: ProtocolName, + _: HashSet, + ) -> Result<(), String> { + Ok(()) + } + async fn remove_from_peers_set( &mut self, _protocol: ProtocolName, diff --git a/polkadot/node/network/bridge/src/validator_discovery.rs b/polkadot/node/network/bridge/src/validator_discovery.rs index f0ef038d5eb40708165f41dcdc5310b5dd44c951..9accd56d86ae603e5c5f37fbe18b550e55d47d47 100644 --- a/polkadot/node/network/bridge/src/validator_discovery.rs +++ b/polkadot/node/network/bridge/src/validator_discovery.rs @@ -92,6 +92,44 @@ impl Service { network_service } + /// Connect to already resolved addresses. + pub async fn on_add_to_resolved_request( + &mut self, + newly_requested: HashSet, + peer_set: PeerSet, + mut network_service: N, + ) -> N { + let state = &mut self.state[peer_set]; + let new_peer_ids: HashSet = extract_peer_ids(newly_requested.iter().cloned()); + let num_peers = new_peer_ids.len(); + + state.previously_requested.extend(new_peer_ids); + + gum::debug!( + target: LOG_TARGET, + ?peer_set, + ?num_peers, + "New add to resolved validators request", + ); + + // ask the network to connect to these nodes and not disconnect + // from them until they are removed from the set. + // + // for peer-set management, the main protocol name should be used regardless of + // the negotiated version. + if let Err(e) = network_service + .add_peers_to_reserved_set( + self.peerset_protocol_names.get_main_name(peer_set), + newly_requested, + ) + .await + { + gum::warn!(target: LOG_TARGET, err = ?e, "AuthorityDiscoveryService returned an invalid multiaddress"); + } + + network_service + } + /// On a new connection request, a peer set update will be issued. /// It will ask the network to connect to the validators and not disconnect /// from them at least until the next request is issued for the same peer set. @@ -222,6 +260,15 @@ mod tests { Ok(()) } + async fn add_peers_to_reserved_set( + &mut self, + _protocol: ProtocolName, + multiaddresses: HashSet, + ) -> Result<(), String> { + self.peers_set.extend(extract_peer_ids(multiaddresses.into_iter())); + Ok(()) + } + async fn remove_from_peers_set( &mut self, _protocol: ProtocolName, diff --git a/polkadot/node/network/collator-protocol/Cargo.toml b/polkadot/node/network/collator-protocol/Cargo.toml index a56c1c7dfe9865dd82b78dda40a5e3aec228daf3..d41fc7ebe8ddb292aadd281c0b34288d8eb49e10 100644 --- a/polkadot/node/network/collator-protocol/Cargo.toml +++ b/polkadot/node/network/collator-protocol/Cargo.toml @@ -10,38 +10,38 @@ license.workspace = true workspace = true [dependencies] -bitvec = { version = "1.0.1", default-features = false, features = ["alloc"] } -futures = "0.3.30" -futures-timer = "3" -gum = { package = "tracing-gum", path = "../../gum" } - -sp-core = { path = "../../../../substrate/primitives/core" } -sp-runtime = { path = "../../../../substrate/primitives/runtime" } -sp-keystore = { path = "../../../../substrate/primitives/keystore" } - -polkadot-primitives = { path = "../../../primitives" } -polkadot-node-network-protocol = { path = "../protocol" } -polkadot-node-primitives = { path = "../../primitives" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } -polkadot-node-subsystem = { path = "../../subsystem" } -fatality = "0.1.1" +bitvec = { features = ["alloc"], workspace = true } +futures = { workspace = true } +futures-timer = { workspace = true } +gum = { workspace = true, default-features = true } + +sp-core = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } + +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +fatality = { workspace = true } thiserror = { workspace = true } -tokio-util = "0.7.1" +tokio-util = { workspace = true } [dev-dependencies] log = { workspace = true, default-features = true } -env_logger = "0.11" -assert_matches = "1.4.0" -rstest = "0.18.2" - -sp-core = { path = "../../../../substrate/primitives/core", features = ["std"] } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -sc-keystore = { path = "../../../../substrate/client/keystore" } -sc-network = { path = "../../../../substrate/client/network" } -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["std"] } - -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } +env_logger = { workspace = true } +assert_matches = { workspace = true } +rstest = { workspace = true } + +sp-core = { features = ["std"], workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sc-keystore = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +codec = { features = ["std"], workspace = true, default-features = true } + +polkadot-node-subsystem-test-helpers = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } [features] default = [] diff --git a/polkadot/node/network/dispute-distribution/Cargo.toml b/polkadot/node/network/dispute-distribution/Cargo.toml index 08713209bb740737df26e36d2f4df7933914406b..ccf1b5daad7c3b7f3dd7d5525cb619781c01bce8 100644 --- a/polkadot/node/network/dispute-distribution/Cargo.toml +++ b/polkadot/node/network/dispute-distribution/Cargo.toml @@ -10,33 +10,33 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.30" -futures-timer = "3.0.2" -gum = { package = "tracing-gum", path = "../../gum" } -derive_more = "0.99.17" -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["std"] } -polkadot-primitives = { path = "../../../primitives" } -polkadot-erasure-coding = { path = "../../../erasure-coding" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-network-protocol = { path = "../protocol" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } -polkadot-node-primitives = { path = "../../primitives" } -sc-network = { path = "../../../../substrate/client/network" } -sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto" } -sp-keystore = { path = "../../../../substrate/primitives/keystore" } +futures = { workspace = true } +futures-timer = { workspace = true } +gum = { workspace = true, default-features = true } +derive_more = { workspace = true, default-features = true } +codec = { features = ["std"], workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-erasure-coding = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } thiserror = { workspace = true } -fatality = "0.1.1" -schnellru = "0.2.1" -indexmap = "2.0.0" +fatality = { workspace = true } +schnellru = { workspace = true } +indexmap = { workspace = true } [dev-dependencies] -async-channel = "1.8.0" -async-trait = "0.1.79" -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -sp-tracing = { path = "../../../../substrate/primitives/tracing" } -sc-keystore = { path = "../../../../substrate/client/keystore" } -futures-timer = "3.0.2" -assert_matches = "1.4.0" -lazy_static = "1.4.0" -polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } +async-channel = { workspace = true } +async-trait = { workspace = true } +polkadot-node-subsystem-test-helpers = { workspace = true } +sp-keyring = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +sc-keystore = { workspace = true, default-features = true } +futures-timer = { workspace = true } +assert_matches = { workspace = true } +lazy_static = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } diff --git a/polkadot/node/network/gossip-support/Cargo.toml b/polkadot/node/network/gossip-support/Cargo.toml index 2d6f2f954c667a8a97aff093f1fa734f6afce9aa..83fdc7e26191e6b2568a9733b163a0f0239f6709 100644 --- a/polkadot/node/network/gossip-support/Cargo.toml +++ b/polkadot/node/network/gossip-support/Cargo.toml @@ -10,34 +10,34 @@ license.workspace = true workspace = true [dependencies] -sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto" } -sp-keystore = { path = "../../../../substrate/primitives/keystore" } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-crypto-hashing = { path = "../../../../substrate/primitives/crypto/hashing" } -sc-network = { path = "../../../../substrate/client/network" } -sc-network-common = { path = "../../../../substrate/client/network/common" } +sp-application-crypto = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-network-common = { workspace = true, default-features = true } -polkadot-node-network-protocol = { path = "../protocol" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } -polkadot-primitives = { path = "../../../primitives" } +polkadot-node-network-protocol = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } -futures = "0.3.30" -futures-timer = "3.0.2" -rand = { version = "0.8.5", default-features = false } -rand_chacha = { version = "0.3.1", default-features = false } -gum = { package = "tracing-gum", path = "../../gum" } +futures = { workspace = true } +futures-timer = { workspace = true } +rand = { workspace = true } +rand_chacha = { workspace = true } +gum = { workspace = true, default-features = true } [dev-dependencies] -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -sp-consensus-babe = { path = "../../../../substrate/primitives/consensus/babe" } -sp-tracing = { path = "../../../../substrate/primitives/tracing" } -sp-authority-discovery = { path = "../../../../substrate/primitives/authority-discovery" } +sp-keyring = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +sp-authority-discovery = { workspace = true, default-features = true } -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } +polkadot-node-subsystem-test-helpers = { workspace = true } -assert_matches = "1.4.0" -async-trait = "0.1.79" -parking_lot = "0.12.1" -lazy_static = "1.4.0" -quickcheck = "1.0.3" +assert_matches = { workspace = true } +async-trait = { workspace = true } +parking_lot = { workspace = true, default-features = true } +lazy_static = { workspace = true } +quickcheck = { workspace = true, default-features = true } diff --git a/polkadot/node/network/gossip-support/src/lib.rs b/polkadot/node/network/gossip-support/src/lib.rs index 4dfdd1f7208f66ec4a787ffe8bc7f72c41575c9d..cd327c11e408c5117f9679938eb157e713b7afd9 100644 --- a/polkadot/node/network/gossip-support/src/lib.rs +++ b/polkadot/node/network/gossip-support/src/lib.rs @@ -69,6 +69,16 @@ const BACKOFF_DURATION: Duration = Duration::from_secs(5); #[cfg(test)] const BACKOFF_DURATION: Duration = Duration::from_millis(500); +// The authorithy_discovery queries runs every ten minutes, +// so it make sense to run a bit more often than that to +// detect changes as often as we can, but not too often since +// it won't help. +#[cfg(not(test))] +const TRY_RERESOLVE_AUTHORITIES: Duration = Duration::from_secs(5 * 60); + +#[cfg(test)] +const TRY_RERESOLVE_AUTHORITIES: Duration = Duration::from_secs(2); + /// Duration after which we consider low connectivity a problem. /// /// Especially at startup low connectivity is expected (authority discovery cache needs to be @@ -91,6 +101,14 @@ pub struct GossipSupport { // `None` otherwise. last_failure: Option, + // Validators can restart during a session, so if they change + // their PeerID, we will connect to them in the best case after + // a session, so we need to try more often to resolved peers and + // reconnect to them. The authorithy_discovery queries runs every ten + // minutes, so we can't detect changes in the address more often + // that that. + last_connection_request: Option, + /// First time we did not reach our connectivity threshold. /// /// This is the time of the first failed attempt to connect to >2/3 of all validators in a @@ -131,6 +149,7 @@ where keystore, last_session_index: None, last_failure: None, + last_connection_request: None, failure_start: None, resolved_authorities: HashMap::new(), connected_authorities: HashMap::new(), @@ -196,15 +215,22 @@ where for leaf in leaves { let current_index = util::request_session_index_for_child(leaf, sender).await.await??; let since_failure = self.last_failure.map(|i| i.elapsed()).unwrap_or_default(); + let since_last_reconnect = + self.last_connection_request.map(|i| i.elapsed()).unwrap_or_default(); + let force_request = since_failure >= BACKOFF_DURATION; + let re_resolve_authorities = since_last_reconnect >= TRY_RERESOLVE_AUTHORITIES; let leaf_session = Some((current_index, leaf)); let maybe_new_session = match self.last_session_index { Some(i) if current_index <= i => None, _ => leaf_session, }; - let maybe_issue_connection = - if force_request { leaf_session } else { maybe_new_session }; + let maybe_issue_connection = if force_request || re_resolve_authorities { + leaf_session + } else { + maybe_new_session + }; if let Some((session_index, relay_parent)) = maybe_issue_connection { let session_info = @@ -248,7 +274,7 @@ where // connections to a much broader set of validators. { let mut connections = authorities_past_present_future(sender, leaf).await?; - + self.last_connection_request = Some(Instant::now()); // Remove all of our locally controlled validator indices so we don't connect to // ourself. let connections = @@ -259,7 +285,12 @@ where // to clean up all connections. Vec::new() }; - self.issue_connection_request(sender, connections).await; + + if force_request || is_new_session { + self.issue_connection_request(sender, connections).await; + } else if re_resolve_authorities { + self.issue_connection_request_to_changed(sender, connections).await; + } } if is_new_session { @@ -324,17 +355,14 @@ where authority_check_result } - async fn issue_connection_request( + async fn resolve_authorities( &mut self, - sender: &mut Sender, authorities: Vec, - ) where - Sender: overseer::GossipSupportSenderTrait, - { - let num = authorities.len(); + ) -> (Vec>, HashMap>, usize) { let mut validator_addrs = Vec::with_capacity(authorities.len()); - let mut failures = 0; let mut resolved = HashMap::with_capacity(authorities.len()); + let mut failures = 0; + for authority in authorities { if let Some(addrs) = self.authority_discovery.get_addresses_by_authority_id(authority.clone()).await @@ -350,6 +378,67 @@ where ); } } + (validator_addrs, resolved, failures) + } + + async fn issue_connection_request_to_changed( + &mut self, + sender: &mut Sender, + authorities: Vec, + ) where + Sender: overseer::GossipSupportSenderTrait, + { + let (_, resolved, _) = self.resolve_authorities(authorities).await; + + let mut changed = Vec::new(); + + for (authority, new_addresses) in &resolved { + let new_peer_ids = new_addresses + .iter() + .flat_map(|addr| parse_addr(addr.clone()).ok().map(|(p, _)| p)) + .collect::>(); + match self.resolved_authorities.get(authority) { + Some(old_addresses) => { + let old_peer_ids = old_addresses + .iter() + .flat_map(|addr| parse_addr(addr.clone()).ok().map(|(p, _)| p)) + .collect::>(); + if !old_peer_ids.is_superset(&new_peer_ids) { + changed.push(new_addresses.clone()); + } + }, + None => changed.push(new_addresses.clone()), + } + } + gum::debug!( + target: LOG_TARGET, + num_changed = ?changed.len(), + ?changed, + "Issuing a connection request to changed validators" + ); + if !changed.is_empty() { + self.resolved_authorities = resolved; + + sender + .send_message(NetworkBridgeTxMessage::AddToResolvedValidators { + validator_addrs: changed, + peer_set: PeerSet::Validation, + }) + .await; + } + } + + async fn issue_connection_request( + &mut self, + sender: &mut Sender, + authorities: Vec, + ) where + Sender: overseer::GossipSupportSenderTrait, + { + let num = authorities.len(); + + let (validator_addrs, resolved, failures) = self.resolve_authorities(authorities).await; + self.resolved_authorities = resolved; gum::debug!(target: LOG_TARGET, %num, "Issuing a connection request"); @@ -399,16 +488,24 @@ where { let mut authority_ids: HashMap> = HashMap::new(); for authority in authorities { - let peer_id = self + let peer_ids = self .authority_discovery .get_addresses_by_authority_id(authority.clone()) .await .into_iter() .flat_map(|list| list.into_iter()) - .find_map(|addr| parse_addr(addr).ok().map(|(p, _)| p)); + .flat_map(|addr| parse_addr(addr).ok().map(|(p, _)| p)) + .collect::>(); + + gum::trace!( + target: LOG_TARGET, + ?peer_ids, + ?authority, + "Resolved to peer ids" + ); - if let Some(p) = peer_id { - authority_ids.entry(p).or_default().insert(authority); + for p in peer_ids { + authority_ids.entry(p).or_default().insert(authority.clone()); } } diff --git a/polkadot/node/network/gossip-support/src/tests.rs b/polkadot/node/network/gossip-support/src/tests.rs index 42197d00e6f3de0f598c8d92bc076bfb225fba9a..09622254f523e5605f8b203645819b2ea176dcfd 100644 --- a/polkadot/node/network/gossip-support/src/tests.rs +++ b/polkadot/node/network/gossip-support/src/tests.rs @@ -119,6 +119,14 @@ impl MockAuthorityDiscovery { } } + fn change_address_for_authority(&self, authority_id: AuthorityDiscoveryId) -> PeerId { + let new_peer_id = PeerId::random(); + let addr = Multiaddr::empty().with(Protocol::P2p(new_peer_id.into())); + self.addrs.lock().insert(authority_id.clone(), HashSet::from([addr])); + self.authorities.lock().insert(new_peer_id, HashSet::from([authority_id])); + new_peer_id + } + fn authorities(&self) -> HashMap> { self.authorities.lock().clone() } @@ -809,6 +817,313 @@ fn issues_update_authorities_after_session() { ); } +// Test we connect to authorities that changed their address `TRY_RERESOLVE_AUTHORITIES` rate +// and that is is no-op if no authority changed. +#[test] +fn test_quickly_connect_to_authorities_that_changed_address() { + let hash = Hash::repeat_byte(0xAA); + + let authorities = PAST_PRESENT_FUTURE_AUTHORITIES.clone(); + let authority_that_changes_address = authorities.get(5).unwrap().clone(); + + let mut authority_discovery_mock = MockAuthorityDiscovery::new(authorities); + + test_harness( + make_subsystem_with_authority_discovery(authority_discovery_mock.clone()), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // 1. Initialize with the first leaf in the session. + overseer_signal_active_leaves(overseer, hash).await; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionIndexForChild(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(1)).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionInfo(s, tx), + )) => { + assert_eq!(relay_parent, hash); + assert_eq!(s, 1); + let mut session_info = make_session_info(); + session_info.discovery_keys = PAST_PRESENT_FUTURE_AUTHORITIES.clone(); + tx.send(Ok(Some(session_info))).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::Authorities(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(PAST_PRESENT_FUTURE_AUTHORITIES.clone())).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ConnectToResolvedValidators { + validator_addrs, + peer_set, + }) => { + let all_without_ferdie: Vec<_> = PAST_PRESENT_FUTURE_AUTHORITIES + .iter() + .cloned() + .filter(|p| p != &Sr25519Keyring::Ferdie.public().into()) + .collect(); + + let addrs = get_multiaddrs(all_without_ferdie, authority_discovery_mock.clone()).await; + + assert_eq!(validator_addrs, addrs); + assert_eq!(peer_set, PeerSet::Validation); + } + ); + + // Ensure neighbors are unaffected + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::CurrentBabeEpoch(tx), + )) => { + let _ = tx.send(Ok(BabeEpoch { + epoch_index: 2 as _, + start_slot: 0.into(), + duration: 200, + authorities: vec![(Sr25519Keyring::Alice.public().into(), 1)], + randomness: [0u8; 32], + config: BabeEpochConfiguration { + c: (1, 4), + allowed_slots: AllowedSlots::PrimarySlots, + }, + })).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeRx(NetworkBridgeRxMessage::NewGossipTopology { + session: _, + local_index: _, + canonical_shuffling: _, + shuffled_indices: _, + }) => { + + } + ); + + // 2. Connect all authorities that are known so far. + let known_authorities = authority_discovery_mock.authorities(); + for (peer_id, _id) in known_authorities.iter() { + let msg = + GossipSupportMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected( + *peer_id, + ObservedRole::Authority, + ValidationVersion::V3.into(), + None, + )); + overseer.send(FromOrchestra::Communication { msg }).await + } + + // 3. Send a new leaf after TRY_RERESOLVE_AUTHORITIES, we should notice + // UpdateAuthorithies is emitted for all ConnectedPeers. + Delay::new(TRY_RERESOLVE_AUTHORITIES).await; + let hash = Hash::repeat_byte(0xBB); + overseer_signal_active_leaves(overseer, hash).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionIndexForChild(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(1)).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionInfo(s, tx), + )) => { + assert_eq!(relay_parent, hash); + assert_eq!(s, 1); + let mut session_info = make_session_info(); + session_info.discovery_keys = PAST_PRESENT_FUTURE_AUTHORITIES.clone(); + tx.send(Ok(Some(session_info))).unwrap(); + + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::Authorities(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(PAST_PRESENT_FUTURE_AUTHORITIES.clone())).unwrap(); + } + ); + + for _ in 0..known_authorities.len() { + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeRx(NetworkBridgeRxMessage::UpdatedAuthorityIds { + peer_id, + authority_ids, + }) => { + assert_eq!(authority_discovery_mock.get_authority_ids_by_peer_id(peer_id).await.unwrap_or_default(), authority_ids); + } + ); + } + + // 4. At next re-resolve no-authorithy changes their address, so it should be no-op. + Delay::new(TRY_RERESOLVE_AUTHORITIES).await; + let hash = Hash::repeat_byte(0xCC); + overseer_signal_active_leaves(overseer, hash).await; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionIndexForChild(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(1)).unwrap(); + } + ); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionInfo(s, tx), + )) => { + assert_eq!(relay_parent, hash); + assert_eq!(s, 1); + let mut session_info = make_session_info(); + session_info.discovery_keys = PAST_PRESENT_FUTURE_AUTHORITIES.clone(); + tx.send(Ok(Some(session_info))).unwrap(); + + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::Authorities(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(PAST_PRESENT_FUTURE_AUTHORITIES.clone())).unwrap(); + } + ); + assert!(overseer.recv().timeout(TIMEOUT).await.is_none()); + + // Change address for one authorithy and check we try to connect to it and + // that we emit UpdateAuthorityID for the old PeerId and the new one. + Delay::new(TRY_RERESOLVE_AUTHORITIES).await; + let changed_peerid = authority_discovery_mock + .change_address_for_authority(authority_that_changes_address.clone()); + let hash = Hash::repeat_byte(0xDD); + let msg = GossipSupportMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected( + changed_peerid, + ObservedRole::Authority, + ValidationVersion::V3.into(), + None, + )); + overseer.send(FromOrchestra::Communication { msg }).await; + + overseer_signal_active_leaves(overseer, hash).await; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionIndexForChild(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(1)).unwrap(); + } + ); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionInfo(s, tx), + )) => { + assert_eq!(relay_parent, hash); + assert_eq!(s, 1); + let mut session_info = make_session_info(); + session_info.discovery_keys = PAST_PRESENT_FUTURE_AUTHORITIES.clone(); + tx.send(Ok(Some(session_info))).unwrap(); + + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::Authorities(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(PAST_PRESENT_FUTURE_AUTHORITIES.clone())).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::AddToResolvedValidators { + validator_addrs, + peer_set, + }) => { + let expected = get_address_map(vec![authority_that_changes_address.clone()], authority_discovery_mock.clone()).await; + let expected: HashSet = expected.into_values().flat_map(|v| v.into_iter()).collect(); + assert_eq!(validator_addrs.into_iter().flat_map(|v| v.into_iter()).collect::>(), expected); + assert_eq!(peer_set, PeerSet::Validation); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeRx(NetworkBridgeRxMessage::UpdatedAuthorityIds { + peer_id, + authority_ids, + }) => { + assert_eq!(authority_discovery_mock.get_authority_ids_by_peer_id(peer_id).await.unwrap(), HashSet::from([authority_that_changes_address.clone()])); + assert!(authority_ids.is_empty()); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeRx(NetworkBridgeRxMessage::UpdatedAuthorityIds { + peer_id, + authority_ids, + }) => { + assert_eq!(authority_ids, HashSet::from([authority_that_changes_address])); + assert_eq!(changed_peerid, peer_id); + } + ); + + assert!(overseer.recv().timeout(TIMEOUT).await.is_none()); + + virtual_overseer + }, + ); +} + #[test] fn disconnect_when_not_in_past_present_future() { sp_tracing::try_init_simple(); diff --git a/polkadot/node/network/protocol/Cargo.toml b/polkadot/node/network/protocol/Cargo.toml index 83145ce4013022b5567d45434c989bba732382c7..c9ae23d756cfc4d39d44286b7a567ed46969bf02 100644 --- a/polkadot/node/network/protocol/Cargo.toml +++ b/polkadot/node/network/protocol/Cargo.toml @@ -10,25 +10,25 @@ description = "Primitives types for the Node-side" workspace = true [dependencies] -async-channel = "1.8.0" -async-trait = "0.1.79" -hex = "0.4.3" -polkadot-primitives = { path = "../../../primitives" } -polkadot-node-primitives = { path = "../../primitives" } -polkadot-node-jaeger = { path = "../../jaeger" } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -sc-network = { path = "../../../../substrate/client/network" } -sc-network-types = { path = "../../../../substrate/client/network/types" } -sc-authority-discovery = { path = "../../../../substrate/client/authority-discovery" } -sp-runtime = { path = "../../../../substrate/primitives/runtime" } -strum = { version = "0.26.2", features = ["derive"] } -futures = "0.3.30" +async-channel = { workspace = true } +async-trait = { workspace = true } +hex = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-jaeger = { workspace = true, default-features = true } +codec = { features = ["derive"], workspace = true } +sc-network = { workspace = true, default-features = true } +sc-network-types = { workspace = true, default-features = true } +sc-authority-discovery = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +strum = { features = ["derive"], workspace = true, default-features = true } +futures = { workspace = true } thiserror = { workspace = true } -fatality = "0.1.1" -rand = "0.8" -derive_more = "0.99" -gum = { package = "tracing-gum", path = "../../gum" } -bitvec = "1" +fatality = { workspace = true } +rand = { workspace = true, default-features = true } +derive_more = { workspace = true, default-features = true } +gum = { workspace = true, default-features = true } +bitvec = { workspace = true, default-features = true } [dev-dependencies] -rand_chacha = "0.3.1" +rand_chacha = { workspace = true, default-features = true } diff --git a/polkadot/node/network/protocol/src/grid_topology.rs b/polkadot/node/network/protocol/src/grid_topology.rs index a14d24610722bfad2d26df9526d8e6d7411e6f68..4dd7d29fc25cde5a010e6c4c28969c142dba6098 100644 --- a/polkadot/node/network/protocol/src/grid_topology.rs +++ b/polkadot/node/network/protocol/src/grid_topology.rs @@ -313,6 +313,23 @@ impl SessionGridTopologyEntry { self.topology.is_validator(peer) } + /// Returns the list of peers to route based on the required routing. + pub fn peers_to_route(&self, required_routing: RequiredRouting) -> Vec { + match required_routing { + RequiredRouting::All => self.topology.peer_ids.iter().copied().collect(), + RequiredRouting::GridX => self.local_neighbors.peers_x.iter().copied().collect(), + RequiredRouting::GridY => self.local_neighbors.peers_y.iter().copied().collect(), + RequiredRouting::GridXY => self + .local_neighbors + .peers_x + .iter() + .chain(self.local_neighbors.peers_y.iter()) + .copied() + .collect(), + RequiredRouting::None | RequiredRouting::PendingTopology => Vec::new(), + } + } + /// Updates the known peer ids for the passed authorities ids. pub fn update_authority_ids( &mut self, @@ -524,6 +541,11 @@ impl RandomRouting { pub fn inc_sent(&mut self) { self.sent += 1 } + + /// Returns `true` if we already took all the necessary samples. + pub fn is_complete(&self) -> bool { + self.sent >= self.target + } } /// Routing mode diff --git a/polkadot/node/network/statement-distribution/Cargo.toml b/polkadot/node/network/statement-distribution/Cargo.toml index b044acd1a86d372019cd93b1c628601ae43a465d..2a9773ddde4bd316d3133086131399829ffc5626 100644 --- a/polkadot/node/network/statement-distribution/Cargo.toml +++ b/polkadot/node/network/statement-distribution/Cargo.toml @@ -10,39 +10,39 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.30" -futures-timer = "3.0.2" -gum = { package = "tracing-gum", path = "../../gum" } -polkadot-primitives = { path = "../../../primitives" } -sp-staking = { path = "../../../../substrate/primitives/staking", default-features = false } -sp-keystore = { path = "../../../../substrate/primitives/keystore" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-primitives = { path = "../../primitives" } -polkadot-node-subsystem-util = { path = "../../subsystem-util" } -polkadot-node-network-protocol = { path = "../protocol" } -arrayvec = "0.7.4" -indexmap = "2.0.0" -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } +futures = { workspace = true } +futures-timer = { workspace = true } +gum = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +sp-staking = { workspace = true } +sp-keystore = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } +arrayvec = { workspace = true } +indexmap = { workspace = true } +codec = { features = ["derive"], workspace = true } thiserror = { workspace = true } -fatality = "0.1.1" -bitvec = "1" +fatality = { workspace = true } +bitvec = { workspace = true, default-features = true } [dev-dependencies] -async-channel = "1.8.0" -assert_matches = "1.4.0" -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } -sp-authority-discovery = { path = "../../../../substrate/primitives/authority-discovery" } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto" } -sp-keystore = { path = "../../../../substrate/primitives/keystore" } -sp-tracing = { path = "../../../../substrate/primitives/tracing" } -sc-keystore = { path = "../../../../substrate/client/keystore" } -sc-network = { path = "../../../../substrate/client/network" } -futures-timer = "3.0.2" -polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } -rand_chacha = "0.3" -polkadot-subsystem-bench = { path = "../../subsystem-bench" } +async-channel = { workspace = true } +assert_matches = { workspace = true } +polkadot-node-subsystem-test-helpers = { workspace = true } +sp-authority-discovery = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +sc-keystore = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +futures-timer = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } +rand_chacha = { workspace = true, default-features = true } +polkadot-subsystem-bench = { workspace = true } [[bench]] name = "statement-distribution-regression-bench" diff --git a/polkadot/node/network/statement-distribution/benches/statement-distribution-regression-bench.rs b/polkadot/node/network/statement-distribution/benches/statement-distribution-regression-bench.rs index 9cbe385e3f42ee5be7dc0e5cda44bdbc92930828..4e7206e0a366d0ff85728313f307ec4a8caf81ea 100644 --- a/polkadot/node/network/statement-distribution/benches/statement-distribution-regression-bench.rs +++ b/polkadot/node/network/statement-distribution/benches/statement-distribution-regression-bench.rs @@ -63,7 +63,7 @@ fn main() -> Result<(), String> { ("Received from peers", 106.4000, 0.001), ("Sent to peers", 127.9100, 0.001), ])); - messages.extend(average_usage.check_cpu_usage(&[("statement-distribution", 0.0390, 0.1)])); + messages.extend(average_usage.check_cpu_usage(&[("statement-distribution", 0.0374, 0.1)])); if messages.is_empty() { Ok(()) diff --git a/polkadot/node/network/statement-distribution/src/lib.rs b/polkadot/node/network/statement-distribution/src/lib.rs index 4d56c795f13b29949a7a3b3e7f9bfc85e89ab274..33431eb1edce585943100e4c23d7234a39779f9c 100644 --- a/polkadot/node/network/statement-distribution/src/lib.rs +++ b/polkadot/node/network/statement-distribution/src/lib.rs @@ -284,7 +284,14 @@ impl StatementDistributionSubsystem { ); }, MuxedMessage::Response(result) => { - v2::handle_response(&mut ctx, &mut state, result, &mut self.reputation).await; + v2::handle_response( + &mut ctx, + &mut state, + result, + &mut self.reputation, + &self.metrics, + ) + .await; }, MuxedMessage::RetryRequest(()) => { // A pending request is ready to retry. This is only a signal to call @@ -320,7 +327,8 @@ impl StatementDistributionSubsystem { let mode = prospective_parachains_mode(ctx.sender(), activated.hash).await?; if let ProspectiveParachainsMode::Enabled { .. } = mode { let res = - v2::handle_active_leaves_update(ctx, state, activated, mode).await; + v2::handle_active_leaves_update(ctx, state, activated, mode, &metrics) + .await; // Regardless of the result of leaf activation, we always prune before // handling it to avoid leaks. v2::handle_deactivate_leaves(state, &deactivated); @@ -370,6 +378,7 @@ impl StatementDistributionSubsystem { relay_parent, statement, &mut self.reputation, + &self.metrics, ) .await?; } @@ -428,11 +437,24 @@ impl StatementDistributionSubsystem { if target.targets_current() { // pass to v2. - v2::handle_network_update(ctx, state, event, &mut self.reputation).await; + v2::handle_network_update( + ctx, + state, + event, + &mut self.reputation, + &self.metrics, + ) + .await; } }, StatementDistributionMessage::Backed(candidate_hash) => { - crate::v2::handle_backed_candidate_message(ctx, state, candidate_hash).await; + crate::v2::handle_backed_candidate_message( + ctx, + state, + candidate_hash, + &self.metrics, + ) + .await; }, }, } diff --git a/polkadot/node/network/statement-distribution/src/metrics.rs b/polkadot/node/network/statement-distribution/src/metrics.rs index 1bc994174263905d3058154ead29eaaa16bd2ad4..e21fff1e6421e3c90df07c6c1c1237721ce33760 100644 --- a/polkadot/node/network/statement-distribution/src/metrics.rs +++ b/polkadot/node/network/statement-distribution/src/metrics.rs @@ -25,13 +25,13 @@ const HISTOGRAM_LATENCY_BUCKETS: &[f64] = &[ #[derive(Clone)] struct MetricsInner { // V1 - statements_distributed: prometheus::Counter, sent_requests: prometheus::Counter, received_responses: prometheus::CounterVec, network_bridge_update: prometheus::HistogramVec, statements_unexpected: prometheus::CounterVec, created_message_size: prometheus::Gauge, // V1+ + statements_distributed: prometheus::Counter, active_leaves_update: prometheus::Histogram, share: prometheus::Histogram, // V2+ @@ -51,6 +51,13 @@ impl Metrics { } } + /// Update statements distributed counter by an amount + pub fn on_statements_distributed(&self, n: usize) { + if let Some(metrics) = &self.0 { + metrics.statements_distributed.inc_by(n as u64); + } + } + /// Update sent requests counter /// This counter is updated merely for the statements sent via request/response method, /// meaning that it counts large statements only diff --git a/polkadot/node/network/statement-distribution/src/v2/mod.rs b/polkadot/node/network/statement-distribution/src/v2/mod.rs index 2bb9c82c6a6fa00a84b5274a12f7e79398ca89f3..47d350849b206913b9e493cd9befd6086d0c4e7b 100644 --- a/polkadot/node/network/statement-distribution/src/v2/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/mod.rs @@ -400,6 +400,7 @@ pub(crate) async fn handle_network_update( state: &mut State, update: NetworkBridgeEvent, reputation: &mut ReputationAggregator, + metrics: &Metrics, ) { match update { NetworkBridgeEvent::PeerConnected(peer_id, role, protocol_version, mut authority_ids) => { @@ -483,23 +484,33 @@ pub(crate) async fn handle_network_update( net_protocol::StatementDistributionMessage::V3( protocol_v3::StatementDistributionMessage::Statement(relay_parent, statement), ) => - handle_incoming_statement(ctx, state, peer_id, relay_parent, statement, reputation) - .await, + handle_incoming_statement( + ctx, + state, + peer_id, + relay_parent, + statement, + reputation, + metrics, + ) + .await, net_protocol::StatementDistributionMessage::V2( protocol_v2::StatementDistributionMessage::BackedCandidateManifest(inner), ) | net_protocol::StatementDistributionMessage::V3( protocol_v3::StatementDistributionMessage::BackedCandidateManifest(inner), - ) => handle_incoming_manifest(ctx, state, peer_id, inner, reputation).await, + ) => handle_incoming_manifest(ctx, state, peer_id, inner, reputation, metrics).await, net_protocol::StatementDistributionMessage::V2( protocol_v2::StatementDistributionMessage::BackedCandidateKnown(inner), ) | net_protocol::StatementDistributionMessage::V3( protocol_v3::StatementDistributionMessage::BackedCandidateKnown(inner), - ) => handle_incoming_acknowledgement(ctx, state, peer_id, inner, reputation).await, + ) => + handle_incoming_acknowledgement(ctx, state, peer_id, inner, reputation, metrics) + .await, }, NetworkBridgeEvent::PeerViewChange(peer_id, view) => - handle_peer_view_update(ctx, state, peer_id, view).await, + handle_peer_view_update(ctx, state, peer_id, view, metrics).await, NetworkBridgeEvent::OurViewChange(_view) => { // handled by `handle_activated_leaf` }, @@ -539,6 +550,7 @@ pub(crate) async fn handle_active_leaves_update( state: &mut State, activated: &ActivatedLeaf, leaf_mode: ProspectiveParachainsMode, + metrics: &Metrics, ) -> JfyiErrorResult<()> { let max_candidate_depth = match leaf_mode { ProspectiveParachainsMode::Disabled => return Ok(()), @@ -714,7 +726,8 @@ pub(crate) async fn handle_active_leaves_update( for (peer, fresh) in update_peers { for fresh_relay_parent in fresh { - send_peer_messages_for_relay_parent(ctx, state, peer, fresh_relay_parent).await; + send_peer_messages_for_relay_parent(ctx, state, peer, fresh_relay_parent, metrics) + .await; } } } @@ -815,6 +828,7 @@ async fn handle_peer_view_update( state: &mut State, peer: PeerId, new_view: View, + metrics: &Metrics, ) { let fresh_implicit = { let peer_data = match state.peers.get_mut(&peer) { @@ -826,7 +840,7 @@ async fn handle_peer_view_update( }; for new_relay_parent in fresh_implicit { - send_peer_messages_for_relay_parent(ctx, state, peer, new_relay_parent).await; + send_peer_messages_for_relay_parent(ctx, state, peer, new_relay_parent, metrics).await; } } @@ -857,6 +871,7 @@ async fn send_peer_messages_for_relay_parent( state: &mut State, peer: PeerId, relay_parent: Hash, + metrics: &Metrics, ) { let peer_data = match state.peers.get_mut(&peer) { None => return, @@ -889,6 +904,7 @@ async fn send_peer_messages_for_relay_parent( &mut active.cluster_tracker, &state.candidates, &relay_parent_state.statement_store, + metrics, ) .await; } @@ -901,6 +917,7 @@ async fn send_peer_messages_for_relay_parent( &per_session_state.groups, relay_parent_state, &state.candidates, + metrics, ) .await; } @@ -949,6 +966,7 @@ async fn send_pending_cluster_statements( cluster_tracker: &mut ClusterTracker, candidates: &Candidates, statement_store: &StatementStore, + metrics: &Metrics, ) { let pending_statements = cluster_tracker.pending_statements_for(peer_validator_id); let network_messages = pending_statements @@ -974,12 +992,12 @@ async fn send_pending_cluster_statements( }) .collect::>(); - if network_messages.is_empty() { - return + if !network_messages.is_empty() { + let count = network_messages.len(); + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessages(network_messages)) + .await; + metrics.on_statements_distributed(count); } - - ctx.send_message(NetworkBridgeTxMessage::SendValidationMessages(network_messages)) - .await; } /// Send a peer all pending grid messages / acknowledgements / follow up statements @@ -993,6 +1011,7 @@ async fn send_pending_grid_messages( groups: &Groups, relay_parent_state: &mut PerRelayParentState, candidates: &Candidates, + metrics: &Metrics, ) { let pending_manifests = { let local_validator = match relay_parent_state.local_validator.as_mut() { @@ -1005,6 +1024,7 @@ async fn send_pending_grid_messages( }; let mut messages: Vec<(Vec, net_protocol::VersionedValidationProtocol)> = Vec::new(); + let mut statements_count = 0; for (candidate_hash, kind) in pending_manifests { let confirmed_candidate = match candidates.get_confirmed(&candidate_hash) { None => continue, // sanity @@ -1079,7 +1099,7 @@ async fn send_pending_grid_messages( }; }, grid::ManifestKind::Acknowledgement => { - messages.extend(acknowledgement_and_statement_messages( + let (m, c) = acknowledgement_and_statement_messages( peer_id, peer_validator_id, groups, @@ -1088,7 +1108,9 @@ async fn send_pending_grid_messages( group_index, candidate_hash, local_knowledge, - )); + ); + messages.extend(m); + statements_count += c; }, } } @@ -1107,8 +1129,9 @@ async fn send_pending_grid_messages( let pending_statements = grid_tracker.all_pending_statements_for(peer_validator_id); - let extra_statements = - pending_statements.into_iter().filter_map(|(originator, compact)| { + let extra_statements = pending_statements + .into_iter() + .filter_map(|(originator, compact)| { let res = pending_statement_network_message( &relay_parent_state.statement_store, relay_parent, @@ -1128,15 +1151,17 @@ async fn send_pending_grid_messages( } res - }); + }) + .collect::>(); + statements_count += extra_statements.len(); messages.extend(extra_statements); } - if messages.is_empty() { - return + if !messages.is_empty() { + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessages(messages)).await; + metrics.on_statements_distributed(statements_count); } - ctx.send_message(NetworkBridgeTxMessage::SendValidationMessages(messages)).await; } // Imports a locally originating statement and distributes it to peers. @@ -1147,6 +1172,7 @@ pub(crate) async fn share_local_statement( relay_parent: Hash, statement: SignedFullStatementWithPVD, reputation: &mut ReputationAggregator, + metrics: &Metrics, ) -> JfyiErrorResult<()> { let per_relay_parent = match state.per_relay_parent.get_mut(&relay_parent) { None => return Err(JfyiError::InvalidShare), @@ -1269,11 +1295,12 @@ pub(crate) async fn share_local_statement( &state.authorities, &state.peers, compact_statement, + metrics, ) .await; if let Some(post_confirmation) = post_confirmation { - apply_post_confirmation(ctx, state, post_confirmation, reputation).await; + apply_post_confirmation(ctx, state, post_confirmation, reputation, metrics).await; } Ok(()) @@ -1310,6 +1337,7 @@ async fn circulate_statement( authorities: &HashMap, peers: &HashMap, statement: SignedStatement, + metrics: &Metrics, ) { let session_info = &per_session.session_info; @@ -1446,6 +1474,7 @@ async fn circulate_statement( .into(), )) .await; + metrics.on_statement_distributed(); } if !statement_to_v3_peers.is_empty() { @@ -1465,6 +1494,7 @@ async fn circulate_statement( .into(), )) .await; + metrics.on_statement_distributed(); } } /// Check a statement signature under this parent hash. @@ -1511,6 +1541,7 @@ async fn handle_incoming_statement( relay_parent: Hash, statement: UncheckedSignedStatement, reputation: &mut ReputationAggregator, + metrics: &Metrics, ) { let peer_state = match state.peers.get(&peer) { None => { @@ -1787,6 +1818,7 @@ async fn handle_incoming_statement( &state.authorities, &state.peers, checked_statement, + metrics, ) .await; } else { @@ -1944,6 +1976,7 @@ async fn provide_candidate_to_grid( per_session: &PerSessionState, authorities: &HashMap, peers: &HashMap, + metrics: &Metrics, ) { let local_validator = match relay_parent_state.local_validator { Some(ref mut v) => v, @@ -2131,8 +2164,10 @@ async fn provide_candidate_to_grid( .await; } if !post_statements.is_empty() { + let count = post_statements.len(); ctx.send_message(NetworkBridgeTxMessage::SendValidationMessages(post_statements)) .await; + metrics.on_statements_distributed(count); } } @@ -2532,6 +2567,7 @@ async fn handle_incoming_manifest( peer: PeerId, manifest: net_protocol::v2::BackedCandidateManifest, reputation: &mut ReputationAggregator, + metrics: &Metrics, ) { gum::debug!( target: LOG_TARGET, @@ -2588,7 +2624,7 @@ async fn handle_incoming_manifest( ) }; - let messages = acknowledgement_and_statement_messages( + let (messages, statements_count) = acknowledgement_and_statement_messages( &( peer, state @@ -2609,6 +2645,7 @@ async fn handle_incoming_manifest( if !messages.is_empty() { ctx.send_message(NetworkBridgeTxMessage::SendValidationMessages(messages)).await; + metrics.on_statements_distributed(statements_count); } } else if !state.candidates.is_confirmed(&manifest.candidate_hash) { // 5. if unconfirmed, add request entry @@ -2636,9 +2673,9 @@ fn acknowledgement_and_statement_messages( group_index: GroupIndex, candidate_hash: CandidateHash, local_knowledge: StatementFilter, -) -> Vec<(Vec, net_protocol::VersionedValidationProtocol)> { +) -> (Vec<(Vec, net_protocol::VersionedValidationProtocol)>, usize) { let local_validator = match relay_parent_state.local_validator.as_mut() { - None => return Vec::new(), + None => return (Vec::new(), 0), Some(l) => l, }; @@ -2666,7 +2703,7 @@ fn acknowledgement_and_statement_messages( "Bug ValidationVersion::V1 should not be used in statement-distribution v2, legacy should have handled this" ); - return Vec::new() + return (Vec::new(), 0) }, }; @@ -2687,10 +2724,11 @@ fn acknowledgement_and_statement_messages( candidate_hash, peer, ); + let statements_count = statement_messages.len(); messages.extend(statement_messages.into_iter().map(|m| (vec![peer.0], m))); - messages + (messages, statements_count) } #[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] @@ -2700,6 +2738,7 @@ async fn handle_incoming_acknowledgement( peer: PeerId, acknowledgement: net_protocol::v2::BackedCandidateAcknowledgement, reputation: &mut ReputationAggregator, + metrics: &Metrics, ) { // The key difference between acknowledgments and full manifests is that only // the candidate hash is included alongside the bitfields, so the candidate @@ -2780,10 +2819,12 @@ async fn handle_incoming_acknowledgement( ); if !messages.is_empty() { + let count = messages.len(); ctx.send_message(NetworkBridgeTxMessage::SendValidationMessages( messages.into_iter().map(|m| (vec![peer], m)).collect(), )) .await; + metrics.on_statements_distributed(count); } } @@ -2793,6 +2834,7 @@ pub(crate) async fn handle_backed_candidate_message( ctx: &mut Context, state: &mut State, candidate_hash: CandidateHash, + metrics: &Metrics, ) { // If the candidate is unknown or unconfirmed, it's a race (pruned before receiving message) // or a bug. Ignore if so @@ -2834,6 +2876,7 @@ pub(crate) async fn handle_backed_candidate_message( per_session, &state.authorities, &state.peers, + metrics, ) .await; @@ -2855,6 +2898,7 @@ async fn send_cluster_candidate_statements( state: &mut State, candidate_hash: CandidateHash, relay_parent: Hash, + metrics: &Metrics, ) { let relay_parent_state = match state.per_relay_parent.get_mut(&relay_parent) { None => return, @@ -2897,6 +2941,7 @@ async fn send_cluster_candidate_statements( &state.authorities, &state.peers, statement, + metrics, ) .await; } @@ -2914,6 +2959,7 @@ async fn apply_post_confirmation( state: &mut State, post_confirmation: PostConfirmation, reputation: &mut ReputationAggregator, + metrics: &Metrics, ) { for peer in post_confirmation.reckoning.incorrect { modify_reputation(reputation, ctx.sender(), peer, COST_INACCURATE_ADVERTISEMENT).await; @@ -2927,6 +2973,7 @@ async fn apply_post_confirmation( state, candidate_hash, post_confirmation.hypothetical.relay_parent(), + metrics, ) .await; new_confirmed_candidate_fragment_chain_updates(ctx, state, post_confirmation.hypothetical) @@ -3052,6 +3099,7 @@ pub(crate) async fn handle_response( state: &mut State, response: UnhandledResponse, reputation: &mut ReputationAggregator, + metrics: &Metrics, ) { let &requests::CandidateIdentifier { relay_parent, candidate_hash, group_index } = response.candidate_identifier(); @@ -3151,7 +3199,7 @@ pub(crate) async fn handle_response( }; // Note that this implicitly circulates all statements via the cluster. - apply_post_confirmation(ctx, state, post_confirmation, reputation).await; + apply_post_confirmation(ctx, state, post_confirmation, reputation, metrics).await; let confirmed = state.candidates.get_confirmed(&candidate_hash).expect("just confirmed; qed"); diff --git a/polkadot/node/overseer/Cargo.toml b/polkadot/node/overseer/Cargo.toml index e77cead4a7565de9afd71d484c57e9fddc4e2d00..2253a5ae0c668c0c107f19ad15ef933c1cf17abc 100644 --- a/polkadot/node/overseer/Cargo.toml +++ b/polkadot/node/overseer/Cargo.toml @@ -10,30 +10,30 @@ description = "System overseer of the Polkadot node" workspace = true [dependencies] -sc-client-api = { path = "../../../substrate/client/api" } -sp-api = { path = "../../../substrate/primitives/api" } -futures = "0.3.30" -futures-timer = "3.0.2" -parking_lot = "0.12.1" -polkadot-node-network-protocol = { path = "../network/protocol" } -polkadot-node-primitives = { path = "../primitives" } -polkadot-node-subsystem-types = { path = "../subsystem-types" } -polkadot-node-metrics = { path = "../metrics" } -polkadot-primitives = { path = "../../primitives" } -orchestra = { version = "0.3.5", default-features = false, features = ["futures_channel"] } -gum = { package = "tracing-gum", path = "../gum" } -sp-core = { path = "../../../substrate/primitives/core" } -async-trait = "0.1.79" -tikv-jemalloc-ctl = { version = "0.5.0", optional = true } +sc-client-api = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +futures = { workspace = true } +futures-timer = { workspace = true } +parking_lot = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem-types = { workspace = true, default-features = true } +polkadot-node-metrics = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +orchestra = { features = ["futures_channel"], workspace = true } +gum = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +async-trait = { workspace = true } +tikv-jemalloc-ctl = { optional = true, workspace = true } [dev-dependencies] -metered = { package = "prioritized-metered-channel", version = "0.6.1", default-features = false, features = ["futures_channel"] } -sp-core = { path = "../../../substrate/primitives/core" } -futures = { version = "0.3.30", features = ["thread-pool"] } -femme = "2.2.1" -assert_matches = "1.4.0" -polkadot-primitives-test-helpers = { path = "../../primitives/test-helpers" } -polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } +metered = { features = ["futures_channel"], workspace = true } +sp-core = { workspace = true, default-features = true } +futures = { features = ["thread-pool"], workspace = true } +femme = { workspace = true } +assert_matches = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } +polkadot-node-subsystem-test-helpers = { workspace = true } [target.'cfg(target_os = "linux")'.dependencies] tikv-jemalloc-ctl = "0.5.0" diff --git a/polkadot/node/overseer/src/lib.rs b/polkadot/node/overseer/src/lib.rs index 24985a99913d82cc265d1cd3b6d6db66dd282247..4e13d5eda76f61c646ad0814e1ec3d8068a11ca1 100644 --- a/polkadot/node/overseer/src/lib.rs +++ b/polkadot/node/overseer/src/lib.rs @@ -105,10 +105,11 @@ pub use polkadot_node_metrics::{ pub use orchestra as gen; pub use orchestra::{ - contextbounds, orchestra, subsystem, FromOrchestra, MapSubsystem, MessagePacket, - OrchestraError as OverseerError, SignalsReceived, Spawner, Subsystem, SubsystemContext, - SubsystemIncomingMessages, SubsystemInstance, SubsystemMeterReadouts, SubsystemMeters, - SubsystemSender, TimeoutExt, ToOrchestra, TrySendError, + contextbounds, orchestra, subsystem, FromOrchestra, HighPriority, MapSubsystem, MessagePacket, + NormalPriority, OrchestraError as OverseerError, Priority, PriorityLevel, SignalsReceived, + Spawner, Subsystem, SubsystemContext, SubsystemIncomingMessages, SubsystemInstance, + SubsystemMeterReadouts, SubsystemMeters, SubsystemSender, TimeoutExt, ToOrchestra, + TrySendError, }; #[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] @@ -495,7 +496,7 @@ pub struct Overseer { RuntimeApiMessage, ProspectiveParachainsMessage, ChainApiMessage, - ])] + ], can_receive_priority_messages)] statement_distribution: StatementDistribution, #[subsystem(AvailabilityDistributionMessage, sends: [ @@ -524,7 +525,7 @@ pub struct Overseer { RuntimeApiMessage, NetworkBridgeTxMessage, ProvisionerMessage, - ])] + ], can_receive_priority_messages)] bitfield_distribution: BitfieldDistribution, #[subsystem(ProvisionerMessage, sends: [ @@ -580,7 +581,7 @@ pub struct Overseer { #[subsystem(blocking, message_capacity: 64000, ApprovalDistributionMessage, sends: [ NetworkBridgeTxMessage, ApprovalVotingMessage, - ])] + ], can_receive_priority_messages)] approval_distribution: ApprovalDistribution, #[subsystem(blocking, ApprovalVotingMessage, sends: [ @@ -599,7 +600,7 @@ pub struct Overseer { NetworkBridgeRxMessage, // TODO RuntimeApiMessage, ChainSelectionMessage, - ])] + ], can_receive_priority_messages)] gossip_support: GossipSupport, #[subsystem(blocking, message_capacity: 32000, DisputeCoordinatorMessage, sends: [ diff --git a/polkadot/node/overseer/src/tests.rs b/polkadot/node/overseer/src/tests.rs index 177e3addf368d715d51c5bcd7d7437515d56cd5b..8e78d8fc8921a8bd26686e295b584c4e1fff6433 100644 --- a/polkadot/node/overseer/src/tests.rs +++ b/polkadot/node/overseer/src/tests.rs @@ -813,7 +813,7 @@ fn test_candidate_validation_msg() -> CandidateValidationMessage { fn test_candidate_backing_msg() -> CandidateBackingMessage { let (sender, _) = oneshot::channel(); - CandidateBackingMessage::GetBackedCandidates(Default::default(), sender) + CandidateBackingMessage::GetBackableCandidates(Default::default(), sender) } fn test_chain_api_msg() -> ChainApiMessage { diff --git a/polkadot/node/primitives/Cargo.toml b/polkadot/node/primitives/Cargo.toml index 0a84e5dae2a589ef5cd165ce2825bf811751af94..cd642bf16ff9bf7d6ffeeea2ce0dac752128bd3c 100644 --- a/polkadot/node/primitives/Cargo.toml +++ b/polkadot/node/primitives/Cargo.toml @@ -10,24 +10,24 @@ license.workspace = true workspace = true [dependencies] -bounded-vec = "0.7" -futures = "0.3.30" -polkadot-primitives = { path = "../../primitives" } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -sp-core = { path = "../../../substrate/primitives/core" } -sp-application-crypto = { path = "../../../substrate/primitives/application-crypto" } -sp-consensus-babe = { path = "../../../substrate/primitives/consensus/babe" } -sp-keystore = { path = "../../../substrate/primitives/keystore" } -sp-maybe-compressed-blob = { path = "../../../substrate/primitives/maybe-compressed-blob" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } -polkadot-parachain-primitives = { path = "../../parachain", default-features = false } -schnorrkel = "0.11.4" +bounded-vec = { workspace = true } +futures = { workspace = true } +polkadot-primitives = { workspace = true, default-features = true } +codec = { features = ["derive"], workspace = true } +sp-core = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-maybe-compressed-blob = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true } +schnorrkel = { workspace = true, default-features = true } thiserror = { workspace = true } -bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } +bitvec = { features = ["alloc"], workspace = true } serde = { features = ["derive"], workspace = true, default-features = true } [target.'cfg(not(target_os = "unknown"))'.dependencies] zstd = { version = "0.12.4", default-features = false } [dev-dependencies] -polkadot-erasure-coding = { path = "../../erasure-coding" } +polkadot-erasure-coding = { workspace = true, default-features = true } diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index ecf79eac2883e930213fb54e4bf16b8a266a0c42..660b504e97fbb1bc11c1bfd57011931157e4770d 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -59,7 +59,7 @@ pub use disputes::{ /// relatively rare. /// /// The associated worker binaries should use the same version as the node that spawns them. -pub const NODE_VERSION: &'static str = "1.13.0"; +pub const NODE_VERSION: &'static str = "1.14.0"; // For a 16-ary Merkle Prefix Trie, we can expect at most 16 32-byte hashes per node // plus some overhead: diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index ec5113d2c8a5f0bc40e404dbf78201c5b2a65102..c0ddbf7dcfc36d89591567a88075c2344b025b04 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -12,147 +12,147 @@ workspace = true [dependencies] # Substrate Client -sc-authority-discovery = { path = "../../../substrate/client/authority-discovery" } -sc-consensus-babe = { path = "../../../substrate/client/consensus/babe" } -sc-consensus-beefy = { path = "../../../substrate/client/consensus/beefy" } -sc-consensus-grandpa = { path = "../../../substrate/client/consensus/grandpa" } -mmr-gadget = { path = "../../../substrate/client/merkle-mountain-range" } -sp-mmr-primitives = { path = "../../../substrate/primitives/merkle-mountain-range" } -sc-block-builder = { path = "../../../substrate/client/block-builder" } -sc-chain-spec = { path = "../../../substrate/client/chain-spec" } -sc-client-api = { path = "../../../substrate/client/api" } -sc-client-db = { path = "../../../substrate/client/db" } -sc-consensus = { path = "../../../substrate/client/consensus/common" } -sc-consensus-slots = { path = "../../../substrate/client/consensus/slots" } -sc-executor = { path = "../../../substrate/client/executor" } -sc-network = { path = "../../../substrate/client/network" } -sc-network-common = { path = "../../../substrate/client/network/common" } -sc-network-sync = { path = "../../../substrate/client/network/sync" } -sc-transaction-pool = { path = "../../../substrate/client/transaction-pool" } -sc-transaction-pool-api = { path = "../../../substrate/client/transaction-pool/api" } -sc-sync-state-rpc = { path = "../../../substrate/client/sync-state-rpc" } -sc-keystore = { path = "../../../substrate/client/keystore" } -sc-basic-authorship = { path = "../../../substrate/client/basic-authorship" } -sc-offchain = { path = "../../../substrate/client/offchain" } -sc-sysinfo = { path = "../../../substrate/client/sysinfo" } -sc-service = { path = "../../../substrate/client/service", default-features = false } -sc-telemetry = { path = "../../../substrate/client/telemetry" } +sc-authority-discovery = { workspace = true, default-features = true } +sc-consensus-babe = { workspace = true, default-features = true } +sc-consensus-beefy = { workspace = true, default-features = true } +sc-consensus-grandpa = { workspace = true, default-features = true } +mmr-gadget = { workspace = true, default-features = true } +sp-mmr-primitives = { workspace = true, default-features = true } +sc-block-builder = { workspace = true, default-features = true } +sc-chain-spec = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-client-db = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sc-consensus-slots = { workspace = true, default-features = true } +sc-executor = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-network-common = { workspace = true, default-features = true } +sc-network-sync = { workspace = true, default-features = true } +sc-transaction-pool = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } +sc-sync-state-rpc = { workspace = true, default-features = true } +sc-keystore = { workspace = true, default-features = true } +sc-basic-authorship = { workspace = true, default-features = true } +sc-offchain = { workspace = true, default-features = true } +sc-sysinfo = { workspace = true, default-features = true } +sc-service = { workspace = true } +sc-telemetry = { workspace = true, default-features = true } # Substrate Primitives -sp-authority-discovery = { path = "../../../substrate/primitives/authority-discovery" } -sp-consensus = { path = "../../../substrate/primitives/consensus/common" } -sp-consensus-beefy = { path = "../../../substrate/primitives/consensus/beefy" } -sp-consensus-grandpa = { path = "../../../substrate/primitives/consensus/grandpa" } -sp-inherents = { path = "../../../substrate/primitives/inherents" } -sp-keyring = { path = "../../../substrate/primitives/keyring" } -sp-api = { path = "../../../substrate/primitives/api" } -sp-block-builder = { path = "../../../substrate/primitives/block-builder" } -sp-blockchain = { path = "../../../substrate/primitives/blockchain" } -sp-core = { path = "../../../substrate/primitives/core" } -sp-io = { path = "../../../substrate/primitives/io" } -sp-keystore = { path = "../../../substrate/primitives/keystore" } -sp-offchain = { package = "sp-offchain", path = "../../../substrate/primitives/offchain" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } -sp-session = { path = "../../../substrate/primitives/session" } -sp-storage = { path = "../../../substrate/primitives/storage" } -sp-transaction-pool = { path = "../../../substrate/primitives/transaction-pool" } -pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment" } -sp-timestamp = { path = "../../../substrate/primitives/timestamp" } -sp-consensus-babe = { path = "../../../substrate/primitives/consensus/babe" } -sp-state-machine = { path = "../../../substrate/primitives/state-machine" } -sp-weights = { path = "../../../substrate/primitives/weights" } -sp-version = { path = "../../../substrate/primitives/version" } +sp-authority-discovery = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-consensus-beefy = { workspace = true, default-features = true } +sp-consensus-grandpa = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-block-builder = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-offchain = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-session = { workspace = true, default-features = true } +sp-storage = { workspace = true, default-features = true } +sp-transaction-pool = { workspace = true, default-features = true } +pallet-transaction-payment = { workspace = true, default-features = true } +sp-timestamp = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } +sp-weights = { workspace = true, default-features = true } +sp-version = { workspace = true, default-features = true } # Substrate Pallets -pallet-babe = { path = "../../../substrate/frame/babe" } -pallet-staking = { path = "../../../substrate/frame/staking" } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../substrate/frame/transaction-payment/rpc/runtime-api" } -frame-metadata-hash-extension = { path = "../../../substrate/frame/metadata-hash-extension", optional = true } -frame-system = { path = "../../../substrate/frame/system" } +pallet-babe = { workspace = true, default-features = true } +pallet-staking = { workspace = true, default-features = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true, default-features = true } +frame-metadata-hash-extension = { optional = true, workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } # Substrate Other -frame-system-rpc-runtime-api = { path = "../../../substrate/frame/system/rpc/runtime-api" } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../substrate/utils/prometheus" } -frame-support = { path = "../../../substrate/frame/support" } -frame-benchmarking-cli = { path = "../../../substrate/utils/frame/benchmarking-cli" } -frame-benchmarking = { path = "../../../substrate/frame/benchmarking" } +frame-system-rpc-runtime-api = { workspace = true, default-features = true } +prometheus-endpoint = { workspace = true, default-features = true } +frame-support = { workspace = true, default-features = true } +frame-benchmarking-cli = { workspace = true, default-features = true } +frame-benchmarking = { workspace = true, default-features = true } # External Crates -async-trait = "0.1.79" -futures = "0.3.30" -hex-literal = "0.4.1" -is_executable = "1.0.1" -gum = { package = "tracing-gum", path = "../gum" } +async-trait = { workspace = true } +futures = { workspace = true } +hex-literal = { workspace = true, default-features = true } +is_executable = { workspace = true } +gum = { workspace = true, default-features = true } log = { workspace = true, default-features = true } -schnellru = "0.2.1" +schnellru = { workspace = true } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } thiserror = { workspace = true } -kvdb = "0.13.0" -kvdb-rocksdb = { version = "0.19.0", optional = true } -parity-db = { version = "0.4.12", optional = true } -codec = { package = "parity-scale-codec", version = "3.6.12" } -parking_lot = "0.12.1" -bitvec = { version = "1.0.1", optional = true } +kvdb = { workspace = true } +kvdb-rocksdb = { optional = true, workspace = true } +parity-db = { optional = true, workspace = true } +codec = { workspace = true, default-features = true } +parking_lot = { workspace = true, default-features = true } +bitvec = { optional = true, workspace = true, default-features = true } # Polkadot -polkadot-core-primitives = { path = "../../core-primitives" } -polkadot-node-core-parachains-inherent = { path = "../core/parachains-inherent" } -polkadot-overseer = { path = "../overseer" } -polkadot-parachain-primitives = { path = "../../parachain" } -polkadot-primitives = { path = "../../primitives" } -polkadot-node-primitives = { path = "../primitives" } -polkadot-rpc = { path = "../../rpc" } -polkadot-node-subsystem = { path = "../subsystem" } -polkadot-node-subsystem-util = { path = "../subsystem-util" } -polkadot-node-subsystem-types = { path = "../subsystem-types" } -polkadot-runtime-parachains = { path = "../../runtime/parachains" } -polkadot-node-network-protocol = { path = "../network/protocol" } +polkadot-core-primitives = { workspace = true, default-features = true } +polkadot-node-core-parachains-inherent = { workspace = true, default-features = true } +polkadot-overseer = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-rpc = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-node-subsystem-types = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } # Polkadot Runtime Constants -rococo-runtime-constants = { path = "../../runtime/rococo/constants", optional = true } -westend-runtime-constants = { path = "../../runtime/westend/constants", optional = true } +rococo-runtime-constants = { optional = true, workspace = true, default-features = true } +westend-runtime-constants = { optional = true, workspace = true, default-features = true } # Polkadot Runtimes -westend-runtime = { path = "../../runtime/westend", optional = true } -rococo-runtime = { path = "../../runtime/rococo", optional = true } +westend-runtime = { optional = true, workspace = true } +rococo-runtime = { optional = true, workspace = true } # Polkadot Subsystems -polkadot-approval-distribution = { path = "../network/approval-distribution", optional = true } -polkadot-availability-bitfield-distribution = { path = "../network/bitfield-distribution", optional = true } -polkadot-availability-distribution = { path = "../network/availability-distribution", optional = true } -polkadot-availability-recovery = { path = "../network/availability-recovery", optional = true } -polkadot-collator-protocol = { path = "../network/collator-protocol", optional = true } -polkadot-dispute-distribution = { path = "../network/dispute-distribution", optional = true } -polkadot-gossip-support = { path = "../network/gossip-support", optional = true } -polkadot-network-bridge = { path = "../network/bridge", optional = true } -polkadot-node-collation-generation = { path = "../collation-generation", optional = true } -polkadot-node-core-approval-voting = { path = "../core/approval-voting", optional = true } -polkadot-node-core-av-store = { path = "../core/av-store", optional = true } -polkadot-node-core-backing = { path = "../core/backing", optional = true } -polkadot-node-core-bitfield-signing = { path = "../core/bitfield-signing", optional = true } -polkadot-node-core-candidate-validation = { path = "../core/candidate-validation", optional = true } -polkadot-node-core-chain-api = { path = "../core/chain-api", optional = true } -polkadot-node-core-chain-selection = { path = "../core/chain-selection", optional = true } -polkadot-node-core-dispute-coordinator = { path = "../core/dispute-coordinator", optional = true } -polkadot-node-core-prospective-parachains = { path = "../core/prospective-parachains", optional = true } -polkadot-node-core-provisioner = { path = "../core/provisioner", optional = true } -polkadot-node-core-pvf = { path = "../core/pvf", optional = true } -polkadot-node-core-pvf-checker = { path = "../core/pvf-checker", optional = true } -polkadot-node-core-runtime-api = { path = "../core/runtime-api", optional = true } -polkadot-statement-distribution = { path = "../network/statement-distribution", optional = true } - -xcm = { package = "staging-xcm", path = "../../xcm" } -xcm-fee-payment-runtime-api = { path = "../../xcm/xcm-fee-payment-runtime-api" } +polkadot-approval-distribution = { optional = true, workspace = true, default-features = true } +polkadot-availability-bitfield-distribution = { optional = true, workspace = true, default-features = true } +polkadot-availability-distribution = { optional = true, workspace = true, default-features = true } +polkadot-availability-recovery = { optional = true, workspace = true, default-features = true } +polkadot-collator-protocol = { optional = true, workspace = true, default-features = true } +polkadot-dispute-distribution = { optional = true, workspace = true, default-features = true } +polkadot-gossip-support = { optional = true, workspace = true, default-features = true } +polkadot-network-bridge = { optional = true, workspace = true, default-features = true } +polkadot-node-collation-generation = { optional = true, workspace = true, default-features = true } +polkadot-node-core-approval-voting = { optional = true, workspace = true, default-features = true } +polkadot-node-core-av-store = { optional = true, workspace = true, default-features = true } +polkadot-node-core-backing = { optional = true, workspace = true, default-features = true } +polkadot-node-core-bitfield-signing = { optional = true, workspace = true, default-features = true } +polkadot-node-core-candidate-validation = { optional = true, workspace = true, default-features = true } +polkadot-node-core-chain-api = { optional = true, workspace = true, default-features = true } +polkadot-node-core-chain-selection = { optional = true, workspace = true, default-features = true } +polkadot-node-core-dispute-coordinator = { optional = true, workspace = true, default-features = true } +polkadot-node-core-prospective-parachains = { optional = true, workspace = true, default-features = true } +polkadot-node-core-provisioner = { optional = true, workspace = true, default-features = true } +polkadot-node-core-pvf = { optional = true, workspace = true, default-features = true } +polkadot-node-core-pvf-checker = { optional = true, workspace = true, default-features = true } +polkadot-node-core-runtime-api = { optional = true, workspace = true, default-features = true } +polkadot-statement-distribution = { optional = true, workspace = true, default-features = true } + +xcm = { workspace = true, default-features = true } +xcm-runtime-apis = { workspace = true, default-features = true } [dev-dependencies] -polkadot-test-client = { path = "../test/client" } -polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } -polkadot-primitives-test-helpers = { path = "../../primitives/test-helpers" } -env_logger = "0.11" -assert_matches = "1.5.0" -serial_test = "2.0.0" -tempfile = "3.2" +polkadot-test-client = { workspace = true } +polkadot-node-subsystem-test-helpers = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } +env_logger = { workspace = true } +assert_matches = { workspace = true } +serial_test = { workspace = true } +tempfile = { workspace = true } [features] default = ["db", "full-node"] @@ -201,6 +201,13 @@ rococo-native = [ "rococo-runtime-constants", ] +# Generate the metadata hash needed for CheckMetadataHash +# in the test runtimes. +metadata-hash = [ + "rococo-runtime?/metadata-hash", + "westend-runtime?/metadata-hash", +] + runtime-benchmarks = [ "frame-benchmarking-cli/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", @@ -217,7 +224,7 @@ runtime-benchmarks = [ "sc-service/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "westend-runtime?/runtime-benchmarks", - "xcm-fee-payment-runtime-api/runtime-benchmarks", + "xcm-runtime-apis/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", diff --git a/polkadot/node/service/chain-specs/kusama.json b/polkadot/node/service/chain-specs/kusama.json index dfe79fd9c5e5d920ad1da8f1cab38a6796316e97..5d2413ac1e0263bc1cd69d4e9af696c95e909cdd 100644 --- a/polkadot/node/service/chain-specs/kusama.json +++ b/polkadot/node/service/chain-specs/kusama.json @@ -10,8 +10,8 @@ "/dns/kusama-bootnode-1.polkadot.io/tcp/443/wss/p2p/12D3KooWQKqane1SqWJNWMQkbia9qiMWXkcHtAdfW5eVF8hbwEDw", "/dns/kusama-boot.dwellir.com/tcp/30333/ws/p2p/12D3KooWFj2ndawdYyk2spc42Y2arYwb2TUoHLHFAsKuHRzWXwoJ", "/dns/kusama-boot.dwellir.com/tcp/443/wss/p2p/12D3KooWFj2ndawdYyk2spc42Y2arYwb2TUoHLHFAsKuHRzWXwoJ", - "/dns/boot.stake.plus/tcp/31333/p2p/12D3KooWLa1UyG5xLPds2GbiRBCTJjpsVwRWHWN7Dff14yiNJRpR", - "/dns/boot.stake.plus/tcp/31334/wss/p2p/12D3KooWLa1UyG5xLPds2GbiRBCTJjpsVwRWHWN7Dff14yiNJRpR", + "/dns/kusama.boot.stake.plus/tcp/30334/wss/p2p/12D3KooWDQ28HsssSyDnso7ZRiMXGtCGPRi2en6djKDsMf9f7mqE", + "/dns/kusama.boot.stake.plus/tcp/31334/wss/p2p/12D3KooWANYqS81DkERRrBW1swoMgqUHK69pJN8XjQCnS6dnUAps", "/dns/boot-node.helikon.io/tcp/7060/p2p/12D3KooWL4KPqfAsPE2aY1g5Zo1CxsDwcdJ7mmAghK7cg6M2fdbD", "/dns/boot-node.helikon.io/tcp/7062/wss/p2p/12D3KooWL4KPqfAsPE2aY1g5Zo1CxsDwcdJ7mmAghK7cg6M2fdbD", "/dns/kusama.bootnode.amforc.com/tcp/30001/p2p/12D3KooWKvYf6qKaAF8UUDw3KsTwjHLnvkED23yxHbH3npMe8w4G", diff --git a/polkadot/node/service/chain-specs/paseo.json b/polkadot/node/service/chain-specs/paseo.json index e307d5213a396ee9221701e39a9b4be239f591b2..35ac9aa6aa93678192b199f07906d943568ac022 100644 --- a/polkadot/node/service/chain-specs/paseo.json +++ b/polkadot/node/service/chain-specs/paseo.json @@ -5,8 +5,8 @@ "bootNodes": [ "/dns/paseo.bootnode.amforc.com/tcp/29999/wss/p2p/12D3KooWSdf63rZjtGdeWXpQwQwPh8K8c22upcB3B1VmqW8rxrjw", "/dns/paseo.bootnode.amforc.com/tcp/30001/p2p/12D3KooWSdf63rZjtGdeWXpQwQwPh8K8c22upcB3B1VmqW8rxrjw", - "/dns/boot.stake.plus/tcp/43334/wss/p2p/12D3KooWNhgAC3hjZHxaT52EpPFZohkCL1AHFAijqcN8xB9Rwud2", - "/dns/boot.stake.plus/tcp/43333/p2p/12D3KooWNhgAC3hjZHxaT52EpPFZohkCL1AHFAijqcN8xB9Rwud2", + "/dns/paseo.boot.stake.plus/tcp/30334/wss/p2p/12D3KooWDVqd8JXGMPsdYynu2RoBhqftTrFibZyBYibqcjQpHoQu", + "/dns/paseo.boot.stake.plus/tcp/31334/wss/p2p/12D3KooWJ4HjAGR9FUHZhc2jjLQX5Zb2zdJBxPYwrE6Ldpg5jjk4", "/dns/boot.metaspan.io/tcp/36017/wss/p2p/12D3KooWSW6nDfM3SS8rUtjMyjdszivK31bu4a1sRngGa2hFETz7", "/dns/boot.metaspan.io/tcp/36018/p2p/12D3KooWSW6nDfM3SS8rUtjMyjdszivK31bu4a1sRngGa2hFETz7", "/dns/paseo.bootnodes.polkadotters.com/tcp/30538/p2p/12D3KooWPbbFy4TefEGTRF5eTYhq8LEzc4VAHdNUVCbY4nAnhqPP", diff --git a/polkadot/node/service/chain-specs/polkadot.json b/polkadot/node/service/chain-specs/polkadot.json index f79b6db90fcf0cc3513f644edf468ed0c2fc2cd7..553ff1bb3e41e87a9b01c3e1d36019604a83e9b1 100644 --- a/polkadot/node/service/chain-specs/polkadot.json +++ b/polkadot/node/service/chain-specs/polkadot.json @@ -11,8 +11,8 @@ "/dns/polkadot-bootnode-1.polkadot.io/tcp/443/wss/p2p/12D3KooWFN2mhgpkJsDBuNuE5427AcDrsib8EoqGMZmkxWwx3Md4", "/dns/polkadot-boot.dwellir.com/tcp/30334/ws/p2p/12D3KooWKvdDyRKqUfSAaUCbYiLwKY8uK3wDWpCuy2FiDLbkPTDJ", "/dns/polkadot-boot.dwellir.com/tcp/443/wss/p2p/12D3KooWKvdDyRKqUfSAaUCbYiLwKY8uK3wDWpCuy2FiDLbkPTDJ", - "/dns/boot.stake.plus/tcp/30333/p2p/12D3KooWKT4ZHNxXH4icMjdrv7EwWBkfbz5duxE5sdJKKeWFYi5n", - "/dns/boot.stake.plus/tcp/30334/wss/p2p/12D3KooWKT4ZHNxXH4icMjdrv7EwWBkfbz5duxE5sdJKKeWFYi5n", + "/dns/polkadot.boot.stake.plus/tcp/30334/wss/p2p/12D3KooWCZKEvAMJRk9nwTHJcTjgVw6bDEqryQ3B7n7scNtfNqPB", + "/dns/polkadot.boot.stake.plus/tcp/31334/wss/p2p/12D3KooWMFwJV935CyJXE8twfkKxRDnNWeEFd8jZWaoWZF22Hv8S", "/dns/boot-node.helikon.io/tcp/7070/p2p/12D3KooWS9ZcvRxyzrSf6p63QfTCWs12nLoNKhGux865crgxVA4H", "/dns/boot-node.helikon.io/tcp/7072/wss/p2p/12D3KooWS9ZcvRxyzrSf6p63QfTCWs12nLoNKhGux865crgxVA4H", "/dns/polkadot.bootnode.amforc.com/tcp/30001/p2p/12D3KooWT2HyZx5C6BBeLbCKhYG2SqJYuiu7sLMxGzUcQBko3BMr", diff --git a/polkadot/node/service/chain-specs/westend.json b/polkadot/node/service/chain-specs/westend.json index 1bfb5ba334cef24e70b6335436ec10c77929f9e2..9059d525689d9ee2e9103fdda81f039d99b8f470 100644 --- a/polkadot/node/service/chain-specs/westend.json +++ b/polkadot/node/service/chain-specs/westend.json @@ -8,8 +8,8 @@ "/dns/westend-bootnode-1.polkadot.io/tcp/30333/p2p/12D3KooWPVPzs42GvRBShdUMtFsk4SvnByrSdWqb6aeAAHvLMSLS", "/dns/westend-bootnode-1.polkadot.io/tcp/30334/ws/p2p/12D3KooWPVPzs42GvRBShdUMtFsk4SvnByrSdWqb6aeAAHvLMSLS", "/dns/westend-bootnode-1.polkadot.io/tcp/443/wss/p2p/12D3KooWPVPzs42GvRBShdUMtFsk4SvnByrSdWqb6aeAAHvLMSLS", - "/dns/boot.stake.plus/tcp/32333/p2p/12D3KooWK8fjVoSvMq5copQYMsdYreSGPGgcMbGMgbMDPfpf3sm7", - "/dns/boot.stake.plus/tcp/32334/wss/p2p/12D3KooWK8fjVoSvMq5copQYMsdYreSGPGgcMbGMgbMDPfpf3sm7", + "/dns/westend.boot.stake.plus/tcp/30334/wss/p2p/12D3KooWAzfLkJarihZAyDeDet2WpYNkzjpXocGmmDFiRaHJjoyw", + "/dns/westend.boot.stake.plus/tcp/31334/wss/p2p/12D3KooWBdcVpUwnB3AgwZQXcyrvd4yzPBXtSLknvoBSHQZNoftP", "/dns/boot-node.helikon.io/tcp/7080/p2p/12D3KooWRFDPyT8vA8mLzh6dJoyujn4QNjeqi6Ch79eSMz9beKXC", "/dns/boot-node.helikon.io/tcp/7082/wss/p2p/12D3KooWRFDPyT8vA8mLzh6dJoyujn4QNjeqi6Ch79eSMz9beKXC", "/dns/westend.bootnode.amforc.com/tcp/30001/p2p/12D3KooWAPmR7rbm2axPjHzF51yvQNDM5GvWfkF5BTV44Y5vJ3ct", diff --git a/polkadot/node/service/src/fake_runtime_api.rs b/polkadot/node/service/src/fake_runtime_api.rs index dd8a0a7e635bc67e298f31f537f9c41fa207b6a5..cdef39d5bdf1805d1066fdeba9cb09f0037261b1 100644 --- a/polkadot/node/service/src/fake_runtime_api.rs +++ b/polkadot/node/service/src/fake_runtime_api.rs @@ -241,7 +241,7 @@ sp_api::impl_runtime_apis! { unimplemented!() } - fn submit_report_equivocation_unsigned_extrinsic( + fn submit_report_double_voting_unsigned_extrinsic( _: sp_consensus_beefy::DoubleVotingProof< BlockNumber, BeefyId, @@ -252,12 +252,37 @@ sp_api::impl_runtime_apis! { unimplemented!() } + fn submit_report_fork_voting_unsigned_extrinsic( + _: sp_consensus_beefy::ForkVotingProof< + ::Header, + BeefyId, + sp_runtime::OpaqueValue + >, + _: sp_consensus_beefy::OpaqueKeyOwnershipProof, + ) -> Option<()> { + unimplemented!() + } + + fn submit_report_future_block_voting_unsigned_extrinsic( + _: sp_consensus_beefy::FutureBlockVotingProof, + _: sp_consensus_beefy::OpaqueKeyOwnershipProof, + ) -> Option<()> { + unimplemented!() + } + fn generate_key_ownership_proof( _: sp_consensus_beefy::ValidatorSetId, _: BeefyId, ) -> Option { unimplemented!() } + + fn generate_ancestry_proof( + _: BlockNumber, + _: Option, + ) -> Option { + unimplemented!() + } } impl sp_mmr_primitives::MmrApi for Runtime { @@ -398,30 +423,30 @@ sp_api::impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { - fn query_acceptable_payment_assets(_: xcm::Version) -> Result, xcm_fee_payment_runtime_api::fees::Error> { + impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(_: xcm::Version) -> Result, xcm_runtime_apis::fees::Error> { unimplemented!() } - fn query_weight_to_asset_fee(_: Weight, _: VersionedAssetId) -> Result { + fn query_weight_to_asset_fee(_: Weight, _: VersionedAssetId) -> Result { unimplemented!() } - fn query_xcm_weight(_: VersionedXcm<()>) -> Result { + fn query_xcm_weight(_: VersionedXcm<()>) -> Result { unimplemented!() } - fn query_delivery_fees(_: VersionedLocation, _: VersionedXcm<()>) -> Result { + fn query_delivery_fees(_: VersionedLocation, _: VersionedXcm<()>) -> Result { unimplemented!() } } - impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { - fn dry_run_call(_: (), _: ()) -> Result, xcm_fee_payment_runtime_api::dry_run::Error> { + impl xcm_runtime_apis::dry_run::DryRunApi for Runtime { + fn dry_run_call(_: (), _: ()) -> Result, xcm_runtime_apis::dry_run::Error> { unimplemented!() } - fn dry_run_xcm(_: VersionedLocation, _: VersionedXcm<()>) -> Result, xcm_fee_payment_runtime_api::dry_run::Error> { + fn dry_run_xcm(_: VersionedLocation, _: VersionedXcm<()>) -> Result, xcm_runtime_apis::dry_run::Error> { unimplemented!() } } diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index b4f63bd2aa06b20b30f4adef7cf4498061cd65e9..5ca566d2c96286a1e4bdb1ee5010e7d2dde5ebed 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -838,8 +838,10 @@ pub fn new_full< let auth_disc_publish_non_global_ips = config.network.allow_non_globals_in_dht; let auth_disc_public_addresses = config.network.public_addresses.clone(); - let mut net_config = - sc_network::config::FullNetworkConfiguration::<_, _, Network>::new(&config.network); + let mut net_config = sc_network::config::FullNetworkConfiguration::<_, _, Network>::new( + &config.network, + config.prometheus_config.as_ref().map(|cfg| cfg.registry.clone()), + ); let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"); let peer_store_handle = net_config.peer_store_handle(); diff --git a/polkadot/node/service/src/overseer.rs b/polkadot/node/service/src/overseer.rs index 5f4db99b00ef9f29ff90267f1d70cc4fcb94a249..add5d239364dfa8b66aaa33cc825512a59b244f4 100644 --- a/polkadot/node/service/src/overseer.rs +++ b/polkadot/node/service/src/overseer.rs @@ -275,6 +275,7 @@ where )) .candidate_validation(CandidateValidationSubsystem::with_config( candidate_validation_config, + keystore.clone(), Metrics::register(registry)?, // candidate-validation metrics Metrics::register(registry)?, // validation host metrics )) diff --git a/polkadot/node/subsystem-bench/Cargo.toml b/polkadot/node/subsystem-bench/Cargo.toml index 5001104f929a2dc2c596567c8b7febd8088e09f2..0325613d25f9a716f9a0189e8bb9db91d9051e8c 100644 --- a/polkadot/node/subsystem-bench/Cargo.toml +++ b/polkadot/node/subsystem-bench/Cargo.toml @@ -20,76 +20,76 @@ path = "src/cli/subsystem-bench.rs" doc = false [dependencies] -polkadot-node-subsystem = { path = "../subsystem" } -polkadot-node-subsystem-util = { path = "../subsystem-util" } -polkadot-node-subsystem-types = { path = "../subsystem-types" } -polkadot-node-primitives = { path = "../primitives" } -polkadot-primitives = { path = "../../primitives" } -polkadot-node-network-protocol = { path = "../network/protocol" } -polkadot-availability-recovery = { path = "../network/availability-recovery", features = ["subsystem-benchmarks"] } -polkadot-availability-distribution = { path = "../network/availability-distribution" } -polkadot-statement-distribution = { path = "../network/statement-distribution" } -polkadot-node-core-av-store = { path = "../core/av-store" } -polkadot-node-core-chain-api = { path = "../core/chain-api" } -polkadot-availability-bitfield-distribution = { path = "../network/bitfield-distribution" } -color-eyre = { version = "0.6.1", default-features = false } -polkadot-overseer = { path = "../overseer" } -colored = "2.0.4" -assert_matches = "1.5" -async-trait = "0.1.79" -sp-keystore = { path = "../../../substrate/primitives/keystore" } -sc-keystore = { path = "../../../substrate/client/keystore" } -sp-core = { path = "../../../substrate/primitives/core" } -clap = { version = "4.5.3", features = ["derive"] } -futures = "0.3.30" -futures-timer = "3.0.2" -bincode = "1.3.3" -sha1 = "0.10.6" -hex = "0.4.3" -gum = { package = "tracing-gum", path = "../gum" } -polkadot-erasure-coding = { package = "polkadot-erasure-coding", path = "../../erasure-coding" } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-node-subsystem-types = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } +polkadot-availability-recovery = { features = ["subsystem-benchmarks"], workspace = true, default-features = true } +polkadot-availability-distribution = { workspace = true, default-features = true } +polkadot-statement-distribution = { workspace = true, default-features = true } +polkadot-node-core-av-store = { workspace = true, default-features = true } +polkadot-node-core-chain-api = { workspace = true, default-features = true } +polkadot-availability-bitfield-distribution = { workspace = true, default-features = true } +color-eyre = { workspace = true } +polkadot-overseer = { workspace = true, default-features = true } +colored = { workspace = true } +assert_matches = { workspace = true } +async-trait = { workspace = true } +sp-keystore = { workspace = true, default-features = true } +sc-keystore = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +clap = { features = ["derive"], workspace = true } +futures = { workspace = true } +futures-timer = { workspace = true } +bincode = { workspace = true } +sha1 = { workspace = true } +hex = { workspace = true, default-features = true } +gum = { workspace = true, default-features = true } +polkadot-erasure-coding = { workspace = true, default-features = true } log = { workspace = true, default-features = true } -env_logger = "0.11" -rand = "0.8.5" +env_logger = { workspace = true } +rand = { workspace = true, default-features = true } # `rand` only supports uniform distribution, we need normal distribution for latency. -rand_distr = "0.4.3" -bitvec = "1.0.1" -kvdb-memorydb = "0.13.0" +rand_distr = { workspace = true } +bitvec = { workspace = true, default-features = true } +kvdb-memorydb = { workspace = true } -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive", "std"] } -tokio = { version = "1.24.2", features = ["parking_lot", "rt-multi-thread"] } -clap-num = "1.0.2" -polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } -sp-keyring = { path = "../../../substrate/primitives/keyring" } -sp-application-crypto = { path = "../../../substrate/primitives/application-crypto" } -sc-network = { path = "../../../substrate/client/network" } -sc-network-types = { path = "../../../substrate/client/network/types" } -sc-service = { path = "../../../substrate/client/service" } -sp-consensus = { path = "../../../substrate/primitives/consensus/common" } -polkadot-node-metrics = { path = "../metrics" } -itertools = "0.11" -polkadot-primitives-test-helpers = { path = "../../primitives/test-helpers" } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../substrate/utils/prometheus" } -prometheus = { version = "0.13.0", default-features = false } +codec = { features = ["derive", "std"], workspace = true, default-features = true } +tokio = { features = ["parking_lot", "rt-multi-thread"], workspace = true, default-features = true } +clap-num = { workspace = true } +polkadot-node-subsystem-test-helpers = { workspace = true } +sp-keyring = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-network-types = { workspace = true, default-features = true } +sc-service = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +polkadot-node-metrics = { workspace = true, default-features = true } +itertools = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } +prometheus-endpoint = { workspace = true, default-features = true } +prometheus = { workspace = true } serde = { workspace = true, default-features = true } serde_yaml = { workspace = true } serde_json = { workspace = true } -polkadot-node-core-approval-voting = { path = "../core/approval-voting" } -polkadot-approval-distribution = { path = "../network/approval-distribution" } -sp-consensus-babe = { path = "../../../substrate/primitives/consensus/babe" } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-timestamp = { path = "../../../substrate/primitives/timestamp" } +polkadot-node-core-approval-voting = { workspace = true, default-features = true } +polkadot-approval-distribution = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-runtime = { workspace = true } +sp-timestamp = { workspace = true, default-features = true } -schnorrkel = { version = "0.11.4", default-features = false } +schnorrkel = { workspace = true } # rand_core should match schnorrkel -rand_core = "0.6.2" -rand_chacha = { version = "0.3.1" } -paste = "1.0.14" -orchestra = { version = "0.3.5", default-features = false, features = ["futures_channel"] } -pyroscope = { version = "0.5.7" } -pyroscope_pprofrs = "0.2.7" -strum = { version = "0.24", features = ["derive"] } +rand_core = { workspace = true } +rand_chacha = { workspace = true, default-features = true } +paste = { workspace = true, default-features = true } +orchestra = { features = ["futures_channel"], workspace = true } +pyroscope = { workspace = true } +pyroscope_pprofrs = { workspace = true } +strum = { features = ["derive"], workspace = true, default-features = true } [features] default = [] diff --git a/polkadot/node/subsystem-bench/examples/approvals_no_shows.yaml b/polkadot/node/subsystem-bench/examples/approvals_no_shows.yaml index 146da57d44c4aaf973e13c886a357028cdbe3559..cae1a30914da78c32a54ad035b8870f3a4412548 100644 --- a/polkadot/node/subsystem-bench/examples/approvals_no_shows.yaml +++ b/polkadot/node/subsystem-bench/examples/approvals_no_shows.yaml @@ -16,3 +16,5 @@ TestConfiguration: peer_bandwidth: 524288000000 bandwidth: 524288000000 num_blocks: 10 + connectivity: 100 + latency: null diff --git a/polkadot/node/subsystem-bench/examples/approvals_throughput.yaml b/polkadot/node/subsystem-bench/examples/approvals_throughput.yaml index 6b17e62c20aa3f69153fb596d1a303a2e0320ddd..7edb48e302a46b464e86d5b3535ab71d1585a408 100644 --- a/polkadot/node/subsystem-bench/examples/approvals_throughput.yaml +++ b/polkadot/node/subsystem-bench/examples/approvals_throughput.yaml @@ -16,3 +16,5 @@ TestConfiguration: peer_bandwidth: 524288000000 bandwidth: 524288000000 num_blocks: 10 + connectivity: 100 + latency: null diff --git a/polkadot/node/subsystem-bench/examples/approvals_throughput_best_case.yaml b/polkadot/node/subsystem-bench/examples/approvals_throughput_best_case.yaml index e946c28e8ef5d4e38736ffc21e56d8b1c6cd0ddc..7c24f50e6af5531ab652e838f362733f0fda6707 100644 --- a/polkadot/node/subsystem-bench/examples/approvals_throughput_best_case.yaml +++ b/polkadot/node/subsystem-bench/examples/approvals_throughput_best_case.yaml @@ -16,3 +16,6 @@ TestConfiguration: peer_bandwidth: 524288000000 bandwidth: 524288000000 num_blocks: 10 + connectivity: 100 + latency: null + diff --git a/polkadot/node/subsystem-bench/examples/approvals_throughput_no_optimisations_enabled.yaml b/polkadot/node/subsystem-bench/examples/approvals_throughput_no_optimisations_enabled.yaml index 8f4b050e72f27dd4b5bb0c52bd49162cd0bb83ec..fe2402faeccdc11f82ef10d7ff8618c8cbbd30c8 100644 --- a/polkadot/node/subsystem-bench/examples/approvals_throughput_no_optimisations_enabled.yaml +++ b/polkadot/node/subsystem-bench/examples/approvals_throughput_no_optimisations_enabled.yaml @@ -16,3 +16,6 @@ TestConfiguration: peer_bandwidth: 524288000000 bandwidth: 524288000000 num_blocks: 10 + connectivity: 100 + latency: null + diff --git a/polkadot/node/subsystem-bench/src/lib/approval/mod.rs b/polkadot/node/subsystem-bench/src/lib/approval/mod.rs index 5c0c65b11cdb5db521ba0045b83f937f72e6b246..404df2f8c65365e66d8bf318ce8c33ba08c5b3b6 100644 --- a/polkadot/node/subsystem-bench/src/lib/approval/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/mod.rs @@ -28,6 +28,8 @@ use crate::{ dummy_builder, environment::{TestEnvironment, TestEnvironmentDependencies, MAX_TIME_OF_FLIGHT}, mock::{ + availability_recovery::MockAvailabilityRecovery, + candidate_validation::MockCandidateValidation, chain_api::{ChainApiState, MockChainApi}, network_bridge::{MockNetworkBridgeRx, MockNetworkBridgeTx}, runtime_api::{MockRuntimeApi, MockRuntimeApiCoreState}, @@ -59,15 +61,17 @@ use polkadot_node_subsystem_types::messages::{ApprovalDistributionMessage, Appro use polkadot_node_subsystem_util::metrics::Metrics; use polkadot_overseer::Handle as OverseerHandleReal; use polkadot_primitives::{ - BlockNumber, CandidateEvent, CandidateIndex, CandidateReceipt, Hash, Header, Slot, - ValidatorIndex, + BlockNumber, CandidateEvent, CandidateIndex, CandidateReceipt, Hash, Header, Slot, ValidatorId, + ValidatorIndex, ASSIGNMENT_KEY_TYPE_ID, }; use prometheus::Registry; use sc_keystore::LocalKeystore; use sc_service::SpawnTaskHandle; use serde::{Deserialize, Serialize}; +use sp_application_crypto::AppCrypto; use sp_consensus_babe::Epoch as BabeEpoch; use sp_core::H256; +use sp_keystore::Keystore; use std::{ cmp::max, collections::{HashMap, HashSet}, @@ -697,12 +701,12 @@ impl PeerMessageProducer { .expect("We can't handle unknown peers") .clone(); - self.network - .send_message_from_peer( - &peer_authority_id, - protocol_v3::ValidationProtocol::ApprovalDistribution(message.msg).into(), - ) - .unwrap_or_else(|_| panic!("Network should be up and running {:?}", sent_by)); + if let Err(err) = self.network.send_message_from_peer( + &peer_authority_id, + protocol_v3::ValidationProtocol::ApprovalDistribution(message.msg).into(), + ) { + gum::warn!(target: LOG_TARGET, ?sent_by, ?err, "Validator can not send message"); + } } // Queues a message to be sent by the peer identified by the `sent_by` value. @@ -785,6 +789,18 @@ fn build_overseer( let db: polkadot_node_subsystem_util::database::kvdb_impl::DbAdapter = polkadot_node_subsystem_util::database::kvdb_impl::DbAdapter::new(db, &[]); let keystore = LocalKeystore::in_memory(); + keystore + .sr25519_generate_new( + ASSIGNMENT_KEY_TYPE_ID, + Some(state.test_authorities.key_seeds.get(NODE_UNDER_TEST as usize).unwrap().as_str()), + ) + .unwrap(); + keystore + .sr25519_generate_new( + ValidatorId::ID, + Some(state.test_authorities.key_seeds.get(NODE_UNDER_TEST as usize).unwrap().as_str()), + ) + .unwrap(); let system_clock = PastSystemClock::new(SystemClock {}, state.delta_tick_from_generated.clone()); @@ -824,7 +840,9 @@ fn build_overseer( .replace_chain_selection(|_| mock_chain_selection) .replace_runtime_api(|_| mock_runtime_api) .replace_network_bridge_tx(|_| mock_tx_bridge) - .replace_network_bridge_rx(|_| mock_rx_bridge); + .replace_network_bridge_rx(|_| mock_rx_bridge) + .replace_availability_recovery(|_| MockAvailabilityRecovery::new()) + .replace_candidate_validation(|_| MockCandidateValidation::new()); let (overseer, raw_handle) = dummy.build_with_connector(overseer_connector).expect("Should not fail"); @@ -987,11 +1005,12 @@ pub async fn bench_approvals_run( "polkadot_parachain_subsystem_bounded_received", Some(("subsystem_name", "approval-distribution-subsystem")), |value| { - gum::info!(target: LOG_TARGET, ?value, ?at_least_messages, "Waiting metric"); + gum::debug!(target: LOG_TARGET, ?value, ?at_least_messages, "Waiting metric"); value >= at_least_messages as f64 }, ) .await; + gum::info!("Requesting approval votes ms"); for info in &state.blocks { @@ -1031,7 +1050,7 @@ pub async fn bench_approvals_run( "polkadot_parachain_subsystem_bounded_received", Some(("subsystem_name", "approval-distribution-subsystem")), |value| { - gum::info!(target: LOG_TARGET, ?value, ?at_least_messages, "Waiting metric"); + gum::debug!(target: LOG_TARGET, ?value, ?at_least_messages, "Waiting metric"); value >= at_least_messages as f64 }, ) diff --git a/polkadot/node/subsystem-bench/src/lib/mock/availability_recovery.rs b/polkadot/node/subsystem-bench/src/lib/mock/availability_recovery.rs new file mode 100644 index 0000000000000000000000000000000000000000..713226de6ad8ebda3f675398278b19d90e9e7a29 --- /dev/null +++ b/polkadot/node/subsystem-bench/src/lib/mock/availability_recovery.rs @@ -0,0 +1,73 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! A generic mock availability recovery suitable to be used in benchmarks. + +use std::sync::Arc; + +use futures::FutureExt; +use polkadot_node_primitives::{AvailableData, BlockData, PoV}; +use polkadot_node_subsystem::{ + messages::AvailabilityRecoveryMessage, overseer, SpawnedSubsystem, SubsystemError, +}; +use polkadot_node_subsystem_types::OverseerSignal; +use polkadot_primitives::{Hash, HeadData, PersistedValidationData}; + +pub struct MockAvailabilityRecovery {} + +impl MockAvailabilityRecovery { + pub fn new() -> Self { + Self {} + } +} + +#[overseer::subsystem(AvailabilityRecovery, error=SubsystemError, prefix=self::overseer)] +impl MockAvailabilityRecovery { + fn start(self, ctx: Context) -> SpawnedSubsystem { + let future = self.run(ctx).map(|_| Ok(())).boxed(); + + SpawnedSubsystem { name: "test-environment", future } + } +} + +#[overseer::contextbounds(AvailabilityRecovery, prefix = self::overseer)] +impl MockAvailabilityRecovery { + async fn run(self, mut ctx: Context) { + loop { + let msg = ctx.recv().await.expect("Overseer never fails us"); + match msg { + orchestra::FromOrchestra::Signal(signal) => + if signal == OverseerSignal::Conclude { + return + }, + orchestra::FromOrchestra::Communication { msg } => match msg { + AvailabilityRecoveryMessage::RecoverAvailableData(_, _, _, _, tx) => { + let available_data = AvailableData { + pov: Arc::new(PoV { block_data: BlockData(Vec::new()) }), + validation_data: PersistedValidationData { + parent_head: HeadData(Vec::new()), + relay_parent_number: 0, + relay_parent_storage_root: Hash::default(), + max_pov_size: 2, + }, + }; + tx.send(Ok(available_data)).unwrap(); + }, + }, + } + } + } +} diff --git a/polkadot/node/subsystem-bench/src/lib/mock/candidate_validation.rs b/polkadot/node/subsystem-bench/src/lib/mock/candidate_validation.rs new file mode 100644 index 0000000000000000000000000000000000000000..941fac2a38c6c7fecaa16bd21d81310d4f6de488 --- /dev/null +++ b/polkadot/node/subsystem-bench/src/lib/mock/candidate_validation.rs @@ -0,0 +1,74 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! A generic mock candidate validation subsystem suitable for using in benchmarks, it +//! is responding with candidate valid for every request. + +use futures::FutureExt; +use polkadot_node_primitives::ValidationResult; +use polkadot_node_subsystem::{ + messages::CandidateValidationMessage, overseer, SpawnedSubsystem, SubsystemError, +}; +use polkadot_node_subsystem_types::OverseerSignal; +use polkadot_primitives::{CandidateCommitments, Hash, HeadData, PersistedValidationData}; + +pub struct MockCandidateValidation {} + +impl MockCandidateValidation { + pub fn new() -> Self { + Self {} + } +} + +#[overseer::subsystem(CandidateValidation, error=SubsystemError, prefix=self::overseer)] +impl MockCandidateValidation { + fn start(self, ctx: Context) -> SpawnedSubsystem { + let future = self.run(ctx).map(|_| Ok(())).boxed(); + + SpawnedSubsystem { name: "test-environment", future } + } +} + +#[overseer::contextbounds(CandidateValidation, prefix = self::overseer)] +impl MockCandidateValidation { + async fn run(self, mut ctx: Context) { + loop { + let msg = ctx.recv().await.expect("Overseer never fails us"); + match msg { + orchestra::FromOrchestra::Signal(signal) => + if signal == OverseerSignal::Conclude { + return + }, + orchestra::FromOrchestra::Communication { msg } => match msg { + CandidateValidationMessage::ValidateFromExhaustive { + response_sender, .. + } => response_sender + .send(Ok(ValidationResult::Valid( + CandidateCommitments::default(), + PersistedValidationData { + parent_head: HeadData(Vec::new()), + relay_parent_number: 0, + relay_parent_storage_root: Hash::default(), + max_pov_size: 2, + }, + ))) + .unwrap(), + _ => unimplemented!("Unexpected chain-api message"), + }, + } + } + } +} diff --git a/polkadot/node/subsystem-bench/src/lib/mock/mod.rs b/polkadot/node/subsystem-bench/src/lib/mock/mod.rs index 12766374bfa9f49ad67699173cdda512623c4b8b..da4ac05e33b7c9af76ab6804961a53cfbe68f9b0 100644 --- a/polkadot/node/subsystem-bench/src/lib/mock/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/mod.rs @@ -19,7 +19,9 @@ use polkadot_node_subsystem_types::Hash; use sp_consensus::SyncOracle; pub mod av_store; +pub mod availability_recovery; pub mod candidate_backing; +pub mod candidate_validation; pub mod chain_api; pub mod dummy; pub mod network_bridge; diff --git a/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs b/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs index be9dbd55cb6f9898a879e7bbaa6c5f5b9c303484..61523de1f1b502600d4e8208021e7a3ddf345e3c 100644 --- a/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs @@ -26,9 +26,9 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_types::OverseerSignal; use polkadot_primitives::{ - node_features, AsyncBackingParams, CandidateEvent, CandidateReceipt, CoreState, GroupIndex, - GroupRotationInfo, IndexedVec, NodeFeatures, OccupiedCore, ScheduledCore, SessionIndex, - SessionInfo, ValidatorIndex, + node_features, ApprovalVotingParams, AsyncBackingParams, CandidateEvent, CandidateReceipt, + CoreState, GroupIndex, GroupRotationInfo, IndexedVec, NodeFeatures, OccupiedCore, + ScheduledCore, SessionIndex, SessionInfo, ValidationCode, ValidatorIndex, }; use sp_consensus_babe::Epoch as BabeEpoch; use sp_core::H256; @@ -288,6 +288,22 @@ impl MockRuntimeApi { }; tx.send(Ok((groups, group_rotation_info))).unwrap(); }, + RuntimeApiMessage::Request( + _parent, + RuntimeApiRequest::ValidationCodeByHash(_, tx), + ) => { + let validation_code = ValidationCode(Vec::new()); + if let Err(err) = tx.send(Ok(Some(validation_code))) { + gum::error!(target: LOG_TARGET, ?err, "validation code wasn't received"); + } + }, + RuntimeApiMessage::Request( + _parent, + RuntimeApiRequest::ApprovalVotingParams(_, tx), + ) => + if let Err(err) = tx.send(Ok(ApprovalVotingParams::default())) { + gum::error!(target: LOG_TARGET, ?err, "Voting params weren't received"); + }, // Long term TODO: implement more as needed. message => { unimplemented!("Unexpected runtime-api message: {:?}", message) diff --git a/polkadot/node/subsystem-test-helpers/Cargo.toml b/polkadot/node/subsystem-test-helpers/Cargo.toml index 57678e8e8d4a1057ec843f097c2cd9811f33a6bb..d3229291673c6da0b1ba12d6983c678ed2d5a343 100644 --- a/polkadot/node/subsystem-test-helpers/Cargo.toml +++ b/polkadot/node/subsystem-test-helpers/Cargo.toml @@ -11,19 +11,19 @@ license.workspace = true workspace = true [dependencies] -async-trait = "0.1.79" -futures = "0.3.30" -parking_lot = "0.12.1" -polkadot-node-subsystem = { path = "../subsystem" } -polkadot-erasure-coding = { path = "../../erasure-coding" } -polkadot-node-subsystem-util = { path = "../subsystem-util" } -polkadot-primitives = { path = "../../primitives" } -polkadot-node-primitives = { path = "../primitives" } +async-trait = { workspace = true } +futures = { workspace = true } +parking_lot = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-erasure-coding = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } -sc-client-api = { path = "../../../substrate/client/api" } -sc-utils = { path = "../../../substrate/client/utils" } -sp-core = { path = "../../../substrate/primitives/core" } -sp-keystore = { path = "../../../substrate/primitives/keystore" } -sc-keystore = { path = "../../../substrate/client/keystore" } -sp-keyring = { path = "../../../substrate/primitives/keyring" } -sp-application-crypto = { path = "../../../substrate/primitives/application-crypto" } +sc-client-api = { workspace = true, default-features = true } +sc-utils = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sc-keystore = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } diff --git a/polkadot/node/subsystem-test-helpers/src/lib.rs b/polkadot/node/subsystem-test-helpers/src/lib.rs index 375121c3746377157e852de382c9d2cb64bce496..bdb0647fee6f5aec1dd6322b68c9a38f6e493b98 100644 --- a/polkadot/node/subsystem-test-helpers/src/lib.rs +++ b/polkadot/node/subsystem-test-helpers/src/lib.rs @@ -36,7 +36,7 @@ use std::{ convert::Infallible, future::Future, pin::Pin, - sync::Arc, + sync::{atomic::AtomicUsize, Arc}, task::{Context, Poll, Waker}, time::Duration, }; @@ -146,12 +146,13 @@ pub fn single_item_sink() -> (SingleItemSink, SingleItemStream) { #[derive(Clone)] pub struct TestSubsystemSender { tx: mpsc::UnboundedSender, + message_counter: MessageCounter, } /// Construct a sender/receiver pair. pub fn sender_receiver() -> (TestSubsystemSender, mpsc::UnboundedReceiver) { let (tx, rx) = mpsc::unbounded(); - (TestSubsystemSender { tx }, rx) + (TestSubsystemSender { tx, message_counter: MessageCounter::default() }, rx) } #[async_trait::async_trait] @@ -161,6 +162,11 @@ where OutgoingMessage: Send + 'static, { async fn send_message(&mut self, msg: OutgoingMessage) { + self.send_message_with_priority::(msg).await; + } + + async fn send_message_with_priority(&mut self, msg: OutgoingMessage) { + self.message_counter.increment(P::priority()); self.tx.send(msg.into()).await.expect("test overseer no longer live"); } @@ -168,6 +174,14 @@ where &mut self, msg: OutgoingMessage, ) -> Result<(), TrySendError> { + self.try_send_message_with_priority::(msg) + } + + fn try_send_message_with_priority( + &mut self, + msg: OutgoingMessage, + ) -> Result<(), TrySendError> { + self.message_counter.increment(P::priority()); self.tx.unbounded_send(msg.into()).expect("test overseer no longer live"); Ok(()) } @@ -277,6 +291,9 @@ pub struct TestSubsystemContextHandle { /// Direct access to the receiver. pub rx: mpsc::UnboundedReceiver, + + /// Message counter over subsystems. + pub message_counter: MessageCounter, } impl TestSubsystemContextHandle { @@ -322,6 +339,34 @@ pub fn make_subsystem_context( make_buffered_subsystem_context(spawner, 0) } +/// Message counter over subsystems. +#[derive(Default, Clone)] +pub struct MessageCounter { + total: Arc, + with_high_priority: Arc, +} + +impl MessageCounter { + /// Increment the message counter. + pub fn increment(&mut self, priority_level: overseer::PriorityLevel) { + self.total.fetch_add(1, std::sync::atomic::Ordering::SeqCst); + if matches!(priority_level, overseer::PriorityLevel::High) { + self.with_high_priority.fetch_add(1, std::sync::atomic::Ordering::SeqCst); + } + } + + /// Reset the message counter. + pub fn reset(&mut self) { + self.total.store(0, std::sync::atomic::Ordering::SeqCst); + self.with_high_priority.store(0, std::sync::atomic::Ordering::SeqCst); + } + + /// Get the messages with high priority count. + pub fn with_high_priority(&self) -> usize { + self.with_high_priority.load(std::sync::atomic::Ordering::SeqCst) + } +} + /// Make a test subsystem context with buffered overseer channel. Some tests (e.g. /// `dispute-coordinator`) create too many parallel operations and deadlock unless /// the channel is buffered. Usually `buffer_size=1` is enough. @@ -331,15 +376,23 @@ pub fn make_buffered_subsystem_context( ) -> (TestSubsystemContext>, TestSubsystemContextHandle) { let (overseer_tx, overseer_rx) = mpsc::channel(buffer_size); let (all_messages_tx, all_messages_rx) = mpsc::unbounded(); + let message_counter = MessageCounter::default(); ( TestSubsystemContext { - tx: TestSubsystemSender { tx: all_messages_tx }, + tx: TestSubsystemSender { + tx: all_messages_tx, + message_counter: message_counter.clone(), + }, rx: overseer_rx, spawn: SpawnGlue(spawner), message_buffer: VecDeque::new(), }, - TestSubsystemContextHandle { tx: overseer_tx, rx: all_messages_rx }, + TestSubsystemContextHandle { + tx: overseer_tx, + rx: all_messages_rx, + message_counter: message_counter.clone(), + }, ) } diff --git a/polkadot/node/subsystem-types/Cargo.toml b/polkadot/node/subsystem-types/Cargo.toml index 0178b193cba8c88f2cc7b4a980beae8f7de106ff..c8fc324699e1754cb0d476a97ef29c8fea4ede74 100644 --- a/polkadot/node/subsystem-types/Cargo.toml +++ b/polkadot/node/subsystem-types/Cargo.toml @@ -10,26 +10,26 @@ license.workspace = true workspace = true [dependencies] -derive_more = "0.99.17" -fatality = "0.1.1" -futures = "0.3.30" -polkadot-primitives = { path = "../../primitives" } -polkadot-node-primitives = { path = "../primitives" } -polkadot-node-network-protocol = { path = "../network/protocol" } -polkadot-statement-table = { path = "../../statement-table" } -polkadot-node-jaeger = { path = "../jaeger" } -orchestra = { version = "0.3.5", default-features = false, features = ["futures_channel"] } -sc-network = { path = "../../../substrate/client/network" } -sc-network-types = { path = "../../../substrate/client/network/types" } -sp-api = { path = "../../../substrate/primitives/api" } -sp-blockchain = { path = "../../../substrate/primitives/blockchain" } -sp-consensus-babe = { path = "../../../substrate/primitives/consensus/babe" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } -sp-authority-discovery = { path = "../../../substrate/primitives/authority-discovery" } -sc-client-api = { path = "../../../substrate/client/api" } -sc-transaction-pool-api = { path = "../../../substrate/client/transaction-pool/api" } -smallvec = "1.8.0" -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../substrate/utils/prometheus" } +derive_more = { workspace = true, default-features = true } +fatality = { workspace = true } +futures = { workspace = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } +polkadot-statement-table = { workspace = true, default-features = true } +polkadot-node-jaeger = { workspace = true, default-features = true } +orchestra = { features = ["futures_channel"], workspace = true } +sc-network = { workspace = true, default-features = true } +sc-network-types = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-authority-discovery = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } +smallvec = { workspace = true, default-features = true } +prometheus-endpoint = { workspace = true, default-features = true } thiserror = { workspace = true } -async-trait = "0.1.79" -bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } +async-trait = { workspace = true } +bitvec = { features = ["alloc"], workspace = true } diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index 722a97989bce0b8587c8992827f6438fd78ff21e..4d27ac9b70e33b09810eaab3a30f5c3c82c8456f 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -85,7 +85,7 @@ pub enum CandidateBackingMessage { /// candidates of the same para that follow it in the input vector. In other words, assuming /// candidates are supplied in dependency order, we must ensure that this dependency order is /// preserved. - GetBackedCandidates( + GetBackableCandidates( HashMap>, oneshot::Sender>>, ), @@ -444,6 +444,16 @@ pub enum NetworkBridgeTxMessage { /// The peer set we want the connection on. peer_set: PeerSet, }, + + /// Extends the known validators set with new peers we already know the `Multiaddrs`, this is + /// usually needed for validators that change their address mid-session. It is usually called + /// after a ConnectToResolvedValidators at the beginning of the session. + AddToResolvedValidators { + /// Each entry corresponds to the addresses of an already resolved validator. + validator_addrs: Vec>, + /// The peer set we want the connection on. + peer_set: PeerSet, + }, } /// Availability Distribution Message. diff --git a/polkadot/node/subsystem-util/Cargo.toml b/polkadot/node/subsystem-util/Cargo.toml index b7fb75b94b2c726cb0171b48b023a9d9517970ac..98ea21f250eda7874f03ba1aeffd482fedbc8808 100644 --- a/polkadot/node/subsystem-util/Cargo.toml +++ b/polkadot/node/subsystem-util/Cargo.toml @@ -10,47 +10,47 @@ license.workspace = true workspace = true [dependencies] -async-trait = "0.1.79" -futures = "0.3.30" -futures-channel = "0.3.23" -itertools = "0.11" -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -parking_lot = "0.12.1" -pin-project = "1.0.9" -rand = "0.8.5" +async-trait = { workspace = true } +futures = { workspace = true } +futures-channel = { workspace = true } +itertools = { workspace = true } +codec = { features = ["derive"], workspace = true } +parking_lot = { workspace = true, default-features = true } +pin-project = { workspace = true } +rand = { workspace = true, default-features = true } thiserror = { workspace = true } -fatality = "0.1.1" -gum = { package = "tracing-gum", path = "../gum" } -derive_more = "0.99.17" -schnellru = "0.2.1" +fatality = { workspace = true } +gum = { workspace = true, default-features = true } +derive_more = { workspace = true, default-features = true } +schnellru = { workspace = true } -polkadot-erasure-coding = { path = "../../erasure-coding" } -polkadot-node-subsystem = { path = "../subsystem" } -polkadot-node-subsystem-types = { path = "../subsystem-types" } -polkadot-node-jaeger = { path = "../jaeger" } -polkadot-node-metrics = { path = "../metrics" } -polkadot-node-network-protocol = { path = "../network/protocol" } -polkadot-primitives = { path = "../../primitives" } -polkadot-node-primitives = { path = "../primitives" } -polkadot-overseer = { path = "../overseer" } -metered = { package = "prioritized-metered-channel", version = "0.6.1", default-features = false, features = ["futures_channel"] } +polkadot-erasure-coding = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-types = { workspace = true, default-features = true } +polkadot-node-jaeger = { workspace = true, default-features = true } +polkadot-node-metrics = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-overseer = { workspace = true, default-features = true } +metered = { features = ["futures_channel"], workspace = true } -sp-core = { path = "../../../substrate/primitives/core" } -sp-application-crypto = { path = "../../../substrate/primitives/application-crypto" } -sp-keystore = { path = "../../../substrate/primitives/keystore" } -sc-client-api = { path = "../../../substrate/client/api" } +sp-core = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } -kvdb = "0.13.0" -parity-db = { version = "0.4.12" } +kvdb = { workspace = true } +parity-db = { workspace = true } [dev-dependencies] -assert_matches = "1.4.0" -env_logger = "0.11" -futures = { version = "0.3.30", features = ["thread-pool"] } +assert_matches = { workspace = true } +env_logger = { workspace = true } +futures = { features = ["thread-pool"], workspace = true } log = { workspace = true, default-features = true } -polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } -lazy_static = "1.4.0" -polkadot-primitives-test-helpers = { path = "../../primitives/test-helpers" } -kvdb-shared-tests = "0.11.0" -tempfile = "3.1.0" -kvdb-memorydb = "0.13.0" +polkadot-node-subsystem-test-helpers = { workspace = true } +lazy_static = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } +kvdb-shared-tests = { workspace = true } +tempfile = { workspace = true } +kvdb-memorydb = { workspace = true } diff --git a/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs b/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs index b5aef325c8b437ec43c2872f130651de65c28a52..2272f048089c7e7f5bda0ce9a2f970789e5c9b34 100644 --- a/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs +++ b/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs @@ -117,9 +117,8 @@ /// That means a few blocks of execution time lost, which is not a big deal for code upgrades /// in practice at most once every few weeks. use polkadot_primitives::{ - async_backing::Constraints as PrimitiveConstraints, BlockNumber, CandidateCommitments, - CollatorId, CollatorSignature, Hash, HeadData, Id as ParaId, PersistedValidationData, - UpgradeRestriction, ValidationCodeHash, + async_backing::Constraints as PrimitiveConstraints, BlockNumber, CandidateCommitments, Hash, + HeadData, Id as ParaId, PersistedValidationData, UpgradeRestriction, ValidationCodeHash, }; use std::{collections::HashMap, sync::Arc}; @@ -521,18 +520,13 @@ impl ConstraintModifications { /// The prospective candidate. /// /// This comprises the key information that represent a candidate -/// without pinning it to a particular session. For example, everything -/// to do with the collator's signature and commitments are represented -/// here. But the erasure-root is not. This means that prospective candidates +/// without pinning it to a particular session. For example commitments are +/// represented here. But the erasure-root is not. This means that prospective candidates /// are not correlated to any session in particular. #[derive(Debug, Clone, PartialEq)] pub struct ProspectiveCandidate { /// The commitments to the output of the execution. pub commitments: CandidateCommitments, - /// The collator that created the candidate. - pub collator: CollatorId, - /// The signature of the collator on the payload. - pub collator_signature: CollatorSignature, /// The persisted validation data used to create the candidate. pub persisted_validation_data: PersistedValidationData, /// The hash of the PoV. @@ -800,10 +794,7 @@ fn validate_against_constraints( #[cfg(test)] mod tests { use super::*; - use polkadot_primitives::{ - CollatorPair, HorizontalMessages, OutboundHrmpMessage, ValidationCode, - }; - use sp_application_crypto::Pair; + use polkadot_primitives::{HorizontalMessages, OutboundHrmpMessage, ValidationCode}; #[test] fn stack_modifications() { @@ -1162,11 +1153,6 @@ mod tests { constraints: &Constraints, relay_parent: &RelayChainBlockInfo, ) -> ProspectiveCandidate { - let collator_pair = CollatorPair::generate().0; - let collator = collator_pair.public(); - - let sig = collator_pair.sign(b"blabla".as_slice()); - ProspectiveCandidate { commitments: CandidateCommitments { upward_messages: Default::default(), @@ -1176,8 +1162,6 @@ mod tests { processed_downward_messages: 0, hrmp_watermark: relay_parent.number, }, - collator, - collator_signature: sig, persisted_validation_data: PersistedValidationData { parent_head: constraints.required_parent.clone(), relay_parent_number: relay_parent.number, diff --git a/polkadot/node/subsystem/Cargo.toml b/polkadot/node/subsystem/Cargo.toml index c59c1f88e33995aef7578da58e28d086668f14ee..8edfea9e26bf5d2176b672c9d24bb1e0251b33ae 100644 --- a/polkadot/node/subsystem/Cargo.toml +++ b/polkadot/node/subsystem/Cargo.toml @@ -10,6 +10,6 @@ license.workspace = true workspace = true [dependencies] -polkadot-overseer = { path = "../overseer" } -polkadot-node-subsystem-types = { path = "../subsystem-types" } -polkadot-node-jaeger = { path = "../jaeger" } +polkadot-overseer = { workspace = true, default-features = true } +polkadot-node-subsystem-types = { workspace = true, default-features = true } +polkadot-node-jaeger = { workspace = true, default-features = true } diff --git a/polkadot/node/test/client/Cargo.toml b/polkadot/node/test/client/Cargo.toml index 0b49866ee2aec4f9676241a50271a16657b221e0..587af659fbd2dfeb142c4f307ce71a92b0fae35b 100644 --- a/polkadot/node/test/client/Cargo.toml +++ b/polkadot/node/test/client/Cargo.toml @@ -10,35 +10,35 @@ license.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } # Polkadot dependencies -polkadot-test-runtime = { path = "../../../runtime/test-runtime" } -polkadot-test-service = { path = "../service" } -polkadot-primitives = { path = "../../../primitives" } -polkadot-node-subsystem = { path = "../../subsystem" } +polkadot-test-runtime = { workspace = true } +polkadot-test-service = { workspace = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } # Substrate dependencies -substrate-test-client = { path = "../../../../substrate/test-utils/client" } -sc-service = { path = "../../../../substrate/client/service" } -sc-block-builder = { path = "../../../../substrate/client/block-builder" } -sc-consensus = { path = "../../../../substrate/client/consensus/common" } -sc-offchain = { path = "../../../../substrate/client/offchain" } -sp-blockchain = { path = "../../../../substrate/primitives/blockchain" } -sp-runtime = { path = "../../../../substrate/primitives/runtime" } -sp-inherents = { path = "../../../../substrate/primitives/inherents" } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-api = { path = "../../../../substrate/primitives/api" } -sp-timestamp = { path = "../../../../substrate/primitives/timestamp" } -sp-consensus = { path = "../../../../substrate/primitives/consensus/common" } -sp-consensus-babe = { path = "../../../../substrate/primitives/consensus/babe" } -sp-state-machine = { path = "../../../../substrate/primitives/state-machine" } -sp-io = { path = "../../../../substrate/primitives/io" } -frame-benchmarking = { path = "../../../../substrate/frame/benchmarking" } +substrate-test-client = { workspace = true } +sc-service = { workspace = true, default-features = true } +sc-block-builder = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sc-offchain = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-timestamp = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +frame-benchmarking = { workspace = true, default-features = true } [dev-dependencies] -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -futures = "0.3.30" +sp-keyring = { workspace = true, default-features = true } +futures = { workspace = true } [features] runtime-benchmarks = [ diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml index 3fc6d060870b1c36940cd7b75e50cddcf55782d3..8eb6105f98e2571bab0257694ccac49ae47c2ca9 100644 --- a/polkadot/node/test/service/Cargo.toml +++ b/polkadot/node/test/service/Cargo.toml @@ -10,60 +10,60 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.30" -hex = "0.4.3" -gum = { package = "tracing-gum", path = "../../gum" } -rand = "0.8.5" +futures = { workspace = true } +hex = { workspace = true, default-features = true } +gum = { workspace = true, default-features = true } +rand = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } -tempfile = "3.2.0" -tokio = "1.37" +tempfile = { workspace = true } +tokio = { workspace = true, default-features = true } # Polkadot dependencies -polkadot-overseer = { path = "../../overseer" } -polkadot-primitives = { path = "../../../primitives" } -polkadot-parachain-primitives = { path = "../../../parachain" } -polkadot-rpc = { path = "../../../rpc" } -polkadot-runtime-common = { path = "../../../runtime/common" } -polkadot-service = { path = "../../service" } -polkadot-node-subsystem = { path = "../../subsystem" } -polkadot-node-primitives = { path = "../../primitives" } -polkadot-test-runtime = { path = "../../../runtime/test-runtime" } -test-runtime-constants = { path = "../../../runtime/test-runtime/constants" } -polkadot-runtime-parachains = { path = "../../../runtime/parachains" } +polkadot-overseer = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-rpc = { workspace = true, default-features = true } +polkadot-runtime-common = { workspace = true, default-features = true } +polkadot-service = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-test-runtime = { workspace = true } +test-runtime-constants = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } # Substrate dependencies -sp-authority-discovery = { path = "../../../../substrate/primitives/authority-discovery" } -sc-authority-discovery = { path = "../../../../substrate/client/authority-discovery" } -sc-consensus-babe = { path = "../../../../substrate/client/consensus/babe" } -sp-consensus-babe = { path = "../../../../substrate/primitives/consensus/babe" } -sp-consensus = { path = "../../../../substrate/primitives/consensus/common" } -frame-system = { path = "../../../../substrate/frame/system" } -sc-consensus-grandpa = { path = "../../../../substrate/client/consensus/grandpa" } -sp-consensus-grandpa = { path = "../../../../substrate/primitives/consensus/grandpa" } -sp-inherents = { path = "../../../../substrate/primitives/inherents" } -pallet-staking = { path = "../../../../substrate/frame/staking" } -pallet-balances = { path = "../../../../substrate/frame/balances" } -pallet-transaction-payment = { path = "../../../../substrate/frame/transaction-payment" } -sc-chain-spec = { path = "../../../../substrate/client/chain-spec" } -sc-cli = { path = "../../../../substrate/client/cli" } -sc-client-api = { path = "../../../../substrate/client/api" } -sc-consensus = { path = "../../../../substrate/client/consensus/common" } -sc-network = { path = "../../../../substrate/client/network" } -sc-tracing = { path = "../../../../substrate/client/tracing" } -sc-transaction-pool = { path = "../../../../substrate/client/transaction-pool" } -sc-service = { path = "../../../../substrate/client/service", default-features = false } -sp-arithmetic = { path = "../../../../substrate/primitives/arithmetic" } -sp-blockchain = { path = "../../../../substrate/primitives/blockchain" } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -sp-runtime = { path = "../../../../substrate/primitives/runtime" } -sp-state-machine = { path = "../../../../substrate/primitives/state-machine" } -substrate-test-client = { path = "../../../../substrate/test-utils/client" } +sp-authority-discovery = { workspace = true, default-features = true } +sc-authority-discovery = { workspace = true, default-features = true } +sc-consensus-babe = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } +sc-consensus-grandpa = { workspace = true, default-features = true } +sp-consensus-grandpa = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +pallet-staking = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +pallet-transaction-payment = { workspace = true, default-features = true } +sc-chain-spec = { workspace = true, default-features = true } +sc-cli = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-tracing = { workspace = true, default-features = true } +sc-transaction-pool = { workspace = true, default-features = true } +sc-service = { workspace = true } +sp-arithmetic = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } +substrate-test-client = { workspace = true } [dev-dependencies] -pallet-balances = { path = "../../../../substrate/frame/balances", default-features = false } -substrate-test-utils = { path = "../../../../substrate/test-utils" } -tokio = { version = "1.37", features = ["macros"] } +pallet-balances = { workspace = true } +substrate-test-utils = { workspace = true } +tokio = { features = ["macros"], workspace = true, default-features = true } [features] runtime-metrics = ["polkadot-test-runtime/runtime-metrics"] diff --git a/polkadot/node/test/service/src/lib.rs b/polkadot/node/test/service/src/lib.rs index 35156a3a9372b54cf438fe086d3642b8fd55992d..a4e58253bb1706c9face2ded9dbbfb66a93ebb40 100644 --- a/polkadot/node/test/service/src/lib.rs +++ b/polkadot/node/test/service/src/lib.rs @@ -232,7 +232,6 @@ pub fn node_config( announce_block: true, data_path: root, base_path, - informant_output_format: Default::default(), } } diff --git a/polkadot/node/zombienet-backchannel/Cargo.toml b/polkadot/node/zombienet-backchannel/Cargo.toml index 31662ccfc464913989e479a12e4bd976451498dc..a9bf1f5ef093a905de7ca96c515a5a1b2c9cd17b 100644 --- a/polkadot/node/zombienet-backchannel/Cargo.toml +++ b/polkadot/node/zombienet-backchannel/Cargo.toml @@ -12,14 +12,14 @@ license.workspace = true workspace = true [dependencies] -tokio = { version = "1.24.2", default-features = false, features = ["macros", "net", "rt-multi-thread", "sync"] } -url = "2.3.1" -tokio-tungstenite = "0.20.1" -futures-util = "0.3.30" -lazy_static = "1.4.0" -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } -reqwest = { version = "0.11", features = ["rustls-tls"], default-features = false } +tokio = { features = ["macros", "net", "rt-multi-thread", "sync"], workspace = true } +url = { workspace = true } +tokio-tungstenite = { workspace = true } +futures-util = { workspace = true, default-features = true } +lazy_static = { workspace = true } +codec = { features = ["derive"], workspace = true, default-features = true } +reqwest = { features = ["rustls-tls"], workspace = true } thiserror = { workspace = true } -gum = { package = "tracing-gum", path = "../gum" } +gum = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } diff --git a/polkadot/parachain/Cargo.toml b/polkadot/parachain/Cargo.toml index 11e8e3ce6d843cf410ce4a2c0bfb2ceacde9ce3e..9d0518fd46ade9644af5c21c0a4c5873bfd458e3 100644 --- a/polkadot/parachain/Cargo.toml +++ b/polkadot/parachain/Cargo.toml @@ -13,15 +13,14 @@ workspace = true # note: special care is taken to avoid inclusion of `sp-io` externals when compiling # this crate for WASM. This is critical to avoid forcing all parachain WASM into implementing # various unnecessary Substrate-specific endpoints. -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } -sp-std = { path = "../../substrate/primitives/std", default-features = false } -sp-runtime = { path = "../../substrate/primitives/runtime", default-features = false, features = ["serde"] } -sp-core = { path = "../../substrate/primitives/core", default-features = false, features = ["serde"] } -sp-weights = { path = "../../substrate/primitives/weights", default-features = false } -polkadot-core-primitives = { path = "../core-primitives", default-features = false } -derive_more = "0.99.11" -bounded-collections = { version = "0.2.0", default-features = false, features = ["serde"] } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive", "serde"], workspace = true } +sp-runtime = { features = ["serde"], workspace = true } +sp-core = { features = ["serde"], workspace = true } +sp-weights = { workspace = true } +polkadot-core-primitives = { workspace = true } +derive_more = { workspace = true, default-features = true } +bounded-collections = { features = ["serde"], workspace = true } # all optional crates. serde = { features = ["alloc", "derive"], workspace = true } @@ -37,7 +36,6 @@ std = [ "serde/std", "sp-core/std", "sp-runtime/std", - "sp-std/std", "sp-weights/std", ] runtime-benchmarks = ["sp-runtime/runtime-benchmarks"] diff --git a/polkadot/parachain/src/lib.rs b/polkadot/parachain/src/lib.rs index bd75296bf837128c7b10b8a89a823cb66dc1ca8b..8941b7fbb911e8338972ff37fe3d7231d4841cd2 100644 --- a/polkadot/parachain/src/lib.rs +++ b/polkadot/parachain/src/lib.rs @@ -51,3 +51,5 @@ mod wasm_api; #[cfg(all(not(feature = "std"), feature = "wasm-api"))] pub use wasm_api::*; + +extern crate alloc; diff --git a/polkadot/parachain/src/primitives.rs b/polkadot/parachain/src/primitives.rs index d92bbee8d28d16ea879094607ab74471551c9313..c5757928c3fc2f86fdd6ddb779856f0f39db70f7 100644 --- a/polkadot/parachain/src/primitives.rs +++ b/polkadot/parachain/src/primitives.rs @@ -17,7 +17,7 @@ //! Primitive types which are strictly necessary from a parachain-execution point //! of view. -use sp_std::vec::Vec; +use alloc::vec::Vec; use bounded_collections::{BoundedVec, ConstU32}; use codec::{CompactAs, Decode, Encode, MaxEncodedLen}; @@ -89,14 +89,14 @@ impl ValidationCode { #[derive(Clone, Copy, Encode, Decode, Hash, Eq, PartialEq, PartialOrd, Ord, TypeInfo)] pub struct ValidationCodeHash(Hash); -impl sp_std::fmt::Display for ValidationCodeHash { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { +impl core::fmt::Display for ValidationCodeHash { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { self.0.fmt(f) } } -impl sp_std::fmt::Debug for ValidationCodeHash { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { +impl core::fmt::Debug for ValidationCodeHash { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{:?}", self.0) } } @@ -119,9 +119,9 @@ impl From<[u8; 32]> for ValidationCodeHash { } } -impl sp_std::fmt::LowerHex for ValidationCodeHash { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - sp_std::fmt::LowerHex::fmt(&self.0, f) +impl core::fmt::LowerHex for ValidationCodeHash { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::LowerHex::fmt(&self.0, f) } } @@ -225,7 +225,7 @@ impl IsSystem for Id { } } -impl sp_std::ops::Add for Id { +impl core::ops::Add for Id { type Output = Self; fn add(self, other: u32) -> Self { @@ -233,7 +233,7 @@ impl sp_std::ops::Add for Id { } } -impl sp_std::ops::Sub for Id { +impl core::ops::Sub for Id { type Output = Self; fn sub(self, other: u32) -> Self { diff --git a/polkadot/parachain/src/wasm_api.rs b/polkadot/parachain/src/wasm_api.rs index f0c832666284c2476401e2c8e7ced49a31864b7e..1c557c9ae50584b61b25004880f8aa4f86308d06 100644 --- a/polkadot/parachain/src/wasm_api.rs +++ b/polkadot/parachain/src/wasm_api.rs @@ -22,7 +22,7 @@ /// function's entry point. #[cfg(not(feature = "std"))] pub unsafe fn load_params(params: *const u8, len: usize) -> crate::primitives::ValidationParams { - let mut slice = sp_std::slice::from_raw_parts(params, len); + let mut slice = core::slice::from_raw_parts(params, len); codec::Decode::decode(&mut slice).expect("Invalid input data") } diff --git a/polkadot/parachain/test-parachains/Cargo.toml b/polkadot/parachain/test-parachains/Cargo.toml index c58b11a11b01f9fb16d80fbe836cdcc956a84890..9f35653f957f3ba8423c5a1e47ca08a05d6bf6c5 100644 --- a/polkadot/parachain/test-parachains/Cargo.toml +++ b/polkadot/parachain/test-parachains/Cargo.toml @@ -11,14 +11,14 @@ publish = false workspace = true [dependencies] -tiny-keccak = { version = "2.0.2", features = ["keccak"] } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } +tiny-keccak = { features = ["keccak"], workspace = true } +codec = { features = ["derive"], workspace = true } -test-parachain-adder = { path = "adder" } -test-parachain-halt = { path = "halt" } +test-parachain-adder = { workspace = true } +test-parachain-halt = { workspace = true } [dev-dependencies] -sp-core = { path = "../../../substrate/primitives/core" } +sp-core = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/polkadot/parachain/test-parachains/adder/Cargo.toml b/polkadot/parachain/test-parachains/adder/Cargo.toml index e0bbe177eedced788de07dc5bf753b4a2f9bb66e..7a150b75d5cdb28a82cdaf9cdeef3cb0c3a4582d 100644 --- a/polkadot/parachain/test-parachains/adder/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/Cargo.toml @@ -12,18 +12,17 @@ publish = false workspace = true [dependencies] -polkadot-parachain-primitives = { path = "../..", default-features = false, features = ["wasm-api"] } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } -tiny-keccak = { version = "2.0.2", features = ["keccak"] } -dlmalloc = { version = "0.2.4", features = ["global"] } +polkadot-parachain-primitives = { features = ["wasm-api"], workspace = true } +codec = { features = ["derive"], workspace = true } +tiny-keccak = { features = ["keccak"], workspace = true } +dlmalloc = { features = ["global"], workspace = true } # We need to make sure the global allocator is disabled until we have support of full substrate externalities -sp-io = { path = "../../../../substrate/primitives/io", default-features = false, features = ["disable_allocator"] } +sp-io = { features = ["disable_allocator"], workspace = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../../substrate/utils/wasm-builder" } +substrate-wasm-builder = { workspace = true, default-features = true } [features] default = ["std"] -std = ["codec/std", "polkadot-parachain-primitives/std", "sp-io/std", "sp-std/std"] +std = ["codec/std", "polkadot-parachain-primitives/std", "sp-io/std"] diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index 996735e8c8bf8e641de15acf4bb2bd2e126c94fe..061378a76a82eb8edcf8823d7ee3d43d7d3fc7e9 100644 --- a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml @@ -15,30 +15,30 @@ name = "adder-collator" path = "src/main.rs" [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -clap = { version = "4.5.3", features = ["derive"] } -futures = "0.3.30" -futures-timer = "3.0.2" +codec = { features = ["derive"], workspace = true } +clap = { features = ["derive"], workspace = true } +futures = { workspace = true } +futures-timer = { workspace = true } log = { workspace = true, default-features = true } -test-parachain-adder = { path = ".." } -polkadot-primitives = { path = "../../../../primitives" } -polkadot-cli = { path = "../../../../cli" } -polkadot-service = { path = "../../../../node/service", features = ["rococo-native"] } -polkadot-node-primitives = { path = "../../../../node/primitives" } -polkadot-node-subsystem = { path = "../../../../node/subsystem" } +test-parachain-adder = { workspace = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-cli = { workspace = true, default-features = true } +polkadot-service = { features = ["rococo-native"], workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } -sc-cli = { path = "../../../../../substrate/client/cli" } -sp-core = { path = "../../../../../substrate/primitives/core" } -sc-service = { path = "../../../../../substrate/client/service" } +sc-cli = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sc-service = { workspace = true, default-features = true } [dev-dependencies] -polkadot-parachain-primitives = { path = "../../.." } -polkadot-test-service = { path = "../../../../node/test/service" } -polkadot-node-core-pvf = { path = "../../../../node/core/pvf", features = ["test-utils"] } +polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-test-service = { workspace = true } +polkadot-node-core-pvf = { features = ["test-utils"], workspace = true, default-features = true } -substrate-test-utils = { path = "../../../../../substrate/test-utils" } -sc-service = { path = "../../../../../substrate/client/service" } -sp-keyring = { path = "../../../../../substrate/primitives/keyring" } +substrate-test-utils = { workspace = true } +sc-service = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } -tokio = { version = "1.24.2", features = ["macros"] } +tokio = { features = ["macros"], workspace = true, default-features = true } diff --git a/polkadot/parachain/test-parachains/adder/src/lib.rs b/polkadot/parachain/test-parachains/adder/src/lib.rs index 28914f02511debbc1beba6253e9f1e74dbfacc17..7e8d1bb1e1383fed96525c34ce44eb4c20f9467d 100644 --- a/polkadot/parachain/test-parachains/adder/src/lib.rs +++ b/polkadot/parachain/test-parachains/adder/src/lib.rs @@ -18,6 +18,8 @@ #![no_std] +extern crate alloc; + use codec::{Decode, Encode}; use tiny_keccak::{Hasher as _, Keccak}; diff --git a/polkadot/parachain/test-parachains/adder/src/wasm_validation.rs b/polkadot/parachain/test-parachains/adder/src/wasm_validation.rs index 7dba7a964d3b0468d48799557a363d374f4aea38..9c3c77f7350b902b3f99203d2be0f2d675e77274 100644 --- a/polkadot/parachain/test-parachains/adder/src/wasm_validation.rs +++ b/polkadot/parachain/test-parachains/adder/src/wasm_validation.rs @@ -17,10 +17,10 @@ //! WASM validation for adder parachain. use crate::{BlockData, HeadData}; +use alloc::vec::Vec; use codec::{Decode, Encode}; use core::panic; use polkadot_parachain_primitives::primitives::{HeadData as GenericHeadData, ValidationResult}; -use sp_std::vec::Vec; #[no_mangle] pub extern "C" fn validate_block(params: *const u8, len: usize) -> u64 { @@ -37,10 +37,8 @@ pub extern "C" fn validate_block(params: *const u8, len: usize) -> u64 { polkadot_parachain_primitives::write_result(&ValidationResult { head_data: GenericHeadData(new_head.encode()), new_validation_code: None, - upward_messages: sp_std::vec::Vec::new().try_into().expect("empty vec fits into bounds"), - horizontal_messages: sp_std::vec::Vec::new() - .try_into() - .expect("empty vec fits into bounds"), + upward_messages: alloc::vec::Vec::new().try_into().expect("empty vec fits into bounds"), + horizontal_messages: alloc::vec::Vec::new().try_into().expect("empty vec fits into bounds"), processed_downward_messages: 0, hrmp_watermark: params.relay_parent_number, }) diff --git a/polkadot/parachain/test-parachains/halt/Cargo.toml b/polkadot/parachain/test-parachains/halt/Cargo.toml index 1bdd4392ad313dbdcf62d36bd04cab7330fdf3fb..f8272f6ed19681adf3faa57dfac3c4f126db6839 100644 --- a/polkadot/parachain/test-parachains/halt/Cargo.toml +++ b/polkadot/parachain/test-parachains/halt/Cargo.toml @@ -14,8 +14,8 @@ workspace = true [dependencies] [build-dependencies] -substrate-wasm-builder = { path = "../../../../substrate/utils/wasm-builder" } -rustversion = "1.0.6" +substrate-wasm-builder = { workspace = true, default-features = true } +rustversion = { workspace = true } [features] default = ["std"] diff --git a/polkadot/parachain/test-parachains/undying/Cargo.toml b/polkadot/parachain/test-parachains/undying/Cargo.toml index 4d3d2abaeafed85dea9a415da47b620981f1e5ca..4b2e12ebf435422c713fd2319eee08d9fa45d8dc 100644 --- a/polkadot/parachain/test-parachains/undying/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/Cargo.toml @@ -12,18 +12,17 @@ license.workspace = true workspace = true [dependencies] -polkadot-parachain-primitives = { path = "../..", default-features = false, features = ["wasm-api"] } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -sp-std = { path = "../../../../substrate/primitives/std", default-features = false } -tiny-keccak = { version = "2.0.2", features = ["keccak"] } -dlmalloc = { version = "0.2.4", features = ["global"] } +polkadot-parachain-primitives = { features = ["wasm-api"], workspace = true } +codec = { features = ["derive"], workspace = true } +tiny-keccak = { features = ["keccak"], workspace = true } +dlmalloc = { features = ["global"], workspace = true } log = { workspace = true } # We need to make sure the global allocator is disabled until we have support of full substrate externalities -sp-io = { path = "../../../../substrate/primitives/io", default-features = false, features = ["disable_allocator"] } +sp-io = { features = ["disable_allocator"], workspace = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../../substrate/utils/wasm-builder" } +substrate-wasm-builder = { workspace = true, default-features = true } [features] default = ["std"] @@ -32,5 +31,4 @@ std = [ "log/std", "polkadot-parachain-primitives/std", "sp-io/std", - "sp-std/std", ] diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index 288549c2c268ab93a3b39d5bc2e184a28b7dc158..5760258c70ea5757f5fda90abbfe5a41e5ee0fb4 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -15,30 +15,30 @@ name = "undying-collator" path = "src/main.rs" [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -clap = { version = "4.5.3", features = ["derive"] } -futures = "0.3.30" -futures-timer = "3.0.2" +codec = { features = ["derive"], workspace = true } +clap = { features = ["derive"], workspace = true } +futures = { workspace = true } +futures-timer = { workspace = true } log = { workspace = true, default-features = true } -test-parachain-undying = { path = ".." } -polkadot-primitives = { path = "../../../../primitives" } -polkadot-cli = { path = "../../../../cli" } -polkadot-service = { path = "../../../../node/service", features = ["rococo-native"] } -polkadot-node-primitives = { path = "../../../../node/primitives" } -polkadot-node-subsystem = { path = "../../../../node/subsystem" } +test-parachain-undying = { workspace = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-cli = { workspace = true, default-features = true } +polkadot-service = { features = ["rococo-native"], workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } -sc-cli = { path = "../../../../../substrate/client/cli" } -sp-core = { path = "../../../../../substrate/primitives/core" } -sc-service = { path = "../../../../../substrate/client/service" } +sc-cli = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sc-service = { workspace = true, default-features = true } [dev-dependencies] -polkadot-parachain-primitives = { path = "../../.." } -polkadot-test-service = { path = "../../../../node/test/service" } -polkadot-node-core-pvf = { path = "../../../../node/core/pvf", features = ["test-utils"] } +polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-test-service = { workspace = true } +polkadot-node-core-pvf = { features = ["test-utils"], workspace = true, default-features = true } -substrate-test-utils = { path = "../../../../../substrate/test-utils" } -sc-service = { path = "../../../../../substrate/client/service" } -sp-keyring = { path = "../../../../../substrate/primitives/keyring" } +substrate-test-utils = { workspace = true } +sc-service = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } -tokio = { version = "1.24.2", features = ["macros"] } +tokio = { features = ["macros"], workspace = true, default-features = true } diff --git a/polkadot/parachain/test-parachains/undying/src/lib.rs b/polkadot/parachain/test-parachains/undying/src/lib.rs index dc056e64fa23fb801a34d7d7b276982e4adf4f55..e4ec7e99346bbef4f3ce2fdb03b6084c053926f8 100644 --- a/polkadot/parachain/test-parachains/undying/src/lib.rs +++ b/polkadot/parachain/test-parachains/undying/src/lib.rs @@ -18,8 +18,10 @@ #![no_std] +extern crate alloc; + +use alloc::vec::Vec; use codec::{Decode, Encode}; -use sp_std::vec::Vec; use tiny_keccak::{Hasher as _, Keccak}; #[cfg(not(feature = "std"))] diff --git a/polkadot/parachain/test-parachains/undying/src/wasm_validation.rs b/polkadot/parachain/test-parachains/undying/src/wasm_validation.rs index 23fac43a3c73129b1af27d12cb0a4a79aa3c7be1..46b66aa518e490e117c6d190d52a4d4dc85574d7 100644 --- a/polkadot/parachain/test-parachains/undying/src/wasm_validation.rs +++ b/polkadot/parachain/test-parachains/undying/src/wasm_validation.rs @@ -37,8 +37,8 @@ pub extern "C" fn validate_block(params: *const u8, len: usize) -> u64 { polkadot_parachain_primitives::write_result(&ValidationResult { head_data: GenericHeadData(new_head.encode()), new_validation_code: None, - upward_messages: sp_std::vec::Vec::new().try_into().expect("empty vec fits within bounds"), - horizontal_messages: sp_std::vec::Vec::new() + upward_messages: alloc::vec::Vec::new().try_into().expect("empty vec fits within bounds"), + horizontal_messages: alloc::vec::Vec::new() .try_into() .expect("empty vec fits within bounds"), processed_downward_messages: 0, diff --git a/polkadot/primitives/Cargo.toml b/polkadot/primitives/Cargo.toml index d6df077b88b771ce556db3cc056745a5254a6bc5..8f7ec314ecffe6d7ca7f1f943a47971b4a1e9558 100644 --- a/polkadot/primitives/Cargo.toml +++ b/polkadot/primitives/Cargo.toml @@ -10,28 +10,27 @@ description = "Shared primitives used by Polkadot runtime" workspace = true [dependencies] -bitvec = { version = "1.0.0", default-features = false, features = ["alloc", "serde"] } -hex-literal = "0.4.1" -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["bit-vec", "derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive", "serde"] } -log = { workspace = true, default-features = false } +bitvec = { features = ["alloc", "serde"], workspace = true } +hex-literal = { workspace = true, default-features = true } +codec = { features = ["bit-vec", "derive"], workspace = true } +scale-info = { features = ["bit-vec", "derive", "serde"], workspace = true } +log = { workspace = true } serde = { features = ["alloc", "derive"], workspace = true } -sp-application-crypto = { path = "../../substrate/primitives/application-crypto", default-features = false, features = ["serde"] } -sp-inherents = { path = "../../substrate/primitives/inherents", default-features = false } -sp-core = { path = "../../substrate/primitives/core", default-features = false } -sp-runtime = { path = "../../substrate/primitives/runtime", default-features = false } -sp-api = { path = "../../substrate/primitives/api", default-features = false } -sp-arithmetic = { path = "../../substrate/primitives/arithmetic", default-features = false, features = ["serde"] } -sp-authority-discovery = { path = "../../substrate/primitives/authority-discovery", default-features = false, features = ["serde"] } -sp-consensus-slots = { path = "../../substrate/primitives/consensus/slots", default-features = false, features = ["serde"] } -sp-io = { path = "../../substrate/primitives/io", default-features = false } -sp-keystore = { path = "../../substrate/primitives/keystore", optional = true, default-features = false } -sp-staking = { path = "../../substrate/primitives/staking", default-features = false, features = ["serde"] } -sp-std = { package = "sp-std", path = "../../substrate/primitives/std", default-features = false } +sp-application-crypto = { features = ["serde"], workspace = true } +sp-inherents = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-api = { workspace = true } +sp-arithmetic = { features = ["serde"], workspace = true } +sp-authority-discovery = { features = ["serde"], workspace = true } +sp-consensus-slots = { features = ["serde"], workspace = true } +sp-io = { workspace = true } +sp-keystore = { optional = true, workspace = true } +sp-staking = { features = ["serde"], workspace = true } -polkadot-core-primitives = { path = "../core-primitives", default-features = false } -polkadot-parachain-primitives = { path = "../parachain", default-features = false } +polkadot-core-primitives = { workspace = true } +polkadot-parachain-primitives = { workspace = true } [features] default = ["std"] @@ -55,7 +54,6 @@ std = [ "sp-keystore?/std", "sp-runtime/std", "sp-staking/std", - "sp-std/std", ] runtime-benchmarks = [ "polkadot-parachain-primitives/runtime-benchmarks", diff --git a/polkadot/primitives/src/lib.rs b/polkadot/primitives/src/lib.rs index 061794ca06d1be1883fd3605eb5bc691e5b7b23b..73736fd4a3d6b7fc6f164952fbbc6a49f139de88 100644 --- a/polkadot/primitives/src/lib.rs +++ b/polkadot/primitives/src/lib.rs @@ -31,6 +31,8 @@ pub mod vstaging; // unstable functions. pub mod runtime_api; +extern crate alloc; + // Current primitives not requiring versioning are exported here. // Primitives requiring versioning must not be exported and must be referred by an exact version. pub use v7::{ diff --git a/polkadot/primitives/src/runtime_api.rs b/polkadot/primitives/src/runtime_api.rs index 7bd92be35c159db35b3db7b9dd91afcc73eebd81..b4816ad15075dcc8d739259b779bfda1a9b5c84a 100644 --- a/polkadot/primitives/src/runtime_api.rs +++ b/polkadot/primitives/src/runtime_api.rs @@ -121,12 +121,12 @@ use crate::{ SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, ValidatorSignature, }; -use polkadot_core_primitives as pcp; -use polkadot_parachain_primitives::primitives as ppp; -use sp_std::{ +use alloc::{ collections::{btree_map::BTreeMap, vec_deque::VecDeque}, - prelude::*, + vec::Vec, }; +use polkadot_core_primitives as pcp; +use polkadot_parachain_primitives::primitives as ppp; sp_api::decl_runtime_apis! { /// The API for querying the state of parachains on-chain. diff --git a/polkadot/primitives/src/v7/async_backing.rs b/polkadot/primitives/src/v7/async_backing.rs index a82d843d28bf1ca9993e7951fa8f51c458bd63c3..55d436e30de07812d4b1d722a5cbb9a85cc7d1aa 100644 --- a/polkadot/primitives/src/v7/async_backing.rs +++ b/polkadot/primitives/src/v7/async_backing.rs @@ -18,6 +18,7 @@ use super::*; +use alloc::vec::Vec; use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_core::RuntimeDebug; diff --git a/polkadot/primitives/src/v7/executor_params.rs b/polkadot/primitives/src/v7/executor_params.rs index e58cf3e76cc2c75137737c2a6e2b34685e1a78fd..bfd42ec30bd39dbaa3299cda634fd0f4743ab2e2 100644 --- a/polkadot/primitives/src/v7/executor_params.rs +++ b/polkadot/primitives/src/v7/executor_params.rs @@ -22,11 +22,12 @@ //! done in `polkadot-node-core-pvf`. use crate::{BlakeTwo256, HashT as _, PvfExecKind, PvfPrepKind}; +use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec}; use codec::{Decode, Encode}; +use core::{ops::Deref, time::Duration}; use polkadot_core_primitives::Hash; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; -use sp_std::{collections::btree_map::BTreeMap, ops::Deref, time::Duration, vec, vec::Vec}; /// Default maximum number of wasm values allowed for the stack during execution of a PVF. pub const DEFAULT_LOGICAL_STACK_MAX: u32 = 65536; @@ -134,21 +135,21 @@ impl ExecutorParamsHash { } } -impl sp_std::fmt::Display for ExecutorParamsHash { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { +impl core::fmt::Display for ExecutorParamsHash { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { self.0.fmt(f) } } -impl sp_std::fmt::Debug for ExecutorParamsHash { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { +impl core::fmt::Debug for ExecutorParamsHash { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{:?}", self.0) } } -impl sp_std::fmt::LowerHex for ExecutorParamsHash { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - sp_std::fmt::LowerHex::fmt(&self.0, f) +impl core::fmt::LowerHex for ExecutorParamsHash { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::LowerHex::fmt(&self.0, f) } } @@ -159,21 +160,21 @@ impl sp_std::fmt::LowerHex for ExecutorParamsHash { #[derive(Clone, Copy, Encode, Decode, Hash, Eq, PartialEq, PartialOrd, Ord, TypeInfo)] pub struct ExecutorParamsPrepHash(Hash); -impl sp_std::fmt::Display for ExecutorParamsPrepHash { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { +impl core::fmt::Display for ExecutorParamsPrepHash { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { self.0.fmt(f) } } -impl sp_std::fmt::Debug for ExecutorParamsPrepHash { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { +impl core::fmt::Debug for ExecutorParamsPrepHash { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{:?}", self.0) } } -impl sp_std::fmt::LowerHex for ExecutorParamsPrepHash { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - sp_std::fmt::LowerHex::fmt(&self.0, f) +impl core::fmt::LowerHex for ExecutorParamsPrepHash { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::LowerHex::fmt(&self.0, f) } } diff --git a/polkadot/primitives/src/v7/metrics.rs b/polkadot/primitives/src/v7/metrics.rs index 1a29471c5450aa23ad00f8a41c54aca34ea7dbf4..1d66c9848a7c4016a86f5ed1eb85e880b35bba91 100644 --- a/polkadot/primitives/src/v7/metrics.rs +++ b/polkadot/primitives/src/v7/metrics.rs @@ -16,8 +16,8 @@ //! Runtime metric primitives. +use alloc::vec::Vec; use codec::{Decode, Encode}; -use sp_std::prelude::*; /// Runtime metric operations. #[derive(Encode, Decode)] @@ -42,7 +42,7 @@ pub struct RuntimeMetricUpdate { } fn vec_to_str<'a>(v: &'a Vec, default: &'static str) -> &'a str { - return sp_std::str::from_utf8(v).unwrap_or(default) + return alloc::str::from_utf8(v).unwrap_or(default) } impl RuntimeMetricLabels { @@ -99,7 +99,7 @@ pub trait AsStr { impl AsStr for RuntimeMetricLabel { fn as_str(&self) -> Option<&str> { - sp_std::str::from_utf8(&self.0).ok() + alloc::str::from_utf8(&self.0).ok() } } diff --git a/polkadot/primitives/src/v7/mod.rs b/polkadot/primitives/src/v7/mod.rs index 6b7985847a10699d36ef0f953cd5d2605c6beca0..a729d8cee4c7eaa7b654c018f115b17457e17256 100644 --- a/polkadot/primitives/src/v7/mod.rs +++ b/polkadot/primitives/src/v7/mod.rs @@ -16,15 +16,17 @@ //! `V7` Primitives. +use alloc::{ + vec, + vec::{IntoIter, Vec}, +}; use bitvec::{field::BitField, slice::BitSlice, vec::BitVec}; use codec::{Decode, Encode}; -use scale_info::TypeInfo; -use sp_std::{ +use core::{ marker::PhantomData, - prelude::*, slice::{Iter, IterMut}, - vec::IntoIter, }; +use scale_info::TypeInfo; use sp_application_crypto::KeyTypeId; use sp_arithmetic::traits::{BaseArithmetic, Saturating}; @@ -172,10 +174,10 @@ pub type ValidatorSignature = validator_app::Signature; /// A declarations of storage keys where an external observer can find some interesting data. pub mod well_known_keys { use super::{HrmpChannelId, Id, WellKnownKey}; + use alloc::vec::Vec; use codec::Encode as _; use hex_literal::hex; use sp_io::hashing::twox_64; - use sp_std::prelude::*; // A note on generating these magic values below: // @@ -617,13 +619,13 @@ impl CommittedCandidateReceipt { } impl PartialOrd for CommittedCandidateReceipt { - fn partial_cmp(&self, other: &Self) -> Option { + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for CommittedCandidateReceipt { - fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { // TODO: compare signatures or something more sane // https://github.com/paritytech/polkadot/issues/222 self.descriptor() @@ -984,7 +986,7 @@ impl GroupRotationInfo { return GroupIndex(0) } - let cores = sp_std::cmp::min(cores, u32::MAX as usize); + let cores = core::cmp::min(cores, u32::MAX as usize); let blocks_since_start = self.now.saturating_sub(self.session_start_block); let rotations = blocks_since_start / self.group_rotation_frequency; @@ -1006,7 +1008,7 @@ impl GroupRotationInfo { return CoreIndex(0) } - let cores = sp_std::cmp::min(cores, u32::MAX as usize); + let cores = core::cmp::min(cores, u32::MAX as usize); let blocks_since_start = self.now.saturating_sub(self.session_start_block); let rotations = blocks_since_start / self.group_rotation_frequency; let rotations = rotations % cores as u32; @@ -1870,7 +1872,7 @@ pub fn effective_minimum_backing_votes( group_len: usize, configured_minimum_backing_votes: u32, ) -> usize { - sp_std::cmp::min(group_len, configured_minimum_backing_votes as usize) + core::cmp::min(group_len, configured_minimum_backing_votes as usize) } /// Information about validator sets of a session. @@ -1966,7 +1968,7 @@ impl PvfCheckStatement { pub struct WellKnownKey { /// The raw storage key. pub key: Vec, - _p: sp_std::marker::PhantomData, + _p: core::marker::PhantomData, } impl From> for WellKnownKey { @@ -2038,10 +2040,14 @@ pub mod node_features { /// Must not be enabled unless all validators and collators have stopped using `req_chunk` /// protocol version 1. If it is enabled, validators can start systematic chunk recovery. AvailabilityChunkMapping = 2, + /// Enables node side support of `CoreIndex` committed candidate receipts. + /// See [RFC-103](https://github.com/polkadot-fellows/RFCs/pull/103) for details. + /// Only enable if at least 2/3 of nodes support the feature. + CandidateReceiptV2 = 3, /// First unassigned feature bit. /// Every time a new feature flag is assigned it should take this value. /// and this should be incremented. - FirstUnassigned = 3, + FirstUnassigned = 4, } } diff --git a/polkadot/primitives/src/v7/signed.rs b/polkadot/primitives/src/v7/signed.rs index 62e4df2385038f02247ce41fc87a1f4243c73970..f819b379a30ae2dde68d215daea712c7c28ecbb2 100644 --- a/polkadot/primitives/src/v7/signed.rs +++ b/polkadot/primitives/src/v7/signed.rs @@ -17,11 +17,11 @@ use codec::{Decode, Encode}; use scale_info::TypeInfo; +use alloc::vec::Vec; #[cfg(feature = "std")] use sp_application_crypto::AppCrypto; #[cfg(feature = "std")] use sp_keystore::{Error as KeystoreError, KeystorePtr}; -use sp_std::prelude::Vec; use sp_core::RuntimeDebug; use sp_runtime::traits::AppVerify; @@ -57,7 +57,7 @@ pub struct UncheckedSigned { /// The signature by the validator of the signed payload. signature: ValidatorSignature, /// This ensures the real payload is tracked at the typesystem level. - real_payload: sp_std::marker::PhantomData, + real_payload: core::marker::PhantomData, } impl, RealPayload: Encode> Signed { @@ -163,7 +163,7 @@ impl, RealPayload: Encode> Signed, RealPayload: Encode> Signed, RealPayload: Encode> UncheckedSigned, RealPayload: Encode> UncheckedSigned NOTE: This module has suffered changes for the elastic scaling implementation. As a result, parts of this document may +be out of date and will be updated at a later time. Issue tracking the update: +https://github.com/paritytech/polkadot-sdk/issues/3699 + The Candidate Backing subsystem ensures every parablock considered for relay block inclusion has been seconded by at least one validator, and approved by a quorum. Parablocks for which not enough validators will assert correctness are discarded. If the block later proves invalid, the initial backers are slashable; this gives Polkadot a rational threat diff --git a/polkadot/roadmap/implementers-guide/src/node/backing/prospective-parachains.md b/polkadot/roadmap/implementers-guide/src/node/backing/prospective-parachains.md index 701f6c87caff0341c36e4b2799d2444c015c411c..61278621cf565c226c2133eb90c0d7e0430c5624 100644 --- a/polkadot/roadmap/implementers-guide/src/node/backing/prospective-parachains.md +++ b/polkadot/roadmap/implementers-guide/src/node/backing/prospective-parachains.md @@ -1,5 +1,9 @@ # Prospective Parachains +> NOTE: This module has suffered changes for the elastic scaling implementation. As a result, parts of this document may +be out of date and will be updated at a later time. Issue tracking the update: +https://github.com/paritytech/polkadot-sdk/issues/3699 + ## Overview **Purpose:** Tracks and handles prospective parachain fragments and informs diff --git a/polkadot/roadmap/implementers-guide/src/node/collators/collator-protocol.md b/polkadot/roadmap/implementers-guide/src/node/collators/collator-protocol.md index 1fed671170c7c42f6de97dead0e53200ef5d675f..432d9ab69bab99297b51fb5af285e7636e8b90ae 100644 --- a/polkadot/roadmap/implementers-guide/src/node/collators/collator-protocol.md +++ b/polkadot/roadmap/implementers-guide/src/node/collators/collator-protocol.md @@ -1,5 +1,9 @@ # Collator Protocol +> NOTE: This module has suffered changes for the elastic scaling implementation. As a result, parts of this document may +be out of date and will be updated at a later time. Issue tracking the update: +https://github.com/paritytech/polkadot-sdk/issues/3699 + The Collator Protocol implements the network protocol by which collators and validators communicate. It is used by collators to distribute collations to validators and used by validators to accept collations by collators. diff --git a/polkadot/roadmap/implementers-guide/src/node/utility/provisioner.md b/polkadot/roadmap/implementers-guide/src/node/utility/provisioner.md index b017259da8c0863e47deb87e916076d20ed95996..64727d39fabe0dee80e047a1444894733c827014 100644 --- a/polkadot/roadmap/implementers-guide/src/node/utility/provisioner.md +++ b/polkadot/roadmap/implementers-guide/src/node/utility/provisioner.md @@ -1,5 +1,9 @@ # Provisioner +> NOTE: This module has suffered changes for the elastic scaling implementation. As a result, parts of this document may +be out of date and will be updated at a later time. Issue tracking the update: +https://github.com/paritytech/polkadot-sdk/issues/3699 + Relay chain block authorship authority is governed by BABE and is beyond the scope of the Overseer and the rest of the subsystems. That said, ultimately the block author needs to select a set of backable parachain candidates and other consensus data, and assemble a block from them. This subsystem is responsible for providing the necessary data to all diff --git a/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md b/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md index 0700a781d426324c2c35e72628caa65b577ef979..5031433cf5a1d7a5517458d5f0a5b31a024c4d49 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md @@ -1,5 +1,9 @@ # Inclusion Pallet +> NOTE: This module has suffered changes for the elastic scaling implementation. As a result, parts of this document may +be out of date and will be updated at a later time. Issue tracking the update: +https://github.com/paritytech/polkadot-sdk/issues/3699 + The inclusion module is responsible for inclusion and availability of scheduled parachains. It also manages the UMP dispatch queue of each parachain. diff --git a/polkadot/roadmap/implementers-guide/src/runtime/parainherent.md b/polkadot/roadmap/implementers-guide/src/runtime/parainherent.md index 7972c706b9ee1ebce2132a49ccf62a194d6c1e58..f21e1a59c1a4c0a9e05ae41361f5d7d9fa216378 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/parainherent.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/parainherent.md @@ -1,5 +1,9 @@ # `ParaInherent` +> NOTE: This module has suffered changes for the elastic scaling implementation. As a result, parts of this document may +be out of date and will be updated at a later time. Issue tracking the update: +https://github.com/paritytech/polkadot-sdk/issues/3699 + This module is responsible for providing all data given to the runtime by the block author to the various parachains modules. The entry-point is mandatory, in that it must be invoked exactly once within every block, and it is also "inherent", in that it is provided with no origin by the block author. The data within it carries its own diff --git a/polkadot/rpc/Cargo.toml b/polkadot/rpc/Cargo.toml index cceb4dc5a93b3f9ccf643572e1ba32b38aa5a853..d01528d4dee07d2d1d5ae59f5dac6a61e60fb197 100644 --- a/polkadot/rpc/Cargo.toml +++ b/polkadot/rpc/Cargo.toml @@ -10,31 +10,31 @@ description = "Polkadot specific RPC functionality." workspace = true [dependencies] -jsonrpsee = { version = "0.22", features = ["server"] } -polkadot-primitives = { path = "../primitives" } -sc-client-api = { path = "../../substrate/client/api" } -sp-blockchain = { path = "../../substrate/primitives/blockchain" } -sp-keystore = { path = "../../substrate/primitives/keystore" } -sp-runtime = { path = "../../substrate/primitives/runtime" } -sp-api = { path = "../../substrate/primitives/api" } -sp-application-crypto = { path = "../../substrate/primitives/application-crypto" } -sp-consensus = { path = "../../substrate/primitives/consensus/common" } -sp-consensus-babe = { path = "../../substrate/primitives/consensus/babe" } -sp-consensus-beefy = { path = "../../substrate/primitives/consensus/beefy" } -sc-chain-spec = { path = "../../substrate/client/chain-spec" } -sc-rpc = { path = "../../substrate/client/rpc" } -sc-rpc-spec-v2 = { path = "../../substrate/client/rpc-spec-v2" } -sc-consensus-babe = { path = "../../substrate/client/consensus/babe" } -sc-consensus-babe-rpc = { path = "../../substrate/client/consensus/babe/rpc" } -sc-consensus-beefy = { path = "../../substrate/client/consensus/beefy" } -sc-consensus-beefy-rpc = { path = "../../substrate/client/consensus/beefy/rpc" } -sc-consensus-epochs = { path = "../../substrate/client/consensus/epochs" } -sc-consensus-grandpa = { path = "../../substrate/client/consensus/grandpa" } -sc-consensus-grandpa-rpc = { path = "../../substrate/client/consensus/grandpa/rpc" } -sc-sync-state-rpc = { path = "../../substrate/client/sync-state-rpc" } -sc-transaction-pool-api = { path = "../../substrate/client/transaction-pool/api" } -substrate-frame-rpc-system = { path = "../../substrate/utils/frame/rpc/system" } -mmr-rpc = { path = "../../substrate/client/merkle-mountain-range/rpc" } -pallet-transaction-payment-rpc = { path = "../../substrate/frame/transaction-payment/rpc" } -sp-block-builder = { path = "../../substrate/primitives/block-builder" } -substrate-state-trie-migration-rpc = { path = "../../substrate/utils/frame/rpc/state-trie-migration-rpc" } +jsonrpsee = { features = ["server"], workspace = true } +polkadot-primitives = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-consensus-beefy = { workspace = true, default-features = true } +sc-chain-spec = { workspace = true, default-features = true } +sc-rpc = { workspace = true, default-features = true } +sc-rpc-spec-v2 = { workspace = true, default-features = true } +sc-consensus-babe = { workspace = true, default-features = true } +sc-consensus-babe-rpc = { workspace = true, default-features = true } +sc-consensus-beefy = { workspace = true, default-features = true } +sc-consensus-beefy-rpc = { workspace = true, default-features = true } +sc-consensus-epochs = { workspace = true, default-features = true } +sc-consensus-grandpa = { workspace = true, default-features = true } +sc-consensus-grandpa-rpc = { workspace = true, default-features = true } +sc-sync-state-rpc = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } +substrate-frame-rpc-system = { workspace = true, default-features = true } +mmr-rpc = { workspace = true, default-features = true } +pallet-transaction-payment-rpc = { workspace = true, default-features = true } +sp-block-builder = { workspace = true, default-features = true } +substrate-state-trie-migration-rpc = { workspace = true, default-features = true } diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index da89bd2251acff0d0c76b49908109a1ff662846c..cda6f3240dd2e4e6460471372a5536fa8cc2307d 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -10,66 +10,65 @@ license.workspace = true workspace = true [dependencies] -impl-trait-for-tuples = "0.2.2" -bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } +impl-trait-for-tuples = { workspace = true } +bitvec = { features = ["alloc"], workspace = true } +codec = { features = ["derive"], workspace = true } log = { workspace = true } -rustc-hex = { version = "2.1.0", default-features = false } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +rustc-hex = { workspace = true } +scale-info = { features = ["derive"], workspace = true } serde = { features = ["alloc"], workspace = true } serde_derive = { workspace = true } -static_assertions = "1.1.0" +static_assertions = { workspace = true, default-features = true } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false } -sp-std = { package = "sp-std", path = "../../../substrate/primitives/std", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false, features = ["serde"] } -sp-session = { path = "../../../substrate/primitives/session", default-features = false } -sp-staking = { path = "../../../substrate/primitives/staking", default-features = false, features = ["serde"] } -sp-core = { path = "../../../substrate/primitives/core", default-features = false, features = ["serde"] } -sp-npos-elections = { path = "../../../substrate/primitives/npos-elections", default-features = false, features = ["serde"] } +sp-api = { workspace = true } +sp-inherents = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { features = ["serde"], workspace = true } +sp-session = { workspace = true } +sp-staking = { features = ["serde"], workspace = true } +sp-core = { features = ["serde"], workspace = true } +sp-npos-elections = { features = ["serde"], workspace = true } -pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } -pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } -pallet-broker = { path = "../../../substrate/frame/broker", default-features = false } -pallet-fast-unstake = { path = "../../../substrate/frame/fast-unstake", default-features = false } -pallet-identity = { path = "../../../substrate/frame/identity", default-features = false } -pallet-session = { path = "../../../substrate/frame/session", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -pallet-staking = { path = "../../../substrate/frame/staking", default-features = false } -pallet-staking-reward-fn = { path = "../../../substrate/frame/staking/reward-fn", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false } -pallet-vesting = { path = "../../../substrate/frame/vesting", default-features = false } -pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false } -pallet-treasury = { path = "../../../substrate/frame/treasury", default-features = false } -pallet-asset-rate = { path = "../../../substrate/frame/asset-rate", default-features = false, optional = true } -pallet-election-provider-multi-phase = { path = "../../../substrate/frame/election-provider-multi-phase", default-features = false } -frame-election-provider-support = { path = "../../../substrate/frame/election-provider-support", default-features = false } +pallet-authorship = { workspace = true } +pallet-balances = { workspace = true } +pallet-broker = { workspace = true } +pallet-fast-unstake = { workspace = true } +pallet-identity = { workspace = true } +pallet-session = { workspace = true } +frame-support = { workspace = true } +pallet-staking = { workspace = true } +pallet-staking-reward-fn = { workspace = true } +frame-system = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-vesting = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-treasury = { workspace = true } +pallet-asset-rate = { optional = true, workspace = true } +pallet-election-provider-multi-phase = { workspace = true } +frame-election-provider-support = { workspace = true } -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } -pallet-babe = { path = "../../../substrate/frame/babe", default-features = false, optional = true } +frame-benchmarking = { optional = true, workspace = true } +pallet-babe = { optional = true, workspace = true } -polkadot-primitives = { path = "../../primitives", default-features = false } -libsecp256k1 = { version = "0.7.0", default-features = false } -polkadot-runtime-parachains = { path = "../parachains", default-features = false } +polkadot-primitives = { workspace = true } +libsecp256k1 = { workspace = true } +polkadot-runtime-parachains = { workspace = true } -slot-range-helper = { path = "slot_range_helper", default-features = false } -xcm = { package = "staging-xcm", path = "../../xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../xcm/xcm-executor", default-features = false, optional = true } -xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false } +slot-range-helper = { workspace = true } +xcm = { workspace = true } +xcm-executor = { optional = true, workspace = true } +xcm-builder = { workspace = true } [dev-dependencies] -hex-literal = "0.4.1" -frame-support-test = { path = "../../../substrate/frame/support/test" } -pallet-babe = { path = "../../../substrate/frame/babe" } -pallet-treasury = { path = "../../../substrate/frame/treasury" } -sp-keystore = { path = "../../../substrate/primitives/keystore" } -sp-keyring = { path = "../../../substrate/primitives/keyring" } +hex-literal = { workspace = true, default-features = true } +frame-support-test = { workspace = true } +pallet-babe = { workspace = true, default-features = true } +pallet-treasury = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } -libsecp256k1 = "0.7.0" -polkadot-primitives-test-helpers = { path = "../../primitives/test-helpers" } +libsecp256k1 = { workspace = true, default-features = true } +polkadot-primitives-test-helpers = { workspace = true } [features] default = ["std"] @@ -111,7 +110,6 @@ std = [ "sp-runtime/std", "sp-session/std", "sp-staking/std", - "sp-std/std", "xcm-builder/std", "xcm-executor/std", "xcm/std", diff --git a/polkadot/runtime/common/slot_range_helper/Cargo.toml b/polkadot/runtime/common/slot_range_helper/Cargo.toml index 47e8fea240025c02c2e6efa81ebbe54f7e3da115..02810b75283f8babda0de26fc91e16b6ac493669 100644 --- a/polkadot/runtime/common/slot_range_helper/Cargo.toml +++ b/polkadot/runtime/common/slot_range_helper/Cargo.toml @@ -10,12 +10,11 @@ description = "Helper crate for generating slot ranges for the Polkadot runtime. workspace = true [dependencies] -paste = "1.0" -enumn = "0.1.12" -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -sp-std = { package = "sp-std", path = "../../../../substrate/primitives/std", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } +paste = { workspace = true, default-features = true } +enumn = { workspace = true } +codec = { features = ["derive"], workspace = true } +sp-runtime = { workspace = true } [features] default = ["std"] -std = ["codec/std", "sp-runtime/std", "sp-std/std"] +std = ["codec/std", "sp-runtime/std"] diff --git a/polkadot/runtime/common/slot_range_helper/src/lib.rs b/polkadot/runtime/common/slot_range_helper/src/lib.rs index f907390bc91b558d49f6aa29714fa5f90b1672ca..0dd893a284f3c657761d870f05dab40fa13b2d3d 100644 --- a/polkadot/runtime/common/slot_range_helper/src/lib.rs +++ b/polkadot/runtime/common/slot_range_helper/src/lib.rs @@ -19,10 +19,10 @@ #![cfg_attr(not(feature = "std"), no_std)] pub use codec::{Decode, Encode}; +pub use core::{ops::Add, result}; pub use enumn::N; pub use paste; pub use sp_runtime::traits::CheckedSub; -pub use sp_std::{ops::Add, result}; /// This macro generates a `SlotRange` enum of arbitrary length for use in the Slot Auction /// mechanism on Polkadot. diff --git a/polkadot/runtime/common/src/assigned_slots/migration.rs b/polkadot/runtime/common/src/assigned_slots/migration.rs index b52509bbdf498a7bc9b03be6b4432326d894211b..c13ee0c572dd6eab8c285da04caa76f7a5c8d38a 100644 --- a/polkadot/runtime/common/src/assigned_slots/migration.rs +++ b/polkadot/runtime/common/src/assigned_slots/migration.rs @@ -18,13 +18,13 @@ use super::{Config, MaxPermanentSlots, MaxTemporarySlots, Pallet, LOG_TARGET}; use frame_support::traits::{Get, GetStorageVersion, UncheckedOnRuntimeUpgrade}; #[cfg(feature = "try-runtime")] -use frame_support::ensure; +use alloc::vec::Vec; #[cfg(feature = "try-runtime")] -use sp_std::vec::Vec; +use frame_support::ensure; pub mod v1 { use super::*; - pub struct VersionUncheckedMigrateToV1(sp_std::marker::PhantomData); + pub struct VersionUncheckedMigrateToV1(core::marker::PhantomData); impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV1 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { diff --git a/polkadot/runtime/common/src/assigned_slots/mod.rs b/polkadot/runtime/common/src/assigned_slots/mod.rs index d0a531b8b6ca5ad995803edc8cbc45daa88176c2..dd39789e10cfdbb481615f728b6cd223ec64f037 100644 --- a/polkadot/runtime/common/src/assigned_slots/mod.rs +++ b/polkadot/runtime/common/src/assigned_slots/mod.rs @@ -30,6 +30,7 @@ use crate::{ slots::{self, Pallet as Slots, WeightInfo as SlotsWeightInfo}, traits::{LeaseError, Leaser, Registrar}, }; +use alloc::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{pallet_prelude::*, traits::Currency}; use frame_system::pallet_prelude::*; @@ -41,7 +42,6 @@ use polkadot_runtime_parachains::{ }; use scale_info::TypeInfo; use sp_runtime::traits::{One, Saturating, Zero}; -use sp_std::prelude::*; const LOG_TARGET: &str = "runtime::assigned_slots"; diff --git a/polkadot/runtime/common/src/auctions.rs b/polkadot/runtime/common/src/auctions.rs index 19d82ae85d0035aea89b5d07f0f042be237da42e..78f20d918bab52b11eccc076070f67a76b95e3de 100644 --- a/polkadot/runtime/common/src/auctions.rs +++ b/polkadot/runtime/common/src/auctions.rs @@ -22,7 +22,9 @@ use crate::{ slot_range::SlotRange, traits::{AuctionStatus, Auctioneer, LeaseError, Leaser, Registrar}, }; +use alloc::{vec, vec::Vec}; use codec::Decode; +use core::mem::swap; use frame_support::{ dispatch::DispatchResult, ensure, @@ -33,7 +35,6 @@ use frame_system::pallet_prelude::BlockNumberFor; pub use pallet::*; use polkadot_primitives::Id as ParaId; use sp_runtime::traits::{CheckedSub, One, Saturating, Zero}; -use sp_std::{mem::swap, prelude::*}; type CurrencyOf = <::Leaser as Leaser>>::Currency; type BalanceOf = <<::Leaser as Leaser>>::Currency as Currency< diff --git a/polkadot/runtime/common/src/claims.rs b/polkadot/runtime/common/src/claims.rs index c12af215a04d7119c1052a09a6eb6bee7ac0acb3..162bf01c38432f95ba25216478205c4046448c98 100644 --- a/polkadot/runtime/common/src/claims.rs +++ b/polkadot/runtime/common/src/claims.rs @@ -16,7 +16,11 @@ //! Pallet to process claims from Ethereum addresses. +#[cfg(not(feature = "std"))] +use alloc::{format, string::String}; +use alloc::{vec, vec::Vec}; use codec::{Decode, Encode}; +use core::fmt::Debug; use frame_support::{ ensure, traits::{Currency, Get, IsSubType, VestingSchedule}, @@ -35,9 +39,6 @@ use sp_runtime::{ }, RuntimeDebug, }; -#[cfg(not(feature = "std"))] -use sp_std::alloc::{format, string::String}; -use sp_std::{fmt::Debug, prelude::*}; type CurrencyOf = <::VestingSchedule as VestingSchedule< ::AccountId, @@ -150,8 +151,8 @@ impl PartialEq for EcdsaSignature { } } -impl sp_std::fmt::Debug for EcdsaSignature { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { +impl core::fmt::Debug for EcdsaSignature { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "EcdsaSignature({:?})", &self.0[..]) } } @@ -596,12 +597,12 @@ where ::RuntimeCall: IsSubType>, { #[cfg(feature = "std")] - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!(f, "PrevalidateAttests") } #[cfg(not(feature = "std"))] - fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result { Ok(()) } } @@ -612,7 +613,7 @@ where { /// Create new `SignedExtension` to check runtime version. pub fn new() -> Self { - Self(sp_std::marker::PhantomData) + Self(core::marker::PhantomData) } } diff --git a/polkadot/runtime/common/src/crowdloan/migration.rs b/polkadot/runtime/common/src/crowdloan/migration.rs index 3afd6b3fbc94b5b30bad162cfcf8236a029b77da..0ee3872a366ea1baf90e44f61f6ac1662b022dfd 100644 --- a/polkadot/runtime/common/src/crowdloan/migration.rs +++ b/polkadot/runtime/common/src/crowdloan/migration.rs @@ -21,7 +21,7 @@ use frame_support::{ Twox64Concat, }; -pub struct MigrateToTrackInactiveV2(sp_std::marker::PhantomData); +pub struct MigrateToTrackInactiveV2(core::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToTrackInactiveV2 { fn on_runtime_upgrade() -> Weight { let on_chain_version = Pallet::::on_chain_storage_version(); diff --git a/polkadot/runtime/common/src/crowdloan/mod.rs b/polkadot/runtime/common/src/crowdloan/mod.rs index 61d406aa681268d8ef0c66567faf7b74555a287d..8cf288197e3dd56085f96c928ae6a5b7f79a2a86 100644 --- a/polkadot/runtime/common/src/crowdloan/mod.rs +++ b/polkadot/runtime/common/src/crowdloan/mod.rs @@ -55,6 +55,7 @@ use crate::{ slot_range::SlotRange, traits::{Auctioneer, Registrar}, }; +use alloc::{vec, vec::Vec}; use codec::{Decode, Encode}; use frame_support::{ ensure, @@ -77,7 +78,6 @@ use sp_runtime::{ }, MultiSignature, MultiSigner, RuntimeDebug, }; -use sp_std::vec::Vec; type CurrencyOf = <::Auctioneer as Auctioneer>>::Currency; type LeasePeriodOf = <::Auctioneer as Auctioneer>>::LeasePeriod; @@ -832,16 +832,16 @@ impl Pallet { impl crate::traits::OnSwap for Pallet { fn on_swap(one: ParaId, other: ParaId) { - Funds::::mutate(one, |x| Funds::::mutate(other, |y| sp_std::mem::swap(x, y))) + Funds::::mutate(one, |x| Funds::::mutate(other, |y| core::mem::swap(x, y))) } } #[cfg(any(feature = "runtime-benchmarks", test))] mod crypto { + use alloc::vec::Vec; use sp_core::ed25519; use sp_io::crypto::{ed25519_generate, ed25519_sign}; use sp_runtime::{MultiSignature, MultiSigner}; - use sp_std::vec::Vec; pub fn create_ed25519_pubkey(seed: Vec) -> MultiSigner { ed25519_generate(0.into(), Some(seed)).into() @@ -1968,7 +1968,6 @@ mod benchmarking { use polkadot_runtime_parachains::paras; use sp_core::crypto::UncheckedFrom; use sp_runtime::traits::{Bounded, CheckedSub}; - use sp_std::prelude::*; use frame_benchmarking::{account, benchmarks, whitelisted_caller}; diff --git a/polkadot/runtime/common/src/identity_migrator.rs b/polkadot/runtime/common/src/identity_migrator.rs index 7d02e24b5368126d22a8f75e1075a75c50fb7e87..126c886280e6ed713d81c93f5afedbb69b03a1b5 100644 --- a/polkadot/runtime/common/src/identity_migrator.rs +++ b/polkadot/runtime/common/src/identity_migrator.rs @@ -172,6 +172,7 @@ impl OnReapIdentity for () { #[benchmarks] mod benchmarks { use super::*; + use alloc::{boxed::Box, vec, vec::Vec}; use codec::Encode; use frame_support::traits::EnsureOrigin; use frame_system::RawOrigin; @@ -180,7 +181,6 @@ mod benchmarks { traits::{Bounded, Hash, StaticLookup}, Saturating, }; - use sp_std::{boxed::Box, vec::Vec, *}; const SEED: u32 = 0; diff --git a/polkadot/runtime/common/src/impls.rs b/polkadot/runtime/common/src/impls.rs index 72ece79f19401aa616c79df41edcc58cd44c41fa..b6a93cf53685418fb2ffcda417a6ea16af5cafdc 100644 --- a/polkadot/runtime/common/src/impls.rs +++ b/polkadot/runtime/common/src/impls.rs @@ -28,7 +28,7 @@ use sp_runtime::{traits::TryConvert, Perquintill, RuntimeDebug}; use xcm::VersionedLocation; /// Logic for the author to get a portion of fees. -pub struct ToAuthor(sp_std::marker::PhantomData); +pub struct ToAuthor(core::marker::PhantomData); impl OnUnbalanced>> for ToAuthor where R: pallet_balances::Config + pallet_authorship::Config, @@ -44,14 +44,14 @@ where } } -pub struct DealWithFees(sp_std::marker::PhantomData); +pub struct DealWithFees(core::marker::PhantomData); impl OnUnbalanced>> for DealWithFees where R: pallet_balances::Config + pallet_authorship::Config + pallet_treasury::Config, ::AccountId: From, ::AccountId: Into, { - fn on_unbalanceds( + fn on_unbalanceds( mut fees_then_tips: impl Iterator>>, ) { if let Some(fees) = fees_then_tips.next() { @@ -67,29 +67,51 @@ where } } -pub fn era_payout( - total_staked: Balance, - total_stakable: Balance, - max_annual_inflation: Perquintill, - period_fraction: Perquintill, - auctioned_slots: u64, -) -> (Balance, Balance) { - use pallet_staking_reward_fn::compute_inflation; +/// Parameters passed into [`relay_era_payout`] function. +pub struct EraPayoutParams { + /// Total staked amount. + pub total_staked: Balance, + /// Total stakable amount. + /// + /// Usually, this is equal to the total issuance, except if a large part of the issuance is + /// locked in another sub-system. + pub total_stakable: Balance, + /// Ideal stake ratio, which is deducted by `legacy_auction_proportion` if not `None`. + pub ideal_stake: Perquintill, + /// Maximum inflation rate. + pub max_annual_inflation: Perquintill, + /// Minimum inflation rate. + pub min_annual_inflation: Perquintill, + /// Falloff used to calculate era payouts. + pub falloff: Perquintill, + /// Fraction of the era period used to calculate era payouts. + pub period_fraction: Perquintill, + /// Legacy auction proportion, which substracts from `ideal_stake` if not `None`. + pub legacy_auction_proportion: Option, +} + +/// A specialized function to compute the inflation of the staking system, tailored for polkadot +/// relay chains, such as Polkadot, Kusama and Westend. +pub fn relay_era_payout(params: EraPayoutParams) -> (Balance, Balance) { use sp_runtime::traits::Saturating; - let min_annual_inflation = Perquintill::from_rational(25u64, 1000u64); - let delta_annual_inflation = max_annual_inflation.saturating_sub(min_annual_inflation); + let EraPayoutParams { + total_staked, + total_stakable, + ideal_stake, + max_annual_inflation, + min_annual_inflation, + falloff, + period_fraction, + legacy_auction_proportion, + } = params; - // 30% reserved for up to 60 slots. - let auction_proportion = Perquintill::from_rational(auctioned_slots.min(60), 200u64); + let delta_annual_inflation = max_annual_inflation.saturating_sub(min_annual_inflation); - // Therefore the ideal amount at stake (as a percentage of total issuance) is 75% less the - // amount that we expect to be taken up with auctions. - let ideal_stake = Perquintill::from_percent(75).saturating_sub(auction_proportion); + let ideal_stake = ideal_stake.saturating_sub(legacy_auction_proportion.unwrap_or_default()); let stake = Perquintill::from_rational(total_staked, total_stakable); - let falloff = Perquintill::from_percent(5); - let adjustment = compute_inflation(stake, ideal_stake, falloff); + let adjustment = pallet_staking_reward_fn::compute_inflation(stake, ideal_stake, falloff); let staking_inflation = min_annual_inflation.saturating_add(delta_annual_inflation * adjustment); @@ -328,10 +350,8 @@ mod tests { impl pallet_treasury::Config for Test { type Currency = pallet_balances::Pallet; - type ApproveOrigin = frame_system::EnsureRoot; type RejectOrigin = frame_system::EnsureRoot; type RuntimeEvent = RuntimeEvent; - type OnSlash = (); type SpendPeriod = (); type Burn = (); type BurnDestination = (); @@ -373,6 +393,46 @@ mod tests { t.into() } + pub fn deprecated_era_payout( + total_staked: Balance, + total_stakable: Balance, + max_annual_inflation: Perquintill, + period_fraction: Perquintill, + auctioned_slots: u64, + ) -> (Balance, Balance) { + use pallet_staking_reward_fn::compute_inflation; + use sp_runtime::traits::Saturating; + + let min_annual_inflation = Perquintill::from_rational(25u64, 1000u64); + let delta_annual_inflation = max_annual_inflation.saturating_sub(min_annual_inflation); + + // 30% reserved for up to 60 slots. + let auction_proportion = Perquintill::from_rational(auctioned_slots.min(60), 200u64); + + // Therefore the ideal amount at stake (as a percentage of total issuance) is 75% less the + // amount that we expect to be taken up with auctions. + let ideal_stake = Perquintill::from_percent(75).saturating_sub(auction_proportion); + + let stake = Perquintill::from_rational(total_staked, total_stakable); + let falloff = Perquintill::from_percent(5); + let adjustment = compute_inflation(stake, ideal_stake, falloff); + let staking_inflation = + min_annual_inflation.saturating_add(delta_annual_inflation * adjustment); + + let max_payout = period_fraction * max_annual_inflation * total_stakable; + let staking_payout = (period_fraction * staking_inflation) * total_stakable; + let rest = max_payout.saturating_sub(staking_payout); + + let other_issuance = total_stakable.saturating_sub(total_staked); + if total_staked > other_issuance { + let _cap_rest = + Perquintill::from_rational(other_issuance, total_staked) * staking_payout; + // We don't do anything with this, but if we wanted to, we could introduce a cap on the + // treasury amount with: `rest = rest.min(cap_rest);` + } + (staking_payout, rest) + } + #[test] fn test_fees_and_tip_split() { new_test_ext().execute_with(|| { @@ -427,13 +487,99 @@ mod tests { #[test] fn era_payout_should_give_sensible_results() { - assert_eq!( - era_payout(75, 100, Perquintill::from_percent(10), Perquintill::one(), 0,), - (10, 0) + let payout = + deprecated_era_payout(75, 100, Perquintill::from_percent(10), Perquintill::one(), 0); + assert_eq!(payout, (10, 0)); + + let payout = + deprecated_era_payout(80, 100, Perquintill::from_percent(10), Perquintill::one(), 0); + assert_eq!(payout, (6, 4)); + } + + #[test] + fn relay_era_payout_should_give_sensible_results() { + let params = EraPayoutParams { + total_staked: 75, + total_stakable: 100, + ideal_stake: Perquintill::from_percent(75), + max_annual_inflation: Perquintill::from_percent(10), + min_annual_inflation: Perquintill::from_rational(25u64, 1000u64), + falloff: Perquintill::from_percent(5), + period_fraction: Perquintill::one(), + legacy_auction_proportion: None, + }; + assert_eq!(relay_era_payout(params), (10, 0)); + + let params = EraPayoutParams { + total_staked: 80, + total_stakable: 100, + ideal_stake: Perquintill::from_percent(75), + max_annual_inflation: Perquintill::from_percent(10), + min_annual_inflation: Perquintill::from_rational(25u64, 1000u64), + falloff: Perquintill::from_percent(5), + period_fraction: Perquintill::one(), + legacy_auction_proportion: None, + }; + assert_eq!(relay_era_payout(params), (6, 4)); + } + + #[test] + fn relay_era_payout_should_give_same_results_as_era_payout() { + let total_staked = 1_000_000; + let total_stakable = 2_000_000; + let max_annual_inflation = Perquintill::from_percent(10); + let period_fraction = Perquintill::from_percent(25); + let auctioned_slots = 30; + + let params = EraPayoutParams { + total_staked, + total_stakable, + ideal_stake: Perquintill::from_percent(75), + max_annual_inflation, + min_annual_inflation: Perquintill::from_rational(25u64, 1000u64), + falloff: Perquintill::from_percent(5), + period_fraction, + legacy_auction_proportion: Some(Perquintill::from_rational( + auctioned_slots.min(60), + 200u64, + )), + }; + + let payout = deprecated_era_payout( + total_staked, + total_stakable, + max_annual_inflation, + period_fraction, + auctioned_slots, ); - assert_eq!( - era_payout(80, 100, Perquintill::from_percent(10), Perquintill::one(), 0,), - (6, 4) + assert_eq!(relay_era_payout(params), payout); + + let total_staked = 1_900_000; + let total_stakable = 2_000_000; + let auctioned_slots = 60; + + let params = EraPayoutParams { + total_staked, + total_stakable, + ideal_stake: Perquintill::from_percent(75), + max_annual_inflation, + min_annual_inflation: Perquintill::from_rational(25u64, 1000u64), + falloff: Perquintill::from_percent(5), + period_fraction, + legacy_auction_proportion: Some(Perquintill::from_rational( + auctioned_slots.min(60), + 200u64, + )), + }; + + let payout = deprecated_era_payout( + total_staked, + total_stakable, + max_annual_inflation, + period_fraction, + auctioned_slots, ); + + assert_eq!(relay_era_payout(params), payout); } } diff --git a/polkadot/runtime/common/src/integration_tests.rs b/polkadot/runtime/common/src/integration_tests.rs index 052fb0389db40c086d2c13b3d30501e093ef5f90..7a689a517eaa2ab97cd827890a0ffeb60bb59bb6 100644 --- a/polkadot/runtime/common/src/integration_tests.rs +++ b/polkadot/runtime/common/src/integration_tests.rs @@ -24,6 +24,7 @@ use crate::{ slots, traits::{AuctionStatus, Auctioneer, Leaser, Registrar as RegistrarT}, }; +use alloc::sync::Arc; use codec::Encode; use frame_support::{ assert_noop, assert_ok, derive_impl, parameter_types, @@ -50,7 +51,6 @@ use sp_runtime::{ transaction_validity::TransactionPriority, AccountId32, BuildStorage, MultiSignature, }; -use sp_std::sync::Arc; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlockU32; diff --git a/polkadot/runtime/common/src/lib.rs b/polkadot/runtime/common/src/lib.rs index 6e50384f68c9cf5972717a1cc60ad901b5f37dab..41e1cdbab8011bc1cb502c5d87f0214bddfc445a 100644 --- a/polkadot/runtime/common/src/lib.rs +++ b/polkadot/runtime/common/src/lib.rs @@ -41,6 +41,8 @@ mod integration_tests; #[cfg(test)] mod mock; +extern crate alloc; + use frame_support::{ parameter_types, traits::{ConstU32, Currency, OneSessionHandler}, @@ -169,7 +171,7 @@ static_assertions::assert_eq_size!(polkadot_primitives::Balance, u128); /// A placeholder since there is currently no provided session key handler for parachain validator /// keys. -pub struct ParachainSessionKeyPlaceholder(sp_std::marker::PhantomData); +pub struct ParachainSessionKeyPlaceholder(core::marker::PhantomData); impl sp_runtime::BoundToRuntimeAppPublic for ParachainSessionKeyPlaceholder { type Public = ValidatorId; } @@ -198,7 +200,7 @@ impl OneSessionHandler /// A placeholder since there is currently no provided session key handler for parachain validator /// keys. -pub struct AssignmentSessionKeyPlaceholder(sp_std::marker::PhantomData); +pub struct AssignmentSessionKeyPlaceholder(core::marker::PhantomData); impl sp_runtime::BoundToRuntimeAppPublic for AssignmentSessionKeyPlaceholder { type Public = AssignmentId; } diff --git a/polkadot/runtime/common/src/mock.rs b/polkadot/runtime/common/src/mock.rs index 6534110cc21043510e5944d1407d28f9d219c067..54170b07fa62c63c226ee5bac8c095b5e479307f 100644 --- a/polkadot/runtime/common/src/mock.rs +++ b/polkadot/runtime/common/src/mock.rs @@ -37,7 +37,7 @@ thread_local! { static MANAGERS: RefCell>> = RefCell::new(HashMap::new()); } -pub struct TestRegistrar(sp_std::marker::PhantomData); +pub struct TestRegistrar(core::marker::PhantomData); impl Registrar for TestRegistrar { type AccountId = T::AccountId; diff --git a/polkadot/runtime/common/src/paras_registrar/migration.rs b/polkadot/runtime/common/src/paras_registrar/migration.rs index 18bb6bbfb559a23e44109230ad7fd87d0b2682ca..6b110d2ff5d5e03ba74bbd79fa835679d46d33a3 100644 --- a/polkadot/runtime/common/src/paras_registrar/migration.rs +++ b/polkadot/runtime/common/src/paras_registrar/migration.rs @@ -25,7 +25,7 @@ pub struct ParaInfoV1 { } pub struct VersionUncheckedMigrateToV1( - sp_std::marker::PhantomData<(T, UnlockParaIds)>, + core::marker::PhantomData<(T, UnlockParaIds)>, ); impl> UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV1 diff --git a/polkadot/runtime/common/src/paras_registrar/mod.rs b/polkadot/runtime/common/src/paras_registrar/mod.rs index 6b9191f7c6f2db0f9e98b0a67ead596d4c3a9822..07f02e92656120267272967d1d86ee3d9181da92 100644 --- a/polkadot/runtime/common/src/paras_registrar/mod.rs +++ b/polkadot/runtime/common/src/paras_registrar/mod.rs @@ -19,6 +19,8 @@ pub mod migration; +use alloc::{vec, vec::Vec}; +use core::result; use frame_support::{ dispatch::DispatchResult, ensure, @@ -34,7 +36,6 @@ use polkadot_runtime_parachains::{ paras::{self, ParaGenesisArgs, UpgradeStrategy}, Origin, ParaLifecycle, }; -use sp_std::{prelude::*, result}; use crate::traits::{OnSwap, Registrar}; use codec::{Decode, Encode}; @@ -210,7 +211,7 @@ pub mod pallet { #[pallet::genesis_config] pub struct GenesisConfig { #[serde(skip)] - pub _config: sp_std::marker::PhantomData, + pub _config: core::marker::PhantomData, pub next_free_para_id: ParaId, } @@ -717,10 +718,9 @@ mod tests { use crate::{ mock::conclude_pvf_checking, paras_registrar, traits::Registrar as RegistrarTrait, }; + use alloc::collections::btree_map::BTreeMap; use frame_support::{ - assert_noop, assert_ok, derive_impl, - error::BadOrigin, - parameter_types, + assert_noop, assert_ok, derive_impl, parameter_types, traits::{OnFinalize, OnInitialize}, }; use frame_system::limits; @@ -731,11 +731,10 @@ mod tests { use sp_io::TestExternalities; use sp_keyring::Sr25519Keyring; use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, + traits::{BadOrigin, BlakeTwo256, IdentityLookup}, transaction_validity::TransactionPriority, BuildStorage, Perbill, }; - use sp_std::collections::btree_map::BTreeMap; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlockU32; diff --git a/polkadot/runtime/common/src/paras_sudo_wrapper.rs b/polkadot/runtime/common/src/paras_sudo_wrapper.rs index 3ff8d4ac08e15d88be618d79e21f2c5d97627982..af93c70b4783f717a2adddd0f0f34365ae27d954 100644 --- a/polkadot/runtime/common/src/paras_sudo_wrapper.rs +++ b/polkadot/runtime/common/src/paras_sudo_wrapper.rs @@ -16,6 +16,7 @@ //! A simple wrapper allowing `Sudo` to call into `paras` routines. +use alloc::boxed::Box; use codec::Encode; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; @@ -26,7 +27,6 @@ use polkadot_runtime_parachains::{ paras::{self, AssignCoretime, ParaGenesisArgs}, ParaLifecycle, }; -use sp_std::boxed::Box; #[frame_support::pallet] pub mod pallet { diff --git a/polkadot/runtime/common/src/purchase.rs b/polkadot/runtime/common/src/purchase.rs index eb480e4efe1f82f657daaa03cd33d883a01d9f7d..d650548b8ac39a4059a7a9721e5926ae5ab528a9 100644 --- a/polkadot/runtime/common/src/purchase.rs +++ b/polkadot/runtime/common/src/purchase.rs @@ -16,6 +16,7 @@ //! Pallet to process purchase of DOTs. +use alloc::vec::Vec; use codec::{Decode, Encode}; use frame_support::{ pallet_prelude::*, @@ -29,7 +30,6 @@ use sp_runtime::{ traits::{CheckedAdd, Saturating, Verify, Zero}, AnySignature, DispatchError, DispatchResult, Permill, RuntimeDebug, }; -use sp_std::prelude::*; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; diff --git a/polkadot/runtime/common/src/slots/mod.rs b/polkadot/runtime/common/src/slots/mod.rs index 747b7b5ca634ed0563061aea2d169624a2ed87ac..333f14c6608acb1d62df7fadbfe297741a39d6cd 100644 --- a/polkadot/runtime/common/src/slots/mod.rs +++ b/polkadot/runtime/common/src/slots/mod.rs @@ -25,6 +25,7 @@ pub mod migration; use crate::traits::{LeaseError, Leaser, Registrar}; +use alloc::{vec, vec::Vec}; use frame_support::{ pallet_prelude::*, traits::{Currency, ReservableCurrency}, @@ -34,7 +35,6 @@ use frame_system::pallet_prelude::*; pub use pallet::*; use polkadot_primitives::Id as ParaId; use sp_runtime::traits::{CheckedConversion, CheckedSub, Saturating, Zero}; -use sp_std::prelude::*; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -309,7 +309,7 @@ impl Pallet { // Useful when trying to clean up a parachain leases, as this would tell // you all the balances you need to unreserve. fn all_deposits_held(para: ParaId) -> Vec<(T::AccountId, BalanceOf)> { - let mut tracker = sp_std::collections::btree_map::BTreeMap::new(); + let mut tracker = alloc::collections::btree_map::BTreeMap::new(); Leases::::get(para).into_iter().for_each(|lease| match lease { Some((who, amount)) => match tracker.get(&who) { Some(prev_amount) => @@ -329,7 +329,7 @@ impl Pallet { impl crate::traits::OnSwap for Pallet { fn on_swap(one: ParaId, other: ParaId) { - Leases::::mutate(one, |x| Leases::::mutate(other, |y| sp_std::mem::swap(x, y))) + Leases::::mutate(one, |x| Leases::::mutate(other, |y| core::mem::swap(x, y))) } } diff --git a/polkadot/runtime/common/src/traits.rs b/polkadot/runtime/common/src/traits.rs index 2ed1fb8af9beacda31b0134ebc72c95b24c2d8cd..6e49abcee98b2778cbe2cce201d5daadf15d80f0 100644 --- a/polkadot/runtime/common/src/traits.rs +++ b/polkadot/runtime/common/src/traits.rs @@ -16,12 +16,12 @@ //! Traits used across pallets for Polkadot. +use alloc::vec::*; use frame_support::{ dispatch::DispatchResult, traits::{Currency, ReservableCurrency}, }; use polkadot_primitives::{HeadData, Id as ParaId, ValidationCode}; -use sp_std::vec::*; /// Parachain registration API. pub trait Registrar { @@ -56,7 +56,7 @@ pub trait Registrar { /// Remove any lock on the para registration. fn remove_lock(id: ParaId); - /// Register a Para ID under control of `who`. Registration may be be + /// Register a Para ID under control of `who`. Registration may be /// delayed by session rotation. fn register( who: Self::AccountId, diff --git a/polkadot/runtime/common/src/try_runtime.rs b/polkadot/runtime/common/src/try_runtime.rs index 81aa34317bfd7a7f82340bc4a8c10760049fd690..b22e1703292067c56160260aa2494d4958e0c589 100644 --- a/polkadot/runtime/common/src/try_runtime.rs +++ b/polkadot/runtime/common/src/try_runtime.rs @@ -16,13 +16,13 @@ //! Common try-runtime only tests for runtimes. +use alloc::{collections::btree_set::BTreeSet, vec::Vec}; use frame_support::{ dispatch::RawOrigin, traits::{Get, Hooks}, }; use pallet_fast_unstake::{Pallet as FastUnstake, *}; use pallet_staking::*; -use sp_std::{collections::btree_set::BTreeSet, prelude::*}; /// register all inactive nominators for fast-unstake, and progress until they have all been /// processed. diff --git a/polkadot/runtime/common/src/xcm_sender.rs b/polkadot/runtime/common/src/xcm_sender.rs index 5858a0ac3ca76e32729efa30b244f3bfadaa2bdf..dace785a535b914b6da3ca322ea11cfe94f5dbfd 100644 --- a/polkadot/runtime/common/src/xcm_sender.rs +++ b/polkadot/runtime/common/src/xcm_sender.rs @@ -16,7 +16,9 @@ //! XCM sender for relay chain. +use alloc::vec::Vec; use codec::{Decode, Encode}; +use core::marker::PhantomData; use frame_support::traits::Get; use frame_system::pallet_prelude::BlockNumberFor; use polkadot_primitives::Id as ParaId; @@ -25,7 +27,6 @@ use polkadot_runtime_parachains::{ dmp, FeeTracker, }; use sp_runtime::FixedPointNumber; -use sp_std::{marker::PhantomData, prelude::*}; use xcm::prelude::*; use xcm_builder::InspectMessageQueues; use SendError::*; @@ -56,7 +57,7 @@ impl PriceForMessageDelivery for NoPriceForMessageDelivery { } /// Implementation of [`PriceForMessageDelivery`] which returns a fixed price. -pub struct ConstantPrice(sp_std::marker::PhantomData); +pub struct ConstantPrice(core::marker::PhantomData); impl> PriceForMessageDelivery for ConstantPrice { type Id = (); @@ -79,7 +80,7 @@ impl> PriceForMessageDelivery for ConstantPrice { /// - `B`: The base fee to pay for message delivery. /// - `M`: The fee to pay for each and every byte of the message after encoding it. /// - `F`: A fee factor multiplier. It can be understood as the exponent term in the formula. -pub struct ExponentialPrice(sp_std::marker::PhantomData<(A, B, M, F)>); +pub struct ExponentialPrice(core::marker::PhantomData<(A, B, M, F)>); impl, B: Get, M: Get, F: FeeTracker> PriceForMessageDelivery for ExponentialPrice { @@ -169,7 +170,7 @@ pub struct ToParachainDeliveryHelper< ParaId, ToParaIdHelper, >( - sp_std::marker::PhantomData<( + core::marker::PhantomData<( XcmConfig, ExistentialDeposit, PriceForDelivery, @@ -223,7 +224,7 @@ impl< } // overestimate delivery fee - let overestimated_xcm = vec![ClearOrigin; 128].into(); + let overestimated_xcm = alloc::vec![ClearOrigin; 128].into(); let overestimated_fees = PriceForDelivery::price_for_delivery(Parachain::get(), &overestimated_xcm); @@ -258,6 +259,7 @@ impl EnsureForParachain for () { mod tests { use super::*; use crate::integration_tests::new_test_ext; + use alloc::vec; use frame_support::{assert_ok, parameter_types}; use polkadot_runtime_parachains::FeeTracker; use sp_runtime::FixedU128; diff --git a/polkadot/runtime/metrics/Cargo.toml b/polkadot/runtime/metrics/Cargo.toml index 342c5a885033884f025c34cadca03f37e1a7297e..3709e1eb697ea1a5941b307a4a8abd06238d3b57 100644 --- a/polkadot/runtime/metrics/Cargo.toml +++ b/polkadot/runtime/metrics/Cargo.toml @@ -10,13 +10,12 @@ description = "Runtime metric interface for the Polkadot node" workspace = true [dependencies] -sp-std = { package = "sp-std", path = "../../../substrate/primitives/std", default-features = false } -sp-tracing = { path = "../../../substrate/primitives/tracing", default-features = false } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -polkadot-primitives = { path = "../../primitives", default-features = false } -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } +sp-tracing = { workspace = true } +codec = { workspace = true } +polkadot-primitives = { workspace = true } +frame-benchmarking = { optional = true, workspace = true } -bs58 = { version = "0.5.0", default-features = false, features = ["alloc"] } +bs58 = { features = ["alloc"], workspace = true } [features] default = ["std"] @@ -25,7 +24,6 @@ std = [ "codec/std", "frame-benchmarking?/std", "polkadot-primitives/std", - "sp-std/std", "sp-tracing/std", ] runtime-metrics = ["frame-benchmarking", "sp-tracing/with-tracing"] diff --git a/polkadot/runtime/metrics/src/lib.rs b/polkadot/runtime/metrics/src/lib.rs index 6164d71f112a47bce0a91da044aa8d9166c8a8b7..479ec7a69c3aaf8a94b9da2a84f2c04f4fea7165 100644 --- a/polkadot/runtime/metrics/src/lib.rs +++ b/polkadot/runtime/metrics/src/lib.rs @@ -22,6 +22,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + #[cfg(feature = "runtime-metrics")] mod with_runtime_metrics; #[cfg(feature = "runtime-metrics")] diff --git a/polkadot/runtime/metrics/src/with_runtime_metrics.rs b/polkadot/runtime/metrics/src/with_runtime_metrics.rs index 1339df9ff6879e6624823fe49cac55eb2854252a..979d5eda9afc645c1b343959a3bf65dc7f3e295c 100644 --- a/polkadot/runtime/metrics/src/with_runtime_metrics.rs +++ b/polkadot/runtime/metrics/src/with_runtime_metrics.rs @@ -22,14 +22,13 @@ const TRACING_TARGET: &'static str = "metrics"; +use alloc::vec::Vec; use codec::Encode; use polkadot_primitives::{ metric_definitions::{CounterDefinition, CounterVecDefinition, HistogramDefinition}, RuntimeMetricLabelValues, RuntimeMetricOp, RuntimeMetricUpdate, }; -use sp_std::prelude::*; - /// Holds a set of counters that have different values for their labels, /// like Prometheus `CounterVec`. pub struct CounterVec { diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 250fee65beefe7af6e9762b8ebcca8020b6a556a..cfe373e8cba2e6c186ea62d7121aff5f3d4cafa7 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -10,66 +10,66 @@ license.workspace = true workspace = true [dependencies] -impl-trait-for-tuples = "0.2.2" -bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } +impl-trait-for-tuples = { workspace = true } +bitvec = { features = ["alloc"], workspace = true } +codec = { features = ["derive", "max-encoded-len"], workspace = true } log = { workspace = true } -rustc-hex = { version = "2.1.0", default-features = false } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } serde = { features = ["alloc", "derive"], workspace = true } -derive_more = "0.99.17" -bitflags = "1.3.2" +derive_more = { workspace = true, default-features = true } +bitflags = { workspace = true } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false } -sp-std = { package = "sp-std", path = "../../../substrate/primitives/std", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false, features = ["serde"] } -sp-session = { path = "../../../substrate/primitives/session", default-features = false } -sp-staking = { path = "../../../substrate/primitives/staking", default-features = false, features = ["serde"] } -sp-core = { path = "../../../substrate/primitives/core", default-features = false, features = ["serde"] } -sp-keystore = { path = "../../../substrate/primitives/keystore", optional = true, default-features = false } -sp-application-crypto = { path = "../../../substrate/primitives/application-crypto", default-features = false, optional = true } -sp-tracing = { path = "../../../substrate/primitives/tracing", default-features = false, optional = true } -sp-arithmetic = { path = "../../../substrate/primitives/arithmetic", default-features = false } +sp-api = { workspace = true } +sp-inherents = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { features = ["serde"], workspace = true } +sp-session = { workspace = true } +sp-staking = { features = ["serde"], workspace = true } +sp-core = { features = ["serde"], workspace = true } +sp-keystore = { optional = true, workspace = true } +sp-application-crypto = { optional = true, workspace = true } +sp-tracing = { optional = true, workspace = true } +sp-arithmetic = { workspace = true } +sp-std = { workspace = true, optional = true } -pallet-authority-discovery = { path = "../../../substrate/frame/authority-discovery", default-features = false } -pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } -pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } -pallet-babe = { path = "../../../substrate/frame/babe", default-features = false } -pallet-broker = { path = "../../../substrate/frame/broker", default-features = false } -pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } -pallet-session = { path = "../../../substrate/frame/session", default-features = false } -pallet-staking = { path = "../../../substrate/frame/staking", default-features = false } -pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false } -pallet-vesting = { path = "../../../substrate/frame/vesting", default-features = false } -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } +pallet-authority-discovery = { workspace = true } +pallet-authorship = { workspace = true } +pallet-balances = { workspace = true } +pallet-babe = { workspace = true } +pallet-broker = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-mmr = { workspace = true, optional = true } +pallet-session = { workspace = true } +pallet-staking = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-vesting = { workspace = true } +frame-benchmarking = { optional = true, workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } -xcm = { package = "staging-xcm", path = "../../xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../xcm/xcm-executor", default-features = false } -polkadot-primitives = { path = "../../primitives", default-features = false } +xcm = { workspace = true } +xcm-executor = { workspace = true } +polkadot-primitives = { workspace = true } -rand = { version = "0.8.5", default-features = false } -rand_chacha = { version = "0.3.1", default-features = false } -static_assertions = { version = "1.1.0", optional = true } -polkadot-parachain-primitives = { path = "../../parachain", default-features = false } -polkadot-runtime-metrics = { path = "../metrics", default-features = false } -polkadot-core-primitives = { path = "../../core-primitives", default-features = false } +rand = { workspace = true } +rand_chacha = { workspace = true } +static_assertions = { optional = true, workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true } +polkadot-runtime-metrics = { workspace = true } +polkadot-core-primitives = { workspace = true } [dev-dependencies] -futures = "0.3.30" -hex-literal = "0.4.1" -sp-keyring = { path = "../../../substrate/primitives/keyring" } -frame-support-test = { path = "../../../substrate/frame/support/test" } -sc-keystore = { path = "../../../substrate/client/keystore" } -polkadot-primitives-test-helpers = { path = "../../primitives/test-helpers" } -sp-tracing = { path = "../../../substrate/primitives/tracing" } -sp-crypto-hashing = { path = "../../../substrate/primitives/crypto/hashing" } -thousands = "0.2.0" -assert_matches = "1" -rstest = "0.18.2" +futures = { workspace = true } +hex-literal = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +frame-support-test = { workspace = true } +sc-keystore = { workspace = true, default-features = true } +polkadot-primitives-test-helpers = { workspace = true } +sp-tracing = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true, default-features = true } +thousands = { workspace = true } +assert_matches = { workspace = true } +rstest = { workspace = true } serde_json = { workspace = true, default-features = true } [features] @@ -88,6 +88,7 @@ std = [ "pallet-balances/std", "pallet-broker/std", "pallet-message-queue/std", + "pallet-mmr?/std", "pallet-session/std", "pallet-staking/std", "pallet-timestamp/std", @@ -98,7 +99,6 @@ std = [ "polkadot-runtime-metrics/std", "rand/std", "rand_chacha/std", - "rustc-hex/std", "scale-info/std", "serde/std", "sp-api/std", @@ -112,7 +112,7 @@ std = [ "sp-runtime/std", "sp-session/std", "sp-staking/std", - "sp-std/std", + "sp-std?/std", "xcm-executor/std", "xcm/std", ] @@ -124,6 +124,7 @@ runtime-benchmarks = [ "pallet-balances/runtime-benchmarks", "pallet-broker/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", + "pallet-mmr/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", @@ -132,6 +133,7 @@ runtime-benchmarks = [ "sp-application-crypto", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", + "sp-std", "static_assertions", "xcm-executor/runtime-benchmarks", ] @@ -145,6 +147,7 @@ try-runtime = [ "pallet-balances/try-runtime", "pallet-broker/try-runtime", "pallet-message-queue/try-runtime", + "pallet-mmr/try-runtime", "pallet-session/try-runtime", "pallet-staking/try-runtime", "pallet-timestamp/try-runtime", diff --git a/polkadot/runtime/parachains/src/assigner_coretime/mod.rs b/polkadot/runtime/parachains/src/assigner_coretime/mod.rs index e68ac2664b898b5594a19fa7a8626c2d3b257160..7ee76600b42c07bdbb011ddad1d238ec95b89bcf 100644 --- a/polkadot/runtime/parachains/src/assigner_coretime/mod.rs +++ b/polkadot/runtime/parachains/src/assigner_coretime/mod.rs @@ -28,20 +28,19 @@ mod mock_helpers; mod tests; use crate::{ - assigner_on_demand, configuration, + configuration, on_demand, paras::AssignCoretime, scheduler::common::{Assignment, AssignmentProvider}, ParaId, }; +use alloc::{vec, vec::Vec}; use frame_support::{defensive, pallet_prelude::*}; use frame_system::pallet_prelude::*; use pallet_broker::CoreAssignment; use polkadot_primitives::CoreIndex; use sp_runtime::traits::{One, Saturating}; -use sp_std::prelude::*; - pub use pallet::*; /// Fraction expressed as a nominator with an assumed denominator of 57,600. @@ -202,10 +201,7 @@ pub mod pallet { pub struct Pallet(_); #[pallet::config] - pub trait Config: - frame_system::Config + configuration::Config + assigner_on_demand::Config - { - } + pub trait Config: frame_system::Config + configuration::Config + on_demand::Config {} /// Scheduled assignment sets. /// @@ -282,8 +278,7 @@ impl AssignmentProvider> for Pallet { match a_type { CoreAssignment::Idle => None, - CoreAssignment::Pool => - assigner_on_demand::Pallet::::pop_assignment_for_core(core_idx), + CoreAssignment::Pool => on_demand::Pallet::::pop_assignment_for_core(core_idx), CoreAssignment::Task(para_id) => Some(Assignment::Bulk((*para_id).into())), } }) @@ -292,7 +287,7 @@ impl AssignmentProvider> for Pallet { fn report_processed(assignment: Assignment) { match assignment { Assignment::Pool { para_id, core_index } => - assigner_on_demand::Pallet::::report_processed(para_id, core_index), + on_demand::Pallet::::report_processed(para_id, core_index), Assignment::Bulk(_) => {}, } } @@ -305,7 +300,7 @@ impl AssignmentProvider> for Pallet { fn push_back_assignment(assignment: Assignment) { match assignment { Assignment::Pool { para_id, core_index } => - assigner_on_demand::Pallet::::push_back_assignment(para_id, core_index), + on_demand::Pallet::::push_back_assignment(para_id, core_index), Assignment::Bulk(_) => { // Session changes are rough. We just drop assignments that did not make it on a // session boundary. This seems sensible as bulk is region based. Meaning, even if diff --git a/polkadot/runtime/parachains/src/assigner_coretime/tests.rs b/polkadot/runtime/parachains/src/assigner_coretime/tests.rs index 81a0988ea67cd3eb3b76784d360d46a1ddf1633e..e7994b8ef820773b4f310b6285303263170a2638 100644 --- a/polkadot/runtime/parachains/src/assigner_coretime/tests.rs +++ b/polkadot/runtime/parachains/src/assigner_coretime/tests.rs @@ -20,16 +20,16 @@ use crate::{ assigner_coretime::{mock_helpers::GenesisConfigBuilder, pallet::Error, Schedule}, initializer::SessionChangeNotification, mock::{ - new_test_ext, Balances, CoretimeAssigner, OnDemandAssigner, Paras, ParasShared, - RuntimeOrigin, Scheduler, System, Test, + new_test_ext, Balances, CoretimeAssigner, OnDemand, Paras, ParasShared, RuntimeOrigin, + Scheduler, System, Test, }, paras::{ParaGenesisArgs, ParaKind}, scheduler::common::Assignment, }; +use alloc::collections::btree_map::BTreeMap; use frame_support::{assert_noop, assert_ok, pallet_prelude::*, traits::Currency}; use pallet_broker::TaskId; use polkadot_primitives::{BlockNumber, Id as ParaId, SessionIndex, ValidationCode}; -use sp_std::collections::btree_map::BTreeMap; fn schedule_blank_para(id: ParaId, parakind: ParaKind) { let validation_code: ValidationCode = vec![1, 2, 3].into(); @@ -74,6 +74,9 @@ fn run_to_block( Paras::initializer_initialize(b + 1); Scheduler::initializer_initialize(b + 1); + // Update the spot traffic and revenue on every block. + OnDemand::on_initialize(b + 1); + // In the real runtime this is expected to be called by the `InclusionInherent` pallet. Scheduler::free_cores_and_fill_claim_queue(BTreeMap::new(), b + 1); } @@ -524,11 +527,7 @@ fn pop_assignment_for_core_works() { schedule_blank_para(para_id, ParaKind::Parathread); Balances::make_free_balance_be(&alice, amt); run_to_block(1, |n| if n == 1 { Some(Default::default()) } else { None }); - assert_ok!(OnDemandAssigner::place_order_allow_death( - RuntimeOrigin::signed(alice), - amt, - para_id - )); + assert_ok!(OnDemand::place_order_allow_death(RuntimeOrigin::signed(alice), amt, para_id)); // Case 1: Assignment idle assert_ok!(CoretimeAssigner::assign_core( diff --git a/polkadot/runtime/parachains/src/assigner_parachains/tests.rs b/polkadot/runtime/parachains/src/assigner_parachains/tests.rs index 14cb1a8978602b6273243ec463dfa36eb7b7c80c..817e43a7138ddbe121e84ea6c02497e07b323469 100644 --- a/polkadot/runtime/parachains/src/assigner_parachains/tests.rs +++ b/polkadot/runtime/parachains/src/assigner_parachains/tests.rs @@ -23,9 +23,9 @@ use crate::{ }, paras::{ParaGenesisArgs, ParaKind}, }; +use alloc::collections::btree_map::BTreeMap; use frame_support::{assert_ok, pallet_prelude::*}; use polkadot_primitives::{BlockNumber, Id as ParaId, SessionIndex, ValidationCode}; -use sp_std::collections::btree_map::BTreeMap; fn schedule_blank_para(id: ParaId, parakind: ParaKind) { let validation_code: ValidationCode = vec![1, 2, 3].into(); diff --git a/polkadot/runtime/parachains/src/builder.rs b/polkadot/runtime/parachains/src/builder.rs index c046526ba372b537d48fac8d7be65e97a6b846f9..b2a67ee8dd24105b1e3f5298dafbba66193681f0 100644 --- a/polkadot/runtime/parachains/src/builder.rs +++ b/polkadot/runtime/parachains/src/builder.rs @@ -21,29 +21,38 @@ use crate::{ scheduler::{self, common::AssignmentProvider, CoreOccupied, ParasEntry}, session_info, shared, }; +use alloc::{ + collections::{btree_map::BTreeMap, btree_set::BTreeSet, vec_deque::VecDeque}, + vec, + vec::Vec, +}; use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; use polkadot_primitives::{ - collator_signature_payload, node_features::FeatureIndex, AvailabilityBitfield, BackedCandidate, - CandidateCommitments, CandidateDescriptor, CandidateHash, CollatorId, CollatorSignature, - CommittedCandidateReceipt, CompactStatement, CoreIndex, DisputeStatement, DisputeStatementSet, - GroupIndex, HeadData, Id as ParaId, IndexedVec, InherentData as ParachainsInherentData, - InvalidDisputeStatementKind, PersistedValidationData, SessionIndex, SigningContext, - UncheckedSigned, ValidDisputeStatementKind, ValidationCode, ValidatorId, ValidatorIndex, - ValidityAttestation, + node_features::FeatureIndex, AvailabilityBitfield, BackedCandidate, CandidateCommitments, + CandidateDescriptor, CandidateHash, CollatorId, CollatorSignature, CommittedCandidateReceipt, + CompactStatement, CoreIndex, DisputeStatement, DisputeStatementSet, GroupIndex, HeadData, + Id as ParaId, IndexedVec, InherentData as ParachainsInherentData, InvalidDisputeStatementKind, + PersistedValidationData, SessionIndex, SigningContext, UncheckedSigned, + ValidDisputeStatementKind, ValidationCode, ValidatorId, ValidatorIndex, ValidityAttestation, }; -use sp_core::{sr25519, H256}; +use sp_core::{sr25519, ByteArray, H256}; use sp_runtime::{ generic::Digest, traits::{Header as HeaderT, One, TrailingZeroInput, Zero}, RuntimeAppPublic, }; -use sp_std::{ - collections::{btree_map::BTreeMap, btree_set::BTreeSet, vec_deque::VecDeque}, - prelude::Vec, - vec, -}; + +/// Create a null collator id. +pub fn dummy_collator() -> CollatorId { + CollatorId::from_slice(&vec![0u8; 32]).expect("32 bytes; qed") +} + +/// Create a null collator signature. +pub fn dummy_collator_signature() -> CollatorSignature { + CollatorSignature::from_slice(&vec![0u8; 64]).expect("64 bytes; qed") +} fn mock_validation_code() -> ValidationCode { ValidationCode(vec![1, 2, 3]) @@ -112,7 +121,7 @@ pub(crate) struct BenchBuilder { fill_claimqueue: bool, /// Cores which should not be available when being populated with pending candidates. unavailable_cores: Vec, - _phantom: sp_std::marker::PhantomData, + _phantom: core::marker::PhantomData, } /// Paras inherent `enter` benchmark scenario. @@ -143,7 +152,7 @@ impl BenchBuilder { code_upgrade: None, fill_claimqueue: true, unavailable_cores: vec![], - _phantom: sp_std::marker::PhantomData::, + _phantom: core::marker::PhantomData::, } } @@ -584,7 +593,6 @@ impl BenchBuilder { // This generates a pair and adds it to the keystore, returning just the // public. - let collator_public = CollatorId::generate_pair(None); let header = Self::header(self.block_number); let relay_parent = header.hash(); @@ -614,14 +622,6 @@ impl BenchBuilder { let pov_hash = Default::default(); let validation_code_hash = mock_validation_code().hash(); - let payload = collator_signature_payload( - &relay_parent, - ¶_id, - &persisted_validation_data_hash, - &pov_hash, - &validation_code_hash, - ); - let signature = collator_public.sign(&payload).unwrap(); let mut past_code_meta = paras::ParaPastCodeMeta::>::default(); @@ -634,11 +634,11 @@ impl BenchBuilder { descriptor: CandidateDescriptor:: { para_id, relay_parent, - collator: collator_public, + collator: dummy_collator(), persisted_validation_data_hash, pov_hash, erasure_root: Default::default(), - signature, + signature: dummy_collator_signature(), para_head: head_data.hash(), validation_code_hash, }, diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index bffeab4a0d21b13d492550eeb0323624cc8c588c..d09962ef2b4412c3e583129c2ab14624062c5dff 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -19,6 +19,7 @@ //! Configuration can change only at session boundaries and is buffered until then. use crate::{inclusion::MAX_UPWARD_MESSAGE_SIZE_BOUND, shared}; +use alloc::vec::Vec; use codec::{Decode, Encode}; use frame_support::{pallet_prelude::*, DefaultNoBound}; use frame_system::pallet_prelude::*; @@ -31,7 +32,6 @@ use polkadot_primitives::{ MAX_POV_SIZE, ON_DEMAND_MAX_QUEUE_MAX_SIZE, }; use sp_runtime::{traits::Zero, Perbill, Percent}; -use sp_std::prelude::*; #[cfg(test)] mod tests; @@ -345,7 +345,7 @@ pub enum InconsistentError { impl HostConfiguration where - BlockNumber: Zero + PartialOrd + sp_std::fmt::Debug + Clone + From, + BlockNumber: Zero + PartialOrd + core::fmt::Debug + Clone + From, { /// Checks that this instance is consistent with the requirements on each individual member. /// @@ -1469,7 +1469,7 @@ impl Pallet { /// The implementation of `Get<(u32, u32)>` which reads `ActiveConfig` and returns `P` percent of /// `hrmp_channel_max_message_size` / `hrmp_channel_max_capacity`. -pub struct ActiveConfigHrmpChannelSizeAndCapacityRatio(sp_std::marker::PhantomData<(T, P)>); +pub struct ActiveConfigHrmpChannelSizeAndCapacityRatio(core::marker::PhantomData<(T, P)>); impl> Get<(u32, u32)> for ActiveConfigHrmpChannelSizeAndCapacityRatio { diff --git a/polkadot/runtime/parachains/src/configuration/migration/v10.rs b/polkadot/runtime/parachains/src/configuration/migration/v10.rs index c53f58faaf03a8ca85d2d6ac3272425976e0f177..9375af88306fd804d079be38672f1527f4ccacd2 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v10.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v10.rs @@ -17,6 +17,7 @@ //! A module that is responsible for migration of storage. use crate::configuration::{Config, Pallet}; +use alloc::vec::Vec; use frame_support::{ pallet_prelude::*, traits::{Defensive, UncheckedOnRuntimeUpgrade}, @@ -28,7 +29,6 @@ use polkadot_primitives::{ LEGACY_MIN_BACKING_VOTES, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, }; use sp_runtime::Perbill; -use sp_std::vec::Vec; use super::v9::V9HostConfiguration; // All configuration of the runtime with respect to paras. @@ -164,7 +164,7 @@ mod v10 { >; } -pub struct VersionUncheckedMigrateToV10(sp_std::marker::PhantomData); +pub struct VersionUncheckedMigrateToV10(core::marker::PhantomData); impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV10 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { diff --git a/polkadot/runtime/parachains/src/configuration/migration/v11.rs b/polkadot/runtime/parachains/src/configuration/migration/v11.rs index 4d1bfc26196ca2ade0b904da2c9be4159b0a099e..4dce48fe52b0e37d954b3006cb69e9e190c8b3aa 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v11.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v11.rs @@ -17,6 +17,7 @@ //! A module that is responsible for migration of storage. use crate::configuration::{self, Config, Pallet}; +use alloc::vec::Vec; use frame_support::{ migrations::VersionedMigration, pallet_prelude::*, @@ -28,7 +29,6 @@ use polkadot_primitives::{ ApprovalVotingParams, AsyncBackingParams, ExecutorParams, NodeFeatures, SessionIndex, LEGACY_MIN_BACKING_VOTES, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, }; -use sp_std::vec::Vec; use polkadot_core_primitives::Balance; use sp_arithmetic::Perbill; @@ -177,7 +177,7 @@ pub type MigrateToV11 = VersionedMigration< ::DbWeight, >; -pub struct UncheckedMigrateToV11(sp_std::marker::PhantomData); +pub struct UncheckedMigrateToV11(core::marker::PhantomData); impl UncheckedOnRuntimeUpgrade for UncheckedMigrateToV11 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { diff --git a/polkadot/runtime/parachains/src/configuration/migration/v12.rs b/polkadot/runtime/parachains/src/configuration/migration/v12.rs index 126597ed845447c059eebb28b230e988db5ac77d..6b77655687f0dfd13bfdf3f425a4d744b9798cd3 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v12.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v12.rs @@ -17,6 +17,7 @@ //! A module that is responsible for migration of storage. use crate::configuration::{self, migration::v11::V11HostConfiguration, Config, Pallet}; +use alloc::vec::Vec; use frame_support::{ migrations::VersionedMigration, pallet_prelude::*, @@ -26,7 +27,6 @@ use frame_system::pallet_prelude::BlockNumberFor; use polkadot_primitives::vstaging::SchedulerParams; use sp_core::Get; use sp_staking::SessionIndex; -use sp_std::vec::Vec; type V12HostConfiguration = configuration::HostConfiguration; @@ -68,7 +68,7 @@ pub type MigrateToV12 = VersionedMigration< ::DbWeight, >; -pub struct UncheckedMigrateToV12(sp_std::marker::PhantomData); +pub struct UncheckedMigrateToV12(core::marker::PhantomData); impl UncheckedOnRuntimeUpgrade for UncheckedMigrateToV12 { #[cfg(feature = "try-runtime")] diff --git a/polkadot/runtime/parachains/src/configuration/migration/v6.rs b/polkadot/runtime/parachains/src/configuration/migration/v6.rs index bec41d3ea0dc51ec83ecce67f7373751cd7e2432..468bf78692a12980d322233f51eb625720944e22 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v6.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v6.rs @@ -17,13 +17,11 @@ //! Contains the V6 storage definition of the host configuration. use crate::configuration::{Config, Pallet}; +use alloc::vec::Vec; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::BlockNumberFor; -use sp_std::vec::Vec; use polkadot_primitives::{AsyncBackingParams, Balance, ExecutorParams, SessionIndex}; -#[cfg(feature = "try-runtime")] -use sp_std::prelude::*; #[derive(codec::Encode, codec::Decode, Debug, Clone)] pub struct V6HostConfiguration { diff --git a/polkadot/runtime/parachains/src/configuration/migration/v7.rs b/polkadot/runtime/parachains/src/configuration/migration/v7.rs index 8fe4087cf9b170754e07f07175a3de1eac6ce216..9acd28d0f764e4f966fd48cbfd3e6fc9a5810200 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v7.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v7.rs @@ -17,6 +17,7 @@ //! A module that is responsible for migration of storage. use crate::configuration::{self, Config, Pallet}; +use alloc::vec::Vec; use frame_support::{ pallet_prelude::*, traits::{Defensive, StorageVersion}, @@ -24,7 +25,6 @@ use frame_support::{ }; use frame_system::pallet_prelude::BlockNumberFor; use polkadot_primitives::{AsyncBackingParams, Balance, ExecutorParams, SessionIndex}; -use sp_std::vec::Vec; use frame_support::traits::OnRuntimeUpgrade; @@ -154,7 +154,7 @@ mod v7 { >; } -pub struct MigrateToV7(sp_std::marker::PhantomData); +pub struct MigrateToV7(core::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV7 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { diff --git a/polkadot/runtime/parachains/src/configuration/migration/v8.rs b/polkadot/runtime/parachains/src/configuration/migration/v8.rs index 0aa7f550b102afea143c762a70e2056f918d5bc8..81ced74bebb9770ff09fb50b42e9c89f213b6019 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v8.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v8.rs @@ -17,6 +17,7 @@ //! A module that is responsible for migration of storage. use crate::configuration::{self, Config, Pallet}; +use alloc::vec::Vec; use frame_support::{ pallet_prelude::*, traits::{Defensive, StorageVersion}, @@ -27,7 +28,6 @@ use polkadot_primitives::{ AsyncBackingParams, Balance, ExecutorParams, SessionIndex, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, }; use sp_runtime::Perbill; -use sp_std::vec::Vec; use frame_support::traits::OnRuntimeUpgrade; @@ -161,7 +161,7 @@ mod v8 { >; } -pub struct MigrateToV8(sp_std::marker::PhantomData); +pub struct MigrateToV8(core::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV8 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { diff --git a/polkadot/runtime/parachains/src/configuration/migration/v9.rs b/polkadot/runtime/parachains/src/configuration/migration/v9.rs index 6afdd3cec29efbb8988cfab5a79c712553b7b8aa..dff5fdb17a697cf209ccffa07b808175cfab2f7b 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v9.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v9.rs @@ -17,6 +17,7 @@ //! A module that is responsible for migration of storage. use crate::configuration::{self, Config, Pallet}; +use alloc::vec::Vec; use frame_support::{ pallet_prelude::*, traits::{Defensive, StorageVersion}, @@ -28,7 +29,6 @@ use polkadot_primitives::{ ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, }; use sp_runtime::Perbill; -use sp_std::vec::Vec; use frame_support::traits::OnRuntimeUpgrade; @@ -164,7 +164,7 @@ mod v9 { >; } -pub struct MigrateToV9(sp_std::marker::PhantomData); +pub struct MigrateToV9(core::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV9 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { diff --git a/polkadot/runtime/parachains/src/coretime/benchmarking.rs b/polkadot/runtime/parachains/src/coretime/benchmarking.rs index d1ac71f580ee0e70015bf130b6836519005ee280..6d593f1954ff1500fd59ae5d178e038dd38e01b5 100644 --- a/polkadot/runtime/parachains/src/coretime/benchmarking.rs +++ b/polkadot/runtime/parachains/src/coretime/benchmarking.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! On demand assigner pallet benchmarking. +//! Coretime pallet benchmarking. #![cfg(feature = "runtime-benchmarks")] @@ -28,6 +28,30 @@ mod benchmarks { use super::*; use assigner_coretime::PartsOf57600; + #[benchmark] + fn request_revenue_at() { + let root_origin = ::RuntimeOrigin::root(); + let mhr = ::MaxHistoricalRevenue::get(); + frame_system::Pallet::::set_block_number((mhr + 2).into()); + let minimum_balance = ::Currency::minimum_balance(); + let rev: BoundedVec< + <::Currency as frame_support::traits::Currency< + T::AccountId, + >>::Balance, + T::MaxHistoricalRevenue, + > = BoundedVec::try_from((1..=mhr).map(|v| minimum_balance * v.into()).collect::>()) + .unwrap(); + on_demand::Revenue::::put(rev); + + ::Currency::make_free_balance_be( + &>::account_id(), + minimum_balance * (mhr * (mhr + 1)).into(), + ); + + #[extrinsic_call] + _(root_origin as ::RuntimeOrigin, mhr + 1) + } + #[benchmark] fn request_core_count() { // Setup diff --git a/polkadot/runtime/parachains/src/coretime/migration.rs b/polkadot/runtime/parachains/src/coretime/migration.rs index 3f82472da8aa4ed15d26230693a7ef7d3d586c79..4e75088675590e54fa6d8dc040732cc032cc0732 100644 --- a/polkadot/runtime/parachains/src/coretime/migration.rs +++ b/polkadot/runtime/parachains/src/coretime/migration.rs @@ -26,10 +26,12 @@ mod v_coretime { coretime::{mk_coretime_call, Config, PartsOf57600, WeightInfo}, paras, }; + use alloc::{vec, vec::Vec}; #[cfg(feature = "try-runtime")] use codec::Decode; #[cfg(feature = "try-runtime")] use codec::Encode; + use core::{iter, result}; #[cfg(feature = "try-runtime")] use frame_support::ensure; use frame_support::{ @@ -43,9 +45,6 @@ mod v_coretime { use sp_arithmetic::traits::SaturatedConversion; use sp_core::Get; use sp_runtime::BoundedVec; - #[cfg(feature = "try-runtime")] - use sp_std::vec::Vec; - use sp_std::{iter, prelude::*, result}; use xcm::prelude::{send_xcm, Instruction, Junction, Location, SendError, WeightLimit, Xcm}; /// Return information about a legacy lease of a parachain. @@ -59,7 +58,7 @@ mod v_coretime { /// This assumes that the `Coretime` and the `AssignerCoretime` pallets are added at the same /// time to a runtime. pub struct MigrateToCoretime( - sp_std::marker::PhantomData<(T, SendXcm, LegacyLease)>, + core::marker::PhantomData<(T, SendXcm, LegacyLease)>, ); impl>> diff --git a/polkadot/runtime/parachains/src/coretime/mod.rs b/polkadot/runtime/parachains/src/coretime/mod.rs index dedffb733d33ef120f6b220afc550f04b77f0979..fbd8935f1990233ebfded2db9f31ac4b241bebde 100644 --- a/polkadot/runtime/parachains/src/coretime/mod.rs +++ b/polkadot/runtime/parachains/src/coretime/mod.rs @@ -18,30 +18,49 @@ //! //! -use sp_std::{prelude::*, result}; - -use frame_support::{pallet_prelude::*, traits::Currency}; +use alloc::{vec, vec::Vec}; +use core::result; +use frame_support::{ + pallet_prelude::*, + traits::{defensive_prelude::*, Currency}, +}; use frame_system::pallet_prelude::*; pub use pallet::*; use pallet_broker::{CoreAssignment, CoreIndex as BrokerCoreIndex}; -use polkadot_primitives::{CoreIndex, Id as ParaId}; +use polkadot_primitives::{Balance, BlockNumber, CoreIndex, Id as ParaId}; use sp_arithmetic::traits::SaturatedConversion; -use xcm::prelude::{ - send_xcm, Instruction, Junction, Location, OriginKind, SendXcm, WeightLimit, Xcm, +use sp_runtime::traits::TryConvert; +use xcm::{ + prelude::{send_xcm, Instruction, Junction, Location, OriginKind, SendXcm, WeightLimit, Xcm}, + v4::{ + Asset, + AssetFilter::Wild, + AssetId, Assets, Error as XcmError, + Fungibility::Fungible, + Instruction::{DepositAsset, ReceiveTeleportedAsset}, + Junctions::Here, + Reanchorable, + WildAsset::AllCounted, + XcmContext, + }, }; +use xcm_executor::traits::TransactAsset; use crate::{ assigner_coretime::{self, PartsOf57600}, initializer::{OnNewSession, SessionChangeNotification}, + on_demand, origin::{ensure_parachain, Origin}, }; mod benchmarking; pub mod migration; +const LOG_TARGET: &str = "runtime::parachains::coretime"; + pub trait WeightInfo { fn request_core_count() -> Weight; - //fn request_revenue_info_at() -> Weight; + fn request_revenue_at() -> Weight; //fn credit_account() -> Weight; fn assign_core(s: u32) -> Weight; } @@ -53,19 +72,23 @@ impl WeightInfo for TestWeightInfo { fn request_core_count() -> Weight { Weight::MAX } - // TODO: Add real benchmarking functionality for each of these to - // benchmarking.rs, then uncomment here and in trait definition. - /*fn request_revenue_info_at() -> Weight { + fn request_revenue_at() -> Weight { Weight::MAX } - fn credit_account() -> Weight { - Weight::MAX - }*/ + // TODO: Add real benchmarking functionality for each of these to + // benchmarking.rs, then uncomment here and in trait definition. + //fn credit_account() -> Weight { + // Weight::MAX + //} fn assign_core(_s: u32) -> Weight { Weight::MAX } } +/// Shorthand for the Balance type the runtime is using. +pub type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + /// Broker pallet index on the coretime chain. Used to /// /// construct remote calls. The codec index must correspond to the index of `Broker` in the @@ -85,13 +108,19 @@ enum CoretimeCalls { SetLease(pallet_broker::TaskId, pallet_broker::Timeslice), #[codec(index = 19)] NotifyCoreCount(u16), + #[codec(index = 20)] + NotifyRevenue((BlockNumber, Balance)), #[codec(index = 99)] SwapLeases(ParaId, ParaId), } #[frame_support::pallet] pub mod pallet { + use crate::configuration; + use sp_runtime::traits::TryConvert; + use xcm::v4::InteriorLocation; + use xcm_executor::traits::TransactAsset; use super::*; @@ -100,7 +129,7 @@ pub mod pallet { pub struct Pallet(_); #[pallet::config] - pub trait Config: frame_system::Config + assigner_coretime::Config { + pub trait Config: frame_system::Config + assigner_coretime::Config + on_demand::Config { type RuntimeOrigin: From<::RuntimeOrigin> + Into::RuntimeOrigin>>; type RuntimeEvent: From> + IsType<::RuntimeEvent>; @@ -109,9 +138,17 @@ pub mod pallet { /// The ParaId of the coretime chain. #[pallet::constant] type BrokerId: Get; + /// The coretime chain pot location. + #[pallet::constant] + type BrokerPotLocation: Get; /// Something that provides the weight of this pallet. type WeightInfo: WeightInfo; + /// The XCM sender. type SendXcm: SendXcm; + /// The asset transactor. + type AssetTransactor: TransactAsset; + /// AccountId to Location converter + type AccountToLocation: for<'a> TryConvert<&'a Self::AccountId, Location>; /// Maximum weight for any XCM transact call that should be executed on the coretime chain. /// @@ -132,6 +169,11 @@ pub mod pallet { pub enum Error { /// The paraid making the call is not the coretime brokerage system parachain. NotBroker, + /// Requested revenue information `when` parameter was in the future from the current + /// block height. + RequestedFutureRevenue, + /// Failed to transfer assets to the coretime chain + AssetTransferFailed, } #[pallet::hooks] @@ -154,17 +196,17 @@ pub mod pallet { configuration::Pallet::::set_coretime_cores_unchecked(u32::from(count)) } - //// TODO Impl me! - ////#[pallet::weight(::WeightInfo::request_revenue_info_at())] - //#[pallet::call_index(2)] - //pub fn request_revenue_info_at( - // origin: OriginFor, - // _when: BlockNumberFor, - //) -> DispatchResult { - // // Ignore requests not coming from the coretime chain or root. - // Self::ensure_root_or_para(origin, ::BrokerId::get().into())?; - // Ok(()) - //} + /// Request to claim the instantaneous coretime sales revenue starting from the block it was + /// last claimed until and up to the block specified. The claimed amount value is sent back + /// to the Coretime chain in a `notify_revenue` message. At the same time, the amount is + /// teleported to the Coretime chain. + #[pallet::weight(::WeightInfo::request_revenue_at())] + #[pallet::call_index(2)] + pub fn request_revenue_at(origin: OriginFor, when: BlockNumber) -> DispatchResult { + // Ignore requests not coming from the Coretime Chain or Root. + Self::ensure_root_or_para(origin, ::BrokerId::get().into())?; + Self::notify_revenue(when) + } //// TODO Impl me! ////#[pallet::weight(::WeightInfo::credit_account())] @@ -244,11 +286,43 @@ impl Pallet { Location::new(0, [Junction::Parachain(T::BrokerId::get())]), message, ) { - log::error!("Sending `NotifyCoreCount` to coretime chain failed: {:?}", err); + log::error!(target: LOG_TARGET, "Sending `NotifyCoreCount` to coretime chain failed: {:?}", err); } } } + /// Provide the amount of revenue accumulated from Instantaneous Coretime Sales from Relay-chain + /// block number last_until to until, not including until itself. last_until is defined as being + /// the until argument of the last notify_revenue message sent, or zero for the first call. If + /// revenue is None, this indicates that the information is no longer available. This explicitly + /// disregards the possibility of multiple parachains requesting and being notified of revenue + /// information. + /// + /// The Relay-chain must be configured to ensure that only a single revenue information + /// destination exists. + pub fn notify_revenue(until: BlockNumber) -> DispatchResult { + let now = >::block_number(); + let until_bnf: BlockNumberFor = until.into(); + + // When cannot be in the future. + ensure!(until_bnf <= now, Error::::RequestedFutureRevenue); + + let amount = >::claim_revenue_until(until_bnf); + log::debug!(target: LOG_TARGET, "Revenue info requested: {:?}", amount); + + let raw_revenue: Balance = amount.try_into().map_err(|_| { + log::error!(target: LOG_TARGET, "Converting on demand revenue for `NotifyRevenue` failed"); + Error::::AssetTransferFailed + })?; + + do_notify_revenue::(until, raw_revenue).map_err(|err| { + log::error!(target: LOG_TARGET, "notify_revenue failed: {err:?}"); + Error::::AssetTransferFailed + })?; + + Ok(()) + } + // Handle legacy swaps in coretime. Notifies coretime chain that a lease swap has occurred via // XCM message. This function is meant to be used in an implementation of `OnSwap` trait. pub fn on_legacy_lease_swap(one: ParaId, other: ParaId) { @@ -263,7 +337,7 @@ impl Pallet { Location::new(0, [Junction::Parachain(T::BrokerId::get())]), message, ) { - log::error!("Sending `SwapLeases` to coretime chain failed: {:?}", err); + log::error!(target: LOG_TARGET, "Sending `SwapLeases` to coretime chain failed: {:?}", err); } } } @@ -281,3 +355,56 @@ fn mk_coretime_call(call: crate::coretime::CoretimeCalls) -> Instruct call: BrokerRuntimePallets::Broker(call).encode().into(), } } + +fn do_notify_revenue(when: BlockNumber, raw_revenue: Balance) -> Result<(), XcmError> { + let dest = Junction::Parachain(T::BrokerId::get()).into_location(); + let mut message = Vec::new(); + let asset = Asset { id: AssetId(Location::here()), fun: Fungible(raw_revenue) }; + let dummy_xcm_context = XcmContext { origin: None, message_id: [0; 32], topic: None }; + + if raw_revenue > 0 { + let on_demand_pot = + T::AccountToLocation::try_convert(&>::account_id()).map_err( + |err| { + log::error!( + target: LOG_TARGET, + "Failed to convert on-demand pot account to XCM location: {err:?}", + ); + XcmError::InvalidLocation + }, + )?; + + let withdrawn = T::AssetTransactor::withdraw_asset(&asset, &on_demand_pot, None)?; + + T::AssetTransactor::can_check_out(&dest, &asset, &dummy_xcm_context)?; + + let assets_reanchored = Into::::into(withdrawn) + .reanchored(&dest, &Here.into()) + .defensive_map_err(|_| XcmError::ReanchorFailed)?; + + message.extend( + [ + Instruction::UnpaidExecution { + weight_limit: WeightLimit::Unlimited, + check_origin: None, + }, + ReceiveTeleportedAsset(assets_reanchored), + DepositAsset { + assets: Wild(AllCounted(1)), + beneficiary: T::BrokerPotLocation::get().into_location(), + }, + ] + .into_iter(), + ); + } + + message.push(mk_coretime_call::(CoretimeCalls::NotifyRevenue((when, raw_revenue)))); + + send_xcm::(dest.clone(), Xcm(message))?; + + if raw_revenue > 0 { + T::AssetTransactor::check_out(&dest, &asset, &dummy_xcm_context); + } + + Ok(()) +} diff --git a/polkadot/runtime/parachains/src/disputes.rs b/polkadot/runtime/parachains/src/disputes.rs index 4a0f2390b45dc87b1e4eb3425ee430e0499d3895..f86573dadf562fee7b4cb63190399cbe390a4865 100644 --- a/polkadot/runtime/parachains/src/disputes.rs +++ b/polkadot/runtime/parachains/src/disputes.rs @@ -19,8 +19,10 @@ use crate::{ configuration, initializer::SessionChangeNotification, metrics::METRICS, session_info, }; +use alloc::{collections::btree_set::BTreeSet, vec::Vec}; use bitvec::{bitvec, order::Lsb0 as BitOrderLsb0}; use codec::{Decode, Encode}; +use core::cmp::Ordering; use frame_support::{ensure, weights::Weight}; use frame_system::pallet_prelude::*; use polkadot_primitives::{ @@ -36,7 +38,6 @@ use sp_runtime::{ traits::{AppVerify, One, Saturating, Zero}, DispatchError, RuntimeDebug, SaturatedConversion, }; -use sp_std::{cmp::Ordering, collections::btree_set::BTreeSet, prelude::*}; #[cfg(test)] #[allow(unused_imports)] diff --git a/polkadot/runtime/parachains/src/disputes/migration.rs b/polkadot/runtime/parachains/src/disputes/migration.rs index e12edffb51b38d83e016d79dabe62c83ee20a098..dd32340c9f64f357913a99d6a50f166f9a9382f2 100644 --- a/polkadot/runtime/parachains/src/disputes/migration.rs +++ b/polkadot/runtime/parachains/src/disputes/migration.rs @@ -21,16 +21,16 @@ use frame_support::traits::StorageVersion; pub mod v1 { use super::*; use crate::disputes::{Config, Pallet}; + use alloc::vec::Vec; use frame_support::{ pallet_prelude::*, storage_alias, traits::OnRuntimeUpgrade, weights::Weight, }; use polkadot_primitives::SessionIndex; - use sp_std::prelude::*; #[storage_alias] type SpamSlots = StorageMap, Twox64Concat, SessionIndex, Vec>; - pub struct MigrateToV1(sp_std::marker::PhantomData); + pub struct MigrateToV1(core::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV1 { fn on_runtime_upgrade() -> Weight { let mut weight: Weight = Weight::zero(); diff --git a/polkadot/runtime/parachains/src/disputes/slashing.rs b/polkadot/runtime/parachains/src/disputes/slashing.rs index b50853ecc696c79d5d8b94cda6161f6d912c96f3..4b76fb47e1f8d5fff51e13274931514930ef5de7 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing.rs @@ -50,6 +50,12 @@ use frame_support::{ }; use frame_system::pallet_prelude::BlockNumberFor; +use alloc::{ + boxed::Box, + collections::{btree_map::Entry, btree_set::BTreeSet}, + vec, + vec::Vec, +}; use polkadot_primitives::{ slashing::{DisputeProof, DisputesTimeSlot, PendingSlashes, SlashingOffenceKind}, CandidateHash, SessionIndex, ValidatorId, ValidatorIndex, @@ -65,10 +71,6 @@ use sp_runtime::{ }; use sp_session::{GetSessionNumber, GetValidatorCount}; use sp_staking::offence::{Kind, Offence, OffenceError, ReportOffence}; -use sp_std::{ - collections::{btree_map::Entry, btree_set::BTreeSet}, - prelude::*, -}; const LOG_TARGET: &str = "runtime::parachains::slashing"; @@ -158,7 +160,7 @@ impl SlashingOffence { /// This type implements `SlashingHandler`. pub struct SlashValidatorsForDisputes { - _phantom: sp_std::marker::PhantomData, + _phantom: core::marker::PhantomData, } impl Default for SlashValidatorsForDisputes { @@ -640,7 +642,7 @@ fn is_known_offence( /// When configured properly, should be instantiated with /// `T::KeyOwnerIdentification, Offences, ReportLongevity` parameters. pub struct SlashingReportHandler { - _phantom: sp_std::marker::PhantomData<(I, R, L)>, + _phantom: core::marker::PhantomData<(I, R, L)>, } impl Default for SlashingReportHandler { diff --git a/polkadot/runtime/parachains/src/dmp.rs b/polkadot/runtime/parachains/src/dmp.rs index c0e1635ba1692c3f3d62a13bb686e95d3511bc0a..54e112d1b8b44206b8a121dd082c60718662e14a 100644 --- a/polkadot/runtime/parachains/src/dmp.rs +++ b/polkadot/runtime/parachains/src/dmp.rs @@ -46,6 +46,8 @@ use crate::{ configuration::{self, HostConfiguration}, initializer, FeeTracker, }; +use alloc::vec::Vec; +use core::fmt; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::BlockNumberFor; use polkadot_primitives::{DownwardMessage, Hash, Id as ParaId, InboundDownwardMessage}; @@ -54,7 +56,6 @@ use sp_runtime::{ traits::{BlakeTwo256, Hash as HashT, SaturatedConversion}, FixedU128, Saturating, }; -use sp_std::{fmt, prelude::*}; use xcm::latest::SendError; pub use pallet::*; diff --git a/polkadot/runtime/parachains/src/hrmp.rs b/polkadot/runtime/parachains/src/hrmp.rs index e34e4a03e711c3592f66a303fb8a2c4d37b64db8..8b01a755c3c7bd75d558989fd593a44334c906b6 100644 --- a/polkadot/runtime/parachains/src/hrmp.rs +++ b/polkadot/runtime/parachains/src/hrmp.rs @@ -18,7 +18,13 @@ use crate::{ configuration::{self, HostConfiguration}, dmp, ensure_parachain, initializer, paras, }; +use alloc::{ + collections::{btree_map::BTreeMap, btree_set::BTreeSet}, + vec, + vec::Vec, +}; use codec::{Decode, Encode}; +use core::{fmt, mem}; use frame_support::{pallet_prelude::*, traits::ReservableCurrency, DefaultNoBound}; use frame_system::pallet_prelude::*; use polkadot_parachain_primitives::primitives::{HorizontalMessages, IsSystem}; @@ -31,11 +37,6 @@ use sp_runtime::{ traits::{AccountIdConversion, BlakeTwo256, Hash as HashT, UniqueSaturatedInto, Zero}, ArithmeticError, }; -use sp_std::{ - collections::{btree_map::BTreeMap, btree_set::BTreeSet}, - fmt, mem, - prelude::*, -}; pub use pallet::*; @@ -487,7 +488,7 @@ pub mod pallet { #[derive(DefaultNoBound)] pub struct GenesisConfig { #[serde(skip)] - _config: sp_std::marker::PhantomData, + _config: core::marker::PhantomData, preopen_hrmp_channels: Vec<(ParaId, ParaId, u32, u32)>, } diff --git a/polkadot/runtime/parachains/src/hrmp/tests.rs b/polkadot/runtime/parachains/src/hrmp/tests.rs index 4fcbc69e98ad8e905afa5b18cd52dc526d6f0c67..52db932c7962b49f0e7f4d99de7527d38882237d 100644 --- a/polkadot/runtime/parachains/src/hrmp/tests.rs +++ b/polkadot/runtime/parachains/src/hrmp/tests.rs @@ -27,8 +27,9 @@ use crate::{ }, shared, }; -use frame_support::{assert_noop, assert_ok, error::BadOrigin}; +use frame_support::{assert_noop, assert_ok}; use polkadot_primitives::{BlockNumber, InboundDownwardMessage}; +use sp_runtime::traits::BadOrigin; use std::collections::BTreeMap; pub(crate) fn run_to_block(to: BlockNumber, new_session: Option>) { diff --git a/polkadot/runtime/parachains/src/inclusion/migration.rs b/polkadot/runtime/parachains/src/inclusion/migration.rs index a340d52643e05df356889a95186170c1e615480e..36a810d341c655cf9309b9b8fec87032a8bc7486 100644 --- a/polkadot/runtime/parachains/src/inclusion/migration.rs +++ b/polkadot/runtime/parachains/src/inclusion/migration.rs @@ -73,9 +73,9 @@ mod v1 { CandidatePendingAvailability as V1CandidatePendingAvailability, Config, Pallet, PendingAvailability as V1PendingAvailability, }; + use alloc::{collections::vec_deque::VecDeque, vec::Vec}; use frame_support::{traits::UncheckedOnRuntimeUpgrade, weights::Weight}; use sp_core::Get; - use sp_std::{collections::vec_deque::VecDeque, vec::Vec}; #[cfg(feature = "try-runtime")] use codec::{Decode, Encode}; @@ -85,7 +85,7 @@ mod v1 { traits::{GetStorageVersion, StorageVersion}, }; - pub struct VersionUncheckedMigrateToV1(sp_std::marker::PhantomData); + pub struct VersionUncheckedMigrateToV1(core::marker::PhantomData); impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV1 { #[cfg(feature = "try-runtime")] diff --git a/polkadot/runtime/parachains/src/inclusion/mod.rs b/polkadot/runtime/parachains/src/inclusion/mod.rs index a86941a1a0b8e5d4f56eeb50ccf20a6dd81cc62c..a5bb6e6cc60fa40f9f19a05ea9e475c2052286c2 100644 --- a/polkadot/runtime/parachains/src/inclusion/mod.rs +++ b/polkadot/runtime/parachains/src/inclusion/mod.rs @@ -27,8 +27,15 @@ use crate::{ shared::{self, AllowedRelayParentsTracker}, util::make_persisted_validation_data_with_parent, }; +use alloc::{ + collections::{btree_map::BTreeMap, btree_set::BTreeSet, vec_deque::VecDeque}, + vec, + vec::Vec, +}; use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; use codec::{Decode, Encode}; +#[cfg(feature = "std")] +use core::fmt; use frame_support::{ defensive, pallet_prelude::*, @@ -46,12 +53,6 @@ use polkadot_primitives::{ }; use scale_info::TypeInfo; use sp_runtime::{traits::One, DispatchError, SaturatedConversion, Saturating}; -#[cfg(feature = "std")] -use sp_std::fmt; -use sp_std::{ - collections::{btree_map::BTreeMap, btree_set::BTreeSet, vec_deque::VecDeque}, - prelude::*, -}; pub use pallet::*; @@ -337,8 +338,6 @@ pub mod pallet { InsufficientBacking, /// Invalid (bad signature, unknown validator, etc.) backing. InvalidBacking, - /// Collator did not sign PoV. - NotCollatorSigned, /// The validation data hash does not match expected. ValidationDataHashMismatch, /// The downward message queue is not processed correctly. @@ -1221,7 +1220,6 @@ impl CandidateCheckContext { /// /// Assures: /// * relay-parent in-bounds - /// * collator signature check passes /// * code hash of commitments matches current code hash /// * para head in the descriptor and commitments match /// @@ -1258,11 +1256,6 @@ impl CandidateCheckContext { ); } - ensure!( - backed_candidate_receipt.descriptor().check_collator_signature().is_ok(), - Error::::NotCollatorSigned, - ); - let validation_code_hash = paras::CurrentCodeHash::::get(para_id) // A candidate for a parachain without current validation code is not scheduled. .ok_or_else(|| Error::::UnscheduledCandidate)?; diff --git a/polkadot/runtime/parachains/src/inclusion/tests.rs b/polkadot/runtime/parachains/src/inclusion/tests.rs index 18def664f4b284434a12e97d72e343d534721d37..3ead456cde5a98eed8950551901ad3bae2107b97 100644 --- a/polkadot/runtime/parachains/src/inclusion/tests.rs +++ b/polkadot/runtime/parachains/src/inclusion/tests.rs @@ -1545,16 +1545,52 @@ fn candidate_checks() { None, ); - assert_noop!( - ParaInclusion::process_candidates( - &allowed_relay_parents, - &vec![(thread_a_assignment.0, vec![(backed, thread_a_assignment.1)])] - .into_iter() - .collect(), - &group_validators, - false - ), - Error::::NotCollatorSigned + let ProcessedCandidates { + core_indices: occupied_cores, + candidate_receipt_with_backing_validator_indices, + } = ParaInclusion::process_candidates( + &allowed_relay_parents, + &vec![(thread_a_assignment.0, vec![(backed.clone(), thread_a_assignment.1)])] + .into_iter() + .collect(), + &group_validators, + false, + ) + .expect("candidate is accepted with bad collator signature"); + + assert_eq!(occupied_cores, vec![(CoreIndex::from(2), thread_a)]); + + let mut expected = std::collections::HashMap::< + CandidateHash, + (CandidateReceipt, Vec<(ValidatorIndex, ValidityAttestation)>), + >::new(); + let backed_candidate = backed; + let candidate_receipt_with_backers = expected + .entry(backed_candidate.hash()) + .or_insert_with(|| (backed_candidate.receipt(), Vec::new())); + let (validator_indices, _maybe_core_index) = + backed_candidate.validator_indices_and_core_index(true); + assert_eq!(backed_candidate.validity_votes().len(), validator_indices.count_ones()); + candidate_receipt_with_backers.1.extend( + validator_indices + .iter() + .enumerate() + .filter(|(_, signed)| **signed) + .zip(backed_candidate.validity_votes().iter().cloned()) + .filter_map(|((validator_index_within_group, _), attestation)| { + let grp_idx = GroupIndex(2); + group_validators(grp_idx).map(|validator_indices| { + (validator_indices[validator_index_within_group], attestation) + }) + }), + ); + + assert_eq!( + expected, + candidate_receipt_with_backing_validator_indices + .into_iter() + .map(|c| (c.0.hash(), c)) + .collect() ); } diff --git a/polkadot/runtime/parachains/src/initializer.rs b/polkadot/runtime/parachains/src/initializer.rs index fd0f1c3c065118f81821b0f8587335537421135d..340f727097b58245d9fa9a2553f9e178544bcea1 100644 --- a/polkadot/runtime/parachains/src/initializer.rs +++ b/polkadot/runtime/parachains/src/initializer.rs @@ -25,6 +25,7 @@ use crate::{ disputes::{self, DisputesHandler as _, SlashingHandler as _}, dmp, hrmp, inclusion, paras, scheduler, session_info, shared, }; +use alloc::vec::Vec; use codec::{Decode, Encode}; use frame_support::{ traits::{OneSessionHandler, Randomness}, @@ -33,7 +34,6 @@ use frame_support::{ use frame_system::limits::BlockWeights; use polkadot_primitives::{BlockNumber, ConsensusLog, SessionIndex, ValidatorId}; use scale_info::TypeInfo; -use sp_std::prelude::*; #[cfg(test)] mod tests; @@ -249,7 +249,7 @@ impl Pallet { // TODO: audit usage of randomness API // https://github.com/paritytech/polkadot/issues/2601 let (random_hash, _) = T::Randomness::random(&b"paras"[..]); - let len = sp_std::cmp::min(32, random_hash.as_ref().len()); + let len = core::cmp::min(32, random_hash.as_ref().len()); buf[..len].copy_from_slice(&random_hash.as_ref()[..len]); buf }; diff --git a/polkadot/runtime/parachains/src/lib.rs b/polkadot/runtime/parachains/src/lib.rs index 51110e89416c373efb1a5226a812ae6ab9f88431..f1162e1cc2154a66db7aa02e465eab9934130769 100644 --- a/polkadot/runtime/parachains/src/lib.rs +++ b/polkadot/runtime/parachains/src/lib.rs @@ -24,7 +24,6 @@ #![cfg_attr(not(feature = "std"), no_std)] pub mod assigner_coretime; -pub mod assigner_on_demand; pub mod assigner_parachains; pub mod configuration; pub mod coretime; @@ -34,6 +33,7 @@ pub mod hrmp; pub mod inclusion; pub mod initializer; pub mod metrics; +pub mod on_demand; pub mod origin; pub mod paras; pub mod paras_inherent; @@ -53,6 +53,8 @@ mod mock; #[cfg(test)] mod ump_tests; +extern crate alloc; + pub use origin::{ensure_parachain, Origin}; pub use paras::{ParaLifecycle, UpgradeStrategy}; use polkadot_primitives::{HeadData, Id as ParaId, ValidationCode}; diff --git a/polkadot/runtime/parachains/src/mock.rs b/polkadot/runtime/parachains/src/mock.rs index 18722ff463cf2398a209bf5589d5acea3283ac84..fbe9ebf809b35f7f57589ad313f415b997fb8fe2 100644 --- a/polkadot/runtime/parachains/src/mock.rs +++ b/polkadot/runtime/parachains/src/mock.rs @@ -17,10 +17,9 @@ //! Mocks for all the traits. use crate::{ - assigner_coretime, assigner_on_demand, assigner_parachains, configuration, coretime, disputes, - dmp, hrmp, + assigner_coretime, assigner_parachains, configuration, coretime, disputes, dmp, hrmp, inclusion::{self, AggregateMessageOrigin, UmpQueueId}, - initializer, origin, paras, + initializer, on_demand, origin, paras, paras::ParaKind, paras_inherent, scheduler, scheduler::common::AssignmentProvider, @@ -36,6 +35,7 @@ use frame_support::{ Currency, ProcessMessage, ProcessMessageError, ValidatorSet, ValidatorSetWithIdentification, }, weights::{Weight, WeightMeter}, + PalletId, }; use frame_support_test::TestRandomness; use frame_system::limits; @@ -50,14 +50,13 @@ use sp_runtime::{ transaction_validity::TransactionPriority, BuildStorage, FixedU128, Perbill, Permill, }; -use sp_std::{ +use std::{ cell::RefCell, - collections::{btree_map::BTreeMap, vec_deque::VecDeque}, + collections::{btree_map::BTreeMap, vec_deque::VecDeque, HashMap}, }; -use std::collections::HashMap; use xcm::{ prelude::XcmVersion, - v4::{Assets, Location, SendError, SendResult, SendXcm, Xcm, XcmHash}, + v4::{Assets, InteriorLocation, Location, SendError, SendResult, SendXcm, Xcm, XcmHash}, IntoVersion, VersionedXcm, WrapVersion, }; @@ -78,7 +77,7 @@ frame_support::construct_runtime!( Scheduler: scheduler, MockAssigner: mock_assigner, ParachainsAssigner: assigner_parachains, - OnDemandAssigner: assigner_on_demand, + OnDemand: on_demand, CoretimeAssigner: assigner_coretime, Coretime: coretime, Initializer: initializer, @@ -391,17 +390,23 @@ impl pallet_message_queue::Config for Test { type IdleMaxServiceWeight = (); } +impl assigner_parachains::Config for Test {} + parameter_types! { pub const OnDemandTrafficDefaultValue: FixedU128 = FixedU128::from_u32(1); + // Production chains should keep this numbar around twice the + // defined Timeslice for Coretime. + pub const MaxHistoricalRevenue: BlockNumber = 2 * 5; + pub const OnDemandPalletId: PalletId = PalletId(*b"py/ondmd"); } -impl assigner_parachains::Config for Test {} - -impl assigner_on_demand::Config for Test { +impl on_demand::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type TrafficDefaultValue = OnDemandTrafficDefaultValue; - type WeightInfo = crate::assigner_on_demand::TestWeightInfo; + type WeightInfo = crate::on_demand::TestWeightInfo; + type MaxHistoricalRevenue = MaxHistoricalRevenue; + type PalletId = OnDemandPalletId; } impl assigner_coretime::Config for Test {} @@ -411,6 +416,13 @@ parameter_types! { pub MaxXcmTransactWeight: Weight = Weight::from_parts(10_000_000, 10_000); } +pub struct BrokerPot; +impl Get for BrokerPot { + fn get() -> InteriorLocation { + unimplemented!() + } +} + impl coretime::Config for Test { type RuntimeOrigin = RuntimeOrigin; type RuntimeEvent = RuntimeEvent; @@ -419,6 +431,9 @@ impl coretime::Config for Test { type WeightInfo = crate::coretime::TestWeightInfo; type SendXcm = DummyXcmSender; type MaxXcmTransactWeight = MaxXcmTransactWeight; + type BrokerPotLocation = BrokerPot; + type AssetTransactor = (); + type AccountToLocation = (); } pub struct DummyXcmSender; @@ -524,7 +539,7 @@ pub mod mock_assigner { // We don't care about core affinity in the test assigner fn report_processed(_assignment: Assignment) {} - // The results of this are tested in assigner_on_demand tests. No need to represent it + // The results of this are tested in on_demand tests. No need to represent it // in the mock assigner. fn push_back_assignment(_assignment: Assignment) {} @@ -660,7 +675,7 @@ impl inclusion::RewardValidators for TestRewardValidators { /// Create a new set of test externalities. pub fn new_test_ext(state: MockGenesisConfig) -> TestExternalities { use sp_keystore::{testing::MemoryKeystore, KeystoreExt, KeystorePtr}; - use sp_std::sync::Arc; + use std::sync::Arc; sp_tracing::try_init_simple(); diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/benchmarking.rs b/polkadot/runtime/parachains/src/on_demand/benchmarking.rs similarity index 97% rename from polkadot/runtime/parachains/src/assigner_on_demand/benchmarking.rs rename to polkadot/runtime/parachains/src/on_demand/benchmarking.rs index ba6951a146921f7f698c02bb49dcaffea76563e4..d494a77a5c4dbeee27e510e4df35f1f78741b885 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/benchmarking.rs +++ b/polkadot/runtime/parachains/src/on_demand/benchmarking.rs @@ -25,6 +25,7 @@ use crate::{ shared::Pallet as ParasShared, }; +use alloc::vec; use frame_benchmarking::v2::*; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; @@ -93,7 +94,7 @@ mod benchmarks { impl_benchmark_test_suite!( Pallet, crate::mock::new_test_ext( - crate::assigner_on_demand::mock_helpers::GenesisConfigBuilder::default().build() + crate::on_demand::mock_helpers::GenesisConfigBuilder::default().build() ), crate::mock::Test ); diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/migration.rs b/polkadot/runtime/parachains/src/on_demand/migration.rs similarity index 89% rename from polkadot/runtime/parachains/src/assigner_on_demand/migration.rs rename to polkadot/runtime/parachains/src/on_demand/migration.rs index 314be11adbeb79bab4fa0ce2d0b4f52fb5176ceb..6cc25b20afb86204aa9324949032b9df67835426 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/migration.rs +++ b/polkadot/runtime/parachains/src/on_demand/migration.rs @@ -23,7 +23,7 @@ use frame_support::{ mod v0 { use super::*; - use sp_std::collections::vec_deque::VecDeque; + use alloc::collections::vec_deque::VecDeque; #[derive(Encode, Decode, TypeInfo, Debug, PartialEq, Clone)] pub(super) struct EnqueuedOrder { @@ -47,10 +47,10 @@ mod v0 { mod v1 { use super::*; - use crate::assigner_on_demand::LOG_TARGET; + use crate::on_demand::LOG_TARGET; /// Migration to V1 - pub struct UncheckedMigrateToV1(sp_std::marker::PhantomData); + pub struct UncheckedMigrateToV1(core::marker::PhantomData); impl UncheckedOnRuntimeUpgrade for UncheckedMigrateToV1 { fn on_runtime_upgrade() -> Weight { let mut weight: Weight = Weight::zero(); @@ -88,7 +88,7 @@ mod v1 { } #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { let n: u32 = v0::OnDemandQueue::::get().len() as u32; log::info!( @@ -100,7 +100,7 @@ mod v1 { } #[cfg(feature = "try-runtime")] - fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + fn post_upgrade(state: alloc::vec::Vec) -> Result<(), sp_runtime::TryRuntimeError> { log::info!(target: LOG_TARGET, "Running post_upgrade()"); ensure!( @@ -142,7 +142,7 @@ pub type MigrateV0ToV1 = VersionedMigration< #[cfg(test)] mod tests { use super::{v0, v1, UncheckedOnRuntimeUpgrade, Weight}; - use crate::mock::{new_test_ext, MockGenesisConfig, OnDemandAssigner, Test}; + use crate::mock::{new_test_ext, MockGenesisConfig, OnDemand, Test}; use polkadot_primitives::Id as ParaId; #[test] @@ -159,7 +159,7 @@ mod tests { let old_queue = v0::OnDemandQueue::::get(); assert_eq!(old_queue.len(), 5); // New queue has 0 orders - assert_eq!(OnDemandAssigner::get_queue_status().size(), 0); + assert_eq!(OnDemand::get_queue_status().size(), 0); // For tests, db weight is zero. assert_eq!( @@ -168,10 +168,10 @@ mod tests { ); // New queue has 5 orders - assert_eq!(OnDemandAssigner::get_queue_status().size(), 5); + assert_eq!(OnDemand::get_queue_status().size(), 5); // Compare each entry from the old queue with the entry in the new queue. - old_queue.iter().zip(OnDemandAssigner::get_free_entries().iter()).for_each( + old_queue.iter().zip(OnDemand::get_free_entries().iter()).for_each( |(old_enq, new_enq)| { assert_eq!(old_enq.para_id, new_enq.para_id); }, diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/mock_helpers.rs b/polkadot/runtime/parachains/src/on_demand/mock_helpers.rs similarity index 100% rename from polkadot/runtime/parachains/src/assigner_on_demand/mock_helpers.rs rename to polkadot/runtime/parachains/src/on_demand/mock_helpers.rs diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs b/polkadot/runtime/parachains/src/on_demand/mod.rs similarity index 75% rename from polkadot/runtime/parachains/src/assigner_on_demand/mod.rs rename to polkadot/runtime/parachains/src/on_demand/mod.rs index 043a36d99c4974c5dd75f3f4172848a4707c871a..dc046c194fd0b114ba0407878dea05d497be1f1b 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs +++ b/polkadot/runtime/parachains/src/on_demand/mod.rs @@ -31,41 +31,42 @@ //! occupying multiple cores in on-demand, we will likely add a separate order type, where the //! intent can be made explicit. +use sp_runtime::traits::Zero; mod benchmarking; pub mod migration; mod mock_helpers; +mod types; extern crate alloc; #[cfg(test)] mod tests; -use core::mem::take; - use crate::{configuration, paras, scheduler::common::Assignment}; - +use alloc::collections::BinaryHeap; +use core::mem::take; use frame_support::{ pallet_prelude::*, traits::{ + defensive_prelude::*, Currency, ExistenceRequirement::{self, AllowDeath, KeepAlive}, WithdrawReasons, }, + PalletId, }; -use frame_system::pallet_prelude::*; -use polkadot_primitives::{CoreIndex, Id as ParaId, ON_DEMAND_MAX_QUEUE_MAX_SIZE}; +use frame_system::{pallet_prelude::*, Pallet as System}; +use polkadot_primitives::{CoreIndex, Id as ParaId}; use sp_runtime::{ - traits::{One, SaturatedConversion}, + traits::{AccountIdConversion, One, SaturatedConversion}, FixedPointNumber, FixedPointOperand, FixedU128, Perbill, Saturating, }; - -use alloc::collections::BinaryHeap; -use sp_std::{ - cmp::{Ord, Ordering, PartialOrd}, - prelude::*, +use types::{ + BalanceOf, CoreAffinityCount, EnqueuedOrder, QueuePushDirection, QueueStatusType, + SpotTrafficCalculationErr, }; -const LOG_TARGET: &str = "runtime::parachains::assigner-on-demand"; +const LOG_TARGET: &str = "runtime::parachains::on-demand"; pub use pallet::*; @@ -87,217 +88,6 @@ impl WeightInfo for TestWeightInfo { } } -/// Meta data for full queue. -/// -/// This includes elements with affinity and free entries. -/// -/// The actual queue is implemented via multiple priority queues. One for each core, for entries -/// which currently have a core affinity and one free queue, with entries without any affinity yet. -/// -/// The design aims to have most queue accessess be O(1) or O(log(N)). Absolute worst case is O(N). -/// Importantly this includes all accessess that happen in a single block. Even with 50 cores, the -/// total complexity of all operations in the block should maintain above complexities. In -/// particular O(N) stays O(N), it should never be O(N*cores). -/// -/// More concrete rundown on complexity: -/// -/// - insert: O(1) for placing an order, O(log(N)) for push backs. -/// - pop_assignment_for_core: O(log(N)), O(N) worst case: Can only happen for one core, next core -/// is already less work. -/// - report_processed & push back: If affinity dropped to 0, then O(N) in the worst case. Again -/// this divides per core. -/// -/// Reads still exist, also improved slightly, but worst case we fetch all entries. -#[derive(Encode, Decode, TypeInfo)] -struct QueueStatusType { - /// Last calculated traffic value. - traffic: FixedU128, - /// The next index to use. - next_index: QueueIndex, - /// Smallest index still in use. - /// - /// In case of a completely empty queue (free + affinity queues), `next_index - smallest_index - /// == 0`. - smallest_index: QueueIndex, - /// Indices that have been freed already. - /// - /// But have a hole to `smallest_index`, so we can not yet bump `smallest_index`. This binary - /// heap is roughly bounded in the number of on demand cores: - /// - /// For a single core, elements will always be processed in order. With each core added, a - /// level of out of order execution is added. - freed_indices: BinaryHeap, -} - -impl Default for QueueStatusType { - fn default() -> QueueStatusType { - QueueStatusType { - traffic: FixedU128::default(), - next_index: QueueIndex(0), - smallest_index: QueueIndex(0), - freed_indices: BinaryHeap::new(), - } - } -} - -impl QueueStatusType { - /// How many orders are queued in total? - /// - /// This includes entries which have core affinity. - fn size(&self) -> u32 { - self.next_index - .0 - .overflowing_sub(self.smallest_index.0) - .0 - .saturating_sub(self.freed_indices.len() as u32) - } - - /// Get current next index - /// - /// to use for an element newly pushed to the back of the queue. - fn push_back(&mut self) -> QueueIndex { - let QueueIndex(next_index) = self.next_index; - self.next_index = QueueIndex(next_index.overflowing_add(1).0); - QueueIndex(next_index) - } - - /// Push something to the front of the queue - fn push_front(&mut self) -> QueueIndex { - self.smallest_index = QueueIndex(self.smallest_index.0.overflowing_sub(1).0); - self.smallest_index - } - - /// The given index is no longer part of the queue. - /// - /// This updates `smallest_index` if need be. - fn consume_index(&mut self, removed_index: QueueIndex) { - if removed_index != self.smallest_index { - self.freed_indices.push(removed_index.reverse()); - return; - } - let mut index = self.smallest_index.0.overflowing_add(1).0; - // Even more to advance? - while self.freed_indices.peek() == Some(&ReverseQueueIndex(index)) { - index = index.overflowing_add(1).0; - self.freed_indices.pop(); - } - self.smallest_index = QueueIndex(index); - } -} - -/// Keeps track of how many assignments a scheduler currently has at a specific `CoreIndex` for a -/// specific `ParaId`. -#[derive(Encode, Decode, Default, Clone, Copy, TypeInfo)] -#[cfg_attr(test, derive(PartialEq, RuntimeDebug))] -struct CoreAffinityCount { - core_index: CoreIndex, - count: u32, -} - -/// An indicator as to which end of the `OnDemandQueue` an assignment will be placed. -#[cfg_attr(test, derive(RuntimeDebug))] -enum QueuePushDirection { - Back, - Front, -} - -/// Shorthand for the Balance type the runtime is using. -type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; - -/// Errors that can happen during spot traffic calculation. -#[derive(PartialEq, RuntimeDebug)] -enum SpotTrafficCalculationErr { - /// The order queue capacity is at 0. - QueueCapacityIsZero, - /// The queue size is larger than the queue capacity. - QueueSizeLargerThanCapacity, - /// Arithmetic error during division, either division by 0 or over/underflow. - Division, -} - -/// Type used for priority indices. -// NOTE: The `Ord` implementation for this type is unsound in the general case. -// Do not use it for anything but it's intended purpose. -#[derive(Encode, Decode, TypeInfo, Debug, PartialEq, Clone, Eq, Copy)] -struct QueueIndex(u32); - -/// QueueIndex with reverse ordering. -/// -/// Same as `Reverse(QueueIndex)`, but with all the needed traits implemented. -#[derive(Encode, Decode, TypeInfo, Debug, PartialEq, Clone, Eq, Copy)] -struct ReverseQueueIndex(u32); - -impl QueueIndex { - fn reverse(self) -> ReverseQueueIndex { - ReverseQueueIndex(self.0) - } -} - -impl Ord for QueueIndex { - fn cmp(&self, other: &Self) -> Ordering { - let diff = self.0.overflowing_sub(other.0).0; - if diff == 0 { - Ordering::Equal - } else if diff <= ON_DEMAND_MAX_QUEUE_MAX_SIZE { - Ordering::Greater - } else { - Ordering::Less - } - } -} - -impl PartialOrd for QueueIndex { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for ReverseQueueIndex { - fn cmp(&self, other: &Self) -> Ordering { - QueueIndex(other.0).cmp(&QueueIndex(self.0)) - } -} -impl PartialOrd for ReverseQueueIndex { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(&other)) - } -} - -/// Internal representation of an order after it has been enqueued already. -/// -/// This data structure is provided for a min BinaryHeap (Ord compares in reverse order with regards -/// to its elements) -#[derive(Encode, Decode, TypeInfo, Debug, PartialEq, Clone, Eq)] -struct EnqueuedOrder { - para_id: ParaId, - idx: QueueIndex, -} - -impl EnqueuedOrder { - fn new(idx: QueueIndex, para_id: ParaId) -> Self { - Self { idx, para_id } - } -} - -impl PartialOrd for EnqueuedOrder { - fn partial_cmp(&self, other: &Self) -> Option { - match other.idx.partial_cmp(&self.idx) { - Some(Ordering::Equal) => other.para_id.partial_cmp(&self.para_id), - o => o, - } - } -} - -impl Ord for EnqueuedOrder { - fn cmp(&self, other: &Self) -> Ordering { - match other.idx.cmp(&self.idx) { - Ordering::Equal => other.para_id.cmp(&self.para_id), - o => o, - } - } -} - #[frame_support::pallet] pub mod pallet { @@ -324,6 +114,15 @@ pub mod pallet { /// The default value for the spot traffic multiplier. #[pallet::constant] type TrafficDefaultValue: Get; + + /// The maximum number of blocks some historical revenue + /// information stored for. + #[pallet::constant] + type MaxHistoricalRevenue: Get; + + /// Identifier for the internal revenue balance. + #[pallet::constant] + type PalletId: Get; } /// Creates an empty queue status for an empty queue with initial traffic value. @@ -365,6 +164,11 @@ pub mod pallet { EntriesOnEmpty, >; + /// Keeps track of accumulated revenue from on demand order sales. + #[pallet::storage] + pub type Revenue = + StorageValue<_, BoundedVec, T::MaxHistoricalRevenue>, ValueQuery>; + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -386,6 +190,19 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { fn on_initialize(_now: BlockNumberFor) -> Weight { + // Update revenue information storage. + Revenue::::mutate(|revenue| { + if let Some(overdue) = + revenue.force_insert_keep_left(0, 0u32.into()).defensive_unwrap_or(None) + { + // We have some overdue revenue not claimed by the Coretime Chain, let's + // accumulate it at the oldest stored block + if let Some(last) = revenue.last_mut() { + *last = last.saturating_add(overdue); + } + } + }); + let config = configuration::ActiveConfig::::get(); // We need to update the spot traffic on block initialize in order to account for idle // blocks. @@ -393,8 +210,9 @@ pub mod pallet { Self::update_spot_traffic(&config, queue_status); }); - // 2 reads in config and queuestatus, at maximum 1 write to queuestatus. - T::DbWeight::get().reads_writes(2, 1) + // Reads: `Revenue`, `ActiveConfig`, `QueueStatus` + // Writes: `Revenue`, `QueueStatus` + T::DbWeight::get().reads_writes(3, 2) } } @@ -527,7 +345,8 @@ where } /// Helper function for `place_order_*` calls. Used to differentiate between placing orders - /// with a keep alive check or to allow the account to be reaped. + /// with a keep alive check or to allow the account to be reaped. The amount charged is + /// stored to the pallet account to be later paid out as revenue. /// /// Parameters: /// - `sender`: The sender of the call, funds will be withdrawn from this account. @@ -562,18 +381,40 @@ where // Is the current price higher than `max_amount` ensure!(spot_price.le(&max_amount), Error::::SpotPriceHigherThanMaxAmount); - // Charge the sending account the spot price - let _ = T::Currency::withdraw( + ensure!( + queue_status.size() < config.scheduler_params.on_demand_queue_max_size, + Error::::QueueFull + ); + + // Charge the sending account the spot price. The amount will be teleported to the + // broker chain once it requests revenue information. + let amt = T::Currency::withdraw( &sender, spot_price, WithdrawReasons::FEE, existence_requirement, )?; - ensure!( - queue_status.size() < config.scheduler_params.on_demand_queue_max_size, - Error::::QueueFull - ); + // Consume the negative imbalance and deposit it into the pallet account. Make sure the + // account preserves even without the existential deposit. + let pot = Self::account_id(); + if !System::::account_exists(&pot) { + System::::inc_providers(&pot); + } + T::Currency::resolve_creating(&pot, amt); + + // Add the amount to the current block's (index 0) revenue information. + Revenue::::mutate(|bounded_revenue| { + if let Some(current_block) = bounded_revenue.get_mut(0) { + *current_block = current_block.saturating_add(spot_price); + } else { + // Revenue has already been claimed in the same block, including the block + // itself. It shouldn't normally happen as revenue claims in the future are + // not allowed. + bounded_revenue.try_push(spot_price).defensive_ok(); + } + }); + Pallet::::add_on_demand_order(queue_status, para_id, QueuePushDirection::Back); Pallet::::deposit_event(Event::::OnDemandOrderPlaced { para_id, @@ -790,6 +631,29 @@ where }) } + /// Collect the revenue from the `when` blockheight + pub fn claim_revenue_until(when: BlockNumberFor) -> BalanceOf { + let now = >::block_number(); + let mut amount: BalanceOf = BalanceOf::::zero(); + Revenue::::mutate(|revenue| { + while !revenue.is_empty() { + let index = (revenue.len() - 1) as u32; + if when > now.saturating_sub(index.into()) { + amount = amount.saturating_add(revenue.pop().defensive_unwrap_or(0u32.into())); + } else { + break + } + } + }); + + amount + } + + /// Account of the pallet pot, where the funds from instantaneous coretime sale are accumulated. + pub fn account_id() -> T::AccountId { + T::PalletId::get().into_account_truncating() + } + /// Getter for the affinity tracker. #[cfg(test)] fn get_affinity_map(para_id: ParaId) -> Option { @@ -831,4 +695,9 @@ where fn get_traffic_default_value() -> FixedU128 { ::TrafficDefaultValue::get() } + + #[cfg(test)] + fn get_revenue() -> Vec> { + Revenue::::get().to_vec() + } } diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs b/polkadot/runtime/parachains/src/on_demand/tests.rs similarity index 59% rename from polkadot/runtime/parachains/src/assigner_on_demand/tests.rs rename to polkadot/runtime/parachains/src/on_demand/tests.rs index 5747413e71478eeb5b65984b58c3fe35beecadab..9742954118103b5b46895dde5fc7456a59bf2877 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs +++ b/polkadot/runtime/parachains/src/on_demand/tests.rs @@ -17,18 +17,27 @@ use super::*; use crate::{ - assigner_on_demand::{mock_helpers::GenesisConfigBuilder, Error}, initializer::SessionChangeNotification, mock::{ - new_test_ext, Balances, OnDemandAssigner, Paras, ParasShared, RuntimeOrigin, Scheduler, - System, Test, + new_test_ext, Balances, OnDemand, Paras, ParasShared, RuntimeOrigin, Scheduler, System, + Test, + }, + on_demand::{ + self, + mock_helpers::GenesisConfigBuilder, + types::{QueueIndex, ReverseQueueIndex}, + Error, }, paras::{ParaGenesisArgs, ParaKind}, }; -use frame_support::{assert_noop, assert_ok, error::BadOrigin}; +use alloc::collections::btree_map::BTreeMap; +use core::cmp::{Ord, Ordering}; +use frame_support::{assert_noop, assert_ok}; use pallet_balances::Error as BalancesError; -use polkadot_primitives::{BlockNumber, SessionIndex, ValidationCode}; -use sp_std::collections::btree_map::BTreeMap; +use polkadot_primitives::{ + BlockNumber, SessionIndex, ValidationCode, ON_DEMAND_MAX_QUEUE_MAX_SIZE, +}; +use sp_runtime::traits::BadOrigin; fn schedule_blank_para(id: ParaId, parakind: ParaKind) { let validation_code: ValidationCode = vec![1, 2, 3].into(); @@ -73,27 +82,37 @@ fn run_to_block( Paras::initializer_initialize(b + 1); Scheduler::initializer_initialize(b + 1); - // We need to update the spot traffic on every block. - OnDemandAssigner::on_initialize(b + 1); + // Update the spot traffic and revenue on every block. + OnDemand::on_initialize(b + 1); // In the real runtime this is expected to be called by the `InclusionInherent` pallet. Scheduler::free_cores_and_fill_claim_queue(BTreeMap::new(), b + 1); } } -fn place_order(para_id: ParaId) { +fn place_order_run_to_blocknumber(para_id: ParaId, blocknumber: Option) { let alice = 100u64; let amt = 10_000_000u128; Balances::make_free_balance_be(&alice, amt); - run_to_block(101, |n| if n == 101 { Some(Default::default()) } else { None }); - OnDemandAssigner::place_order_allow_death(RuntimeOrigin::signed(alice), amt, para_id).unwrap() + if let Some(bn) = blocknumber { + run_to_block(bn, |n| if n == bn { Some(Default::default()) } else { None }); + } + OnDemand::place_order_allow_death(RuntimeOrigin::signed(alice), amt, para_id).unwrap() +} + +fn place_order_run_to_101(para_id: ParaId) { + place_order_run_to_blocknumber(para_id, Some(101)); +} + +fn place_order(para_id: ParaId) { + place_order_run_to_blocknumber(para_id, None); } #[test] fn spot_traffic_capacity_zero_returns_none() { - match OnDemandAssigner::calculate_spot_traffic( + match OnDemand::calculate_spot_traffic( FixedU128::from(u128::MAX), 0u32, u32::MAX, @@ -107,7 +126,7 @@ fn spot_traffic_capacity_zero_returns_none() { #[test] fn spot_traffic_queue_size_larger_than_capacity_returns_none() { - match OnDemandAssigner::calculate_spot_traffic( + match OnDemand::calculate_spot_traffic( FixedU128::from(u128::MAX), 1u32, 2u32, @@ -121,7 +140,7 @@ fn spot_traffic_queue_size_larger_than_capacity_returns_none() { #[test] fn spot_traffic_calculation_identity() { - match OnDemandAssigner::calculate_spot_traffic( + match OnDemand::calculate_spot_traffic( FixedU128::from_u32(1), 1000, 100, @@ -137,7 +156,7 @@ fn spot_traffic_calculation_identity() { #[test] fn spot_traffic_calculation_u32_max() { - match OnDemandAssigner::calculate_spot_traffic( + match OnDemand::calculate_spot_traffic( FixedU128::from_u32(1), u32::MAX, u32::MAX, @@ -153,7 +172,7 @@ fn spot_traffic_calculation_u32_max() { #[test] fn spot_traffic_calculation_u32_traffic_max() { - match OnDemandAssigner::calculate_spot_traffic( + match OnDemand::calculate_spot_traffic( FixedU128::from(u128::MAX), u32::MAX, u32::MAX, @@ -169,7 +188,7 @@ fn spot_traffic_calculation_u32_traffic_max() { fn sustained_target_increases_spot_traffic() { let mut traffic = FixedU128::from_u32(1u32); for _ in 0..50 { - traffic = OnDemandAssigner::calculate_spot_traffic( + traffic = OnDemand::calculate_spot_traffic( traffic, 100, 12, @@ -184,7 +203,7 @@ fn sustained_target_increases_spot_traffic() { #[test] fn spot_traffic_can_decrease() { let traffic = FixedU128::from_u32(100u32); - match OnDemandAssigner::calculate_spot_traffic( + match OnDemand::calculate_spot_traffic( traffic, 100u32, 0u32, @@ -201,7 +220,7 @@ fn spot_traffic_can_decrease() { fn spot_traffic_decreases_over_time() { let mut traffic = FixedU128::from_u32(100u32); for _ in 0..5 { - traffic = OnDemandAssigner::calculate_spot_traffic( + traffic = OnDemand::calculate_spot_traffic( traffic, 100u32, 0u32, @@ -230,23 +249,20 @@ fn spot_traffic_decreases_between_idle_blocks() { assert!(Paras::is_parathread(para_id)); // Set the spot traffic to a large number - OnDemandAssigner::set_queue_status(QueueStatusType { + OnDemand::set_queue_status(QueueStatusType { traffic: FixedU128::from_u32(10), ..Default::default() }); - assert_eq!(OnDemandAssigner::get_queue_status().traffic, FixedU128::from_u32(10)); + assert_eq!(OnDemand::get_queue_status().traffic, FixedU128::from_u32(10)); // Run to block 101 and ensure that the traffic decreases. run_to_block(101, |n| if n == 100 { Some(Default::default()) } else { None }); - assert!(OnDemandAssigner::get_queue_status().traffic < FixedU128::from_u32(10)); + assert!(OnDemand::get_queue_status().traffic < FixedU128::from_u32(10)); // Run to block 102 and observe that we've hit the default traffic value. run_to_block(102, |n| if n == 100 { Some(Default::default()) } else { None }); - assert_eq!( - OnDemandAssigner::get_queue_status().traffic, - OnDemandAssigner::get_traffic_default_value() - ); + assert_eq!(OnDemand::get_queue_status().traffic, OnDemand::get_traffic_default_value()); }) } @@ -268,35 +284,27 @@ fn place_order_works() { // Does not work unsigned assert_noop!( - OnDemandAssigner::place_order_allow_death(RuntimeOrigin::none(), amt, para_id), + OnDemand::place_order_allow_death(RuntimeOrigin::none(), amt, para_id), BadOrigin ); // Does not work with max_amount lower than fee let low_max_amt = 1u128; assert_noop!( - OnDemandAssigner::place_order_allow_death( - RuntimeOrigin::signed(alice), - low_max_amt, - para_id, - ), + OnDemand::place_order_allow_death(RuntimeOrigin::signed(alice), low_max_amt, para_id,), Error::::SpotPriceHigherThanMaxAmount, ); // Does not work with insufficient balance assert_noop!( - OnDemandAssigner::place_order_allow_death(RuntimeOrigin::signed(alice), amt, para_id), + OnDemand::place_order_allow_death(RuntimeOrigin::signed(alice), amt, para_id), BalancesError::::InsufficientBalance ); // Works Balances::make_free_balance_be(&alice, amt); run_to_block(101, |n| if n == 101 { Some(Default::default()) } else { None }); - assert_ok!(OnDemandAssigner::place_order_allow_death( - RuntimeOrigin::signed(alice), - amt, - para_id - )); + assert_ok!(OnDemand::place_order_allow_death(RuntimeOrigin::signed(alice), amt, para_id)); }); } @@ -317,11 +325,7 @@ fn place_order_keep_alive_keeps_alive() { assert!(Paras::is_parathread(para_id)); assert_noop!( - OnDemandAssigner::place_order_keep_alive( - RuntimeOrigin::signed(alice), - max_amt, - para_id - ), + OnDemand::place_order_keep_alive(RuntimeOrigin::signed(alice), max_amt, para_id), BalancesError::::InsufficientBalance ); }); @@ -338,7 +342,7 @@ fn pop_assignment_for_core_works() { run_to_block(11, |n| if n == 11 { Some(Default::default()) } else { None }); // Pop should return none with empty queue - assert_eq!(OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)), None); + assert_eq!(OnDemand::pop_assignment_for_core(CoreIndex(0)), None); // Add enough assignments to the order queue. for _ in 0..2 { @@ -348,19 +352,19 @@ fn pop_assignment_for_core_works() { // Popped assignments should be for the correct paras and cores assert_eq!( - OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)).map(|a| a.para_id()), + OnDemand::pop_assignment_for_core(CoreIndex(0)).map(|a| a.para_id()), Some(para_a) ); assert_eq!( - OnDemandAssigner::pop_assignment_for_core(CoreIndex(1)).map(|a| a.para_id()), + OnDemand::pop_assignment_for_core(CoreIndex(1)).map(|a| a.para_id()), Some(para_b) ); assert_eq!( - OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)).map(|a| a.para_id()), + OnDemand::pop_assignment_for_core(CoreIndex(0)).map(|a| a.para_id()), Some(para_a) ); assert_eq!( - OnDemandAssigner::pop_assignment_for_core(CoreIndex(1)).map(|a| a.para_id()), + OnDemand::pop_assignment_for_core(CoreIndex(1)).map(|a| a.para_id()), Some(para_b) ); }); @@ -377,34 +381,25 @@ fn push_back_assignment_works() { run_to_block(11, |n| if n == 11 { Some(Default::default()) } else { None }); // Add enough assignments to the order queue. - place_order(para_a); - place_order(para_b); + place_order_run_to_101(para_a); + place_order_run_to_101(para_b); // Pop order a - assert_eq!( - OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)).unwrap().para_id(), - para_a - ); + assert_eq!(OnDemand::pop_assignment_for_core(CoreIndex(0)).unwrap().para_id(), para_a); // Para a should have affinity for core 0 - assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 1); - assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().core_index, CoreIndex(0)); + assert_eq!(OnDemand::get_affinity_map(para_a).unwrap().count, 1); + assert_eq!(OnDemand::get_affinity_map(para_a).unwrap().core_index, CoreIndex(0)); // Push back order a - OnDemandAssigner::push_back_assignment(para_a, CoreIndex(0)); + OnDemand::push_back_assignment(para_a, CoreIndex(0)); // Para a should have no affinity - assert_eq!(OnDemandAssigner::get_affinity_map(para_a).is_none(), true); + assert_eq!(OnDemand::get_affinity_map(para_a).is_none(), true); // Queue should contain orders a, b. A in front of b. - assert_eq!( - OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)).unwrap().para_id(), - para_a - ); - assert_eq!( - OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)).unwrap().para_id(), - para_b - ); + assert_eq!(OnDemand::pop_assignment_for_core(CoreIndex(0)).unwrap().para_id(), para_a); + assert_eq!(OnDemand::pop_assignment_for_core(CoreIndex(0)).unwrap().para_id(), para_b); }); } @@ -420,59 +415,59 @@ fn affinity_prohibits_parallel_scheduling() { run_to_block(11, |n| if n == 11 { Some(Default::default()) } else { None }); // There should be no affinity before starting. - assert!(OnDemandAssigner::get_affinity_map(para_a).is_none()); - assert!(OnDemandAssigner::get_affinity_map(para_b).is_none()); + assert!(OnDemand::get_affinity_map(para_a).is_none()); + assert!(OnDemand::get_affinity_map(para_b).is_none()); // Add 2 assignments for para_a for every para_b. - place_order(para_a); - place_order(para_a); - place_order(para_b); + place_order_run_to_101(para_a); + place_order_run_to_101(para_a); + place_order_run_to_101(para_b); // Approximate having 1 core. for _ in 0..3 { - assert!(OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)).is_some()); + assert!(OnDemand::pop_assignment_for_core(CoreIndex(0)).is_some()); } - assert!(OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)).is_none()); + assert!(OnDemand::pop_assignment_for_core(CoreIndex(0)).is_none()); // Affinity on one core is meaningless. - assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 2); - assert_eq!(OnDemandAssigner::get_affinity_map(para_b).unwrap().count, 1); + assert_eq!(OnDemand::get_affinity_map(para_a).unwrap().count, 2); + assert_eq!(OnDemand::get_affinity_map(para_b).unwrap().count, 1); assert_eq!( - OnDemandAssigner::get_affinity_map(para_a).unwrap().core_index, - OnDemandAssigner::get_affinity_map(para_b).unwrap().core_index, + OnDemand::get_affinity_map(para_a).unwrap().core_index, + OnDemand::get_affinity_map(para_b).unwrap().core_index, ); // Clear affinity - OnDemandAssigner::report_processed(para_a, 0.into()); - OnDemandAssigner::report_processed(para_a, 0.into()); - OnDemandAssigner::report_processed(para_b, 0.into()); + OnDemand::report_processed(para_a, 0.into()); + OnDemand::report_processed(para_a, 0.into()); + OnDemand::report_processed(para_b, 0.into()); // Add 2 assignments for para_a for every para_b. - place_order(para_a); - place_order(para_a); - place_order(para_b); + place_order_run_to_101(para_a); + place_order_run_to_101(para_a); + place_order_run_to_101(para_b); // Approximate having 3 cores. CoreIndex 2 should be unable to obtain an assignment for _ in 0..3 { - OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)); - OnDemandAssigner::pop_assignment_for_core(CoreIndex(1)); - assert!(OnDemandAssigner::pop_assignment_for_core(CoreIndex(2)).is_none()); + OnDemand::pop_assignment_for_core(CoreIndex(0)); + OnDemand::pop_assignment_for_core(CoreIndex(1)); + assert!(OnDemand::pop_assignment_for_core(CoreIndex(2)).is_none()); } // Affinity should be the same as before, but on different cores. - assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 2); - assert_eq!(OnDemandAssigner::get_affinity_map(para_b).unwrap().count, 1); - assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().core_index, CoreIndex(0)); - assert_eq!(OnDemandAssigner::get_affinity_map(para_b).unwrap().core_index, CoreIndex(1)); + assert_eq!(OnDemand::get_affinity_map(para_a).unwrap().count, 2); + assert_eq!(OnDemand::get_affinity_map(para_b).unwrap().count, 1); + assert_eq!(OnDemand::get_affinity_map(para_a).unwrap().core_index, CoreIndex(0)); + assert_eq!(OnDemand::get_affinity_map(para_b).unwrap().core_index, CoreIndex(1)); // Clear affinity - OnDemandAssigner::report_processed(para_a, CoreIndex(0)); - OnDemandAssigner::report_processed(para_a, CoreIndex(0)); - OnDemandAssigner::report_processed(para_b, CoreIndex(1)); + OnDemand::report_processed(para_a, CoreIndex(0)); + OnDemand::report_processed(para_a, CoreIndex(0)); + OnDemand::report_processed(para_b, CoreIndex(1)); // There should be no affinity after clearing. - assert!(OnDemandAssigner::get_affinity_map(para_a).is_none()); - assert!(OnDemandAssigner::get_affinity_map(para_b).is_none()); + assert!(OnDemand::get_affinity_map(para_a).is_none()); + assert!(OnDemand::get_affinity_map(para_b).is_none()); }); } @@ -486,54 +481,54 @@ fn affinity_changes_work() { run_to_block(11, |n| if n == 11 { Some(Default::default()) } else { None }); // There should be no affinity before starting. - assert!(OnDemandAssigner::get_affinity_map(para_a).is_none()); + assert!(OnDemand::get_affinity_map(para_a).is_none()); // Add enough assignments to the order queue. for _ in 0..10 { - place_order(para_a); + place_order_run_to_101(para_a); } // There should be no affinity before the scheduler pops. - assert!(OnDemandAssigner::get_affinity_map(para_a).is_none()); + assert!(OnDemand::get_affinity_map(para_a).is_none()); - OnDemandAssigner::pop_assignment_for_core(core_index); + OnDemand::pop_assignment_for_core(core_index); // Affinity count is 1 after popping. - assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 1); + assert_eq!(OnDemand::get_affinity_map(para_a).unwrap().count, 1); - OnDemandAssigner::report_processed(para_a, 0.into()); - OnDemandAssigner::pop_assignment_for_core(core_index); + OnDemand::report_processed(para_a, 0.into()); + OnDemand::pop_assignment_for_core(core_index); // Affinity count is 1 after popping with a previous para. - assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 1); + assert_eq!(OnDemand::get_affinity_map(para_a).unwrap().count, 1); for _ in 0..3 { - OnDemandAssigner::pop_assignment_for_core(core_index); + OnDemand::pop_assignment_for_core(core_index); } // Affinity count is 4 after popping 3 times without a previous para. - assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 4); + assert_eq!(OnDemand::get_affinity_map(para_a).unwrap().count, 4); for _ in 0..5 { - OnDemandAssigner::report_processed(para_a, 0.into()); - assert!(OnDemandAssigner::pop_assignment_for_core(core_index).is_some()); + OnDemand::report_processed(para_a, 0.into()); + assert!(OnDemand::pop_assignment_for_core(core_index).is_some()); } // Affinity count should still be 4 but queue should be empty. - assert!(OnDemandAssigner::pop_assignment_for_core(core_index).is_none()); - assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 4); + assert!(OnDemand::pop_assignment_for_core(core_index).is_none()); + assert_eq!(OnDemand::get_affinity_map(para_a).unwrap().count, 4); // Pop 4 times and get to exactly 0 (None) affinity. for _ in 0..4 { - OnDemandAssigner::report_processed(para_a, 0.into()); - assert!(OnDemandAssigner::pop_assignment_for_core(core_index).is_none()); + OnDemand::report_processed(para_a, 0.into()); + assert!(OnDemand::pop_assignment_for_core(core_index).is_none()); } - assert!(OnDemandAssigner::get_affinity_map(para_a).is_none()); + assert!(OnDemand::get_affinity_map(para_a).is_none()); // Decreasing affinity beyond 0 should still be None. - OnDemandAssigner::report_processed(para_a, 0.into()); - assert!(OnDemandAssigner::pop_assignment_for_core(core_index).is_none()); - assert!(OnDemandAssigner::get_affinity_map(para_a).is_none()); + OnDemand::report_processed(para_a, 0.into()); + assert!(OnDemand::pop_assignment_for_core(core_index).is_none()); + assert!(OnDemand::get_affinity_map(para_a).is_none()); }); } @@ -554,32 +549,29 @@ fn new_affinity_for_a_core_must_come_from_free_entries() { // Place orders for all chains. parachains.iter().for_each(|chain| { - place_order(*chain); + place_order_run_to_101(*chain); }); // There are 4 entries in free_entries. - let start_free_entries = OnDemandAssigner::get_free_entries().len(); + let start_free_entries = OnDemand::get_free_entries().len(); assert_eq!(start_free_entries, 4); // Pop assignments on all cores. core_indices.iter().enumerate().for_each(|(n, core_index)| { // There is no affinity on the core prior to popping. - assert!(OnDemandAssigner::get_affinity_entries(*core_index).is_empty()); + assert!(OnDemand::get_affinity_entries(*core_index).is_empty()); // There's always an order to be popped for each core. - let free_entries = OnDemandAssigner::get_free_entries(); + let free_entries = OnDemand::get_free_entries(); let next_order = free_entries.peek(); // There is no affinity on the paraid prior to popping. - assert!(OnDemandAssigner::get_affinity_map(next_order.unwrap().para_id).is_none()); + assert!(OnDemand::get_affinity_map(next_order.unwrap().para_id).is_none()); - match OnDemandAssigner::pop_assignment_for_core(*core_index) { + match OnDemand::pop_assignment_for_core(*core_index) { Some(assignment) => { // The popped assignment came from free entries. - assert_eq!( - start_free_entries - 1 - n, - OnDemandAssigner::get_free_entries().len() - ); + assert_eq!(start_free_entries - 1 - n, OnDemand::get_free_entries().len()); // The popped assignment has the same para id as the next order. assert_eq!(assignment.para_id(), next_order.unwrap().para_id); }, @@ -588,11 +580,11 @@ fn new_affinity_for_a_core_must_come_from_free_entries() { }); // All entries have been removed from free_entries. - assert!(OnDemandAssigner::get_free_entries().is_empty()); + assert!(OnDemand::get_free_entries().is_empty()); // All chains have an affinity count of 1. parachains.iter().for_each(|chain| { - assert_eq!(OnDemandAssigner::get_affinity_map(*chain).unwrap().count, 1); + assert_eq!(OnDemand::get_affinity_map(*chain).unwrap().count, 1); }); }); } @@ -672,38 +664,151 @@ fn queue_status_size_fn_works() { schedule_blank_para(*chain, ParaKind::Parathread); }); - assert_eq!(OnDemandAssigner::get_queue_status().size(), 0); + assert_eq!(OnDemand::get_queue_status().size(), 0); run_to_block(11, |n| if n == 11 { Some(Default::default()) } else { None }); // Place orders for all chains. parachains.iter().for_each(|chain| { // 2 per chain for a total of 6 - place_order(*chain); - place_order(*chain); + place_order_run_to_101(*chain); + place_order_run_to_101(*chain); }); // 6 orders in free entries - assert_eq!(OnDemandAssigner::get_free_entries().len(), 6); + assert_eq!(OnDemand::get_free_entries().len(), 6); // 6 orders via queue status size assert_eq!( - OnDemandAssigner::get_free_entries().len(), - OnDemandAssigner::get_queue_status().size() as usize + OnDemand::get_free_entries().len(), + OnDemand::get_queue_status().size() as usize ); core_indices.iter().for_each(|core_index| { - OnDemandAssigner::pop_assignment_for_core(*core_index); + OnDemand::pop_assignment_for_core(*core_index); }); // There should be 2 orders in the scheduler's claimqueue, // 2 in assorted AffinityMaps and 2 in free. // ParaId 111 - assert_eq!(OnDemandAssigner::get_affinity_entries(core_indices[0]).len(), 1); + assert_eq!(OnDemand::get_affinity_entries(core_indices[0]).len(), 1); // ParaId 222 - assert_eq!(OnDemandAssigner::get_affinity_entries(core_indices[1]).len(), 1); + assert_eq!(OnDemand::get_affinity_entries(core_indices[1]).len(), 1); // Free entries are from ParaId 333 - assert_eq!(OnDemandAssigner::get_free_entries().len(), 2); + assert_eq!(OnDemand::get_free_entries().len(), 2); // For a total size of 4. - assert_eq!(OnDemandAssigner::get_queue_status().size(), 4) + assert_eq!(OnDemand::get_queue_status().size(), 4) + }); +} + +#[test] +fn revenue_information_fetching_works() { + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + let para_a = ParaId::from(111); + schedule_blank_para(para_a, ParaKind::Parathread); + // Mock assigner sets max revenue history to 10. + run_to_block(10, |n| if n == 10 { Some(Default::default()) } else { None }); + let revenue = OnDemand::claim_revenue_until(10); + + // No revenue should be recorded. + assert_eq!(revenue, 0); + + // Place one order + place_order_run_to_blocknumber(para_a, Some(11)); + let revenue = OnDemand::get_revenue(); + let amt = OnDemand::claim_revenue_until(11); + + // Revenue until the current block is still zero as "until" is non-inclusive + assert_eq!(amt, 0); + + let amt = OnDemand::claim_revenue_until(12); + + // Revenue for a single order should be recorded and shouldn't have been pruned by the + // previous call + assert_eq!(amt, revenue[0]); + + run_to_block(12, |n| if n == 12 { Some(Default::default()) } else { None }); + let revenue = OnDemand::claim_revenue_until(13); + + // No revenue should be recorded. + assert_eq!(revenue, 0); + + // Place many orders + place_order(para_a); + place_order(para_a); + + run_to_block(13, |n| if n == 13 { Some(Default::default()) } else { None }); + + place_order(para_a); + + run_to_block(14, |n| if n == 14 { Some(Default::default()) } else { None }); + + let revenue = OnDemand::claim_revenue_until(15); + + // All 3 orders should be accounted for. + assert_eq!(revenue, 30_000); + + // Place one order + place_order_run_to_blocknumber(para_a, Some(16)); + + let revenue = OnDemand::claim_revenue_until(15); + + // Order is not in range of the revenue_until call + assert_eq!(revenue, 0); + + run_to_block(20, |n| if n == 20 { Some(Default::default()) } else { None }); + let revenue = OnDemand::claim_revenue_until(21); + assert_eq!(revenue, 10_000); + + // Make sure overdue revenue is accumulated + for i in 21..=35 { + run_to_block(i, |n| if n % 10 == 0 { Some(Default::default()) } else { None }); + place_order(para_a); + } + let revenue = OnDemand::claim_revenue_until(36); + assert_eq!(revenue, 150_000); + }); +} + +#[test] +fn pot_account_is_immortal() { + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + let para_a = ParaId::from(111); + let pot = OnDemand::account_id(); + assert!(!System::account_exists(&pot)); + schedule_blank_para(para_a, ParaKind::Parathread); + // Mock assigner sets max revenue history to 10. + + run_to_block(10, |n| if n == 10 { Some(Default::default()) } else { None }); + place_order_run_to_blocknumber(para_a, Some(12)); + let purchase_revenue = Balances::free_balance(&pot); + assert!(purchase_revenue > 0); + + run_to_block(15, |_| None); + let _imb = ::Currency::withdraw( + &pot, + purchase_revenue, + WithdrawReasons::FEE, + ExistenceRequirement::AllowDeath, + ); + assert_eq!(Balances::free_balance(&pot), 0); + assert!(System::account_exists(&pot)); + assert_eq!(System::providers(&pot), 1); + + // One more cycle to make sure providers are not increased on every transition from zero + run_to_block(20, |n| if n == 20 { Some(Default::default()) } else { None }); + place_order_run_to_blocknumber(para_a, Some(22)); + let purchase_revenue = Balances::free_balance(&pot); + assert!(purchase_revenue > 0); + + run_to_block(25, |_| None); + let _imb = ::Currency::withdraw( + &pot, + purchase_revenue, + WithdrawReasons::FEE, + ExistenceRequirement::AllowDeath, + ); + assert_eq!(Balances::free_balance(&pot), 0); + assert!(System::account_exists(&pot)); + assert_eq!(System::providers(&pot), 1); }); } diff --git a/polkadot/runtime/parachains/src/on_demand/types.rs b/polkadot/runtime/parachains/src/on_demand/types.rs new file mode 100644 index 0000000000000000000000000000000000000000..c87e7abaf86071f6233d4ed6532b3813c45e2a7f --- /dev/null +++ b/polkadot/runtime/parachains/src/on_demand/types.rs @@ -0,0 +1,238 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! On demand module types. + +use super::{alloc, pallet::Config}; +use alloc::collections::BinaryHeap; +use core::cmp::{Ord, Ordering, PartialOrd}; +use frame_support::{ + pallet_prelude::{Decode, Encode, RuntimeDebug, TypeInfo}, + traits::Currency, +}; +use polkadot_primitives::{CoreIndex, Id as ParaId, ON_DEMAND_MAX_QUEUE_MAX_SIZE}; +use sp_runtime::FixedU128; + +/// Shorthand for the Balance type the runtime is using. +pub type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + +/// Meta data for full queue. +/// +/// This includes elements with affinity and free entries. +/// +/// The actual queue is implemented via multiple priority queues. One for each core, for entries +/// which currently have a core affinity and one free queue, with entries without any affinity yet. +/// +/// The design aims to have most queue accessess be O(1) or O(log(N)). Absolute worst case is O(N). +/// Importantly this includes all accessess that happen in a single block. Even with 50 cores, the +/// total complexity of all operations in the block should maintain above complexities. In +/// particular O(N) stays O(N), it should never be O(N*cores). +/// +/// More concrete rundown on complexity: +/// +/// - insert: O(1) for placing an order, O(log(N)) for push backs. +/// - pop_assignment_for_core: O(log(N)), O(N) worst case: Can only happen for one core, next core +/// is already less work. +/// - report_processed & push back: If affinity dropped to 0, then O(N) in the worst case. Again +/// this divides per core. +/// +/// Reads still exist, also improved slightly, but worst case we fetch all entries. +#[derive(Encode, Decode, TypeInfo)] +pub struct QueueStatusType { + /// Last calculated traffic value. + pub traffic: FixedU128, + /// The next index to use. + pub next_index: QueueIndex, + /// Smallest index still in use. + /// + /// In case of a completely empty queue (free + affinity queues), `next_index - smallest_index + /// == 0`. + pub smallest_index: QueueIndex, + /// Indices that have been freed already. + /// + /// But have a hole to `smallest_index`, so we can not yet bump `smallest_index`. This binary + /// heap is roughly bounded in the number of on demand cores: + /// + /// For a single core, elements will always be processed in order. With each core added, a + /// level of out of order execution is added. + pub freed_indices: BinaryHeap, +} + +impl Default for QueueStatusType { + fn default() -> QueueStatusType { + QueueStatusType { + traffic: FixedU128::default(), + next_index: QueueIndex(0), + smallest_index: QueueIndex(0), + freed_indices: BinaryHeap::new(), + } + } +} + +impl QueueStatusType { + /// How many orders are queued in total? + /// + /// This includes entries which have core affinity. + pub fn size(&self) -> u32 { + self.next_index + .0 + .overflowing_sub(self.smallest_index.0) + .0 + .saturating_sub(self.freed_indices.len() as u32) + } + + /// Get current next index + /// + /// to use for an element newly pushed to the back of the queue. + pub fn push_back(&mut self) -> QueueIndex { + let QueueIndex(next_index) = self.next_index; + self.next_index = QueueIndex(next_index.overflowing_add(1).0); + QueueIndex(next_index) + } + + /// Push something to the front of the queue + pub fn push_front(&mut self) -> QueueIndex { + self.smallest_index = QueueIndex(self.smallest_index.0.overflowing_sub(1).0); + self.smallest_index + } + + /// The given index is no longer part of the queue. + /// + /// This updates `smallest_index` if need be. + pub fn consume_index(&mut self, removed_index: QueueIndex) { + if removed_index != self.smallest_index { + self.freed_indices.push(removed_index.reverse()); + return + } + let mut index = self.smallest_index.0.overflowing_add(1).0; + // Even more to advance? + while self.freed_indices.peek() == Some(&ReverseQueueIndex(index)) { + index = index.overflowing_add(1).0; + self.freed_indices.pop(); + } + self.smallest_index = QueueIndex(index); + } +} + +/// Type used for priority indices. +// NOTE: The `Ord` implementation for this type is unsound in the general case. +// Do not use it for anything but it's intended purpose. +#[derive(Encode, Decode, TypeInfo, Debug, PartialEq, Clone, Eq, Copy)] +pub struct QueueIndex(pub u32); + +/// QueueIndex with reverse ordering. +/// +/// Same as `Reverse(QueueIndex)`, but with all the needed traits implemented. +#[derive(Encode, Decode, TypeInfo, Debug, PartialEq, Clone, Eq, Copy)] +pub struct ReverseQueueIndex(pub u32); + +impl QueueIndex { + fn reverse(self) -> ReverseQueueIndex { + ReverseQueueIndex(self.0) + } +} + +impl Ord for QueueIndex { + fn cmp(&self, other: &Self) -> Ordering { + let diff = self.0.overflowing_sub(other.0).0; + if diff == 0 { + Ordering::Equal + } else if diff <= ON_DEMAND_MAX_QUEUE_MAX_SIZE { + Ordering::Greater + } else { + Ordering::Less + } + } +} + +impl PartialOrd for QueueIndex { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for ReverseQueueIndex { + fn cmp(&self, other: &Self) -> Ordering { + QueueIndex(other.0).cmp(&QueueIndex(self.0)) + } +} +impl PartialOrd for ReverseQueueIndex { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(&other)) + } +} + +/// Internal representation of an order after it has been enqueued already. +/// +/// This data structure is provided for a min BinaryHeap (Ord compares in reverse order with regards +/// to its elements) +#[derive(Encode, Decode, TypeInfo, Debug, PartialEq, Clone, Eq)] +pub struct EnqueuedOrder { + pub para_id: ParaId, + pub idx: QueueIndex, +} + +impl EnqueuedOrder { + pub fn new(idx: QueueIndex, para_id: ParaId) -> Self { + Self { idx, para_id } + } +} + +impl PartialOrd for EnqueuedOrder { + fn partial_cmp(&self, other: &Self) -> Option { + match other.idx.partial_cmp(&self.idx) { + Some(Ordering::Equal) => other.para_id.partial_cmp(&self.para_id), + o => o, + } + } +} + +impl Ord for EnqueuedOrder { + fn cmp(&self, other: &Self) -> Ordering { + match other.idx.cmp(&self.idx) { + Ordering::Equal => other.para_id.cmp(&self.para_id), + o => o, + } + } +} + +/// Keeps track of how many assignments a scheduler currently has at a specific `CoreIndex` for a +/// specific `ParaId`. +#[derive(Encode, Decode, Default, Clone, Copy, TypeInfo)] +#[cfg_attr(test, derive(PartialEq, RuntimeDebug))] +pub struct CoreAffinityCount { + pub core_index: CoreIndex, + pub count: u32, +} + +/// An indicator as to which end of the `OnDemandQueue` an assignment will be placed. +#[cfg_attr(test, derive(RuntimeDebug))] +pub enum QueuePushDirection { + Back, + Front, +} + +/// Errors that can happen during spot traffic calculation. +#[derive(PartialEq, RuntimeDebug)] +pub enum SpotTrafficCalculationErr { + /// The order queue capacity is at 0. + QueueCapacityIsZero, + /// The queue size is larger than the queue capacity. + QueueSizeLargerThanCapacity, + /// Arithmetic error during division, either division by 0 or over/underflow. + Division, +} diff --git a/polkadot/runtime/parachains/src/origin.rs b/polkadot/runtime/parachains/src/origin.rs index 5202cba232d20a9f4303747f55c50ce144a0d68f..fd22929b08ff547398c7f731e9a823a780391a6c 100644 --- a/polkadot/runtime/parachains/src/origin.rs +++ b/polkadot/runtime/parachains/src/origin.rs @@ -16,9 +16,9 @@ //! Declaration of the parachain specific origin and a pallet that hosts it. +use core::result; use polkadot_primitives::Id as ParaId; use sp_runtime::traits::BadOrigin; -use sp_std::result; pub use pallet::*; diff --git a/polkadot/runtime/parachains/src/paras/benchmarking.rs b/polkadot/runtime/parachains/src/paras/benchmarking.rs index 0f3318612a77c7bc2ec831e2c7ac67c08eae0392..7bf8b833ed915df49aabcb9047ec889076836af0 100644 --- a/polkadot/runtime/parachains/src/paras/benchmarking.rs +++ b/polkadot/runtime/parachains/src/paras/benchmarking.rs @@ -16,6 +16,7 @@ use super::*; use crate::configuration::HostConfiguration; +use alloc::vec; use frame_benchmarking::benchmarks; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use polkadot_primitives::{ @@ -23,6 +24,7 @@ use polkadot_primitives::{ }; use sp_runtime::traits::{One, Saturating}; +pub mod mmr_setup; mod pvf_check; use self::pvf_check::{VoteCause, VoteOutcome}; diff --git a/polkadot/runtime/parachains/src/paras/benchmarking/mmr_setup.rs b/polkadot/runtime/parachains/src/paras/benchmarking/mmr_setup.rs new file mode 100644 index 0000000000000000000000000000000000000000..ab007692e78dc2e3b56dfdd4ad682accdfa0c037 --- /dev/null +++ b/polkadot/runtime/parachains/src/paras/benchmarking/mmr_setup.rs @@ -0,0 +1,40 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Implements benchmarking setup for the `merkle-mountain-range` pallet. + +use crate::paras::*; +use pallet_mmr::BenchmarkHelper; +use sp_std::vec; + +/// Struct to setup benchmarks for the `merkle-mountain-range` pallet. +pub struct MmrSetup(core::marker::PhantomData); + +impl BenchmarkHelper for MmrSetup +where + T: Config, +{ + fn setup() { + // Create a head with 1024 bytes of data. + let head = vec![42u8; 1024]; + + for para in 0..MAX_PARA_HEADS { + let id = (para as u32).into(); + let h = head.clone().into(); + Pallet::::heads_insert(&id, h); + } + } +} diff --git a/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs b/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs index 0bf5fe783a0e7bc51e473240f87bcdb7692e5414..80443c7626e2b438ff754d140aa22f91bdc16805 100644 --- a/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs +++ b/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs @@ -17,6 +17,7 @@ //! This module focuses on the benchmarking of the `include_pvf_check_statement` dispatchable. use crate::{configuration, paras::*, shared::Pallet as ParasShared}; +use alloc::{vec, vec::Vec}; use frame_support::assert_ok; use frame_system::RawOrigin; use polkadot_primitives::{HeadData, Id as ParaId, ValidationCode, ValidatorId, ValidatorIndex}; diff --git a/polkadot/runtime/parachains/src/paras/mod.rs b/polkadot/runtime/parachains/src/paras/mod.rs index 8cffcbbbb024fd454f57ed89c7448ffc297e0977..a4c404de2a651d0a4359a59fa9efb66b275defe8 100644 --- a/polkadot/runtime/parachains/src/paras/mod.rs +++ b/polkadot/runtime/parachains/src/paras/mod.rs @@ -113,8 +113,10 @@ use crate::{ initializer::SessionChangeNotification, shared, }; +use alloc::{collections::btree_set::BTreeSet, vec::Vec}; use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; use codec::{Decode, Encode}; +use core::{cmp, mem}; use frame_support::{pallet_prelude::*, traits::EstimateNextSessionRotation, DefaultNoBound}; use frame_system::pallet_prelude::*; use polkadot_primitives::{ @@ -127,14 +129,13 @@ use sp_runtime::{ traits::{AppVerify, One, Saturating}, DispatchResult, SaturatedConversion, }; -use sp_std::{cmp, collections::btree_set::BTreeSet, mem, prelude::*}; use serde::{Deserialize, Serialize}; pub use crate::Origin as ParachainOrigin; #[cfg(feature = "runtime-benchmarks")] -pub(crate) mod benchmarking; +pub mod benchmarking; #[cfg(test)] pub(crate) mod tests; @@ -863,7 +864,7 @@ pub mod pallet { #[derive(DefaultNoBound)] pub struct GenesisConfig { #[serde(skip)] - pub _config: sp_std::marker::PhantomData, + pub _config: core::marker::PhantomData, pub paras: Vec<(ParaId, ParaGenesisArgs)>, } @@ -1221,6 +1222,15 @@ const INVALID_TX_BAD_VALIDATOR_IDX: u8 = 1; const INVALID_TX_BAD_SUBJECT: u8 = 2; const INVALID_TX_DOUBLE_VOTE: u8 = 3; +/// This is intermediate "fix" for this issue: +/// +/// +/// It does not actually fix it, but makes the worst case better. Without that limit someone +/// could completely DoS the relay chain by registering a ridiculously high amount of paras. +/// With this limit the same attack could lead to some parachains ceasing to being able to +/// communicate via offchain XCMP. Snowbridge will still work as it only cares about `BridgeHub`. +pub const MAX_PARA_HEADS: usize = 1024; + impl Pallet { /// This is a call to schedule code upgrades for parachains which is safe to be called /// outside of this module. That means this function does all checks necessary to ensure @@ -1290,6 +1300,16 @@ impl Pallet { }) } + /// Get a list of the first [`MAX_PARA_HEADS`] para heads sorted by para_id. + /// This method is likely to be removed in the future. + pub fn sorted_para_heads() -> Vec<(u32, Vec)> { + let mut heads: Vec<(u32, Vec)> = + Heads::::iter().map(|(id, head)| (id.into(), head.0)).collect(); + heads.sort_by_key(|(id, _)| *id); + heads.truncate(MAX_PARA_HEADS); + heads + } + // Apply all para actions queued for the given session index. // // The actions to take are based on the lifecycle of of the paras. diff --git a/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs b/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs index 4c8b093451ed5ac1e917ab980539bc8277374d70..c5284ba1dd1f850d5fdabc7bfd782b488ea12cba 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs @@ -16,9 +16,10 @@ use super::*; use crate::{inclusion, ParaId}; +use alloc::collections::btree_map::BTreeMap; +use core::cmp::min; use frame_benchmarking::{benchmarks, impl_benchmark_test_suite}; use frame_system::RawOrigin; -use sp_std::{cmp::min, collections::btree_map::BTreeMap}; use polkadot_primitives::v7::GroupIndex; diff --git a/polkadot/runtime/parachains/src/paras_inherent/misc.rs b/polkadot/runtime/parachains/src/paras_inherent/misc.rs index dac9e6e256d0ef60c6b18b51d48f44c65e1cae8f..2858c3f95de2602e5020646f69d58ef54a63d97a 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/misc.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/misc.rs @@ -14,7 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use sp_std::{cmp::Ordering, vec::Vec}; +use alloc::vec::Vec; +use core::cmp::Ordering; /// A helper trait to allow calling retain while getting access /// to the index of the item in the `vec`. diff --git a/polkadot/runtime/parachains/src/paras_inherent/mod.rs b/polkadot/runtime/parachains/src/paras_inherent/mod.rs index 8b527c09490d65c95d268e22d6be4a904d514e02..fe4eef16f02279badc275cd89652ff26435a8dff 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/mod.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/mod.rs @@ -32,6 +32,11 @@ use crate::{ shared::{self, AllowedRelayParentsTracker}, ParaId, }; +use alloc::{ + collections::{btree_map::BTreeMap, btree_set::BTreeSet}, + vec, + vec::Vec, +}; use bitvec::prelude::BitVec; use frame_support::{ defensive, @@ -53,11 +58,6 @@ use polkadot_primitives::{ use rand::{seq::SliceRandom, SeedableRng}; use scale_info::TypeInfo; use sp_runtime::traits::{Header as HeaderT, One}; -use sp_std::{ - collections::{btree_map::BTreeMap, btree_set::BTreeSet}, - prelude::*, - vec::Vec, -}; mod misc; mod weights; @@ -295,7 +295,7 @@ impl Pallet { fn process_inherent_data( data: ParachainsInherentData>, context: ProcessInherentDataContext, - ) -> sp_std::result::Result< + ) -> core::result::Result< (ParachainsInherentData>, PostDispatchInfo), DispatchErrorWithPostInfo, > { @@ -762,7 +762,7 @@ pub(crate) fn apply_weight_limit( let mut chained_candidates: Vec> = Vec::new(); let mut current_para_id = None; - for candidate in sp_std::mem::take(candidates).into_iter() { + for candidate in core::mem::take(candidates).into_iter() { let candidate_para_id = candidate.descriptor().para_id; if Some(candidate_para_id) == current_para_id { let chain = chained_candidates diff --git a/polkadot/runtime/parachains/src/paras_inherent/tests.rs b/polkadot/runtime/parachains/src/paras_inherent/tests.rs index abf1c1a56b24b9ee27db011d4538d5864a10c556..0d5653eb729d6114abf6e3f5dcd334b8506fec0c 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/tests.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/tests.rs @@ -53,13 +53,13 @@ mod enter { }, session_info, }; + use alloc::collections::btree_map::BTreeMap; use assert_matches::assert_matches; use core::panic; use frame_support::assert_ok; use frame_system::limits; use polkadot_primitives::{vstaging::SchedulerParams, AvailabilityBitfield, UncheckedSigned}; use sp_runtime::Perbill; - use sp_std::collections::btree_map::BTreeMap; struct TestConfig { dispute_statements: BTreeMap, @@ -1744,8 +1744,8 @@ mod sanitizers { scheduler::{common::Assignment, ParasEntry}, util::{make_persisted_validation_data, make_persisted_validation_data_with_parent}, }; + use alloc::collections::vec_deque::VecDeque; use polkadot_primitives::ValidationCode; - use sp_std::collections::vec_deque::VecDeque; use super::*; diff --git a/polkadot/runtime/parachains/src/reward_points.rs b/polkadot/runtime/parachains/src/reward_points.rs index 5f45445b0ba2a29cddc3806b84a25cbdcb1ce77d..69ef2db756c217e022cb37b5a0eefeeabb938171 100644 --- a/polkadot/runtime/parachains/src/reward_points.rs +++ b/polkadot/runtime/parachains/src/reward_points.rs @@ -22,9 +22,9 @@ //! for the time being, although we will build schemes to do so in the future. use crate::{session_info, shared}; +use alloc::collections::btree_set::BTreeSet; use frame_support::traits::{Defensive, ValidatorSet}; use polkadot_primitives::{SessionIndex, ValidatorIndex}; -use sp_std::collections::btree_set::BTreeSet; /// The amount of era points given by backing a candidate that is included. pub const BACKING_POINTS: u32 = 20; @@ -32,7 +32,7 @@ pub const BACKING_POINTS: u32 = 20; pub const DISPUTE_STATEMENT_POINTS: u32 = 20; /// Rewards validators for participating in parachains with era points in pallet-staking. -pub struct RewardValidatorsWithEraPoints(sp_std::marker::PhantomData); +pub struct RewardValidatorsWithEraPoints(core::marker::PhantomData); impl RewardValidatorsWithEraPoints where diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/v10.rs b/polkadot/runtime/parachains/src/runtime_api_impl/v10.rs index 4417ec75abd67bb1ba50b616ceb137e42cf6a7f6..697890232211315af749a365c95fa8cc23425450 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/v10.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/v10.rs @@ -22,6 +22,7 @@ use crate::{ scheduler::{self, CoreOccupied}, session_info, shared, }; +use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec}; use frame_support::traits::{GetStorageVersion, StorageVersion}; use frame_system::pallet_prelude::*; use polkadot_primitives::{ @@ -37,7 +38,6 @@ use polkadot_primitives::{ ValidatorId, ValidatorIndex, ValidatorSignature, }; use sp_runtime::traits::One; -use sp_std::{collections::btree_map::BTreeMap, prelude::*}; /// Implementation for the `validators` function of the runtime API. pub fn validators() -> Vec { diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs index f4e3db185fead7144e6cb0ae3455af98229d59f7..4aa381e33b1bc2246abd3c16044cc56290597b12 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs @@ -17,12 +17,12 @@ //! Put implementations of functions from staging APIs here. use crate::{configuration, inclusion, initializer, scheduler}; -use polkadot_primitives::{CommittedCandidateReceipt, CoreIndex, Id as ParaId}; -use sp_runtime::traits::One; -use sp_std::{ +use alloc::{ collections::{btree_map::BTreeMap, vec_deque::VecDeque}, vec::Vec, }; +use polkadot_primitives::{CommittedCandidateReceipt, CoreIndex, Id as ParaId}; +use sp_runtime::traits::One; /// Returns the claimqueue from the scheduler pub fn claim_queue() -> BTreeMap> { diff --git a/polkadot/runtime/parachains/src/scheduler.rs b/polkadot/runtime/parachains/src/scheduler.rs index d7fe5c06863c87413f988a972790c5d3482b513f..445583d929aba9a82322f8fb94a70d38632a4f8f 100644 --- a/polkadot/runtime/parachains/src/scheduler.rs +++ b/polkadot/runtime/parachains/src/scheduler.rs @@ -39,6 +39,13 @@ use core::iter::Peekable; use crate::{configuration, initializer::SessionChangeNotification, paras}; +use alloc::{ + collections::{ + btree_map::{self, BTreeMap}, + vec_deque::VecDeque, + }, + vec::Vec, +}; use frame_support::{pallet_prelude::*, traits::Defensive}; use frame_system::pallet_prelude::BlockNumberFor; pub use polkadot_core_primitives::v2::BlockNumber; @@ -46,13 +53,6 @@ use polkadot_primitives::{ CoreIndex, GroupIndex, GroupRotationInfo, Id as ParaId, ScheduledCore, ValidatorIndex, }; use sp_runtime::traits::One; -use sp_std::{ - collections::{ - btree_map::{self, BTreeMap}, - vec_deque::VecDeque, - }, - prelude::*, -}; pub mod common; @@ -314,10 +314,8 @@ impl Pallet { .into_iter() .filter(|(freed_index, _)| (freed_index.0 as usize) < c_len) .for_each(|(freed_index, freed_reason)| { - match sp_std::mem::replace( - &mut cores[freed_index.0 as usize], - CoreOccupied::Free, - ) { + match core::mem::replace(&mut cores[freed_index.0 as usize], CoreOccupied::Free) + { CoreOccupied::Free => {}, CoreOccupied::Paras(entry) => { match freed_reason { @@ -569,7 +567,7 @@ impl Pallet { fn push_occupied_cores_to_assignment_provider() { AvailabilityCores::::mutate(|cores| { for core in cores.iter_mut() { - match sp_std::mem::replace(core, CoreOccupied::Free) { + match core::mem::replace(core, CoreOccupied::Free) { CoreOccupied::Free => continue, CoreOccupied::Paras(entry) => { Self::maybe_push_assignment(entry); diff --git a/polkadot/runtime/parachains/src/scheduler/migration.rs b/polkadot/runtime/parachains/src/scheduler/migration.rs index 84d7d4b567102f6757409d88018f2d4e3072644b..125f105ef70668c8ebacfdb9e2b267b9d00bfcbf 100644 --- a/polkadot/runtime/parachains/src/scheduler/migration.rs +++ b/polkadot/runtime/parachains/src/scheduler/migration.rs @@ -17,6 +17,7 @@ //! A module that is responsible for migration of storage. use super::*; +use alloc::vec::Vec; use frame_support::{ migrations::VersionedMigration, pallet_prelude::ValueQuery, storage_alias, traits::UncheckedOnRuntimeUpgrade, weights::Weight, @@ -164,7 +165,7 @@ mod v1 { } /// Migration to V1 - pub struct UncheckedMigrateToV1(sp_std::marker::PhantomData); + pub struct UncheckedMigrateToV1(core::marker::PhantomData); impl UncheckedOnRuntimeUpgrade for UncheckedMigrateToV1 { fn on_runtime_upgrade() -> Weight { let mut weight: Weight = Weight::zero(); @@ -301,7 +302,7 @@ mod v2 { } /// Migration to V2 - pub struct UncheckedMigrateToV2(sp_std::marker::PhantomData); + pub struct UncheckedMigrateToV2(core::marker::PhantomData); impl UncheckedOnRuntimeUpgrade for UncheckedMigrateToV2 { fn on_runtime_upgrade() -> Weight { diff --git a/polkadot/runtime/parachains/src/scheduler/tests.rs b/polkadot/runtime/parachains/src/scheduler/tests.rs index 32811241e171cfd07af586bdf6b06b37df644603..f3866146e81121e7fe1ad85e09719df00a89a212 100644 --- a/polkadot/runtime/parachains/src/scheduler/tests.rs +++ b/polkadot/runtime/parachains/src/scheduler/tests.rs @@ -16,12 +16,12 @@ use super::*; +use alloc::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; use frame_support::assert_ok; use polkadot_primitives::{ vstaging::SchedulerParams, BlockNumber, SessionIndex, ValidationCode, ValidatorId, }; use sp_keyring::Sr25519Keyring; -use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; use crate::{ configuration::HostConfiguration, diff --git a/polkadot/runtime/parachains/src/session_info.rs b/polkadot/runtime/parachains/src/session_info.rs index ff032f7e34d5efc130b5ce0859fd3160b6039d39..ea05c1aacaa946aa50bcb68e69930acbd60d79eb 100644 --- a/polkadot/runtime/parachains/src/session_info.rs +++ b/polkadot/runtime/parachains/src/session_info.rs @@ -24,6 +24,7 @@ use crate::{ configuration, paras, scheduler, shared, util::{take_active_subset, take_active_subset_and_inactive}, }; +use alloc::vec::Vec; use frame_support::{ pallet_prelude::*, traits::{OneSessionHandler, ValidatorSet, ValidatorSetWithIdentification}, @@ -32,7 +33,6 @@ use frame_system::pallet_prelude::BlockNumberFor; use polkadot_primitives::{ AssignmentId, AuthorityDiscoveryId, ExecutorParams, SessionIndex, SessionInfo, }; -use sp_std::vec::Vec; pub use pallet::*; diff --git a/polkadot/runtime/parachains/src/shared.rs b/polkadot/runtime/parachains/src/shared.rs index 417de1fa3fb0debeb8099d167859dc21e20329ca..154b7cfefc3aca68b3773b49194dba7038feccc5 100644 --- a/polkadot/runtime/parachains/src/shared.rs +++ b/polkadot/runtime/parachains/src/shared.rs @@ -19,14 +19,14 @@ //! To avoid cyclic dependencies, it is important that this pallet is not //! dependent on any of the other pallets. +use alloc::{ + collections::{btree_map::BTreeMap, vec_deque::VecDeque}, + vec::Vec, +}; use frame_support::{pallet_prelude::*, traits::DisabledValidators}; use frame_system::pallet_prelude::BlockNumberFor; use polkadot_primitives::{SessionIndex, ValidatorId, ValidatorIndex}; use sp_runtime::traits::AtLeast32BitUnsigned; -use sp_std::{ - collections::{btree_map::BTreeMap, vec_deque::VecDeque}, - vec::Vec, -}; use rand::{seq::SliceRandom, SeedableRng}; use rand_chacha::ChaCha20Rng; diff --git a/polkadot/runtime/parachains/src/ump_tests.rs b/polkadot/runtime/parachains/src/ump_tests.rs index 4d6da8c9e3c1ba9047ebba784138869733f33ec7..d914bf8b666120fba1c3db2f85f3420427fb9186 100644 --- a/polkadot/runtime/parachains/src/ump_tests.rs +++ b/polkadot/runtime/parachains/src/ump_tests.rs @@ -34,7 +34,6 @@ use frame_support::{ use polkadot_primitives::{well_known_keys, Id as ParaId, UpwardMessage}; use sp_crypto_hashing::{blake2_256, twox_64}; use sp_runtime::traits::Bounded; -use sp_std::prelude::*; pub(super) struct GenesisConfigBuilder { max_upward_message_size: u32, diff --git a/polkadot/runtime/parachains/src/util.rs b/polkadot/runtime/parachains/src/util.rs index cb2deffd7f6593ac69ea1fd7f10d5dfee9dc4577..3588e494438d066ffd925b2b2cc486431b8feab8 100644 --- a/polkadot/runtime/parachains/src/util.rs +++ b/polkadot/runtime/parachains/src/util.rs @@ -17,9 +17,9 @@ //! Utilities that don't belong to any particular module but may draw //! on all modules. +use alloc::{collections::btree_set::BTreeSet, vec::Vec}; use frame_system::pallet_prelude::BlockNumberFor; use polkadot_primitives::{HeadData, Id as ParaId, PersistedValidationData, ValidatorIndex}; -use sp_std::{collections::btree_set::BTreeSet, vec::Vec}; use crate::{configuration, hrmp, paras}; @@ -118,7 +118,7 @@ pub fn take_active_subset(active: &[ValidatorIndex], set: &[T]) -> Vec #[cfg(test)] mod tests { - use sp_std::vec::Vec; + use alloc::vec::Vec; use crate::util::{split_active_subset, take_active_subset}; use polkadot_primitives::ValidatorIndex; diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index d342926d3c5a08eb50e6317882a9b4521c3115d2..50970965e11e6ebbd4f984ed16c21be44cd978c6 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -11,117 +11,116 @@ license.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +codec = { features = ["derive", "max-encoded-len"], workspace = true } +scale-info = { features = ["derive"], workspace = true } log = { workspace = true } serde = { workspace = true } serde_derive = { optional = true, workspace = true } serde_json = { features = ["alloc"], workspace = true } -static_assertions = "1.1.0" -smallvec = "1.8.0" -bitvec = { version = "1.0.1", default-features = false, features = ["alloc"] } +static_assertions = { workspace = true, default-features = true } +smallvec = { workspace = true, default-features = true } +bitvec = { features = ["alloc"], workspace = true } -sp-authority-discovery = { path = "../../../substrate/primitives/authority-discovery", default-features = false } -sp-consensus-babe = { path = "../../../substrate/primitives/consensus/babe", default-features = false } -sp-consensus-beefy = { path = "../../../substrate/primitives/consensus/beefy", default-features = false } -sp-consensus-grandpa = { path = "../../../substrate/primitives/consensus/grandpa", default-features = false } -binary-merkle-tree = { path = "../../../substrate/utils/binary-merkle-tree", default-features = false } -rococo-runtime-constants = { package = "rococo-runtime-constants", path = "constants", default-features = false } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-genesis-builder = { path = "../../../substrate/primitives/genesis-builder", default-features = false } -sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false } -sp-offchain = { path = "../../../substrate/primitives/offchain", default-features = false } -sp-arithmetic = { path = "../../../substrate/primitives/arithmetic", default-features = false } -sp-std = { package = "sp-std", path = "../../../substrate/primitives/std", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -sp-mmr-primitives = { path = "../../../substrate/primitives/merkle-mountain-range", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-staking = { path = "../../../substrate/primitives/staking", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-session = { path = "../../../substrate/primitives/session", default-features = false } -sp-storage = { path = "../../../substrate/primitives/storage", default-features = false } -sp-version = { path = "../../../substrate/primitives/version", default-features = false } -sp-transaction-pool = { path = "../../../substrate/primitives/transaction-pool", default-features = false } -sp-block-builder = { path = "../../../substrate/primitives/block-builder", default-features = false } +sp-authority-discovery = { workspace = true } +sp-consensus-babe = { workspace = true } +sp-consensus-beefy = { workspace = true } +sp-consensus-grandpa = { workspace = true } +binary-merkle-tree = { workspace = true } +rococo-runtime-constants = { workspace = true } +sp-api = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } +sp-offchain = { workspace = true } +sp-arithmetic = { workspace = true } +sp-io = { workspace = true } +sp-mmr-primitives = { workspace = true } +sp-runtime = { workspace = true } +sp-staking = { workspace = true } +sp-core = { workspace = true } +sp-session = { workspace = true } +sp-storage = { workspace = true } +sp-version = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-block-builder = { workspace = true } -pallet-authority-discovery = { path = "../../../substrate/frame/authority-discovery", default-features = false } -pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } -pallet-babe = { path = "../../../substrate/frame/babe", default-features = false } -pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } -pallet-beefy = { path = "../../../substrate/frame/beefy", default-features = false } -pallet-beefy-mmr = { path = "../../../substrate/frame/beefy-mmr", default-features = false } -pallet-bounties = { path = "../../../substrate/frame/bounties", default-features = false } -pallet-child-bounties = { path = "../../../substrate/frame/child-bounties", default-features = false } -pallet-state-trie-migration = { path = "../../../substrate/frame/state-trie-migration", default-features = false } -pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } -pallet-collective = { path = "../../../substrate/frame/collective", default-features = false } -pallet-conviction-voting = { path = "../../../substrate/frame/conviction-voting", default-features = false } -pallet-democracy = { path = "../../../substrate/frame/democracy", default-features = false } -pallet-elections-phragmen = { path = "../../../substrate/frame/elections-phragmen", default-features = false } -pallet-asset-rate = { path = "../../../substrate/frame/asset-rate", default-features = false } -frame-executive = { path = "../../../substrate/frame/executive", default-features = false } -pallet-grandpa = { path = "../../../substrate/frame/grandpa", default-features = false } -pallet-identity = { path = "../../../substrate/frame/identity", default-features = false } -pallet-indices = { path = "../../../substrate/frame/indices", default-features = false } -pallet-membership = { path = "../../../substrate/frame/membership", default-features = false } -pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } -pallet-mmr = { path = "../../../substrate/frame/merkle-mountain-range", default-features = false } -pallet-multisig = { path = "../../../substrate/frame/multisig", default-features = false } -pallet-nis = { path = "../../../substrate/frame/nis", default-features = false } -pallet-offences = { path = "../../../substrate/frame/offences", default-features = false } -pallet-parameters = { path = "../../../substrate/frame/parameters", default-features = false } -pallet-preimage = { path = "../../../substrate/frame/preimage", default-features = false } -pallet-proxy = { path = "../../../substrate/frame/proxy", default-features = false } -pallet-ranked-collective = { path = "../../../substrate/frame/ranked-collective", default-features = false } -pallet-recovery = { path = "../../../substrate/frame/recovery", default-features = false } -pallet-referenda = { path = "../../../substrate/frame/referenda", default-features = false } -pallet-scheduler = { path = "../../../substrate/frame/scheduler", default-features = false } -pallet-session = { path = "../../../substrate/frame/session", default-features = false } -pallet-society = { path = "../../../substrate/frame/society", default-features = false } -pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false, features = ["tuples-96"] } -pallet-staking = { path = "../../../substrate/frame/staking", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -frame-system-rpc-runtime-api = { path = "../../../substrate/frame/system/rpc/runtime-api", default-features = false } -pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false } -pallet-tips = { path = "../../../substrate/frame/tips", default-features = false } -pallet-treasury = { path = "../../../substrate/frame/treasury", default-features = false } -pallet-utility = { path = "../../../substrate/frame/utility", default-features = false } -pallet-vesting = { path = "../../../substrate/frame/vesting", default-features = false } -pallet-whitelist = { path = "../../../substrate/frame/whitelist", default-features = false } -pallet-xcm = { path = "../../xcm/pallet-xcm", default-features = false } -pallet-xcm-benchmarks = { path = "../../xcm/pallet-xcm-benchmarks", default-features = false, optional = true } -pallet-root-testing = { path = "../../../substrate/frame/root-testing", default-features = false } +pallet-authority-discovery = { workspace = true } +pallet-authorship = { workspace = true } +pallet-babe = { workspace = true } +pallet-balances = { workspace = true } +pallet-beefy = { workspace = true } +pallet-beefy-mmr = { workspace = true } +pallet-bounties = { workspace = true } +pallet-child-bounties = { workspace = true } +pallet-state-trie-migration = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-collective = { workspace = true } +pallet-conviction-voting = { workspace = true } +pallet-democracy = { workspace = true } +pallet-elections-phragmen = { workspace = true } +pallet-asset-rate = { workspace = true } +frame-executive = { workspace = true } +pallet-grandpa = { workspace = true } +pallet-identity = { workspace = true } +pallet-indices = { workspace = true } +pallet-membership = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-mmr = { workspace = true } +pallet-multisig = { workspace = true } +pallet-nis = { workspace = true } +pallet-offences = { workspace = true } +pallet-parameters = { workspace = true } +pallet-preimage = { workspace = true } +pallet-proxy = { workspace = true } +pallet-ranked-collective = { workspace = true } +pallet-recovery = { workspace = true } +pallet-referenda = { workspace = true } +pallet-scheduler = { workspace = true } +pallet-session = { workspace = true } +pallet-society = { workspace = true } +pallet-sudo = { workspace = true } +frame-support = { features = ["tuples-96"], workspace = true } +pallet-staking = { workspace = true } +frame-system = { workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-tips = { workspace = true } +pallet-treasury = { workspace = true } +pallet-utility = { workspace = true } +pallet-vesting = { workspace = true } +pallet-whitelist = { workspace = true } +pallet-xcm = { workspace = true } +pallet-xcm-benchmarks = { optional = true, workspace = true } +pallet-root-testing = { workspace = true } -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-metadata-hash-extension = { path = "../../../substrate/frame/metadata-hash-extension", default-features = false } -frame-try-runtime = { path = "../../../substrate/frame/try-runtime", default-features = false, optional = true } -frame-system-benchmarking = { path = "../../../substrate/frame/system/benchmarking", default-features = false, optional = true } -hex-literal = { version = "0.4.1" } +frame-benchmarking = { optional = true, workspace = true } +frame-metadata-hash-extension = { workspace = true } +frame-try-runtime = { optional = true, workspace = true } +frame-system-benchmarking = { optional = true, workspace = true } +hex-literal = { workspace = true, default-features = true } -polkadot-runtime-common = { path = "../common", default-features = false } -polkadot-runtime-parachains = { path = "../parachains", default-features = false } -polkadot-primitives = { path = "../../primitives", default-features = false } -polkadot-parachain-primitives = { path = "../../parachain", default-features = false } +polkadot-runtime-common = { workspace = true } +polkadot-runtime-parachains = { workspace = true } +polkadot-primitives = { workspace = true } +polkadot-parachain-primitives = { workspace = true } -xcm = { package = "staging-xcm", path = "../../xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../xcm/xcm-executor", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false } -xcm-fee-payment-runtime-api = { path = "../../xcm/xcm-fee-payment-runtime-api", default-features = false } +xcm = { workspace = true } +xcm-executor = { workspace = true } +xcm-builder = { workspace = true } +xcm-runtime-apis = { workspace = true } [dev-dependencies] -tiny-keccak = { version = "2.0.2", features = ["keccak"] } -sp-keyring = { path = "../../../substrate/primitives/keyring" } -remote-externalities = { package = "frame-remote-externalities", path = "../../../substrate/utils/frame/remote-externalities" } -sp-trie = { path = "../../../substrate/primitives/trie" } -separator = "0.4.1" +tiny-keccak = { features = ["keccak"], workspace = true } +sp-keyring = { workspace = true, default-features = true } +remote-externalities = { workspace = true, default-features = true } +sp-trie = { workspace = true, default-features = true } +separator = { workspace = true } serde_json = { workspace = true, default-features = true } -sp-tracing = { path = "../../../substrate/primitives/tracing", default-features = false } -tokio = { version = "1.24.2", features = ["macros"] } +sp-tracing = { workspace = true } +tokio = { features = ["macros"], workspace = true, default-features = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [features] default = ["std"] @@ -209,7 +208,6 @@ std = [ "sp-runtime/std", "sp-session/std", "sp-staking/std", - "sp-std/std", "sp-storage/std", "sp-tracing/std", "sp-transaction-pool/std", @@ -217,7 +215,7 @@ std = [ "substrate-wasm-builder", "xcm-builder/std", "xcm-executor/std", - "xcm-fee-payment-runtime-api/std", + "xcm-runtime-apis/std", "xcm/std", ] runtime-benchmarks = [ @@ -228,6 +226,7 @@ runtime-benchmarks = [ "pallet-asset-rate/runtime-benchmarks", "pallet-babe/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-beefy-mmr/runtime-benchmarks", "pallet-bounties/runtime-benchmarks", "pallet-child-bounties/runtime-benchmarks", "pallet-collective/runtime-benchmarks", @@ -270,7 +269,7 @@ runtime-benchmarks = [ "sp-staking/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", - "xcm-fee-payment-runtime-api/runtime-benchmarks", + "xcm-runtime-apis/runtime-benchmarks", ] try-runtime = [ "frame-executive/try-runtime", @@ -332,7 +331,10 @@ metadata-hash = ["substrate-wasm-builder/metadata-hash"] # Set timing constants (e.g. session period) to faster versions to speed up testing. fast-runtime = ["rococo-runtime-constants/fast-runtime"] -runtime-metrics = ["polkadot-runtime-parachains/runtime-metrics", "sp-io/with-tracing"] +runtime-metrics = [ + "polkadot-runtime-parachains/runtime-metrics", + "sp-io/with-tracing", +] # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm diff --git a/polkadot/runtime/rococo/constants/Cargo.toml b/polkadot/runtime/rococo/constants/Cargo.toml index 2c49488077e6f82b6a306c2b98d7d0f493c4681c..b67c36d71fd8721c583789a7a283868111afc037 100644 --- a/polkadot/runtime/rococo/constants/Cargo.toml +++ b/polkadot/runtime/rococo/constants/Cargo.toml @@ -10,17 +10,17 @@ license.workspace = true workspace = true [dependencies] -smallvec = "1.8.0" +smallvec = { workspace = true, default-features = true } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -polkadot-primitives = { path = "../../../primitives", default-features = false } -polkadot-runtime-common = { path = "../../common", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-weights = { path = "../../../../substrate/primitives/weights", default-features = false } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } +frame-support = { workspace = true } +polkadot-primitives = { workspace = true } +polkadot-runtime-common = { workspace = true } +sp-runtime = { workspace = true } +sp-weights = { workspace = true } +sp-core = { workspace = true } -xcm = { package = "staging-xcm", path = "../../../xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../xcm/xcm-builder", default-features = false } +xcm = { workspace = true } +xcm-builder = { workspace = true } [features] default = ["std"] diff --git a/polkadot/runtime/rococo/constants/src/lib.rs b/polkadot/runtime/rococo/constants/src/lib.rs index 1dcafdcbc4d9a6fe48fd460e3ac836d95bb3372b..47b50bf6c106918c5539cb327dd02af617de8c45 100644 --- a/polkadot/runtime/rococo/constants/src/lib.rs +++ b/polkadot/runtime/rococo/constants/src/lib.rs @@ -121,6 +121,17 @@ pub mod system_parachain { /// All system parachains of Rococo. pub type SystemParachains = IsChildSystemParachain; + + /// Coretime constants + pub mod coretime { + /// Coretime timeslice period in blocks + /// WARNING: This constant is used accross chains, so additional care should be taken + /// when changing it. + #[cfg(feature = "fast-runtime")] + pub const TIMESLICE_PERIOD: u32 = 20; + #[cfg(not(feature = "fast-runtime"))] + pub const TIMESLICE_PERIOD: u32 = 80; + } } /// Rococo Treasury pallet instance. diff --git a/polkadot/runtime/rococo/src/genesis_config_presets.rs b/polkadot/runtime/rococo/src/genesis_config_presets.rs index 1c70c94ce04840db1c25f525cca32fff8d99ffeb..67dcd6cd7a510d117eab9299793c7842db1b036e 100644 --- a/polkadot/runtime/rococo/src/genesis_config_presets.rs +++ b/polkadot/runtime/rococo/src/genesis_config_presets.rs @@ -17,6 +17,9 @@ //! Genesis configs presets for the Rococo runtime use crate::{SessionKeys, BABE_GENESIS_EPOCH_CONFIG}; +#[cfg(not(feature = "std"))] +use alloc::format; +use alloc::vec::Vec; use polkadot_primitives::{ vstaging::SchedulerParams, AccountId, AccountPublic, AssignmentId, ValidatorId, }; @@ -27,9 +30,6 @@ use sp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId; use sp_consensus_grandpa::AuthorityId as GrandpaId; use sp_core::{sr25519, Pair, Public}; use sp_runtime::traits::IdentifyAccount; -#[cfg(not(feature = "std"))] -use sp_std::alloc::format; -use sp_std::vec::Vec; /// Helper function to generate a crypto pair from seed fn get_from_seed(seed: &str) -> ::Public { @@ -530,7 +530,7 @@ fn wococo_local_testnet_genesis() -> serde_json::Value { } /// Provides the JSON representation of predefined genesis config for given `id`. -pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option> { +pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option> { let patch = match id.try_into() { Ok("local_testnet") => rococo_local_testnet_genesis(), Ok("development") => rococo_development_config_genesis(), diff --git a/polkadot/runtime/rococo/src/governance/fellowship.rs b/polkadot/runtime/rococo/src/governance/fellowship.rs index a589b768afde2c0757e74a6535509228f1613a82..27a58a0eebd183bc5d21efa655113cf3a0251cc0 100644 --- a/polkadot/runtime/rococo/src/governance/fellowship.rs +++ b/polkadot/runtime/rococo/src/governance/fellowship.rs @@ -356,6 +356,7 @@ impl pallet_ranked_collective::Config for Runtime type MinRankOfClass = sp_runtime::traits::Identity; type MemberSwappedHandler = (); type VoteWeight = pallet_ranked_collective::Geometric; + type MaxMemberCount = (); #[cfg(feature = "runtime-benchmarks")] type BenchmarkSetup = (); } diff --git a/polkadot/runtime/rococo/src/impls.rs b/polkadot/runtime/rococo/src/impls.rs index 7b5c7b1fb4aca8b9e574734ca9bf21cf0bc5e527..a4440a1c6e0b986780454d6aaa1bce19ff5a85ad 100644 --- a/polkadot/runtime/rococo/src/impls.rs +++ b/polkadot/runtime/rococo/src/impls.rs @@ -15,13 +15,14 @@ // along with Polkadot. If not, see . use crate::xcm_config; +use alloc::{boxed::Box, vec}; use codec::{Decode, Encode}; +use core::marker::PhantomData; use frame_support::pallet_prelude::DispatchResult; use frame_system::RawOrigin; use polkadot_primitives::Balance; use polkadot_runtime_common::identity_migrator::{OnReapIdentity, WeightInfo}; use rococo_runtime_constants::currency::*; -use sp_std::{marker::PhantomData, prelude::*}; use xcm::{latest::prelude::*, VersionedLocation, VersionedXcm}; use xcm_executor::traits::TransactAsset; diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 5023a709870ce834f9fe7cdc54b644957aea66c9..0633fc33ebbaa9e2c6fced5342586e99c6b3b458 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -20,7 +20,15 @@ // `construct_runtime!` does a lot of recursion and requires us to increase the limit. #![recursion_limit = "512"] +extern crate alloc; + +use alloc::{ + collections::{btree_map::BTreeMap, vec_deque::VecDeque}, + vec, + vec::Vec, +}; use codec::{Decode, Encode, MaxEncodedLen}; +use core::cmp::Ordering; use frame_support::{ dynamic_params::{dynamic_pallet_params, dynamic_params}, traits::FromContains, @@ -45,14 +53,14 @@ use polkadot_runtime_common::{ BlockHashCount, BlockLength, SlowAdjustingFeeUpdate, }; use polkadot_runtime_parachains::{ - assigner_coretime as parachains_assigner_coretime, - assigner_on_demand as parachains_assigner_on_demand, configuration as parachains_configuration, + assigner_coretime as parachains_assigner_coretime, configuration as parachains_configuration, configuration::ActiveConfigHrmpChannelSizeAndCapacityRatio, coretime, disputes as parachains_disputes, disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, inclusion::{AggregateMessageOrigin, UmpQueueId}, - initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras, + initializer as parachains_initializer, on_demand as parachains_on_demand, + origin as parachains_origin, paras as parachains_paras, paras_inherent as parachains_paras_inherent, runtime_api_impl::{ v10 as parachains_runtime_api_impl, vstaging as vstaging_parachains_runtime_api_impl, @@ -60,7 +68,7 @@ use polkadot_runtime_parachains::{ scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; -use rococo_runtime_constants::system_parachain::BROKER_ID; +use rococo_runtime_constants::system_parachain::{coretime::TIMESLICE_PERIOD, BROKER_ID}; use scale_info::TypeInfo; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_beefy::{ @@ -68,11 +76,6 @@ use sp_consensus_beefy::{ mmr::{BeefyDataProvider, MmrLeafVersion}, }; use sp_genesis_builder::PresetId; -use sp_std::{ - cmp::Ordering, - collections::{btree_map::BTreeMap, vec_deque::VecDeque}, - prelude::*, -}; use frame_support::{ construct_runtime, derive_impl, @@ -92,12 +95,13 @@ use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; use pallet_identity::legacy::IdentityInfo; use pallet_session::historical as session_historical; use pallet_transaction_payment::{FeeDetails, FungibleAdapter, RuntimeDispatchInfo}; -use sp_core::{ConstU128, ConstU8, OpaqueMetadata, H256}; +use sp_core::{ConstU128, ConstU8, Get, OpaqueMetadata, H256}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{ - BlakeTwo256, Block as BlockT, ConstU32, ConvertInto, Extrinsic as ExtrinsicT, - IdentityLookup, Keccak256, OpaqueKeys, SaturatedConversion, Verify, + AccountIdConversion, BlakeTwo256, Block as BlockT, ConstU32, ConvertInto, + Extrinsic as ExtrinsicT, IdentityLookup, Keccak256, OpaqueKeys, SaturatedConversion, + Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, RuntimeDebug, @@ -131,7 +135,7 @@ use governance::{ pallet_custom_origins, AuctionAdmin, Fellows, GeneralAdmin, LeaseAdmin, Treasurer, TreasurySpender, }; -use xcm_fee_payment_runtime_api::{ +use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, }; @@ -162,7 +166,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("rococo"), impl_name: create_runtime_str!("parity-rococo-v2.0"), authoring_version: 0, - spec_version: 1_013_000, + spec_version: 1_014_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 26, @@ -498,10 +502,8 @@ parameter_types! { impl pallet_treasury::Config for Runtime { type PalletId = TreasuryPalletId; type Currency = Balances; - type ApproveOrigin = EitherOfDiverse, Treasurer>; type RejectOrigin = EitherOfDiverse, Treasurer>; type RuntimeEvent = RuntimeEvent; - type OnSlash = Treasury; type SpendPeriod = SpendPeriod; type Burn = Burn; type BurnDestination = Society; @@ -560,6 +562,7 @@ impl pallet_bounties::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MaximumReasonLength = MaximumReasonLength; type WeightInfo = weights::pallet_bounties::WeightInfo; + type OnSlash = Treasury; } parameter_types! { @@ -1058,28 +1061,48 @@ impl parachains_scheduler::Config for Runtime { parameter_types! { pub const BrokerId: u32 = BROKER_ID; + pub const BrokerPalletId: PalletId = PalletId(*b"py/broke"); pub MaxXcmTransactWeight: Weight = Weight::from_parts(200_000_000, 20_000); } +pub struct BrokerPot; +impl Get for BrokerPot { + fn get() -> InteriorLocation { + Junction::AccountId32 { network: None, id: BrokerPalletId::get().into_account_truncating() } + .into() + } +} + impl coretime::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeEvent = RuntimeEvent; type Currency = Balances; type BrokerId = BrokerId; + type BrokerPotLocation = BrokerPot; type WeightInfo = weights::runtime_parachains_coretime::WeightInfo; type SendXcm = crate::xcm_config::XcmRouter; + type AssetTransactor = crate::xcm_config::LocalAssetTransactor; + type AccountToLocation = xcm_builder::AliasesIntoAccountId32< + xcm_config::ThisNetwork, + ::AccountId, + >; type MaxXcmTransactWeight = MaxXcmTransactWeight; } parameter_types! { pub const OnDemandTrafficDefaultValue: FixedU128 = FixedU128::from_u32(1); + // Keep 2 timeslices worth of revenue information. + pub const MaxHistoricalRevenue: BlockNumber = 2 * TIMESLICE_PERIOD; + pub const OnDemandPalletId: PalletId = PalletId(*b"py/ondmd"); } -impl parachains_assigner_on_demand::Config for Runtime { +impl parachains_on_demand::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type TrafficDefaultValue = OnDemandTrafficDefaultValue; - type WeightInfo = weights::runtime_parachains_assigner_on_demand::WeightInfo; + type WeightInfo = weights::runtime_parachains_on_demand::WeightInfo; + type MaxHistoricalRevenue = MaxHistoricalRevenue; + type PalletId = OnDemandPalletId; } impl parachains_assigner_coretime::Config for Runtime {} @@ -1263,6 +1286,7 @@ impl pallet_beefy::Config for Runtime { type MaxNominators = ConstU32<0>; type MaxSetIdSessionEntries = BeefySetIdSessionEntries; type OnNewValidatorSet = MmrLeaf; + type AncestryHelper = MmrLeaf; type WeightInfo = (); type KeyOwnerProof = >::Proof; type EquivocationReportSystem = @@ -1283,9 +1307,11 @@ impl pallet_mmr::Config for Runtime { const INDEXING_PREFIX: &'static [u8] = mmr::INDEXING_PREFIX; type Hashing = Keccak256; type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest; - type WeightInfo = (); type LeafData = pallet_beefy_mmr::Pallet; type BlockHashProvider = pallet_mmr::DefaultBlockHashProvider; + type WeightInfo = weights::pallet_mmr::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = parachains_paras::benchmarking::mmr_setup::MmrSetup; } parameter_types! { @@ -1295,13 +1321,8 @@ parameter_types! { pub struct ParaHeadsRootProvider; impl BeefyDataProvider for ParaHeadsRootProvider { fn extra_data() -> H256 { - let mut para_heads: Vec<(u32, Vec)> = parachains_paras::Parachains::::get() - .into_iter() - .filter_map(|id| { - parachains_paras::Heads::::get(&id).map(|head| (id.into(), head.0)) - }) - .collect(); - para_heads.sort(); + let para_heads: Vec<(u32, Vec)> = + parachains_paras::Pallet::::sorted_para_heads(); binary_merkle_tree::merkle_root::( para_heads.into_iter().map(|pair| pair.encode()), ) @@ -1461,7 +1482,7 @@ construct_runtime! { ParasDisputes: parachains_disputes = 62, ParasSlashing: parachains_slashing = 63, MessageQueue: pallet_message_queue = 64, - OnDemandAssignmentProvider: parachains_assigner_on_demand = 66, + OnDemandAssignmentProvider: parachains_on_demand = 66, CoretimeAssignmentProvider: parachains_assigner_coretime = 68, // Parachain Onboarding Pallets. Start indices at 70 to leave room. @@ -1642,7 +1663,7 @@ pub mod migrations { // This needs to come after the `parachains_configuration` above as we are reading the configuration. coretime::migration::MigrateToCoretime, parachains_configuration::migration::v12::MigrateToV12, - parachains_assigner_on_demand::migration::MigrateV0ToV1, + parachains_on_demand::migration::MigrateV0ToV1, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, @@ -1697,13 +1718,13 @@ mod benches { // the that path resolves correctly in the generated file. [polkadot_runtime_common::assigned_slots, AssignedSlots] [polkadot_runtime_common::auctions, Auctions] - [polkadot_runtime_common::coretime, Coretime] [polkadot_runtime_common::crowdloan, Crowdloan] [polkadot_runtime_common::claims, Claims] [polkadot_runtime_common::identity_migrator, IdentityMigrator] [polkadot_runtime_common::slots, Slots] [polkadot_runtime_common::paras_registrar, Registrar] [polkadot_runtime_parachains::configuration, Configuration] + [polkadot_runtime_parachains::coretime, Coretime] [polkadot_runtime_parachains::hrmp, Hrmp] [polkadot_runtime_parachains::disputes, ParasDisputes] [polkadot_runtime_parachains::inclusion, ParaInclusion] @@ -1722,6 +1743,7 @@ mod benches { [pallet_identity, Identity] [pallet_indices, Indices] [pallet_message_queue, MessageQueue] + [pallet_mmr, Mmr] [pallet_multisig, Multisig] [pallet_parameters, Parameters] [pallet_preimage, Preimage] @@ -1761,7 +1783,7 @@ sp_api::impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { let acceptable_assets = vec![AssetId(xcm_config::TokenLocation::get())]; XcmPallet::query_acceptable_payment_assets(xcm_version, acceptable_assets) @@ -1774,11 +1796,11 @@ sp_api::impl_runtime_apis! { Ok(WeightToFee::weight_to_fee(&weight)) }, Ok(asset_id) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + log::trace!(target: "xcm::xcm_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); Err(XcmPaymentApiError::AssetNotFound) }, Err(_) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + log::trace!(target: "xcm::xcm_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); Err(XcmPaymentApiError::VersionedConversionFailed) } } @@ -1793,7 +1815,7 @@ sp_api::impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + impl xcm_runtime_apis::dry_run::DryRunApi for Runtime { fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { XcmPallet::dry_run_call::(origin, call) } @@ -1803,6 +1825,18 @@ sp_api::impl_runtime_apis! { } } + impl xcm_runtime_apis::conversions::LocationToAccountApi for Runtime { + fn convert_location(location: VersionedLocation) -> Result< + AccountId, + xcm_runtime_apis::conversions::Error + > { + xcm_runtime_apis::conversions::LocationToAccountHelper::< + AccountId, + xcm_config::LocationConverter, + >::convert_location(location) + } + } + impl sp_api::Metadata for Runtime { fn metadata() -> OpaqueMetadata { OpaqueMetadata::new(Runtime::metadata().into()) @@ -1812,7 +1846,7 @@ sp_api::impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { Runtime::metadata_versions() } } @@ -2020,7 +2054,7 @@ sp_api::impl_runtime_apis! { } } - #[api_version(3)] + #[api_version(5)] impl sp_consensus_beefy::BeefyApi for Runtime { fn beefy_genesis() -> Option { pallet_beefy::GenesisBlock::::get() @@ -2030,7 +2064,7 @@ sp_api::impl_runtime_apis! { Beefy::validator_set() } - fn submit_report_equivocation_unsigned_extrinsic( + fn submit_report_double_voting_unsigned_extrinsic( equivocation_proof: sp_consensus_beefy::DoubleVotingProof< BlockNumber, BeefyId, @@ -2040,12 +2074,37 @@ sp_api::impl_runtime_apis! { ) -> Option<()> { let key_owner_proof = key_owner_proof.decode()?; - Beefy::submit_unsigned_equivocation_report( + Beefy::submit_unsigned_double_voting_report( equivocation_proof, key_owner_proof, ) } + fn submit_report_fork_voting_unsigned_extrinsic( + equivocation_proof: + sp_consensus_beefy::ForkVotingProof< + ::Header, + BeefyId, + sp_runtime::OpaqueValue + >, + key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof, + ) -> Option<()> { + Beefy::submit_unsigned_fork_voting_report( + equivocation_proof.try_into()?, + key_owner_proof.decode()?, + ) + } + + fn submit_report_future_block_voting_unsigned_extrinsic( + equivocation_proof: sp_consensus_beefy::FutureBlockVotingProof, + key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof, + ) -> Option<()> { + Beefy::submit_unsigned_future_block_voting_report( + equivocation_proof, + key_owner_proof.decode()?, + ) + } + fn generate_key_ownership_proof( _set_id: sp_consensus_beefy::ValidatorSetId, authority_id: BeefyId, @@ -2056,6 +2115,17 @@ sp_api::impl_runtime_apis! { .map(|p| p.encode()) .map(sp_consensus_beefy::OpaqueKeyOwnershipProof::new) } + + fn generate_ancestry_proof( + prev_block_number: BlockNumber, + best_known_block_number: Option, + ) -> Option { + use sp_consensus_beefy::AncestryHelper; + + MmrLeaf::generate_proof(prev_block_number, best_known_block_number) + .map(|p| p.encode()) + .map(sp_runtime::OpaqueValue::new) + } } #[api_version(2)] @@ -2356,7 +2426,7 @@ sp_api::impl_runtime_apis! { } fn set_up_complex_asset_transfer( - ) -> Option<(Assets, u32, Location, Box)> { + ) -> Option<(Assets, u32, Location, alloc::boxed::Box)> { // Relay supports only native token, either reserve transfer it to non-system parachains, // or teleport it to system parachain. Use the teleport case for benchmarking as it's // slightly heavier. diff --git a/polkadot/runtime/rococo/src/validator_manager.rs b/polkadot/runtime/rococo/src/validator_manager.rs index 0677ba7fbb2b29afda7039ba8b396cb2d66131d8..ecfbff4fa0688486acebe0313d149d1d87cbab42 100644 --- a/polkadot/runtime/rococo/src/validator_manager.rs +++ b/polkadot/runtime/rococo/src/validator_manager.rs @@ -16,8 +16,8 @@ //! A pallet for managing validators on Rococo. +use alloc::vec::Vec; use sp_staking::SessionIndex; -use sp_std::vec::Vec; pub use pallet::*; diff --git a/polkadot/runtime/rococo/src/weights/mod.rs b/polkadot/runtime/rococo/src/weights/mod.rs index 3c6845dfb43e65e85dc33b2e288f35a9a8742e1e..0512a393a6c4a49732b135cc61f96ae370c18309 100644 --- a/polkadot/runtime/rococo/src/weights/mod.rs +++ b/polkadot/runtime/rococo/src/weights/mod.rs @@ -25,6 +25,7 @@ pub mod pallet_conviction_voting; pub mod pallet_identity; pub mod pallet_indices; pub mod pallet_message_queue; +pub mod pallet_mmr; pub mod pallet_multisig; pub mod pallet_nis; pub mod pallet_parameters; @@ -49,13 +50,13 @@ pub mod runtime_common_crowdloan; pub mod runtime_common_identity_migrator; pub mod runtime_common_paras_registrar; pub mod runtime_common_slots; -pub mod runtime_parachains_assigner_on_demand; pub mod runtime_parachains_configuration; pub mod runtime_parachains_coretime; pub mod runtime_parachains_disputes; pub mod runtime_parachains_hrmp; pub mod runtime_parachains_inclusion; pub mod runtime_parachains_initializer; +pub mod runtime_parachains_on_demand; pub mod runtime_parachains_paras; pub mod runtime_parachains_paras_inherent; pub mod xcm; diff --git a/polkadot/runtime/rococo/src/weights/pallet_mmr.rs b/polkadot/runtime/rococo/src/weights/pallet_mmr.rs new file mode 100644 index 0000000000000000000000000000000000000000..361bfc7a661b0737c936a95d20f1b6751db76aec --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_mmr.rs @@ -0,0 +1,77 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_mmr` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-15, STEPS: `5`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/testnet/polkadot +// benchmark +// pallet +// --steps=5 +// --repeat=1 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --pallet=pallet_mmr +// --chain=westend-dev +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/westend/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_mmr`. +pub struct WeightInfo(PhantomData); +impl pallet_mmr::WeightInfo for WeightInfo { + /// Storage: `Mmr::NumberOfLeaves` (r:1 w:1) + /// Proof: `Mmr::NumberOfLeaves` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `Paras::Heads` (r:2049 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `BeefyMmrLeaf::BeefyNextAuthorities` (r:1 w:0) + /// Proof: `BeefyMmrLeaf::BeefyNextAuthorities` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: `System::Digest` (r:1 w:1) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Mmr::Nodes` (r:0 w:1000) + /// Proof: `Mmr::Nodes` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Mmr::RootHash` (r:0 w:1) + /// Proof: `Mmr::RootHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// The range of component `x` is `[1, 1000]`. + fn on_initialize(x: u32) -> Weight { + // Proof Size summary in bytes: + // Measured: `2140817` + // Estimated: `7213082` + // Minimum execution time: 20_387_000_000 picoseconds. + Weight::from_parts(223_625_477_528, 0) + .saturating_add(Weight::from_parts(0, 7213082)) + // Standard Error: 310_550_970 + .saturating_add(Weight::from_parts(16_906_397_286, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2053)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(x.into()))) + } +} diff --git a/polkadot/runtime/rococo/src/weights/pallet_session.rs b/polkadot/runtime/rococo/src/weights/pallet_session.rs index dbeca534add8259fdf77010296d0c6d557365204..7f573d4e3952e8b0cdfbd1253d8c02bf389d5bb5 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_session.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_session.rs @@ -38,7 +38,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `pallet_session`. pub struct WeightInfo(PhantomData); diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_coretime.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_coretime.rs index 0ad32996c49595db1a414e4d0c0fc5961ea2d3e7..b2329c098cead5d2780b6ac44a1d6b5963efcaf8 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_coretime.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_coretime.rs @@ -14,12 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Autogenerated weights for `runtime_parachains::coretime` +//! Autogenerated weights for `runtime_common::coretime` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-1pho9goo-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -45,28 +45,61 @@ use frame_support::{traits::Get, weights::Weight}; use core::marker::PhantomData; -use polkadot_runtime_parachains::configuration::{self, WeightInfo as ConfigWeightInfo}; - /// Weight functions for `runtime_common::coretime`. pub struct WeightInfo(PhantomData); -impl polkadot_runtime_parachains::coretime::WeightInfo for WeightInfo { +impl polkadot_runtime_parachains::coretime::WeightInfo for WeightInfo { + /// Storage: `OnDemandAssignmentProvider::Revenue` (r:1 w:1) + /// Proof: `OnDemandAssignmentProvider::Revenue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn request_revenue_at() -> Weight { + // Proof Size summary in bytes: + // Measured: `2963` + // Estimated: `6428` + // Minimum execution time: 36_613_000 picoseconds. + Weight::from_parts(37_637_000, 0) + .saturating_add(Weight::from_parts(0, 6428)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn request_core_count() -> Weight { - ::WeightInfo::set_config_with_u32() + // Proof Size summary in bytes: + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 7_527_000 picoseconds. + Weight::from_parts(7_784_000, 0) + .saturating_add(Weight::from_parts(0, 1636)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `CoreTimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoreTimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `CoreTimeAssignmentProvider::CoreSchedules` (r:0 w:1) - /// Proof: `CoreTimeAssignmentProvider::CoreSchedules` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreSchedules` (r:0 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreSchedules` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `s` is `[1, 100]`. fn assign_core(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `3541` - // Minimum execution time: 6_275_000 picoseconds. - Weight::from_parts(6_883_543, 0) - .saturating_add(Weight::from_parts(0, 3541)) - // Standard Error: 202 - .saturating_add(Weight::from_parts(15_028, 0).saturating_mul(s.into())) + // Measured: `180` + // Estimated: `3645` + // Minimum execution time: 9_220_000 picoseconds. + Weight::from_parts(9_905_773, 0) + .saturating_add(Weight::from_parts(0, 3645)) + // Standard Error: 257 + .saturating_add(Weight::from_parts(12_400, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_on_demand.rs similarity index 62% rename from polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs rename to polkadot/runtime/rococo/src/weights/runtime_parachains_on_demand.rs index 9f275e7b8cdc24fdcb251ef95beca3eb2b81be25..0c36eeaf7d4506c0d4d6045b4720faf8ae4ae437 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_on_demand.rs @@ -14,12 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Autogenerated weights for `runtime_parachains::assigner_on_demand` +//! Autogenerated weights for `runtime_parachains::on_demand` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-1pho9goo-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -32,7 +32,7 @@ // --wasm-execution=compiled // --heap-pages=4096 // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=runtime_parachains::assigner_on_demand +// --pallet=runtime_parachains::on_demand // --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ @@ -45,11 +45,15 @@ use frame_support::{traits::Get, weights::Weight}; use core::marker::PhantomData; -/// Weight functions for `runtime_parachains::assigner_on_demand`. +/// Weight functions for `runtime_parachains::on_demand`. pub struct WeightInfo(PhantomData); -impl polkadot_runtime_parachains::assigner_on_demand::WeightInfo for WeightInfo { +impl polkadot_runtime_parachains::on_demand::WeightInfo for WeightInfo { /// Storage: `OnDemandAssignmentProvider::QueueStatus` (r:1 w:1) /// Proof: `OnDemandAssignmentProvider::QueueStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `OnDemandAssignmentProvider::Revenue` (r:1 w:1) + /// Proof: `OnDemandAssignmentProvider::Revenue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `OnDemandAssignmentProvider::ParaIdAffinity` (r:1 w:0) /// Proof: `OnDemandAssignmentProvider::ParaIdAffinity` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `OnDemandAssignmentProvider::FreeEntries` (r:1 w:1) @@ -57,19 +61,23 @@ impl polkadot_runtime_parachains::assigner_on_demand::W /// The range of component `s` is `[1, 9999]`. fn place_order_keep_alive(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `218 + s * (8 ยฑ0)` - // Estimated: `3681 + s * (8 ยฑ0)` - // Minimum execution time: 21_053_000 picoseconds. - Weight::from_parts(17_291_897, 0) - .saturating_add(Weight::from_parts(0, 3681)) - // Standard Error: 104 - .saturating_add(Weight::from_parts(18_779, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `270 + s * (8 ยฑ0)` + // Estimated: `3733 + s * (8 ยฑ0)` + // Minimum execution time: 28_422_000 picoseconds. + Weight::from_parts(28_146_882, 0) + .saturating_add(Weight::from_parts(0, 3733)) + // Standard Error: 140 + .saturating_add(Weight::from_parts(21_283, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(s.into())) } /// Storage: `OnDemandAssignmentProvider::QueueStatus` (r:1 w:1) /// Proof: `OnDemandAssignmentProvider::QueueStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `OnDemandAssignmentProvider::Revenue` (r:1 w:1) + /// Proof: `OnDemandAssignmentProvider::Revenue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `OnDemandAssignmentProvider::ParaIdAffinity` (r:1 w:0) /// Proof: `OnDemandAssignmentProvider::ParaIdAffinity` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `OnDemandAssignmentProvider::FreeEntries` (r:1 w:1) @@ -77,15 +85,15 @@ impl polkadot_runtime_parachains::assigner_on_demand::W /// The range of component `s` is `[1, 9999]`. fn place_order_allow_death(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `218 + s * (8 ยฑ0)` - // Estimated: `3681 + s * (8 ยฑ0)` - // Minimum execution time: 20_843_000 picoseconds. - Weight::from_parts(16_881_986, 0) - .saturating_add(Weight::from_parts(0, 3681)) - // Standard Error: 104 - .saturating_add(Weight::from_parts(18_788, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `270 + s * (8 ยฑ0)` + // Estimated: `3733 + s * (8 ยฑ0)` + // Minimum execution time: 28_680_000 picoseconds. + Weight::from_parts(31_024_579, 0) + .saturating_add(Weight::from_parts(0, 3733)) + // Standard Error: 119 + .saturating_add(Weight::from_parts(20_989, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(s.into())) } } diff --git a/polkadot/runtime/rococo/src/weights/xcm/mod.rs b/polkadot/runtime/rococo/src/weights/xcm/mod.rs index 12f3df897b1eedb6e722e8f4871eb631bd35aaa3..bd2b0fbb8c061519f99ac1b33b53bb3a387ece74 100644 --- a/polkadot/runtime/rococo/src/weights/xcm/mod.rs +++ b/polkadot/runtime/rococo/src/weights/xcm/mod.rs @@ -18,8 +18,8 @@ mod pallet_xcm_benchmarks_fungible; mod pallet_xcm_benchmarks_generic; use crate::Runtime; +use alloc::vec::Vec; use frame_support::weights::Weight; -use sp_std::prelude::*; use xcm::{latest::prelude::*, DoubleEncoded}; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmBalancesWeight; diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index 96416821e4c8396c20c45409fe3ec524ebee066b..05e0ee64820a421eb4a8bdb6d8bd7624edcf611e 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -41,10 +41,10 @@ use xcm_builder::{ AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, DescribeAllTerminal, DescribeFamily, FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsChildSystemParachain, - IsConcrete, MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + IsConcrete, MintLocation, OriginToPluralityVoice, SendXcmFeeToAccount, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; @@ -213,7 +213,7 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type FeeManager = XcmFeeManagerFromComponents< WaivedLocations, - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = Nothing; diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index c4d78b1081a626effc136b3a3ee42acd4b514bdf..ac379b69e3f2ca99f22a7ed336b09b6193342fec 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -11,68 +11,67 @@ license.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } +codec = { features = ["derive"], workspace = true } log = { workspace = true } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +scale-info = { features = ["derive"], workspace = true } serde = { workspace = true } -sp-authority-discovery = { path = "../../../substrate/primitives/authority-discovery", default-features = false } -sp-consensus-babe = { path = "../../../substrate/primitives/consensus/babe", default-features = false } -sp-consensus-beefy = { path = "../../../substrate/primitives/consensus/beefy", default-features = false } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false } -sp-offchain = { path = "../../../substrate/primitives/offchain", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-staking = { path = "../../../substrate/primitives/staking", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-genesis-builder = { path = "../../../substrate/primitives/genesis-builder", default-features = false } -sp-mmr-primitives = { path = "../../../substrate/primitives/merkle-mountain-range", default-features = false } -sp-session = { path = "../../../substrate/primitives/session", default-features = false } -sp-version = { path = "../../../substrate/primitives/version", default-features = false } -frame-election-provider-support = { path = "../../../substrate/frame/election-provider-support", default-features = false } -sp-transaction-pool = { path = "../../../substrate/primitives/transaction-pool", default-features = false } -sp-block-builder = { path = "../../../substrate/primitives/block-builder", default-features = false } +sp-authority-discovery = { workspace = true } +sp-consensus-babe = { workspace = true } +sp-consensus-beefy = { workspace = true } +sp-api = { workspace = true } +sp-inherents = { workspace = true } +sp-offchain = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +sp-staking = { workspace = true } +sp-core = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-mmr-primitives = { workspace = true } +sp-session = { workspace = true } +sp-version = { workspace = true } +frame-election-provider-support = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-block-builder = { workspace = true } -pallet-authority-discovery = { path = "../../../substrate/frame/authority-discovery", default-features = false } -pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } -pallet-babe = { path = "../../../substrate/frame/babe", default-features = false } -pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } -pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } -frame-executive = { path = "../../../substrate/frame/executive", default-features = false } -pallet-grandpa = { path = "../../../substrate/frame/grandpa", default-features = false } -pallet-indices = { path = "../../../substrate/frame/indices", default-features = false } -pallet-offences = { path = "../../../substrate/frame/offences", default-features = false } -pallet-session = { path = "../../../substrate/frame/session", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -pallet-staking = { path = "../../../substrate/frame/staking", default-features = false } -pallet-staking-reward-curve = { path = "../../../substrate/frame/staking/reward-curve" } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -frame-system-rpc-runtime-api = { path = "../../../substrate/frame/system/rpc/runtime-api", default-features = false } -test-runtime-constants = { package = "test-runtime-constants", path = "constants", default-features = false } -pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false } -pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false } -pallet-vesting = { path = "../../../substrate/frame/vesting", default-features = false } +pallet-authority-discovery = { workspace = true } +pallet-authorship = { workspace = true } +pallet-babe = { workspace = true } +pallet-balances = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +frame-executive = { workspace = true } +pallet-grandpa = { workspace = true } +pallet-indices = { workspace = true } +pallet-offences = { workspace = true } +pallet-session = { workspace = true } +frame-support = { workspace = true } +pallet-staking = { workspace = true } +pallet-staking-reward-curve = { workspace = true, default-features = true } +frame-system = { workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +test-runtime-constants = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-sudo = { workspace = true } +pallet-vesting = { workspace = true } -polkadot-runtime-common = { path = "../common", default-features = false } -polkadot-primitives = { path = "../../primitives", default-features = false } -pallet-xcm = { path = "../../xcm/pallet-xcm", default-features = false } -polkadot-runtime-parachains = { path = "../parachains", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../xcm/xcm-executor", default-features = false } -xcm = { package = "staging-xcm", path = "../../xcm", default-features = false } +polkadot-runtime-common = { workspace = true } +polkadot-primitives = { workspace = true } +pallet-xcm = { workspace = true } +polkadot-runtime-parachains = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm = { workspace = true } [dev-dependencies] -hex-literal = "0.4.1" -tiny-keccak = { version = "2.0.2", features = ["keccak"] } -sp-keyring = { path = "../../../substrate/primitives/keyring" } -sp-trie = { path = "../../../substrate/primitives/trie" } +hex-literal = { workspace = true, default-features = true } +tiny-keccak = { features = ["keccak"], workspace = true } +sp-keyring = { workspace = true, default-features = true } +sp-trie = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder" } +substrate-wasm-builder = { workspace = true, default-features = true } [features] default = ["std"] @@ -125,7 +124,6 @@ std = [ "sp-runtime/std", "sp-session/std", "sp-staking/std", - "sp-std/std", "sp-transaction-pool/std", "sp-version/std", "test-runtime-constants/std", diff --git a/polkadot/runtime/test-runtime/constants/Cargo.toml b/polkadot/runtime/test-runtime/constants/Cargo.toml index ed10ece54f67c43a7b8aedfaebfb03452605cfe8..807774be7136961b5b2fa146cca50f4efc666fa7 100644 --- a/polkadot/runtime/test-runtime/constants/Cargo.toml +++ b/polkadot/runtime/test-runtime/constants/Cargo.toml @@ -10,11 +10,11 @@ license.workspace = true workspace = true [dependencies] -smallvec = "1.8.0" +smallvec = { workspace = true, default-features = true } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -polkadot-primitives = { path = "../../../primitives", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } +frame-support = { workspace = true } +polkadot-primitives = { workspace = true } +sp-runtime = { workspace = true } [features] default = ["std"] diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 0fc06570e1aacdd81b2ef9451cd8489450e8d773..96cd7fd099c9505576833784301983682f21d7f8 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -20,12 +20,15 @@ // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. #![recursion_limit = "256"] -use codec::Encode; -use pallet_transaction_payment::FungibleAdapter; -use sp_std::{ +extern crate alloc; + +use alloc::{ collections::{btree_map::BTreeMap, vec_deque::VecDeque}, - prelude::*, + vec, + vec::Vec, }; +use codec::Encode; +use pallet_transaction_payment::FungibleAdapter; use polkadot_runtime_parachains::{ assigner_parachains as parachains_assigner_parachains, @@ -793,7 +796,7 @@ sp_api::impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> Vec { Runtime::metadata_versions() } } @@ -1015,7 +1018,7 @@ sp_api::impl_runtime_apis! { None } - fn submit_report_equivocation_unsigned_extrinsic( + fn submit_report_double_voting_unsigned_extrinsic( _equivocation_proof: sp_consensus_beefy::DoubleVotingProof< BlockNumber, BeefyId, @@ -1026,12 +1029,38 @@ sp_api::impl_runtime_apis! { None } + fn submit_report_fork_voting_unsigned_extrinsic( + _equivocation_proof: + sp_consensus_beefy::ForkVotingProof< + ::Header, + BeefyId, + sp_runtime::OpaqueValue + >, + _key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof, + ) -> Option<()> { + None + } + + fn submit_report_future_block_voting_unsigned_extrinsic( + _equivocation_proof: sp_consensus_beefy::FutureBlockVotingProof, + _key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof, + ) -> Option<()> { + None + } + fn generate_key_ownership_proof( _set_id: sp_consensus_beefy::ValidatorSetId, _authority_id: BeefyId, ) -> Option { None } + + fn generate_ancestry_proof( + _prev_block_number: BlockNumber, + _best_known_block_number: Option, + ) -> Option { + None + } } impl mmr::MmrApi for Runtime { diff --git a/polkadot/runtime/test-runtime/src/xcm_config.rs b/polkadot/runtime/test-runtime/src/xcm_config.rs index b1d86ff9a85e9fc6a9a5f361b933d78898715d49..b424b9a3ee55b4f3504cf3a72849cd5ad5dd09e4 100644 --- a/polkadot/runtime/test-runtime/src/xcm_config.rs +++ b/polkadot/runtime/test-runtime/src/xcm_config.rs @@ -54,7 +54,7 @@ pub type LocalOriginToLocation = ( /// This implementation ensures that messages with non-reanchored assets return higher /// prices than messages with reanchored assets. /// Useful for `deposit_reserve_asset_works_for_any_xcm_sender` integration test. -pub struct TestDeliveryPrice(sp_std::marker::PhantomData<(A, F)>); +pub struct TestDeliveryPrice(core::marker::PhantomData<(A, F)>); impl, F: FeeTracker> PriceForMessageDelivery for TestDeliveryPrice { type Id = F::Id; diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index ccb8a02b981cc36782c796eae7b13081e0c985de..4226595cd2ffb25cc753f85583724bc1222b2f7e 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -11,123 +11,121 @@ license.workspace = true workspace = true [dependencies] -bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +bitvec = { features = ["alloc"], workspace = true } +codec = { features = ["derive", "max-encoded-len"], workspace = true } +scale-info = { features = ["derive"], workspace = true } log = { workspace = true } -rustc-hex = { version = "2.1.0", default-features = false } serde = { workspace = true } serde_derive = { optional = true, workspace = true } -smallvec = "1.8.0" +smallvec = { workspace = true, default-features = true } -sp-authority-discovery = { path = "../../../substrate/primitives/authority-discovery", default-features = false } -sp-consensus-babe = { path = "../../../substrate/primitives/consensus/babe", default-features = false } -sp-consensus-beefy = { path = "../../../substrate/primitives/consensus/beefy", default-features = false } -binary-merkle-tree = { path = "../../../substrate/utils/binary-merkle-tree", default-features = false } -sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false } -sp-offchain = { path = "../../../substrate/primitives/offchain", default-features = false } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-application-crypto = { path = "../../../substrate/primitives/application-crypto", default-features = false } -sp-arithmetic = { path = "../../../substrate/primitives/arithmetic", default-features = false } -sp-std = { package = "sp-std", path = "../../../substrate/primitives/std", default-features = false } -sp-genesis-builder = { path = "../../../substrate/primitives/genesis-builder", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -sp-mmr-primitives = { path = "../../../substrate/primitives/merkle-mountain-range", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-staking = { path = "../../../substrate/primitives/staking", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-session = { path = "../../../substrate/primitives/session", default-features = false } -sp-storage = { path = "../../../substrate/primitives/storage", default-features = false } -sp-version = { path = "../../../substrate/primitives/version", default-features = false } -sp-transaction-pool = { path = "../../../substrate/primitives/transaction-pool", default-features = false } -sp-block-builder = { path = "../../../substrate/primitives/block-builder", default-features = false } -sp-npos-elections = { path = "../../../substrate/primitives/npos-elections", default-features = false } +sp-authority-discovery = { workspace = true } +sp-consensus-babe = { workspace = true } +sp-consensus-beefy = { workspace = true } +binary-merkle-tree = { workspace = true } +sp-inherents = { workspace = true } +sp-offchain = { workspace = true } +sp-api = { workspace = true } +sp-application-crypto = { workspace = true } +sp-arithmetic = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-io = { workspace = true } +sp-mmr-primitives = { workspace = true } +sp-runtime = { workspace = true } +sp-staking = { workspace = true } +sp-core = { workspace = true } +sp-session = { workspace = true } +sp-storage = { workspace = true } +sp-version = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-block-builder = { workspace = true } +sp-npos-elections = { workspace = true } -frame-election-provider-support = { path = "../../../substrate/frame/election-provider-support", default-features = false } -frame-executive = { path = "../../../substrate/frame/executive", default-features = false } -frame-metadata-hash-extension = { path = "../../../substrate/frame/metadata-hash-extension", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false, features = ["experimental", "tuples-96"] } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -frame-system-rpc-runtime-api = { path = "../../../substrate/frame/system/rpc/runtime-api", default-features = false } -westend-runtime-constants = { package = "westend-runtime-constants", path = "constants", default-features = false } -pallet-asset-rate = { path = "../../../substrate/frame/asset-rate", default-features = false } -pallet-authority-discovery = { path = "../../../substrate/frame/authority-discovery", default-features = false } -pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } -pallet-babe = { path = "../../../substrate/frame/babe", default-features = false } -pallet-bags-list = { path = "../../../substrate/frame/bags-list", default-features = false } -pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } -pallet-beefy = { path = "../../../substrate/frame/beefy", default-features = false } -pallet-beefy-mmr = { path = "../../../substrate/frame/beefy-mmr", default-features = false } -pallet-collective = { path = "../../../substrate/frame/collective", default-features = false } -pallet-democracy = { path = "../../../substrate/frame/democracy", default-features = false } -pallet-elections-phragmen = { package = "pallet-elections-phragmen", path = "../../../substrate/frame/elections-phragmen", default-features = false } -pallet-election-provider-multi-phase = { path = "../../../substrate/frame/election-provider-multi-phase", default-features = false } -pallet-fast-unstake = { path = "../../../substrate/frame/fast-unstake", default-features = false } -pallet-grandpa = { path = "../../../substrate/frame/grandpa", default-features = false } -pallet-identity = { path = "../../../substrate/frame/identity", default-features = false } -pallet-indices = { path = "../../../substrate/frame/indices", default-features = false } -pallet-membership = { path = "../../../substrate/frame/membership", default-features = false } -pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } -pallet-mmr = { path = "../../../substrate/frame/merkle-mountain-range", default-features = false } -pallet-multisig = { path = "../../../substrate/frame/multisig", default-features = false } -pallet-nomination-pools = { path = "../../../substrate/frame/nomination-pools", default-features = false } -pallet-conviction-voting = { path = "../../../substrate/frame/conviction-voting", default-features = false } -pallet-offences = { path = "../../../substrate/frame/offences", default-features = false } -pallet-preimage = { path = "../../../substrate/frame/preimage", default-features = false } -pallet-proxy = { path = "../../../substrate/frame/proxy", default-features = false } -pallet-recovery = { path = "../../../substrate/frame/recovery", default-features = false } -pallet-referenda = { path = "../../../substrate/frame/referenda", default-features = false } -pallet-scheduler = { path = "../../../substrate/frame/scheduler", default-features = false } -pallet-session = { path = "../../../substrate/frame/session", default-features = false } -pallet-society = { path = "../../../substrate/frame/society", default-features = false } -pallet-staking = { path = "../../../substrate/frame/staking", default-features = false } -pallet-staking-reward-curve = { package = "pallet-staking-reward-curve", path = "../../../substrate/frame/staking/reward-curve" } -pallet-staking-runtime-api = { path = "../../../substrate/frame/staking/runtime-api", default-features = false } -pallet-delegated-staking = { path = "../../../substrate/frame/delegated-staking", default-features = false } -pallet-state-trie-migration = { path = "../../../substrate/frame/state-trie-migration", default-features = false } -pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false } -pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false } -pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } -pallet-nomination-pools-runtime-api = { path = "../../../substrate/frame/nomination-pools/runtime-api", default-features = false } -pallet-treasury = { path = "../../../substrate/frame/treasury", default-features = false } -pallet-utility = { path = "../../../substrate/frame/utility", default-features = false } -pallet-vesting = { path = "../../../substrate/frame/vesting", default-features = false } -pallet-whitelist = { path = "../../../substrate/frame/whitelist", default-features = false } -pallet-xcm = { path = "../../xcm/pallet-xcm", default-features = false } -pallet-xcm-benchmarks = { path = "../../xcm/pallet-xcm-benchmarks", default-features = false, optional = true } -pallet-root-testing = { path = "../../../substrate/frame/root-testing", default-features = false } +frame-election-provider-support = { workspace = true } +frame-executive = { workspace = true } +frame-metadata-hash-extension = { workspace = true } +frame-support = { features = ["experimental", "tuples-96"], workspace = true } +frame-system = { workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +westend-runtime-constants = { workspace = true } +pallet-asset-rate = { workspace = true } +pallet-authority-discovery = { workspace = true } +pallet-authorship = { workspace = true } +pallet-babe = { workspace = true } +pallet-bags-list = { workspace = true } +pallet-balances = { workspace = true } +pallet-beefy = { workspace = true } +pallet-beefy-mmr = { workspace = true } +pallet-collective = { workspace = true } +pallet-democracy = { workspace = true } +pallet-elections-phragmen = { workspace = true } +pallet-election-provider-multi-phase = { workspace = true } +pallet-fast-unstake = { workspace = true } +pallet-grandpa = { workspace = true } +pallet-identity = { workspace = true } +pallet-indices = { workspace = true } +pallet-membership = { workspace = true } +pallet-message-queue = { workspace = true } +pallet-mmr = { workspace = true } +pallet-multisig = { workspace = true } +pallet-nomination-pools = { workspace = true } +pallet-conviction-voting = { workspace = true } +pallet-offences = { workspace = true } +pallet-parameters = { workspace = true } +pallet-preimage = { workspace = true } +pallet-proxy = { workspace = true } +pallet-recovery = { workspace = true } +pallet-referenda = { workspace = true } +pallet-scheduler = { workspace = true } +pallet-session = { workspace = true } +pallet-society = { workspace = true } +pallet-staking = { workspace = true } +pallet-staking-runtime-api = { workspace = true } +pallet-delegated-staking = { workspace = true } +pallet-state-trie-migration = { workspace = true } +pallet-sudo = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-nomination-pools-runtime-api = { workspace = true } +pallet-treasury = { workspace = true } +pallet-utility = { workspace = true } +pallet-vesting = { workspace = true } +pallet-whitelist = { workspace = true } +pallet-xcm = { workspace = true } +pallet-xcm-benchmarks = { optional = true, workspace = true } +pallet-root-testing = { workspace = true } -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-try-runtime = { path = "../../../substrate/frame/try-runtime", default-features = false, optional = true } -frame-system-benchmarking = { path = "../../../substrate/frame/system/benchmarking", default-features = false, optional = true } -pallet-election-provider-support-benchmarking = { path = "../../../substrate/frame/election-provider-support/benchmarking", default-features = false, optional = true } -pallet-nomination-pools-benchmarking = { path = "../../../substrate/frame/nomination-pools/benchmarking", default-features = false, optional = true } -pallet-offences-benchmarking = { path = "../../../substrate/frame/offences/benchmarking", default-features = false, optional = true } -pallet-session-benchmarking = { path = "../../../substrate/frame/session/benchmarking", default-features = false, optional = true } -hex-literal = { version = "0.4.1", optional = true } +frame-benchmarking = { optional = true, workspace = true } +frame-try-runtime = { optional = true, workspace = true } +frame-system-benchmarking = { optional = true, workspace = true } +pallet-election-provider-support-benchmarking = { optional = true, workspace = true } +pallet-nomination-pools-benchmarking = { optional = true, workspace = true } +pallet-offences-benchmarking = { optional = true, workspace = true } +pallet-session-benchmarking = { optional = true, workspace = true } +hex-literal = { optional = true, workspace = true, default-features = true } -polkadot-runtime-common = { path = "../common", default-features = false } -polkadot-primitives = { path = "../../primitives", default-features = false } -polkadot-parachain-primitives = { path = "../../parachain", default-features = false } -polkadot-runtime-parachains = { path = "../parachains", default-features = false } +polkadot-runtime-common = { workspace = true } +polkadot-primitives = { workspace = true } +polkadot-parachain-primitives = { workspace = true } +polkadot-runtime-parachains = { workspace = true } -xcm = { package = "staging-xcm", path = "../../xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../xcm/xcm-executor", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false } -xcm-fee-payment-runtime-api = { path = "../../xcm/xcm-fee-payment-runtime-api", default-features = false } +xcm = { workspace = true } +xcm-executor = { workspace = true } +xcm-builder = { workspace = true } +xcm-runtime-apis = { workspace = true } [dev-dependencies] -hex-literal = "0.4.1" -tiny-keccak = { version = "2.0.2", features = ["keccak"] } -sp-keyring = { path = "../../../substrate/primitives/keyring" } +hex-literal = { workspace = true, default-features = true } +tiny-keccak = { features = ["keccak"], workspace = true } +sp-keyring = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } -remote-externalities = { package = "frame-remote-externalities", path = "../../../substrate/utils/frame/remote-externalities" } -tokio = { version = "1.24.2", features = ["macros"] } -sp-tracing = { path = "../../../substrate/primitives/tracing", default-features = false } +remote-externalities = { workspace = true, default-features = true } +tokio = { features = ["macros"], workspace = true, default-features = true } +sp-tracing = { workspace = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder" } +substrate-wasm-builder = { workspace = true, default-features = true } [features] default = ["std"] @@ -175,6 +173,7 @@ std = [ "pallet-nomination-pools/std", "pallet-offences-benchmarking?/std", "pallet-offences/std", + "pallet-parameters/std", "pallet-preimage/std", "pallet-proxy/std", "pallet-recovery/std", @@ -201,7 +200,6 @@ std = [ "polkadot-primitives/std", "polkadot-runtime-common/std", "polkadot-runtime-parachains/std", - "rustc-hex/std", "scale-info/std", "serde/std", "serde_derive", @@ -222,7 +220,6 @@ std = [ "sp-runtime/std", "sp-session/std", "sp-staking/std", - "sp-std/std", "sp-storage/std", "sp-tracing/std", "sp-transaction-pool/std", @@ -230,7 +227,7 @@ std = [ "westend-runtime-constants/std", "xcm-builder/std", "xcm-executor/std", - "xcm-fee-payment-runtime-api/std", + "xcm-runtime-apis/std", "xcm/std", ] runtime-benchmarks = [ @@ -244,6 +241,7 @@ runtime-benchmarks = [ "pallet-babe/runtime-benchmarks", "pallet-bags-list/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-beefy-mmr/runtime-benchmarks", "pallet-collective/runtime-benchmarks", "pallet-conviction-voting/runtime-benchmarks", "pallet-delegated-staking/runtime-benchmarks", @@ -263,6 +261,7 @@ runtime-benchmarks = [ "pallet-nomination-pools/runtime-benchmarks", "pallet-offences-benchmarking/runtime-benchmarks", "pallet-offences/runtime-benchmarks", + "pallet-parameters/runtime-benchmarks", "pallet-preimage/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-recovery/runtime-benchmarks", @@ -288,7 +287,7 @@ runtime-benchmarks = [ "sp-staking/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", - "xcm-fee-payment-runtime-api/runtime-benchmarks", + "xcm-runtime-apis/runtime-benchmarks", ] try-runtime = [ "frame-election-provider-support/try-runtime", @@ -321,6 +320,7 @@ try-runtime = [ "pallet-multisig/try-runtime", "pallet-nomination-pools/try-runtime", "pallet-offences/try-runtime", + "pallet-parameters/try-runtime", "pallet-preimage/try-runtime", "pallet-proxy/try-runtime", "pallet-recovery/try-runtime", @@ -350,7 +350,10 @@ metadata-hash = ["substrate-wasm-builder/metadata-hash"] # Set timing constants (e.g. session period) to faster versions to speed up testing. fast-runtime = [] -runtime-metrics = ["polkadot-runtime-parachains/runtime-metrics", "sp-io/with-tracing"] +runtime-metrics = [ + "polkadot-runtime-parachains/runtime-metrics", + "sp-io/with-tracing", +] # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm diff --git a/polkadot/runtime/westend/constants/Cargo.toml b/polkadot/runtime/westend/constants/Cargo.toml index d50b168fac52ee12709ece481375f73efdd878ac..f9b99ea5284d3322b6e0bf100f8314000a4b5bce 100644 --- a/polkadot/runtime/westend/constants/Cargo.toml +++ b/polkadot/runtime/westend/constants/Cargo.toml @@ -10,17 +10,17 @@ license.workspace = true workspace = true [dependencies] -smallvec = "1.8.0" +smallvec = { workspace = true, default-features = true } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -polkadot-primitives = { path = "../../../primitives", default-features = false } -polkadot-runtime-common = { path = "../../common", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-weights = { path = "../../../../substrate/primitives/weights", default-features = false } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } +frame-support = { workspace = true } +polkadot-primitives = { workspace = true } +polkadot-runtime-common = { workspace = true } +sp-runtime = { workspace = true } +sp-weights = { workspace = true } +sp-core = { workspace = true } -xcm = { package = "staging-xcm", path = "../../../xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../../xcm/xcm-builder", default-features = false } +xcm = { workspace = true } +xcm-builder = { workspace = true } [features] default = ["std"] @@ -34,3 +34,6 @@ std = [ "xcm-builder/std", "xcm/std", ] + +# Set timing constants (e.g. session period) to faster versions to speed up testing. +fast-runtime = [] diff --git a/polkadot/runtime/westend/constants/src/lib.rs b/polkadot/runtime/westend/constants/src/lib.rs index 58048272e791a06b9169bf2ccf59a5e8d005c2d6..8d66ac2868d0b7a53011b8624c41161860b2cd42 100644 --- a/polkadot/runtime/westend/constants/src/lib.rs +++ b/polkadot/runtime/westend/constants/src/lib.rs @@ -116,6 +116,17 @@ pub mod system_parachain { /// All system parachains of Westend. pub type SystemParachains = IsChildSystemParachain; + + /// Coretime constants + pub mod coretime { + /// Coretime timeslice period in blocks + /// WARNING: This constant is used accross chains, so additional care should be taken + /// when changing it. + #[cfg(feature = "fast-runtime")] + pub const TIMESLICE_PERIOD: u32 = 20; + #[cfg(not(feature = "fast-runtime"))] + pub const TIMESLICE_PERIOD: u32 = 80; + } } /// Westend Treasury pallet instance. diff --git a/polkadot/runtime/westend/src/impls.rs b/polkadot/runtime/westend/src/impls.rs index d7ca677a7620e26aeb2f00e35ec23e67057c8293..11665953bd8e17b2f0368602b176a19046d44be9 100644 --- a/polkadot/runtime/westend/src/impls.rs +++ b/polkadot/runtime/westend/src/impls.rs @@ -15,12 +15,13 @@ // along with Polkadot. If not, see . use crate::xcm_config; +use alloc::{boxed::Box, vec}; use codec::{Decode, Encode}; +use core::marker::PhantomData; use frame_support::pallet_prelude::DispatchResult; use frame_system::RawOrigin; use polkadot_primitives::Balance; use polkadot_runtime_common::identity_migrator::{OnReapIdentity, WeightInfo}; -use sp_std::{marker::PhantomData, prelude::*}; use westend_runtime_constants::currency::*; use xcm::{latest::prelude::*, VersionedLocation, VersionedXcm}; use xcm_executor::traits::TransactAsset; diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 4d6a885b4dad300bee84010f0d576ab176bd29c6..01ee7dbe5a4cdc2f5bea46173d398578ae4eaa2e 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -20,16 +20,25 @@ // `#[frame_support::runtime]!` does a lot of recursion and requires us to increase the limit. #![recursion_limit = "512"] +extern crate alloc; + +use alloc::{ + collections::{btree_map::BTreeMap, vec_deque::VecDeque}, + vec, + vec::Vec, +}; use codec::{Decode, Encode, MaxEncodedLen}; use frame_election_provider_support::{bounds::ElectionBoundsBuilder, onchain, SequentialPhragmen}; use frame_support::{ derive_impl, + dynamic_params::{dynamic_pallet_params, dynamic_params}, genesis_builder_helper::{build_state, get_preset}, parameter_types, traits::{ fungible::HoldConsideration, tokens::UnityOrOuterConversion, ConstU32, Contains, EitherOf, - EitherOfDiverse, EverythingBut, FromContains, InstanceFilter, KeyOwnerProofSystem, - LinearStoragePrice, ProcessMessage, ProcessMessageError, VariantCountOf, WithdrawReasons, + EitherOfDiverse, EnsureOriginWithArg, EverythingBut, FromContains, InstanceFilter, + KeyOwnerProofSystem, LinearStoragePrice, ProcessMessage, ProcessMessageError, + VariantCountOf, WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter, WeightToFee as _}, PalletId, @@ -52,8 +61,8 @@ use polkadot_runtime_common::{ elections::OnChainAccuracy, identity_migrator, impl_runtime_weights, impls::{ - ContainsParts, LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, - VersionedLocationConverter, + relay_era_payout, ContainsParts, EraPayoutParams, LocatableAssetConverter, ToAuthor, + VersionedLocatableAsset, VersionedLocationConverter, }, paras_registrar, paras_sudo_wrapper, prod_or_fast, slots, traits::{Leaser, OnSwap}, @@ -61,14 +70,14 @@ use polkadot_runtime_common::{ U256ToBalance, }; use polkadot_runtime_parachains::{ - assigner_coretime as parachains_assigner_coretime, - assigner_on_demand as parachains_assigner_on_demand, configuration as parachains_configuration, + assigner_coretime as parachains_assigner_coretime, configuration as parachains_configuration, configuration::ActiveConfigHrmpChannelSizeAndCapacityRatio, coretime, disputes as parachains_disputes, disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, inclusion::{AggregateMessageOrigin, UmpQueueId}, - initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras, + initializer as parachains_initializer, on_demand as parachains_on_demand, + origin as parachains_origin, paras as parachains_paras, paras_inherent as parachains_paras_inherent, reward_points as parachains_reward_points, runtime_api_impl::{ v10 as parachains_runtime_api_impl, vstaging as vstaging_parachains_runtime_api_impl, @@ -84,28 +93,22 @@ use sp_consensus_beefy::{ }; use sp_core::{ConstU8, OpaqueMetadata, RuntimeDebug, H256}; use sp_runtime::{ - create_runtime_str, - curve::PiecewiseLinear, - generic, impl_opaque_keys, + create_runtime_str, generic, impl_opaque_keys, traits::{ - BlakeTwo256, Block as BlockT, ConvertInto, Extrinsic as ExtrinsicT, IdentityLookup, - Keccak256, OpaqueKeys, SaturatedConversion, Verify, + AccountIdConversion, BlakeTwo256, Block as BlockT, ConvertInto, Extrinsic as ExtrinsicT, + IdentityLookup, Keccak256, OpaqueKeys, SaturatedConversion, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, }; use sp_staking::SessionIndex; -use sp_std::{ - collections::{btree_map::BTreeMap, vec_deque::VecDeque}, - prelude::*, -}; #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; use sp_version::RuntimeVersion; use xcm::{latest::prelude::*, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}; use xcm_builder::PayOverXcm; -use xcm_fee_payment_runtime_api::{ +use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, }; @@ -122,7 +125,12 @@ use sp_runtime::traits::Get; pub use sp_runtime::BuildStorage; /// Constant values used within the runtime. -use westend_runtime_constants::{currency::*, fee::*, system_parachain::BROKER_ID, time::*}; +use westend_runtime_constants::{ + currency::*, + fee::*, + system_parachain::{coretime::TIMESLICE_PERIOD, BROKER_ID}, + time::*, +}; mod bag_thresholds; mod weights; @@ -154,7 +162,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westend"), impl_name: create_runtime_str!("parity-westend"), authoring_version: 2, - spec_version: 1_013_000, + spec_version: 1_014_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 26, @@ -236,6 +244,80 @@ parameter_types! { pub const PreimageHoldReason: RuntimeHoldReason = RuntimeHoldReason::Preimage(pallet_preimage::HoldReason::Preimage); } +/// Dynamic params that can be adjusted at runtime. +#[dynamic_params(RuntimeParameters, pallet_parameters::Parameters::)] +pub mod dynamic_params { + use super::*; + + /// Parameters used to calculate era payouts, see + /// [`polkadot_runtime_common::impls::EraPayoutParams`]. + #[dynamic_pallet_params] + #[codec(index = 0)] + pub mod inflation { + /// Minimum inflation rate used to calculate era payouts. + #[codec(index = 0)] + pub static MinInflation: Perquintill = Perquintill::from_rational(25u64, 1000u64); + + /// Maximum inflation rate used to calculate era payouts. + #[codec(index = 1)] + pub static MaxInflation: Perquintill = Perquintill::from_rational(10u64, 100u64); + + /// Ideal stake ratio used to calculate era payouts. + #[codec(index = 2)] + pub static IdealStake: Perquintill = Perquintill::from_rational(50u64, 100u64); + + /// Falloff used to calculate era payouts. + #[codec(index = 3)] + pub static Falloff: Perquintill = Perquintill::from_rational(50u64, 1000u64); + + /// Whether to use auction slots or not in the calculation of era payouts. If set to true, + /// the `legacy_auction_proportion` of 60% will be used in the calculation of era payouts. + #[codec(index = 4)] + pub static UseAuctionSlots: bool = false; + } +} + +#[cfg(feature = "runtime-benchmarks")] +impl Default for RuntimeParameters { + fn default() -> Self { + RuntimeParameters::Inflation(dynamic_params::inflation::Parameters::MinInflation( + dynamic_params::inflation::MinInflation, + Some(Perquintill::from_rational(25u64, 1000u64)), + )) + } +} + +impl pallet_parameters::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeParameters = RuntimeParameters; + type AdminOrigin = DynamicParameterOrigin; + type WeightInfo = weights::pallet_parameters::WeightInfo; +} + +/// Defines what origin can modify which dynamic parameters. +pub struct DynamicParameterOrigin; +impl EnsureOriginWithArg for DynamicParameterOrigin { + type Success = (); + + fn try_origin( + origin: RuntimeOrigin, + key: &RuntimeParametersKey, + ) -> Result { + use crate::RuntimeParametersKey::*; + + match key { + Inflation(_) => frame_system::ensure_root(origin.clone()), + } + .map_err(|_| origin) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin(_key: &RuntimeParametersKey) -> Result { + // Provide the origin for the parameter returned by `Default`: + Ok(RuntimeOrigin::root()) + } +} + impl pallet_preimage::Config for Runtime { type WeightInfo = weights::pallet_preimage::WeightInfo; type RuntimeEvent = RuntimeEvent; @@ -323,6 +405,7 @@ impl pallet_beefy::Config for Runtime { type MaxNominators = MaxNominators; type MaxSetIdSessionEntries = BeefySetIdSessionEntries; type OnNewValidatorSet = BeefyMmrLeaf; + type AncestryHelper = BeefyMmrLeaf; type WeightInfo = (); type KeyOwnerProof = sp_session::MembershipProof; type EquivocationReportSystem = @@ -333,9 +416,11 @@ impl pallet_mmr::Config for Runtime { const INDEXING_PREFIX: &'static [u8] = mmr::INDEXING_PREFIX; type Hashing = Keccak256; type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest; - type WeightInfo = (); type LeafData = pallet_beefy_mmr::Pallet; type BlockHashProvider = pallet_mmr::DefaultBlockHashProvider; + type WeightInfo = weights::pallet_mmr::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = parachains_paras::benchmarking::mmr_setup::MmrSetup; } /// MMR helper types. @@ -357,13 +442,8 @@ parameter_types! { pub struct ParaHeadsRootProvider; impl BeefyDataProvider for ParaHeadsRootProvider { fn extra_data() -> H256 { - let mut para_heads: Vec<(u32, Vec)> = parachains_paras::Parachains::::get() - .into_iter() - .filter_map(|id| { - parachains_paras::Heads::::get(&id).map(|head| (id.into(), head.0)) - }) - .collect(); - para_heads.sort_by_key(|k| k.0); + let para_heads: Vec<(u32, Vec)> = + parachains_paras::Pallet::::sorted_para_heads(); binary_merkle_tree::merkle_root::( para_heads.into_iter().map(|pair| pair.encode()), ) @@ -550,7 +630,7 @@ impl pallet_election_provider_multi_phase::Config for Runtime { ::MaxWeight; type MinerConfig = Self; type SlashHandler = (); // burn slashes - type RewardHandler = (); // nothing to do upon rewards + type RewardHandler = (); // rewards are minted from the void type BetterSignedThreshold = (); type OffchainRepeat = OffchainRepeat; type MinerTxPriority = NposSolutionPriority; @@ -590,15 +670,37 @@ impl pallet_bags_list::Config for Runtime { type Score = sp_npos_elections::VoteWeight; } -pallet_staking_reward_curve::build! { - const REWARD_CURVE: PiecewiseLinear<'static> = curve!( - min_inflation: 0_025_000, - max_inflation: 0_100_000, - ideal_stake: 0_500_000, - falloff: 0_050_000, - max_piece_count: 40, - test_precision: 0_005_000, - ); +pub struct EraPayout; +impl pallet_staking::EraPayout for EraPayout { + fn era_payout( + total_staked: Balance, + total_issuance: Balance, + era_duration_millis: u64, + ) -> (Balance, Balance) { + const MILLISECONDS_PER_YEAR: u64 = 1000 * 3600 * 24 * 36525 / 100; + + let params = EraPayoutParams { + total_staked, + total_stakable: total_issuance, + ideal_stake: dynamic_params::inflation::IdealStake::get(), + max_annual_inflation: dynamic_params::inflation::MaxInflation::get(), + min_annual_inflation: dynamic_params::inflation::MinInflation::get(), + falloff: dynamic_params::inflation::Falloff::get(), + period_fraction: Perquintill::from_rational(era_duration_millis, MILLISECONDS_PER_YEAR), + legacy_auction_proportion: if dynamic_params::inflation::UseAuctionSlots::get() { + let auctioned_slots = parachains_paras::Parachains::::get() + .into_iter() + // all active para-ids that do not belong to a system chain is the number of + // parachains that we should take into account for inflation. + .filter(|i| *i >= 2000.into()) + .count() as u64; + Some(Perquintill::from_rational(auctioned_slots.min(60), 200u64)) + } else { + None + }, + }; + relay_era_payout(params) + } } parameter_types! { @@ -608,7 +710,6 @@ parameter_types! { pub const BondingDuration: sp_staking::EraIndex = 2; // 1 era in which slashes can be cancelled (6 hours). pub const SlashDeferDuration: sp_staking::EraIndex = 1; - pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxExposurePageSize: u32 = 64; // Note: this is not really correct as Max Nominators is (MaxExposurePageSize * page_count) but // this is an unbounded number. We just set it to a reasonably high value, 1 full page @@ -632,7 +733,7 @@ impl pallet_staking::Config for Runtime { type SlashDeferDuration = SlashDeferDuration; type AdminOrigin = EitherOf, StakingAdmin>; type SessionInterface = Self; - type EraPayout = pallet_staking::ConvertCurve; + type EraPayout = EraPayout; type MaxExposurePageSize = MaxExposurePageSize; type NextNewSession = Session; type ElectionProvider = ElectionProviderMultiPhase; @@ -683,10 +784,8 @@ parameter_types! { impl pallet_treasury::Config for Runtime { type PalletId = TreasuryPalletId; type Currency = Balances; - type ApproveOrigin = EitherOfDiverse, Treasurer>; type RejectOrigin = EitherOfDiverse, Treasurer>; type RuntimeEvent = RuntimeEvent; - type OnSlash = Treasury; type SpendPeriod = SpendPeriod; type Burn = Burn; type BurnDestination = (); @@ -1187,28 +1286,48 @@ impl parachains_scheduler::Config for Runtime { parameter_types! { pub const BrokerId: u32 = BROKER_ID; + pub const BrokerPalletId: PalletId = PalletId(*b"py/broke"); pub MaxXcmTransactWeight: Weight = Weight::from_parts(200_000_000, 20_000); } +pub struct BrokerPot; +impl Get for BrokerPot { + fn get() -> InteriorLocation { + Junction::AccountId32 { network: None, id: BrokerPalletId::get().into_account_truncating() } + .into() + } +} + impl coretime::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeEvent = RuntimeEvent; type Currency = Balances; type BrokerId = BrokerId; + type BrokerPotLocation = BrokerPot; type WeightInfo = weights::runtime_parachains_coretime::WeightInfo; type SendXcm = crate::xcm_config::XcmRouter; + type AssetTransactor = crate::xcm_config::LocalAssetTransactor; + type AccountToLocation = xcm_builder::AliasesIntoAccountId32< + xcm_config::ThisNetwork, + ::AccountId, + >; type MaxXcmTransactWeight = MaxXcmTransactWeight; } parameter_types! { pub const OnDemandTrafficDefaultValue: FixedU128 = FixedU128::from_u32(1); + // Keep 2 timeslices worth of revenue information. + pub const MaxHistoricalRevenue: BlockNumber = 2 * TIMESLICE_PERIOD; + pub const OnDemandPalletId: PalletId = PalletId(*b"py/ondmd"); } -impl parachains_assigner_on_demand::Config for Runtime { +impl parachains_on_demand::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type TrafficDefaultValue = OnDemandTrafficDefaultValue; - type WeightInfo = weights::runtime_parachains_assigner_on_demand::WeightInfo; + type WeightInfo = weights::runtime_parachains_on_demand::WeightInfo; + type MaxHistoricalRevenue = MaxHistoricalRevenue; + type PalletId = OnDemandPalletId; } impl parachains_assigner_coretime::Config for Runtime {} @@ -1451,6 +1570,8 @@ mod runtime { pub type Offences = pallet_offences; #[runtime::pallet_index(27)] pub type Historical = session_historical; + #[runtime::pallet_index(70)] + pub type Parameters = pallet_parameters; #[runtime::pallet_index(8)] pub type Session = pallet_session; @@ -1558,7 +1679,7 @@ mod runtime { #[runtime::pallet_index(54)] pub type ParasSlashing = parachains_slashing; #[runtime::pallet_index(56)] - pub type OnDemandAssignmentProvider = parachains_assigner_on_demand; + pub type OnDemandAssignmentProvider = parachains_on_demand; #[runtime::pallet_index(57)] pub type CoretimeAssignmentProvider = parachains_assigner_coretime; @@ -1716,7 +1837,7 @@ mod benches { [polkadot_runtime_parachains::initializer, Initializer] [polkadot_runtime_parachains::paras, Paras] [polkadot_runtime_parachains::paras_inherent, ParaInherent] - [polkadot_runtime_parachains::assigner_on_demand, OnDemandAssignmentProvider] + [polkadot_runtime_parachains::on_demand, OnDemandAssignmentProvider] [polkadot_runtime_parachains::coretime, Coretime] // Substrate [pallet_bags_list, VoterList] @@ -1728,9 +1849,11 @@ mod benches { [pallet_identity, Identity] [pallet_indices, Indices] [pallet_message_queue, MessageQueue] + [pallet_mmr, Mmr] [pallet_multisig, Multisig] [pallet_nomination_pools, NominationPoolsBench::] [pallet_offences, OffencesBench::] + [pallet_parameters, Parameters] [pallet_preimage, Preimage] [pallet_proxy, Proxy] [pallet_recovery, Recovery] @@ -1778,7 +1901,7 @@ sp_api::impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { Runtime::metadata_versions() } } @@ -1986,6 +2109,7 @@ sp_api::impl_runtime_apis! { } } + #[api_version(5)] impl sp_consensus_beefy::BeefyApi for Runtime { fn beefy_genesis() -> Option { pallet_beefy::GenesisBlock::::get() @@ -1995,7 +2119,7 @@ sp_api::impl_runtime_apis! { Beefy::validator_set() } - fn submit_report_equivocation_unsigned_extrinsic( + fn submit_report_double_voting_unsigned_extrinsic( equivocation_proof: sp_consensus_beefy::DoubleVotingProof< BlockNumber, BeefyId, @@ -2005,12 +2129,37 @@ sp_api::impl_runtime_apis! { ) -> Option<()> { let key_owner_proof = key_owner_proof.decode()?; - Beefy::submit_unsigned_equivocation_report( + Beefy::submit_unsigned_double_voting_report( equivocation_proof, key_owner_proof, ) } + fn submit_report_fork_voting_unsigned_extrinsic( + equivocation_proof: + sp_consensus_beefy::ForkVotingProof< + ::Header, + BeefyId, + sp_runtime::OpaqueValue + >, + key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof, + ) -> Option<()> { + Beefy::submit_unsigned_fork_voting_report( + equivocation_proof.try_into()?, + key_owner_proof.decode()?, + ) + } + + fn submit_report_future_block_voting_unsigned_extrinsic( + equivocation_proof: sp_consensus_beefy::FutureBlockVotingProof, + key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof, + ) -> Option<()> { + Beefy::submit_unsigned_future_block_voting_report( + equivocation_proof, + key_owner_proof.decode()?, + ) + } + fn generate_key_ownership_proof( _set_id: sp_consensus_beefy::ValidatorSetId, authority_id: BeefyId, @@ -2021,6 +2170,17 @@ sp_api::impl_runtime_apis! { .map(|p| p.encode()) .map(sp_consensus_beefy::OpaqueKeyOwnershipProof::new) } + + fn generate_ancestry_proof( + prev_block_number: BlockNumber, + best_known_block_number: Option, + ) -> Option { + use sp_consensus_beefy::AncestryHelper; + + BeefyMmrLeaf::generate_proof(prev_block_number, best_known_block_number) + .map(|p| p.encode()) + .map(sp_runtime::OpaqueValue::new) + } } impl mmr::MmrApi for Runtime { @@ -2223,7 +2383,7 @@ sp_api::impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { let acceptable_assets = vec![AssetId(xcm_config::TokenLocation::get())]; XcmPallet::query_acceptable_payment_assets(xcm_version, acceptable_assets) @@ -2236,11 +2396,11 @@ sp_api::impl_runtime_apis! { Ok(WeightToFee::weight_to_fee(&weight)) }, Ok(asset_id) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); Err(XcmPaymentApiError::AssetNotFound) }, Err(_) => { - log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); Err(XcmPaymentApiError::VersionedConversionFailed) } } @@ -2255,7 +2415,7 @@ sp_api::impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + impl xcm_runtime_apis::dry_run::DryRunApi for Runtime { fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { XcmPallet::dry_run_call::(origin, call) } @@ -2265,6 +2425,18 @@ sp_api::impl_runtime_apis! { } } + impl xcm_runtime_apis::conversions::LocationToAccountApi for Runtime { + fn convert_location(location: VersionedLocation) -> Result< + AccountId, + xcm_runtime_apis::conversions::Error + > { + xcm_runtime_apis::conversions::LocationToAccountHelper::< + AccountId, + xcm_config::LocationConverter, + >::convert_location(location) + } + } + impl pallet_nomination_pools_runtime_api::NominationPoolsApi< Block, AccountId, @@ -2383,6 +2555,8 @@ sp_api::impl_runtime_apis! { use xcm_config::{AssetHub, TokenLocation}; + use alloc::boxed::Box; + parameter_types! { pub ExistentialDepositAsset: Option = Some(( TokenLocation::get(), diff --git a/polkadot/runtime/westend/src/weights/mod.rs b/polkadot/runtime/westend/src/weights/mod.rs index f6a9008d71876726dda2ad240ecdb4588a1f82a3..2248e421e63948e19283fd8ceab2d70631062687 100644 --- a/polkadot/runtime/westend/src/weights/mod.rs +++ b/polkadot/runtime/westend/src/weights/mod.rs @@ -26,8 +26,10 @@ pub mod pallet_fast_unstake; pub mod pallet_identity; pub mod pallet_indices; pub mod pallet_message_queue; +pub mod pallet_mmr; pub mod pallet_multisig; pub mod pallet_nomination_pools; +pub mod pallet_parameters; pub mod pallet_preimage; pub mod pallet_proxy; pub mod pallet_referenda_fellowship_referenda; @@ -48,7 +50,6 @@ pub mod runtime_common_crowdloan; pub mod runtime_common_identity_migrator; pub mod runtime_common_paras_registrar; pub mod runtime_common_slots; -pub mod runtime_parachains_assigner_on_demand; pub mod runtime_parachains_configuration; pub mod runtime_parachains_coretime; pub mod runtime_parachains_disputes; @@ -56,6 +57,7 @@ pub mod runtime_parachains_disputes_slashing; pub mod runtime_parachains_hrmp; pub mod runtime_parachains_inclusion; pub mod runtime_parachains_initializer; +pub mod runtime_parachains_on_demand; pub mod runtime_parachains_paras; pub mod runtime_parachains_paras_inherent; pub mod xcm; diff --git a/polkadot/runtime/westend/src/weights/pallet_mmr.rs b/polkadot/runtime/westend/src/weights/pallet_mmr.rs new file mode 100644 index 0000000000000000000000000000000000000000..1a410e7fc46ea4aa3944765ef662f4419c4cd16a --- /dev/null +++ b/polkadot/runtime/westend/src/weights/pallet_mmr.rs @@ -0,0 +1,76 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_mmr` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-17, STEPS: `5`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `am1max.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/testnet/polkadot +// benchmark +// pallet +// --steps=5 +// --repeat=1 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --pallet=pallet_mmr +// --chain=westend-dev +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/westend/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_mmr`. +pub struct WeightInfo(PhantomData); +impl pallet_mmr::WeightInfo for WeightInfo { + /// Storage: `Mmr::NumberOfLeaves` (r:1 w:1) + /// Proof: `Mmr::NumberOfLeaves` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `Paras::Heads` (r:1025 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `BeefyMmrLeaf::BeefyNextAuthorities` (r:1 w:0) + /// Proof: `BeefyMmrLeaf::BeefyNextAuthorities` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: `Mmr::Nodes` (r:8 w:4) + /// Proof: `Mmr::Nodes` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `System::Digest` (r:1 w:1) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Mmr::RootHash` (r:0 w:1) + /// Proof: `Mmr::RootHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// The range of component `x` is `[1, 1000]`. + fn on_initialize(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1071043 + x * (39 ยฑ0)` + // Estimated: `3608787 + x * (39 ยฑ6)` + // Minimum execution time: 11_102_000_000 picoseconds. + Weight::from_parts(21_772_042_215, 0) + .saturating_add(Weight::from_parts(0, 3608787)) + .saturating_add(T::DbWeight::get().reads(1031)) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(Weight::from_parts(0, 39).saturating_mul(x.into())) + } +} diff --git a/polkadot/runtime/westend/src/weights/pallet_parameters.rs b/polkadot/runtime/westend/src/weights/pallet_parameters.rs new file mode 100644 index 0000000000000000000000000000000000000000..2e131ce55f31961a5279f0be4c91eb7f92b9deec --- /dev/null +++ b/polkadot/runtime/westend/src/weights/pallet_parameters.rs @@ -0,0 +1,63 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_parameters` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-04-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend")`, DB CACHE: 1024 + +// Executed Command: +// target/production/polkadot +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_parameters +// --chain=westend +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/westend/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_parameters`. +pub struct WeightInfo(PhantomData); +impl pallet_parameters::WeightInfo for WeightInfo { + /// Storage: `Parameters::Parameters` (r:1 w:1) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + fn set_parameter() -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `3493` + // Minimum execution time: 6_937_000 picoseconds. + Weight::from_parts(7_242_000, 0) + .saturating_add(Weight::from_parts(0, 3493)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/polkadot/runtime/westend/src/weights/runtime_parachains_coretime.rs b/polkadot/runtime/westend/src/weights/runtime_parachains_coretime.rs index 443651a6fda44380d89b02c53dc70338bdc7f4ee..9df382875f5f12ddee62751eeca5feb16dfece41 100644 --- a/polkadot/runtime/westend/src/weights/runtime_parachains_coretime.rs +++ b/polkadot/runtime/westend/src/weights/runtime_parachains_coretime.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `runtime_parachains::coretime` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-06-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-1pho9goo-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -48,6 +48,28 @@ use core::marker::PhantomData; /// Weight functions for `runtime_parachains::coretime`. pub struct WeightInfo(PhantomData); impl polkadot_runtime_parachains::coretime::WeightInfo for WeightInfo { + /// Storage: `OnDemandAssignmentProvider::Revenue` (r:1 w:1) + /// Proof: `OnDemandAssignmentProvider::Revenue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn request_revenue_at() -> Weight { + // Proof Size summary in bytes: + // Measured: `2930` + // Estimated: `6395` + // Minimum execution time: 34_947_000 picoseconds. + Weight::from_parts(35_550_000, 0) + .saturating_add(Weight::from_parts(0, 6395)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) + } /// Storage: `Configuration::PendingConfigs` (r:1 w:1) /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) @@ -58,8 +80,8 @@ impl polkadot_runtime_parachains::coretime::WeightInfo // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_486_000 picoseconds. - Weight::from_parts(7_889_000, 0) + // Minimum execution time: 7_519_000 picoseconds. + Weight::from_parts(7_803_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -73,11 +95,11 @@ impl polkadot_runtime_parachains::coretime::WeightInfo // Proof Size summary in bytes: // Measured: `147` // Estimated: `3612` - // Minimum execution time: 9_409_000 picoseconds. - Weight::from_parts(10_177_115, 0) + // Minimum execution time: 9_697_000 picoseconds. + Weight::from_parts(10_610_219, 0) .saturating_add(Weight::from_parts(0, 3612)) - // Standard Error: 259 - .saturating_add(Weight::from_parts(13_932, 0).saturating_mul(s.into())) + // Standard Error: 732 + .saturating_add(Weight::from_parts(10_364, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/polkadot/runtime/westend/src/weights/runtime_parachains_assigner_on_demand.rs b/polkadot/runtime/westend/src/weights/runtime_parachains_on_demand.rs similarity index 62% rename from polkadot/runtime/westend/src/weights/runtime_parachains_assigner_on_demand.rs rename to polkadot/runtime/westend/src/weights/runtime_parachains_on_demand.rs index 8b046f5d34ad7d3f0800b6d48f2cbb83cd5ab010..fc7efa6edfcf361f51892ef809721d3c34e915dd 100644 --- a/polkadot/runtime/westend/src/weights/runtime_parachains_assigner_on_demand.rs +++ b/polkadot/runtime/westend/src/weights/runtime_parachains_on_demand.rs @@ -14,12 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Autogenerated weights for `runtime_parachains::assigner_on_demand` +//! Autogenerated weights for `runtime_parachains::on_demand` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-1pho9goo-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -32,7 +32,7 @@ // --wasm-execution=compiled // --heap-pages=4096 // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=runtime_parachains::assigner_on_demand +// --pallet=runtime_parachains::on_demand // --chain=westend-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/westend/src/weights/ @@ -45,11 +45,15 @@ use frame_support::{traits::Get, weights::Weight}; use core::marker::PhantomData; -/// Weight functions for `runtime_parachains::assigner_on_demand`. +/// Weight functions for `runtime_parachains::on_demand`. pub struct WeightInfo(PhantomData); -impl polkadot_runtime_parachains::assigner_on_demand::WeightInfo for WeightInfo { +impl polkadot_runtime_parachains::on_demand::WeightInfo for WeightInfo { /// Storage: `OnDemandAssignmentProvider::QueueStatus` (r:1 w:1) /// Proof: `OnDemandAssignmentProvider::QueueStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `OnDemandAssignmentProvider::Revenue` (r:1 w:1) + /// Proof: `OnDemandAssignmentProvider::Revenue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `OnDemandAssignmentProvider::ParaIdAffinity` (r:1 w:0) /// Proof: `OnDemandAssignmentProvider::ParaIdAffinity` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `OnDemandAssignmentProvider::FreeEntries` (r:1 w:1) @@ -57,19 +61,23 @@ impl polkadot_runtime_parachains::assigner_on_demand::W /// The range of component `s` is `[1, 9999]`. fn place_order_keep_alive(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `218 + s * (8 ยฑ0)` - // Estimated: `3681 + s * (8 ยฑ0)` - // Minimum execution time: 21_396_000 picoseconds. - Weight::from_parts(20_585_695, 0) - .saturating_add(Weight::from_parts(0, 3681)) - // Standard Error: 127 - .saturating_add(Weight::from_parts(20_951, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `270 + s * (8 ยฑ0)` + // Estimated: `3733 + s * (8 ยฑ0)` + // Minimum execution time: 29_427_000 picoseconds. + Weight::from_parts(26_756_913, 0) + .saturating_add(Weight::from_parts(0, 3733)) + // Standard Error: 121 + .saturating_add(Weight::from_parts(20_849, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(s.into())) } /// Storage: `OnDemandAssignmentProvider::QueueStatus` (r:1 w:1) /// Proof: `OnDemandAssignmentProvider::QueueStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `OnDemandAssignmentProvider::Revenue` (r:1 w:1) + /// Proof: `OnDemandAssignmentProvider::Revenue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `OnDemandAssignmentProvider::ParaIdAffinity` (r:1 w:0) /// Proof: `OnDemandAssignmentProvider::ParaIdAffinity` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `OnDemandAssignmentProvider::FreeEntries` (r:1 w:1) @@ -77,15 +85,15 @@ impl polkadot_runtime_parachains::assigner_on_demand::W /// The range of component `s` is `[1, 9999]`. fn place_order_allow_death(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `218 + s * (8 ยฑ0)` - // Estimated: `3681 + s * (8 ยฑ0)` - // Minimum execution time: 21_412_000 picoseconds. - Weight::from_parts(19_731_554, 0) - .saturating_add(Weight::from_parts(0, 3681)) - // Standard Error: 128 - .saturating_add(Weight::from_parts(21_055, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `270 + s * (8 ยฑ0)` + // Estimated: `3733 + s * (8 ยฑ0)` + // Minimum execution time: 29_329_000 picoseconds. + Weight::from_parts(26_415_340, 0) + .saturating_add(Weight::from_parts(0, 3733)) + // Standard Error: 129 + .saturating_add(Weight::from_parts(20_909, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(s.into())) } } diff --git a/polkadot/runtime/westend/src/weights/xcm/mod.rs b/polkadot/runtime/westend/src/weights/xcm/mod.rs index 09e883a9f7af5820832e7db52a8eeba5148d3a48..cb5894ea51e3c5106e75e86bc35249f24e8a03b4 100644 --- a/polkadot/runtime/westend/src/weights/xcm/mod.rs +++ b/polkadot/runtime/westend/src/weights/xcm/mod.rs @@ -18,8 +18,8 @@ mod pallet_xcm_benchmarks_fungible; mod pallet_xcm_benchmarks_generic; use crate::Runtime; +use alloc::vec::Vec; use frame_support::weights::Weight; -use sp_std::prelude::*; use xcm::{ latest::{prelude::*, QueryResponseInfo}, DoubleEncoded, diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index 9d7143c96bb5eecda25309634d395ba24b6a8b11..d75083929a04511e104d8c36d7628fa5e329ec84 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -42,10 +42,9 @@ use xcm_builder::{ AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, DescribeAllTerminal, DescribeFamily, FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsChildSystemParachain, IsConcrete, MintLocation, - OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32, + OriginToPluralityVoice, SendXcmFeeToAccount, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, - XcmFeeToAccount, }; use xcm_executor::XcmExecutor; @@ -211,7 +210,7 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type FeeManager = XcmFeeManagerFromComponents< WaivedLocations, - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = Nothing; diff --git a/polkadot/statement-table/Cargo.toml b/polkadot/statement-table/Cargo.toml index 7181afd9989ec9e0b00d1335bf35f2c5f2441836..53ea0b74463bc2466df2ff37f190f429d9b2973a 100644 --- a/polkadot/statement-table/Cargo.toml +++ b/polkadot/statement-table/Cargo.toml @@ -10,7 +10,7 @@ description = "Stores messages other authorities issue about candidates in Polka workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -sp-core = { path = "../../substrate/primitives/core" } -polkadot-primitives = { path = "../primitives" } -gum = { package = "tracing-gum", path = "../node/gum" } +codec = { features = ["derive"], workspace = true } +sp-core = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +gum = { workspace = true, default-features = true } diff --git a/polkadot/utils/generate-bags/Cargo.toml b/polkadot/utils/generate-bags/Cargo.toml index ad6d7259d2483e11e9df8c121bab75461a71c525..16205b0f51f57a62b923eff0952a45795c6cb3b6 100644 --- a/polkadot/utils/generate-bags/Cargo.toml +++ b/polkadot/utils/generate-bags/Cargo.toml @@ -10,9 +10,9 @@ description = "CLI to generate voter bags for Polkadot runtimes" workspace = true [dependencies] -clap = { version = "4.5.3", features = ["derive"] } +clap = { features = ["derive"], workspace = true } -generate-bags = { path = "../../../substrate/utils/frame/generate-bags" } -sp-io = { path = "../../../substrate/primitives/io" } +generate-bags = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } -westend-runtime = { path = "../../runtime/westend" } +westend-runtime = { workspace = true } diff --git a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml index 20e4130f888bcb1f826dab81fb7e5a721a53a225..206ca8cf19a90df9bc2becd0c65039f35d714191 100644 --- a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml +++ b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml @@ -10,14 +10,14 @@ license.workspace = true workspace = true [dependencies] -westend-runtime = { path = "../../../runtime/westend" } -westend-runtime-constants = { path = "../../../runtime/westend/constants" } +westend-runtime = { workspace = true } +westend-runtime-constants = { workspace = true, default-features = true } -pallet-bags-list-remote-tests = { path = "../../../../substrate/frame/bags-list/remote-tests" } -sp-tracing = { path = "../../../../substrate/primitives/tracing" } -frame-system = { path = "../../../../substrate/frame/system" } -sp-core = { path = "../../../../substrate/primitives/core" } +pallet-bags-list-remote-tests = { workspace = true } +sp-tracing = { workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } -clap = { version = "4.5.3", features = ["derive"] } +clap = { features = ["derive"], workspace = true } log = { workspace = true, default-features = true } -tokio = { version = "1.24.2", features = ["macros"] } +tokio = { features = ["macros"], workspace = true, default-features = true } diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index 690fb377dad78a8f6fb6d946fabab1ce68ba91df..862f5557a012a9bd1953607e774b36009c87d9e5 100644 --- a/polkadot/xcm/Cargo.toml +++ b/polkadot/xcm/Cargo.toml @@ -10,23 +10,24 @@ license.workspace = true workspace = true [dependencies] -array-bytes = "6.2.2" -bounded-collections = { version = "0.2.0", default-features = false, features = ["serde"] } -derivative = { version = "2.2.0", default-features = false, features = ["use_core"] } -impl-trait-for-tuples = "0.2.2" +array-bytes = { workspace = true, default-features = true } +bounded-collections = { features = ["serde"], workspace = true } +derivative = { features = ["use_core"], workspace = true } +impl-trait-for-tuples = { workspace = true } log = { workspace = true } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } -sp-weights = { path = "../../substrate/primitives/weights", default-features = false, features = ["serde"] } +codec = { features = ["derive", "max-encoded-len"], workspace = true } +scale-info = { features = ["derive", "serde"], workspace = true } +sp-runtime = { workspace = true } +sp-weights = { features = ["serde"], workspace = true } serde = { features = ["alloc", "derive", "rc"], workspace = true } -schemars = { version = "0.8.13", default-features = true, optional = true } -xcm-procedural = { path = "procedural" } -environmental = { version = "1.1.4", default-features = false } +schemars = { default-features = true, optional = true, workspace = true } +xcm-procedural = { workspace = true, default-features = true } +environmental = { workspace = true } [dev-dependencies] -sp-io = { path = "../../substrate/primitives/io" } -hex = "0.4.3" -hex-literal = "0.4.1" +sp-io = { workspace = true, default-features = true } +hex = { workspace = true, default-features = true } +hex-literal = { workspace = true, default-features = true } [features] default = ["std"] @@ -38,6 +39,11 @@ std = [ "log/std", "scale-info/std", "serde/std", + "sp-runtime/std", "sp-weights/std", ] -json-schema = ["bounded-collections/json-schema", "dep:schemars", "sp-weights/json-schema"] +json-schema = [ + "bounded-collections/json-schema", + "dep:schemars", + "sp-weights/json-schema", +] diff --git a/polkadot/xcm/docs/Cargo.toml b/polkadot/xcm/docs/Cargo.toml index 9820bd36dc0b1fb84fb6c4e43e4b1608308432a2..9d8f4c0a6430b71e2b2d1ba09719a8c397b4e4d5 100644 --- a/polkadot/xcm/docs/Cargo.toml +++ b/polkadot/xcm/docs/Cargo.toml @@ -10,30 +10,30 @@ publish = false [dependencies] # For XCM stuff -xcm = { path = "../../xcm", package = "staging-xcm" } -xcm-executor = { path = "../../xcm/xcm-executor", package = "staging-xcm-executor" } -xcm-builder = { path = "../../xcm/xcm-builder", package = "staging-xcm-builder" } -xcm-simulator = { path = "../../xcm/xcm-simulator" } -pallet-xcm = { path = "../../xcm/pallet-xcm" } +xcm = { workspace = true, default-features = true } +xcm-executor = { workspace = true, default-features = true } +xcm-builder = { workspace = true, default-features = true } +xcm-simulator = { workspace = true, default-features = true } +pallet-xcm = { workspace = true, default-features = true } # For building FRAME runtimes -frame = { package = "polkadot-sdk-frame", path = "../../../substrate/frame", features = ["experimental", "runtime"] } -codec = { package = "parity-scale-codec", version = "3.6.9" } -scale-info = { version = "2.6.0", default-features = false } -polkadot-parachain-primitives = { path = "../../../polkadot/parachain" } -polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains" } -polkadot-primitives = { path = "../../../polkadot/primitives" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } -sp-std = { path = "../../../substrate/primitives/std" } -sp-io = { path = "../../../substrate/primitives/io" } +frame = { features = ["experimental", "runtime"], workspace = true, default-features = true } +codec = { workspace = true, default-features = true } +scale-info = { workspace = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } # Some pallets -pallet-message-queue = { path = "../../../substrate/frame/message-queue" } -pallet-balances = { path = "../../../substrate/frame/balances" } +pallet-message-queue = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } # For building docs simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", branch = "main" } -docify = "0.2.6" +docify = { workspace = true } [dev-dependencies] -test-log = "0.2.14" +test-log = { workspace = true } diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/mod.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/mod.rs index e7d00ac71038b4f02d5172584a398f185864f46c..23d6664bdafcbc147f63c3a99ce2d788277679b5 100644 --- a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/mod.rs +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/mod.rs @@ -16,7 +16,7 @@ //! # Runtime -use frame::{deps::frame_system, prelude::*, runtime::prelude::*, traits::IdentityLookup}; +use frame::{deps::frame_system, runtime::prelude::*, traits::IdentityLookup}; use xcm_executor::XcmExecutor; use xcm_simulator::mock_message_queue; diff --git a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml index 8bf3b9abf66349834b3c2b7d7cd367e4b0b835d8..b07bdfdca3d196095a45370a9b2d622dd2a1636a 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml +++ b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml @@ -13,29 +13,28 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false } -xcm = { package = "staging-xcm", path = "..", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder", default-features = false } +codec = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-runtime = { workspace = true } +sp-io = { workspace = true } +xcm-executor = { workspace = true } +frame-benchmarking = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } log = { workspace = true, default-features = true } [dev-dependencies] -pallet-balances = { path = "../../../substrate/frame/balances" } -pallet-assets = { path = "../../../substrate/frame/assets" } -sp-tracing = { path = "../../../substrate/primitives/tracing" } -xcm = { package = "staging-xcm", path = ".." } +pallet-balances = { workspace = true, default-features = true } +pallet-assets = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +xcm = { workspace = true, default-features = true } # temp -pallet-xcm = { path = "../pallet-xcm" } -polkadot-runtime-common = { path = "../../runtime/common" } +pallet-xcm = { workspace = true, default-features = true } +polkadot-runtime-common = { workspace = true, default-features = true } # westend-runtime = { path = "../../runtime/westend", features = ["runtime-benchmarks"] } -polkadot-primitives = { path = "../../primitives" } +polkadot-primitives = { workspace = true, default-features = true } [features] default = ["std"] @@ -48,7 +47,6 @@ std = [ "scale-info/std", "sp-io/std", "sp-runtime/std", - "sp-std/std", "xcm-builder/std", "xcm-executor/std", ] diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs index d99da9184b5d8c7f2680b23140df1083d487b452..6ce49074a6e2b1fa02dd0f1fbe4f90db1058e560 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs @@ -16,6 +16,7 @@ use super::*; use crate::{account_and_location, new_executor, AssetTransactorOf, EnsureDelivery, XcmCallOf}; +use alloc::{vec, vec::Vec}; use frame_benchmarking::{benchmarks_instance_pallet, BenchmarkError, BenchmarkResult}; use frame_support::{ pallet_prelude::Get, @@ -23,7 +24,6 @@ use frame_support::{ weights::Weight, }; use sp_runtime::traits::{Bounded, Zero}; -use sp_std::{prelude::*, vec}; use xcm::latest::{prelude::*, MAX_ITEMS_IN_ASSETS}; use xcm_executor::traits::{ConvertLocation, FeeReason, TransactAsset}; @@ -37,7 +37,7 @@ benchmarks_instance_pallet! { >::Balance as TryInto - >::Error: sp_std::fmt::Debug, + >::Error: core::fmt::Debug, } withdraw_asset { diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs index 760b21f93566e12b77a00f2c7b9b744f6db91d68..40a7da58a687c186664404e0a00734b457b60e51 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs @@ -16,10 +16,10 @@ use super::*; use crate::{account_and_location, new_executor, EnsureDelivery, XcmCallOf}; +use alloc::{vec, vec::Vec}; use codec::Encode; use frame_benchmarking::{benchmarks, BenchmarkError}; use frame_support::{dispatch::GetDispatchInfo, traits::fungible::Inspect}; -use sp_std::{prelude::*, vec}; use xcm::{ latest::{prelude::*, MaxDispatchErrorLen, MaybeErrorCode, Weight, MAX_ITEMS_IN_ASSETS}, DoubleEncoded, diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs index a43f27bf47e7242308adc1b53d146508f14e36b2..4a12bb7f47c665ed6f302d5e665cf9c2b0e911a2 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs @@ -18,9 +18,11 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + +use alloc::vec::Vec; use codec::Encode; use frame_benchmarking::{account, BenchmarkError}; -use sp_std::prelude::*; use xcm::latest::prelude::*; use xcm_builder::EnsureDelivery; use xcm_executor::{traits::ConvertLocation, Config as XcmConfig}; diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 6f9b389ab6f12db50c27fab0f5f20961c7f171c6..ed4b441d7c33c347cccda054b8bc7019b3d11388 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -10,32 +10,31 @@ license.workspace = true workspace = true [dependencies] -bounded-collections = { version = "0.2.0", default-features = false } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } +bounded-collections = { workspace = true } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } log = { workspace = true } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } -xcm = { package = "staging-xcm", path = "..", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder", default-features = false } -xcm-fee-payment-runtime-api = { path = "../xcm-fee-payment-runtime-api", default-features = false } +xcm = { workspace = true } +xcm-executor = { workspace = true } +xcm-builder = { workspace = true } +xcm-runtime-apis = { workspace = true } # marked optional, used in benchmarking -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } -pallet-balances = { path = "../../../substrate/frame/balances", default-features = false, optional = true } +frame-benchmarking = { optional = true, workspace = true } +pallet-balances = { optional = true, workspace = true } [dev-dependencies] -pallet-assets = { path = "../../../substrate/frame/assets" } -polkadot-runtime-parachains = { path = "../../runtime/parachains" } -polkadot-parachain-primitives = { path = "../../parachain" } +pallet-assets = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } [features] default = ["std"] @@ -52,10 +51,9 @@ std = [ "sp-core/std", "sp-io/std", "sp-runtime/std", - "sp-std/std", "xcm-builder/std", "xcm-executor/std", - "xcm-fee-payment-runtime-api/std", + "xcm-runtime-apis/std", "xcm/std", ] runtime-benchmarks = [ @@ -69,7 +67,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", - "xcm-fee-payment-runtime-api/runtime-benchmarks", + "xcm-runtime-apis/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index da46a6a37c0654f6ef34daf7bbd37cd5b655ac45..d09c81bf434e2ce843b55fc5b05baee121e562c8 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -18,7 +18,6 @@ use super::*; use frame_benchmarking::{benchmarks, whitelisted_caller, BenchmarkError, BenchmarkResult}; use frame_support::{assert_ok, weights::Weight}; use frame_system::RawOrigin; -use sp_std::prelude::*; use xcm::latest::prelude::*; use xcm_builder::EnsureDelivery; use xcm_executor::traits::FeeReason; diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 8f67e6e7d949693e25556af272ea73e443b620df..6451901279b166e116dd8dcf1d204da74db98d35 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -27,7 +27,11 @@ mod tests; pub mod migration; +extern crate alloc; + +use alloc::{boxed::Box, vec, vec::Vec}; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; +use core::{marker::PhantomData, result::Result}; use frame_support::{ dispatch::{ DispatchErrorWithPostInfo, GetDispatchInfo, PostDispatchInfo, WithPostDispatchInfo, @@ -49,7 +53,6 @@ use sp_runtime::{ }, Either, RuntimeDebug, }; -use sp_std::{boxed::Box, marker::PhantomData, prelude::*, result::Result, vec}; use xcm::{latest::QueryResponseInfo, prelude::*}; use xcm_builder::{ ExecuteController, ExecuteControllerWeightInfo, InspectMessageQueues, QueryController, @@ -64,7 +67,7 @@ use xcm_executor::{ }, AssetsInHolding, }; -use xcm_fee_payment_runtime_api::{ +use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, }; @@ -792,7 +795,7 @@ pub mod pallet { #[pallet::genesis_config] pub struct GenesisConfig { #[serde(skip)] - pub _config: sp_std::marker::PhantomData, + pub _config: core::marker::PhantomData, /// The default version to encode outgoing XCM messages with. pub safe_xcm_version: Option, } @@ -1376,7 +1379,7 @@ pub mod pallet { /// - `assets`: The assets to be withdrawn. This should include the assets used to pay the /// fee on the `dest` (and possibly reserve) chains. /// - `assets_transfer_type`: The XCM `TransferType` used to transfer the `assets`. - /// - `remote_fees_id`: One of the included `assets` to be be used to pay fees. + /// - `remote_fees_id`: One of the included `assets` to be used to pay fees. /// - `fees_transfer_type`: The XCM `TransferType` used to transfer the `fees` assets. /// - `custom_xcm_on_dest`: The XCM to be executed on `dest` chain as the last step of the /// transfer, which also determines what happens to the assets on the destination chain. @@ -1438,8 +1441,8 @@ enum FeesHandling { Separate { local_xcm: Xcm<::RuntimeCall>, remote_xcm: Xcm<()> }, } -impl sp_std::fmt::Debug for FeesHandling { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { +impl core::fmt::Debug for FeesHandling { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Self::Batched { fees } => write!(f, "FeesHandling::Batched({:?})", fees), Self::Separate { local_xcm, remote_xcm } => write!( @@ -1840,8 +1843,8 @@ impl Pallet { FeesHandling::Separate { local_xcm: mut local_fees, remote_xcm: mut remote_fees } => { // fees are handled by separate XCM instructions, prepend fees instructions (for // remote XCM they have to be prepended instead of appended to pass barriers). - sp_std::mem::swap(local, &mut local_fees); - sp_std::mem::swap(remote, &mut remote_fees); + core::mem::swap(local, &mut local_fees); + core::mem::swap(remote, &mut remote_fees); // these are now swapped so fees actually go first local.inner_mut().append(&mut local_fees.into_inner()); remote.inner_mut().append(&mut remote_fees.into_inner()); @@ -2442,7 +2445,7 @@ impl Pallet { /// /// Returns not only the call result and events, but also the local XCM, if any, /// and any XCMs forwarded to other locations. - /// Meant to be used in the `xcm_fee_payment_runtime_api::dry_run::DryRunApi` runtime API. + /// Meant to be used in the `xcm_runtime_apis::dry_run::DryRunApi` runtime API. pub fn dry_run_call( origin: OriginCaller, call: RuntimeCall, @@ -2474,7 +2477,7 @@ impl Pallet { /// Dry-runs `xcm` with the given `origin_location`. /// /// Returns execution result, events, and any forwarded XCMs to other locations. - /// Meant to be used in the `xcm_fee_payment_runtime_api::dry_run::DryRunApi` runtime API. + /// Meant to be used in the `xcm_runtime_apis::dry_run::DryRunApi` runtime API. pub fn dry_run_xcm( origin_location: VersionedLocation, xcm: VersionedXcm, diff --git a/polkadot/xcm/pallet-xcm/src/migration.rs b/polkadot/xcm/pallet-xcm/src/migration.rs index b157e6b5c3d5f27d206b73a1b040ca5d7944b8f2..0aec97ab410516c35860f397d41ede599768c5c6 100644 --- a/polkadot/xcm/pallet-xcm/src/migration.rs +++ b/polkadot/xcm/pallet-xcm/src/migration.rs @@ -34,7 +34,7 @@ pub mod v1 { /// enacted on-chain. /// /// Use experimental [`MigrateToV1`] instead. - pub struct VersionUncheckedMigrateToV1(sp_std::marker::PhantomData); + pub struct VersionUncheckedMigrateToV1(core::marker::PhantomData); impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV1 { fn on_runtime_upgrade() -> Weight { let mut weight = T::DbWeight::get().reads(1); @@ -81,7 +81,7 @@ pub mod v1 { /// `XCM_VERSION`. /// /// NOTE: This migration can be permanently added to the runtime migrations. -pub struct MigrateToLatestXcmVersion(sp_std::marker::PhantomData); +pub struct MigrateToLatestXcmVersion(core::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToLatestXcmVersion { fn on_runtime_upgrade() -> Weight { CurrentMigration::::put(VersionMigrationStage::default()); diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 2be6f301f85621489ab6986aaf300251fd239fbc..8d0476b0e70d77f7cc1d63033392eb274dbb337c 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -15,6 +15,7 @@ // along with Polkadot. If not, see . use codec::Encode; +pub use core::cell::RefCell; use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{ @@ -28,16 +29,15 @@ use polkadot_parachain_primitives::primitives::Id as ParaId; use polkadot_runtime_parachains::origin; use sp_core::H256; use sp_runtime::{traits::IdentityLookup, AccountId32, BuildStorage}; -pub use sp_std::cell::RefCell; use xcm::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, DescribeAllTerminal, EnsureDecodableXcm, FixedRateOfFungible, FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, - HashedDescription, IsConcrete, MatchedConvertedConcreteId, NoChecking, + HashedDescription, IsConcrete, MatchedConvertedConcreteId, NoChecking, SendXcmFeeToAccount, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - XcmFeeManagerFromComponents, XcmFeeToAccount, + XcmFeeManagerFromComponents, }; use xcm_executor::{ traits::{Identity, JustTry}, @@ -504,7 +504,7 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type FeeManager = XcmFeeManagerFromComponents< EverythingBut, - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = Nothing; diff --git a/polkadot/xcm/procedural/Cargo.toml b/polkadot/xcm/procedural/Cargo.toml index ca9fb351bd3cad1f805106e405cfdcc496c9d8a8..a7db183bcdbf89b2b642f2eb8eea9f87019f086d 100644 --- a/polkadot/xcm/procedural/Cargo.toml +++ b/polkadot/xcm/procedural/Cargo.toml @@ -14,11 +14,11 @@ workspace = true proc-macro = true [dependencies] -proc-macro2 = "1.0.56" +proc-macro2 = { workspace = true } quote = { workspace = true } syn = { workspace = true } -Inflector = "0.11.4" +Inflector = { workspace = true } [dev-dependencies] -trybuild = { version = "1.0.88", features = ["diff"] } -xcm = { package = "staging-xcm", path = ".." } +trybuild = { features = ["diff"], workspace = true } +xcm = { workspace = true, default-features = true } diff --git a/polkadot/xcm/procedural/src/builder_pattern.rs b/polkadot/xcm/procedural/src/builder_pattern.rs index 0a33d52580fca02166990c72258fa77bcfb21d45..09ead1389d19da15f167793b041b9ef849c0e741 100644 --- a/polkadot/xcm/procedural/src/builder_pattern.rs +++ b/polkadot/xcm/procedural/src/builder_pattern.rs @@ -233,6 +233,32 @@ fn generate_builder_impl(name: &Ident, data_enum: &DataEnum) -> Result = data_enum + .variants + .iter() + .filter(|variant| variant.ident == "ClearOrigin") + .map(|variant| { + let variant_name = &variant.ident; + let method_name_string = &variant_name.to_string().to_snake_case(); + let method_name = syn::Ident::new(method_name_string, variant_name.span()); + let docs = get_doc_comments(variant); + let method = match &variant.fields { + Fields::Unit => { + quote! { + #(#docs)* + pub fn #method_name(mut self) -> XcmBuilder { + self.instructions.push(#name::::#variant_name); + self + } + } + }, + _ => return Err(Error::new_spanned(variant, "ClearOrigin should have no fields")), + }; + Ok(method) + }) + .collect::, _>>()?; + // Then we require fees to be paid let buy_execution_method = data_enum .variants @@ -276,6 +302,7 @@ fn generate_builder_impl(name: &Ident, data_enum: &DataEnum) -> Result XcmBuilder { + #(#allowed_after_load_holding_methods)* #buy_execution_method } }; diff --git a/polkadot/xcm/procedural/tests/builder_pattern.rs b/polkadot/xcm/procedural/tests/builder_pattern.rs index 96b16fb7e4565c2e3e891ccf8ee3ac2bedc68b0b..4202309bf3f71cb6a6a81968ad19eea2cc999515 100644 --- a/polkadot/xcm/procedural/tests/builder_pattern.rs +++ b/polkadot/xcm/procedural/tests/builder_pattern.rs @@ -79,3 +79,24 @@ fn default_builder_requires_buy_execution() { ]) ); } + +#[test] +fn default_builder_allows_clear_origin_before_buy_execution() { + let asset: Asset = (Here, 100u128).into(); + let beneficiary: Location = [0u8; 32].into(); + let message: Xcm<()> = Xcm::builder() + .receive_teleported_asset(asset.clone()) + .clear_origin() + .buy_execution(asset.clone(), Unlimited) + .deposit_asset(asset.clone(), beneficiary.clone()) + .build(); + assert_eq!( + message, + Xcm(vec![ + ReceiveTeleportedAsset(asset.clone().into()), + ClearOrigin, + BuyExecution { fees: asset.clone(), weight_limit: Unlimited }, + DepositAsset { assets: asset.into(), beneficiary }, + ]) + ); +} diff --git a/polkadot/xcm/src/v2/mod.rs b/polkadot/xcm/src/v2/mod.rs index 38e55d0ea51e5844640b2e9613f830f7cd636e7f..1afc120f500c65253e462762e2e69e6e3338210a 100644 --- a/polkadot/xcm/src/v2/mod.rs +++ b/polkadot/xcm/src/v2/mod.rs @@ -62,7 +62,10 @@ use super::{ }; use alloc::{vec, vec::Vec}; use bounded_collections::{ConstU32, WeakBoundedVec}; -use codec::{self, Decode, Encode, MaxEncodedLen}; +use codec::{ + self, decode_vec_with_len, Compact, Decode, Encode, Error as CodecError, Input as CodecInput, + MaxEncodedLen, +}; use core::{fmt::Debug, result}; use derivative::Derivative; use scale_info::TypeInfo; @@ -237,7 +240,7 @@ pub enum BodyPart { #[codec(compact)] denom: u32, }, - /// More than than the given proportion of members of the body. + /// More than the given proportion of members of the body. MoreThanProportion { #[codec(compact)] nom: u32, @@ -278,7 +281,7 @@ pub const VERSION: super::Version = 2; pub type QueryId = u64; /// DEPRECATED. Please use XCMv3 or XCMv4 instead. -#[derive(Derivative, Default, Encode, Decode, TypeInfo)] +#[derive(Derivative, Default, Encode, TypeInfo)] #[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))] #[codec(encode_bound())] #[codec(decode_bound())] @@ -286,6 +289,31 @@ pub type QueryId = u64; #[scale_info(replace_segment("staging_xcm", "xcm"))] pub struct Xcm(pub Vec>); +environmental::environmental!(instructions_count: u8); + +impl Decode for Xcm { + fn decode(input: &mut I) -> core::result::Result { + instructions_count::using_once(&mut 0, || { + let number_of_instructions: u32 = >::decode(input)?.into(); + instructions_count::with(|count| { + *count = count.saturating_add(number_of_instructions as u8); + if *count > MAX_INSTRUCTIONS_TO_DECODE { + return Err(CodecError::from("Max instructions exceeded")) + } + Ok(()) + }) + .unwrap_or(Ok(()))?; + let decoded_instructions = decode_vec_with_len(input, number_of_instructions as usize)?; + Ok(Self(decoded_instructions)) + }) + } +} + +/// The maximal number of instructions in an XCM before decoding fails. +/// +/// This is a deliberate limit - not a technical one. +pub const MAX_INSTRUCTIONS_TO_DECODE: u8 = 100; + impl Xcm { /// Create an empty instance. pub fn new() -> Self { @@ -1157,3 +1185,38 @@ impl TryFrom> for Instruction(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize]); + let encoded = max_xcm.encode(); + assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok()); + + let big_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize + 1]); + let encoded = big_xcm.encode(); + assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err()); + + let nested_xcm = Xcm::<()>(vec![ + DepositReserveAsset { + assets: All.into(), + dest: Here.into(), + xcm: max_xcm, + max_assets: 1, + }; + (MAX_INSTRUCTIONS_TO_DECODE / 2) as usize + ]); + let encoded = nested_xcm.encode(); + assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err()); + + let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]); + let encoded = even_more_nested_xcm.encode(); + assert_eq!(encoded.len(), 345730); + // This should not decode since the limit is 100 + assert_eq!(MAX_INSTRUCTIONS_TO_DECODE, 100, "precondition"); + assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err()); + } +} diff --git a/polkadot/xcm/src/v3/junction.rs b/polkadot/xcm/src/v3/junction.rs index aea4e03725159bcd08233353c60de6cde6d6b9ed..24348bf2e67213e9396a3120dfab8816695ba497 100644 --- a/polkadot/xcm/src/v3/junction.rs +++ b/polkadot/xcm/src/v3/junction.rs @@ -241,7 +241,7 @@ pub enum BodyPart { #[codec(compact)] denom: u32, }, - /// More than than the given proportion of members of the body. + /// More than the given proportion of members of the body. MoreThanProportion { #[codec(compact)] nom: u32, diff --git a/polkadot/xcm/src/v4/location.rs b/polkadot/xcm/src/v4/location.rs index 9e94d13626d619b2d4db5593561abacb7bad2e8f..f2c302495c73d2ebb96c53774c6cd98387242504 100644 --- a/polkadot/xcm/src/v4/location.rs +++ b/polkadot/xcm/src/v4/location.rs @@ -534,6 +534,12 @@ impl From<[u8; 32]> for Location { } } +impl From for Location { + fn from(id: sp_runtime::AccountId32) -> Self { + Junction::AccountId32 { network: None, id: id.into() }.into() + } +} + xcm_procedural::impl_conversion_functions_for_location_v4!(); #[cfg(test)] diff --git a/polkadot/xcm/src/v4/mod.rs b/polkadot/xcm/src/v4/mod.rs index 57840562ba3e4754efea5eb6185f86691bd3c326..2a279f989e9b23084925c1484f7f366c08325080 100644 --- a/polkadot/xcm/src/v4/mod.rs +++ b/polkadot/xcm/src/v4/mod.rs @@ -231,15 +231,15 @@ parameter_types! { #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] pub struct PalletInfo { #[codec(compact)] - index: u32, - name: BoundedVec, - module_name: BoundedVec, + pub index: u32, + pub name: BoundedVec, + pub module_name: BoundedVec, #[codec(compact)] - major: u32, + pub major: u32, #[codec(compact)] - minor: u32, + pub minor: u32, #[codec(compact)] - patch: u32, + pub patch: u32, } impl TryInto for PalletInfo { diff --git a/polkadot/xcm/xcm-builder/Cargo.toml b/polkadot/xcm/xcm-builder/Cargo.toml index 79c601b98b4fd012202a8a4de00b2d254a7c8023..7702e2f9be07db04aafcd911a7fbb9fb2cdfb957 100644 --- a/polkadot/xcm/xcm-builder/Cargo.toml +++ b/polkadot/xcm/xcm-builder/Cargo.toml @@ -10,34 +10,33 @@ version = "7.0.0" workspace = true [dependencies] -impl-trait-for-tuples = "0.2.1" -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } -xcm = { package = "staging-xcm", path = "..", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-arithmetic = { path = "../../../substrate/primitives/arithmetic", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-weights = { path = "../../../substrate/primitives/weights", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false } +impl-trait-for-tuples = { workspace = true } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } +xcm = { workspace = true } +xcm-executor = { workspace = true } +sp-arithmetic = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +sp-weights = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-transaction-payment = { workspace = true } log = { workspace = true } # Polkadot dependencies -polkadot-parachain-primitives = { path = "../../parachain", default-features = false } +polkadot-parachain-primitives = { workspace = true } [dev-dependencies] -primitive-types = "0.12.1" -pallet-balances = { path = "../../../substrate/frame/balances" } -pallet-xcm = { path = "../pallet-xcm" } -pallet-salary = { path = "../../../substrate/frame/salary" } -pallet-assets = { path = "../../../substrate/frame/assets" } -polkadot-primitives = { path = "../../primitives" } -polkadot-runtime-parachains = { path = "../../runtime/parachains" } -assert_matches = "1.5.0" -polkadot-test-runtime = { path = "../../runtime/test-runtime" } +primitive-types = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +pallet-xcm = { workspace = true, default-features = true } +pallet-salary = { workspace = true, default-features = true } +pallet-assets = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } +assert_matches = { workspace = true } +polkadot-test-runtime = { workspace = true } [features] default = ["std"] @@ -66,7 +65,6 @@ std = [ "sp-arithmetic/std", "sp-io/std", "sp-runtime/std", - "sp-std/std", "sp-weights/std", "xcm-executor/std", "xcm/std", diff --git a/polkadot/xcm/xcm-builder/src/asset_conversion.rs b/polkadot/xcm/xcm-builder/src/asset_conversion.rs index 520ce87448ea4f868fbb62130a7da45353d220b6..16ae05c20795e27a9aa6b4d2ec78d47b7665bbb2 100644 --- a/polkadot/xcm/xcm-builder/src/asset_conversion.rs +++ b/polkadot/xcm/xcm-builder/src/asset_conversion.rs @@ -16,9 +16,9 @@ //! Adapters to work with [`frame_support::traits::fungibles`] through XCM. +use core::{marker::PhantomData, result}; use frame_support::traits::{Contains, Get}; use sp_runtime::traits::MaybeEquivalence; -use sp_std::{marker::PhantomData, prelude::*, result}; use xcm::latest::prelude::*; use xcm_executor::traits::{Error as MatchError, MatchesFungibles, MatchesNonFungibles}; diff --git a/polkadot/xcm/xcm-builder/src/barriers.rs b/polkadot/xcm/xcm-builder/src/barriers.rs index 11e9122f9a121b1b08db7a5aec2fd423d63c98cf..5d95005eb663097b8130cd01640d6dd29a4f2307 100644 --- a/polkadot/xcm/xcm-builder/src/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/barriers.rs @@ -17,12 +17,12 @@ //! Various implementations for `ShouldExecute`. use crate::{CreateMatcher, MatchXcm}; +use core::{cell::Cell, marker::PhantomData, ops::ControlFlow, result::Result}; use frame_support::{ ensure, traits::{Contains, Get, ProcessMessageError}, }; use polkadot_parachain_primitives::primitives::IsSystem; -use sp_std::{cell::Cell, marker::PhantomData, ops::ControlFlow, result::Result}; use xcm::prelude::*; use xcm_executor::traits::{CheckSuspension, OnResponse, Properties, ShouldExecute}; diff --git a/polkadot/xcm/xcm-builder/src/controller.rs b/polkadot/xcm/xcm-builder/src/controller.rs index 04b19eaa587009aa118e7c7d51ce69b159e4d948..d4ce2ca5b353c94b8d4e512236008eae9a6dd28e 100644 --- a/polkadot/xcm/xcm-builder/src/controller.rs +++ b/polkadot/xcm/xcm-builder/src/controller.rs @@ -18,11 +18,11 @@ //! Controller traits defined in this module are high-level traits that will rely on other traits //! from `xcm-executor` to perform their tasks. +use alloc::boxed::Box; use frame_support::{ dispatch::{DispatchErrorWithPostInfo, WithPostDispatchInfo}, pallet_prelude::DispatchError, }; -use sp_std::boxed::Box; use xcm::prelude::*; pub use xcm_executor::traits::QueryHandler; diff --git a/polkadot/xcm/xcm-builder/src/currency_adapter.rs b/polkadot/xcm/xcm-builder/src/currency_adapter.rs index 99a736d6ac1f9dd197a6813cf377f35991638e9a..355d6ad85388cb1709139112384890354eb8da7a 100644 --- a/polkadot/xcm/xcm-builder/src/currency_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/currency_adapter.rs @@ -19,9 +19,9 @@ #![allow(deprecated)] use super::MintLocation; +use core::{marker::PhantomData, result}; use frame_support::traits::{ExistenceRequirement::AllowDeath, Get, WithdrawReasons}; use sp_runtime::traits::CheckedSub; -use sp_std::{marker::PhantomData, result}; use xcm::latest::{Asset, Error as XcmError, Location, Result, XcmContext}; use xcm_executor::{ traits::{ConvertLocation, MatchesFungible, TransactAsset}, diff --git a/polkadot/xcm/xcm-builder/src/fee_handling.rs b/polkadot/xcm/xcm-builder/src/fee_handling.rs index e114b3601c84a45cc0400114b7aaff2bfdae4bb8..17e9e64e00c9d2aa2cecb73c7355416b2d6ce6ac 100644 --- a/polkadot/xcm/xcm-builder/src/fee_handling.rs +++ b/polkadot/xcm/xcm-builder/src/fee_handling.rs @@ -68,36 +68,20 @@ impl, FeeHandler: HandleFee> FeeManager } } -/// Try to deposit the given fee in the specified account. -/// Burns the fee in case of a failure. -pub fn deposit_or_burn_fee>( - fee: Assets, - context: Option<&XcmContext>, - receiver: AccountId, -) { - let dest = AccountId32 { network: None, id: receiver.into() }.into(); - for asset in fee.into_inner() { - if let Err(e) = AssetTransactor::deposit_asset(&asset, &dest, context) { - log::trace!( - target: "xcm::fees", - "`AssetTransactor::deposit_asset` returned error: {:?}. Burning fee: {:?}. \ - They might be burned.", - e, asset, - ); - } - } -} - /// A `HandleFee` implementation that simply deposits the fees into a specific on-chain /// `ReceiverAccount`. /// /// It reuses the `AssetTransactor` configured on the XCM executor to deposit fee assets. If /// the `AssetTransactor` returns an error while calling `deposit_asset`, then a warning will be /// logged and the fee burned. +#[deprecated( + note = "`XcmFeeToAccount` will be removed in January 2025. Use `SendXcmFeeToAccount` instead." +)] pub struct XcmFeeToAccount( PhantomData<(AssetTransactor, AccountId, ReceiverAccount)>, ); +#[allow(deprecated)] impl< AssetTransactor: TransactAsset, AccountId: Clone + Into<[u8; 32]>, @@ -105,8 +89,49 @@ impl< > HandleFee for XcmFeeToAccount { fn handle_fee(fee: Assets, context: Option<&XcmContext>, _reason: FeeReason) -> Assets { - deposit_or_burn_fee::(fee, context, ReceiverAccount::get()); + let dest = AccountId32 { network: None, id: ReceiverAccount::get().into() }.into(); + deposit_or_burn_fee::(fee, context, dest); + + Assets::new() + } +} + +/// A `HandleFee` implementation that simply deposits the fees into a specific on-chain +/// `ReceiverAccount`. +/// +/// It reuses the `AssetTransactor` configured on the XCM executor to deposit fee assets. If +/// the `AssetTransactor` returns an error while calling `deposit_asset`, then a warning will be +/// logged and the fee burned. +/// +/// `ReceiverAccount` should implement `Get`. +pub struct SendXcmFeeToAccount( + PhantomData<(AssetTransactor, ReceiverAccount)>, +); + +impl> HandleFee + for SendXcmFeeToAccount +{ + fn handle_fee(fee: Assets, context: Option<&XcmContext>, _reason: FeeReason) -> Assets { + deposit_or_burn_fee::(fee, context, ReceiverAccount::get()); Assets::new() } } + +/// Try to deposit the given fee in the specified account. +/// Burns the fee in case of a failure. +pub fn deposit_or_burn_fee( + fee: Assets, + context: Option<&XcmContext>, + dest: Location, +) { + for asset in fee.into_inner() { + if let Err(e) = AssetTransactor::deposit_asset(&asset, &dest, context) { + log::trace!( + target: "xcm::fees", + "`AssetTransactor::deposit_asset` returned error: {e:?}. Burning fee: {asset:?}. \ + They might be burned.", + ); + } + } +} diff --git a/polkadot/xcm/xcm-builder/src/filter_asset_location.rs b/polkadot/xcm/xcm-builder/src/filter_asset_location.rs index d80c5d70deea8c00fbe32af758e8986cc8c6fa7a..16b7be7f3ba98432b75035e99dbc674dc9a26201 100644 --- a/polkadot/xcm/xcm-builder/src/filter_asset_location.rs +++ b/polkadot/xcm/xcm-builder/src/filter_asset_location.rs @@ -17,8 +17,9 @@ //! Various implementations of `ContainsPair` or //! `Contains<(Location, Vec)>`. +use alloc::vec::Vec; +use core::marker::PhantomData; use frame_support::traits::{Contains, ContainsPair, Get}; -use sp_std::{marker::PhantomData, vec::Vec}; use xcm::latest::{Asset, AssetFilter, AssetId, Location, WildAsset}; /// Accepts an asset iff it is a native asset. @@ -44,7 +45,7 @@ impl> ContainsPair for Case /// implementation of the given `Location` and if every asset from `assets` matches at least one of /// the `AssetFilter` instances provided by the `Get` implementation of `AssetFilters`. pub struct LocationWithAssetFilters( - sp_std::marker::PhantomData<(LocationFilter, AssetFilters)>, + core::marker::PhantomData<(LocationFilter, AssetFilters)>, ); impl, AssetFilters: Get>> Contains<(Location, Vec)> for LocationWithAssetFilters @@ -75,7 +76,7 @@ impl, AssetFilters: Get>> pub struct AllAssets; impl Get> for AllAssets { fn get() -> Vec { - sp_std::vec![AssetFilter::Wild(WildAsset::All)] + alloc::vec![AssetFilter::Wild(WildAsset::All)] } } @@ -96,11 +97,11 @@ mod tests { pub AssetYLocation: Location = Location::new(1, [GeneralIndex(2222)]); pub AssetZLocation: Location = Location::new(1, [GeneralIndex(3333)]); - pub OnlyAssetXOrAssetY: sp_std::vec::Vec = sp_std::vec![ + pub OnlyAssetXOrAssetY: alloc::vec::Vec = alloc::vec![ Wild(AllOf { fun: WildFungible, id: AssetId(AssetXLocation::get()) }), Wild(AllOf { fun: WildFungible, id: AssetId(AssetYLocation::get()) }), ]; - pub OnlyAssetZ: sp_std::vec::Vec = sp_std::vec![ + pub OnlyAssetZ: alloc::vec::Vec = alloc::vec![ Wild(AllOf { fun: WildFungible, id: AssetId(AssetZLocation::get()) }) ]; } diff --git a/polkadot/xcm/xcm-builder/src/fungible_adapter.rs b/polkadot/xcm/xcm-builder/src/fungible_adapter.rs index 45a0e2bdca2862c2142f3ecae17ae19ac6ec1839..25a705a39eb73906ca4c7ececfe4526e7450d712 100644 --- a/polkadot/xcm/xcm-builder/src/fungible_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/fungible_adapter.rs @@ -17,6 +17,7 @@ //! Adapters to work with [`frame_support::traits::fungible`] through XCM. use super::MintLocation; +use core::{marker::PhantomData, result}; use frame_support::traits::{ tokens::{ fungible, @@ -27,7 +28,6 @@ use frame_support::traits::{ }, Get, }; -use sp_std::{marker::PhantomData, prelude::*, result}; use xcm::latest::prelude::*; use xcm_executor::{ traits::{ConvertLocation, Error as MatchError, MatchesFungible, TransactAsset}, diff --git a/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs b/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs index 88bbf01d9e1f8c35d2b884be6a0c5a43f24c1073..a259afc6e682565718b86210a746e39928b140ab 100644 --- a/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs @@ -16,6 +16,7 @@ //! Adapters to work with [`frame_support::traits::fungibles`] through XCM. +use core::{marker::PhantomData, result}; use frame_support::traits::{ tokens::{ fungibles, @@ -26,7 +27,6 @@ use frame_support::traits::{ }, Contains, Get, }; -use sp_std::{marker::PhantomData, prelude::*, result}; use xcm::latest::prelude::*; use xcm_executor::traits::{ConvertLocation, Error as MatchError, MatchesFungibles, TransactAsset}; @@ -101,7 +101,7 @@ impl AssetChecking for NoChecking { /// Implementation of `AssetChecking` which subjects a given set of assets `T` to having their /// teleportations recorded with a `MintLocation::Local`. -pub struct LocalMint(sp_std::marker::PhantomData); +pub struct LocalMint(core::marker::PhantomData); impl> AssetChecking for LocalMint { fn asset_checking(asset: &AssetId) -> Option { match T::contains(asset) { @@ -113,7 +113,7 @@ impl> AssetChecking for LocalMint { /// Implementation of `AssetChecking` which subjects a given set of assets `T` to having their /// teleportations recorded with a `MintLocation::NonLocal`. -pub struct NonLocalMint(sp_std::marker::PhantomData); +pub struct NonLocalMint(core::marker::PhantomData); impl> AssetChecking for NonLocalMint { fn asset_checking(asset: &AssetId) -> Option { match T::contains(asset) { @@ -126,7 +126,7 @@ impl> AssetChecking for NonLocalMint { /// Implementation of `AssetChecking` which subjects a given set of assets `L` to having their /// teleportations recorded with a `MintLocation::Local` and a second set of assets `R` to having /// their teleportations recorded with a `MintLocation::NonLocal`. -pub struct DualMint(sp_std::marker::PhantomData<(L, R)>); +pub struct DualMint(core::marker::PhantomData<(L, R)>); impl, R: Contains> AssetChecking for DualMint { diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs index cc06c298a418d56f6a70d58b5f24bf8ccb14db5d..4cf83c9fc4517e5e76b751c5a6639a8950508734 100644 --- a/polkadot/xcm/xcm-builder/src/lib.rs +++ b/polkadot/xcm/xcm-builder/src/lib.rs @@ -20,6 +20,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + #[cfg(test)] mod tests; @@ -54,7 +56,7 @@ pub use currency_adapter::CurrencyAdapter; mod fee_handling; pub use fee_handling::{ - deposit_or_burn_fee, HandleFee, XcmFeeManagerFromComponents, XcmFeeToAccount, + deposit_or_burn_fee, HandleFee, SendXcmFeeToAccount, XcmFeeManagerFromComponents, }; mod filter_asset_location; diff --git a/polkadot/xcm/xcm-builder/src/location_conversion.rs b/polkadot/xcm/xcm-builder/src/location_conversion.rs index f95258492381b387fd71c7186b74b0f09a0aea66..1d840e9c0dde45cd2bb47024b713656b91051392 100644 --- a/polkadot/xcm/xcm-builder/src/location_conversion.rs +++ b/polkadot/xcm/xcm-builder/src/location_conversion.rs @@ -15,11 +15,12 @@ // along with Polkadot. If not, see . use crate::universal_exports::ensure_is_remote; +use alloc::vec::Vec; use codec::{Compact, Decode, Encode}; +use core::marker::PhantomData; use frame_support::traits::Get; use sp_io::hashing::blake2_256; use sp_runtime::traits::{AccountIdConversion, TrailingZeroInput, TryConvert}; -use sp_std::{marker::PhantomData, prelude::*}; use xcm::latest::prelude::*; use xcm_executor::traits::ConvertLocation; @@ -460,7 +461,9 @@ impl #[cfg(test)] mod tests { use super::*; + use alloc::vec; use polkadot_primitives::AccountId; + pub type ForeignChainAliasAccount = HashedDescription; diff --git a/polkadot/xcm/xcm-builder/src/matches_location.rs b/polkadot/xcm/xcm-builder/src/matches_location.rs index b6c2807e6b29db302e2d1182729c5acb4426b24b..71c5ec1efd6f95cc177e931cd7e774d291f71fc2 100644 --- a/polkadot/xcm/xcm-builder/src/matches_location.rs +++ b/polkadot/xcm/xcm-builder/src/matches_location.rs @@ -17,14 +17,14 @@ //! Various implementations and utilities for matching and filtering `Location` and //! `InteriorLocation` types. +use core::marker::PhantomData; use frame_support::traits::{Contains, Get}; use sp_runtime::traits::MaybeEquivalence; -use sp_std::marker::PhantomData; use xcm::latest::{InteriorLocation, Location, NetworkId}; /// An implementation of `Contains` that checks for `Location` or /// `InteriorLocation` if starts with the provided type `T`. -pub struct StartsWith(sp_std::marker::PhantomData<(T, L)>); +pub struct StartsWith(core::marker::PhantomData<(T, L)>); impl, L: TryInto + Clone> Contains for StartsWith { fn contains(location: &L) -> bool { let latest_location: Location = @@ -42,7 +42,7 @@ impl> Contains for StartsWith { /// An implementation of `Contains` that checks for `Location` or /// `InteriorLocation` if starts with expected `GlobalConsensus(NetworkId)` provided as type /// `T`. -pub struct StartsWithExplicitGlobalConsensus(sp_std::marker::PhantomData); +pub struct StartsWithExplicitGlobalConsensus(core::marker::PhantomData); impl> Contains for StartsWithExplicitGlobalConsensus { fn contains(location: &Location) -> bool { matches!(location.interior().global_consensus(), Ok(requested_network) if requested_network.eq(&T::get())) diff --git a/polkadot/xcm/xcm-builder/src/matches_token.rs b/polkadot/xcm/xcm-builder/src/matches_token.rs index e49fd18f88d806b09614696040fab29ead657ee2..095c50a5a25b006e44fdf3baf7fa911209b6dd5d 100644 --- a/polkadot/xcm/xcm-builder/src/matches_token.rs +++ b/polkadot/xcm/xcm-builder/src/matches_token.rs @@ -16,8 +16,8 @@ //! Various implementations for the `MatchesFungible` trait. +use core::marker::PhantomData; use frame_support::traits::Get; -use sp_std::marker::PhantomData; use xcm::latest::{ Asset, AssetId, AssetInstance, Fungibility::{Fungible, NonFungible}, diff --git a/polkadot/xcm/xcm-builder/src/nonfungible_adapter.rs b/polkadot/xcm/xcm-builder/src/nonfungible_adapter.rs index b69002eafc5b9945c9991a0fd3c981dd3d922338..8e6232ea64d271a9142a07adea573a59f4c17312 100644 --- a/polkadot/xcm/xcm-builder/src/nonfungible_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/nonfungible_adapter.rs @@ -17,11 +17,11 @@ //! Adapters to work with [`frame_support::traits::tokens::nonfungible`] through XCM. use crate::MintLocation; +use core::{marker::PhantomData, result}; use frame_support::{ ensure, traits::{tokens::nonfungible, Get}, }; -use sp_std::{marker::PhantomData, prelude::*, result}; use xcm::latest::prelude::*; use xcm_executor::traits::{ ConvertLocation, Error as MatchError, MatchesNonFungible, TransactAsset, diff --git a/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs b/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs index 3fce953848ebdaf0021d84a333fdb00c346b5096..b111a05a4f1fc2a9c0559c42f672a9734fd110fe 100644 --- a/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs @@ -17,11 +17,11 @@ //! Adapters to work with [`frame_support::traits::tokens::nonfungibles`] through XCM. use crate::{AssetChecking, MintLocation}; +use core::{marker::PhantomData, result}; use frame_support::{ ensure, traits::{tokens::nonfungibles, Get}, }; -use sp_std::{marker::PhantomData, prelude::*, result}; use xcm::latest::prelude::*; use xcm_executor::traits::{ ConvertLocation, Error as MatchError, MatchesNonFungibles, TransactAsset, diff --git a/polkadot/xcm/xcm-builder/src/origin_aliases.rs b/polkadot/xcm/xcm-builder/src/origin_aliases.rs index bbf810463a7c5054b368207774c977a49e3232aa..d568adc3127ce0c83207e04c87a27294f45c34fa 100644 --- a/polkadot/xcm/xcm-builder/src/origin_aliases.rs +++ b/polkadot/xcm/xcm-builder/src/origin_aliases.rs @@ -16,8 +16,8 @@ //! Implementation for `ContainsPair`. +use core::marker::PhantomData; use frame_support::traits::{Contains, ContainsPair}; -use sp_std::marker::PhantomData; use xcm::latest::prelude::*; /// Alias a Foreign `AccountId32` with a local `AccountId32` if the foreign `AccountId32` matches diff --git a/polkadot/xcm/xcm-builder/src/origin_conversion.rs b/polkadot/xcm/xcm-builder/src/origin_conversion.rs index f64b5660f66748458b6eec7cc3eb02625525de14..6e73c0dae7b698e151b67763e03a3f6dc2ea45b8 100644 --- a/polkadot/xcm/xcm-builder/src/origin_conversion.rs +++ b/polkadot/xcm/xcm-builder/src/origin_conversion.rs @@ -16,11 +16,11 @@ //! Various implementations for `ConvertOrigin`. +use core::marker::PhantomData; use frame_support::traits::{EnsureOrigin, Get, GetBacking, OriginTrait}; use frame_system::RawOrigin as SystemRawOrigin; use polkadot_parachain_primitives::primitives::IsSystem; use sp_runtime::traits::TryConvert; -use sp_std::marker::PhantomData; use xcm::latest::{BodyId, BodyPart, Junction, Junctions::*, Location, NetworkId, OriginKind}; use xcm_executor::traits::{ConvertLocation, ConvertOrigin}; diff --git a/polkadot/xcm/xcm-builder/src/pay.rs b/polkadot/xcm/xcm-builder/src/pay.rs index 35b624b041539e3d89fdb98a56d0910d5033417f..978c6870cdaf1e65ffc74adb175fd2e80ba53031 100644 --- a/polkadot/xcm/xcm-builder/src/pay.rs +++ b/polkadot/xcm/xcm-builder/src/pay.rs @@ -16,12 +16,13 @@ //! `PayOverXcm` struct for paying through XCM and getting the status back. +use alloc::vec; +use core::marker::PhantomData; use frame_support::traits::{ tokens::{Pay, PaymentStatus}, Get, }; use sp_runtime::traits::TryConvert; -use sp_std::{marker::PhantomData, vec}; use xcm::{opaque::lts::Weight, prelude::*}; use xcm_executor::traits::{QueryHandler, QueryResponseStatus}; @@ -199,7 +200,7 @@ pub struct LocatableAssetId { /// Adapter `struct` which implements a conversion from any `AssetKind` into a [`LocatableAssetId`] /// value using a fixed `Location` for the `location` field. -pub struct FixedLocation(sp_std::marker::PhantomData); +pub struct FixedLocation(core::marker::PhantomData); impl, AssetKind: Into> TryConvert for FixedLocation { diff --git a/polkadot/xcm/xcm-builder/src/process_xcm_message.rs b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs index ef8c71fc2495175c3db20d89688fb983e180776d..2e6f8c5fb566166f600bd9d9a7ef20f8a39fae40 100644 --- a/polkadot/xcm/xcm-builder/src/process_xcm_message.rs +++ b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs @@ -17,9 +17,9 @@ //! Implementation of `ProcessMessage` for an `ExecuteXcm` implementation. use codec::{Decode, FullCodec, MaxEncodedLen}; +use core::{fmt::Debug, marker::PhantomData}; use frame_support::traits::{ProcessMessage, ProcessMessageError}; use scale_info::TypeInfo; -use sp_std::{fmt::Debug, marker::PhantomData}; use sp_weights::{Weight, WeightMeter}; use xcm::prelude::*; @@ -118,6 +118,7 @@ impl< #[cfg(test)] mod tests { use super::*; + use alloc::vec; use codec::Encode; use frame_support::{ assert_err, assert_ok, diff --git a/polkadot/xcm/xcm-builder/src/routing.rs b/polkadot/xcm/xcm-builder/src/routing.rs index 543aef97c34095b06c8f4ef840d55f8a9eb0d49b..03ef780ef0325c24e4f53b1013e558a3e0d3990b 100644 --- a/polkadot/xcm/xcm-builder/src/routing.rs +++ b/polkadot/xcm/xcm-builder/src/routing.rs @@ -16,9 +16,10 @@ //! Various implementations for `SendXcm`. +use alloc::vec::Vec; use codec::Encode; +use core::{marker::PhantomData, result::Result}; use frame_system::unique; -use sp_std::{marker::PhantomData, result::Result, vec::Vec}; use xcm::prelude::*; use xcm_executor::{traits::FeeReason, FeesMode}; @@ -173,7 +174,7 @@ impl InspectMessageQueues for Tuple { /// `Inner::Ticket`. Therefore, this router aims to validate at least the passed `message`. /// /// NOTE: For use in mock runtimes which don't have the DMP/UMP/HRMP XCM validations. -pub struct EnsureDecodableXcm(sp_std::marker::PhantomData); +pub struct EnsureDecodableXcm(core::marker::PhantomData); impl SendXcm for EnsureDecodableXcm { type Ticket = Inner::Ticket; diff --git a/polkadot/xcm/xcm-builder/src/test_utils.rs b/polkadot/xcm/xcm-builder/src/test_utils.rs index 3131dece37570ecda2650c9e03ba44e5346b5f43..37a49a1b3dc7e742c291e49274490dd20aa1ddee 100644 --- a/polkadot/xcm/xcm-builder/src/test_utils.rs +++ b/polkadot/xcm/xcm-builder/src/test_utils.rs @@ -16,11 +16,11 @@ // Shared test utilities and implementations for the XCM Builder. +use alloc::vec::Vec; use frame_support::{ parameter_types, traits::{Contains, CrateVersion, PalletInfoData, PalletsInfoAccess}, }; -use sp_std::vec::Vec; pub use xcm::latest::{prelude::*, Weight}; use xcm_executor::traits::{ClaimAssets, DropAssets, VersionChangeNotifier}; pub use xcm_executor::{ diff --git a/polkadot/xcm/xcm-builder/src/tests/mock.rs b/polkadot/xcm/xcm-builder/src/tests/mock.rs index f35c73bdb68572b326557b362d20ec888850691e..ac43d217ff3ff221becd89878e95772cf4000ded 100644 --- a/polkadot/xcm/xcm-builder/src/tests/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/mock.rs @@ -26,7 +26,12 @@ pub use crate::{ AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, FixedRateOfFungible, FixedWeightBounds, TakeWeightCredit, }; +pub use alloc::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; pub use codec::{Decode, Encode}; +pub use core::{ + cell::{Cell, RefCell}, + fmt::Debug, +}; use frame_support::traits::{ContainsPair, Everything}; pub use frame_support::{ dispatch::{DispatchInfo, DispatchResultWithPostInfo, GetDispatchInfo, PostDispatchInfo}, @@ -34,11 +39,6 @@ pub use frame_support::{ sp_runtime::{traits::Dispatchable, DispatchError, DispatchErrorWithPostInfo}, traits::{Contains, Get, IsInVec}, }; -pub use sp_std::{ - cell::{Cell, RefCell}, - collections::{btree_map::BTreeMap, btree_set::BTreeSet}, - fmt::Debug, -}; pub use xcm::latest::{prelude::*, QueryId, Weight}; use xcm_executor::traits::{Properties, QueryHandler, QueryResponseStatus}; pub use xcm_executor::{ diff --git a/polkadot/xcm/xcm-builder/src/tests/mod.rs b/polkadot/xcm/xcm-builder/src/tests/mod.rs index 16ce3d2cf8ffef68d1f218fb1082cee8dc122b4b..379baaf5e37678a712a6ee337993b37bcbc2ecf5 100644 --- a/polkadot/xcm/xcm-builder/src/tests/mod.rs +++ b/polkadot/xcm/xcm-builder/src/tests/mod.rs @@ -15,6 +15,7 @@ // along with Polkadot. If not, see . use super::{test_utils::*, *}; +use alloc::{vec, vec::Vec}; use frame_support::{ assert_err, traits::{ConstU32, ContainsPair, ProcessMessageError}, diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs index 10e9f4c6c0855a82dce07949cc53e2950971047b..18bde3aab485a9660892ab1f5dc7c3de4b508338 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs @@ -299,6 +299,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { (1, TreasuryAccountId::get(), INITIAL_BALANCE), (100, TreasuryAccountId::get(), INITIAL_BALANCE), ], + next_asset_id: None, } .assimilate_storage(&mut t) .unwrap(); diff --git a/polkadot/xcm/xcm-builder/src/universal_exports.rs b/polkadot/xcm/xcm-builder/src/universal_exports.rs index 9820d535f7efdeab1097d8b305fb9f62a19a02f4..8aa9602fcc297e9a402f7df11188773466b6ac90 100644 --- a/polkadot/xcm/xcm-builder/src/universal_exports.rs +++ b/polkadot/xcm/xcm-builder/src/universal_exports.rs @@ -17,9 +17,10 @@ //! Traits and utilities to help with origin mutation and bridging. use crate::InspectMessageQueues; +use alloc::{vec, vec::Vec}; use codec::{Decode, Encode}; +use core::{convert::TryInto, marker::PhantomData}; use frame_support::{ensure, traits::Get}; -use sp_std::{convert::TryInto, marker::PhantomData, prelude::*}; use xcm::prelude::*; use xcm_executor::traits::{validate_export, ExportXcm}; use SendError::*; @@ -149,7 +150,7 @@ impl NetworkExportTableItem { /// An adapter for the implementation of `ExporterFor`, which attempts to find the /// `(bridge_location, payment)` for the requested `network` and `remote_location` in the provided /// `T` table containing various exporters. -pub struct NetworkExportTable(sp_std::marker::PhantomData); +pub struct NetworkExportTable(core::marker::PhantomData); impl>> ExporterFor for NetworkExportTable { fn exporter_for( network: &NetworkId, @@ -649,7 +650,7 @@ mod tests { pub PaymentForNetworkAAndParachain2000: Asset = (Location::parent(), 150).into(); - pub BridgeTable: sp_std::vec::Vec = sp_std::vec![ + pub BridgeTable: alloc::vec::Vec = alloc::vec![ // NetworkA allows `Parachain(1000)` as remote location WITHOUT payment. NetworkExportTableItem::new( NetworkA::get(), diff --git a/polkadot/xcm/xcm-builder/src/weight.rs b/polkadot/xcm/xcm-builder/src/weight.rs index 1efa42ce95601d34b1f28e69b3c3ce59685ce9af..7861fdcc2e579b54b03fe509956c9a46e3405c2c 100644 --- a/polkadot/xcm/xcm-builder/src/weight.rs +++ b/polkadot/xcm/xcm-builder/src/weight.rs @@ -15,6 +15,7 @@ // along with Polkadot. If not, see . use codec::Decode; +use core::{marker::PhantomData, result::Result}; use frame_support::{ dispatch::GetDispatchInfo, traits::{ @@ -27,7 +28,6 @@ use frame_support::{ }, }; use sp_runtime::traits::{SaturatedConversion, Saturating, Zero}; -use sp_std::{marker::PhantomData, result::Result}; use xcm::latest::{prelude::*, GetWeight, Weight}; use xcm_executor::{ traits::{WeightBounds, WeightTrader}, diff --git a/polkadot/xcm/xcm-builder/tests/mock/mod.rs b/polkadot/xcm/xcm-builder/tests/mock/mod.rs index 582d596b78f1092397dc821dd9152f4295a350fd..0468b0a5410c416a0703502cc38a13dba2a79853 100644 --- a/polkadot/xcm/xcm-builder/tests/mock/mod.rs +++ b/polkadot/xcm/xcm-builder/tests/mock/mod.rs @@ -15,6 +15,7 @@ // along with Polkadot. If not, see . use codec::Encode; +use core::cell::RefCell; use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{Everything, Nothing}, @@ -23,7 +24,6 @@ use frame_support::{ use frame_system::EnsureRoot; use primitive_types::H256; use sp_runtime::{traits::IdentityLookup, AccountId32, BuildStorage}; -use sp_std::cell::RefCell; use polkadot_parachain_primitives::primitives::Id as ParaId; use polkadot_runtime_parachains::{configuration, origin, shared}; diff --git a/polkadot/xcm/xcm-executor/Cargo.toml b/polkadot/xcm/xcm-executor/Cargo.toml index 3b30b4f13e2dd498945767a6e6d4c87a43333bc1..cc966f91fe4db948c38a9d4faeff267aefc7e59c 100644 --- a/polkadot/xcm/xcm-executor/Cargo.toml +++ b/polkadot/xcm/xcm-executor/Cargo.toml @@ -10,20 +10,19 @@ version = "7.0.0" workspace = true [dependencies] -impl-trait-for-tuples = "0.2.2" -environmental = { version = "1.1.4", default-features = false } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } -xcm = { package = "staging-xcm", path = "..", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -sp-arithmetic = { path = "../../../substrate/primitives/arithmetic", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-weights = { path = "../../../substrate/primitives/weights", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -log = { workspace = true } -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } +impl-trait-for-tuples = { workspace = true } +environmental = { workspace = true } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive", "serde"], workspace = true } +xcm = { workspace = true } +sp-io = { workspace = true } +sp-arithmetic = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-weights = { workspace = true } +frame-support = { workspace = true } +tracing = { workspace = true } +frame-benchmarking = { optional = true, workspace = true } [features] default = ["std"] @@ -37,13 +36,12 @@ std = [ "environmental/std", "frame-benchmarking/std", "frame-support/std", - "log/std", "scale-info/std", "sp-arithmetic/std", "sp-core/std", "sp-io/std", "sp-runtime/std", - "sp-std/std", "sp-weights/std", + "tracing/std", "xcm/std", ] diff --git a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml index 37c2117e7b06fc62f33e71c3c57164caf26d4c9b..e669e5d2b2312fbba56a86a6b8518506ba350543 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml +++ b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml @@ -11,24 +11,24 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12" } -frame-support = { path = "../../../../substrate/frame/support", default-features = false } -frame-system = { path = "../../../../substrate/frame/system" } -futures = "0.3.30" -pallet-transaction-payment = { path = "../../../../substrate/frame/transaction-payment" } -pallet-xcm = { path = "../../pallet-xcm" } -polkadot-test-client = { path = "../../../node/test/client" } -polkadot-test-runtime = { path = "../../../runtime/test-runtime" } -polkadot-test-service = { path = "../../../node/test/service" } -polkadot-service = { path = "../../../node/service" } -sp-consensus = { path = "../../../../substrate/primitives/consensus/common" } -sp-keyring = { path = "../../../../substrate/primitives/keyring" } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-state-machine = { path = "../../../../substrate/primitives/state-machine" } -xcm = { package = "staging-xcm", path = "../..", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = ".." } -sp-tracing = { path = "../../../../substrate/primitives/tracing" } -sp-core = { path = "../../../../substrate/primitives/core" } +codec = { workspace = true, default-features = true } +frame-support = { workspace = true } +frame-system = { workspace = true, default-features = true } +futures = { workspace = true } +pallet-transaction-payment = { workspace = true, default-features = true } +pallet-xcm = { workspace = true, default-features = true } +polkadot-test-client = { workspace = true } +polkadot-test-runtime = { workspace = true } +polkadot-test-service = { workspace = true } +polkadot-service = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-runtime = { workspace = true } +sp-state-machine = { workspace = true, default-features = true } +xcm = { workspace = true } +xcm-executor = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/polkadot/xcm/xcm-executor/src/assets.rs b/polkadot/xcm/xcm-executor/src/assets.rs index 4407752f7024273a28883b695d895bcd6a9e7d35..09e7535ebf81d09f07a119224dad42647d4bc366 100644 --- a/polkadot/xcm/xcm-executor/src/assets.rs +++ b/polkadot/xcm/xcm-executor/src/assets.rs @@ -14,12 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use sp_runtime::{traits::Saturating, RuntimeDebug}; -use sp_std::{ +use alloc::{ collections::{btree_map::BTreeMap, btree_set::BTreeSet}, - mem, - prelude::*, + vec::Vec, }; +use core::mem; +use sp_runtime::{traits::Saturating, RuntimeDebug}; use xcm::latest::{ Asset, AssetFilter, AssetId, AssetInstance, Assets, Fungibility::{Fungible, NonFungible}, @@ -520,7 +520,9 @@ impl AssetsInHolding { #[cfg(test)] mod tests { use super::*; + use alloc::vec; use xcm::latest::prelude::*; + #[allow(non_snake_case)] /// Concrete fungible constructor fn CF(amount: u128) -> Asset { diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index da9de93ca0f6f1a94f388d9078e95305e5c210e9..1daf5ae750cfbd0bb5a407eceb8d621023586fe0 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -16,7 +16,11 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + +use alloc::{vec, vec::Vec}; use codec::{Decode, Encode}; +use core::{fmt::Debug, marker::PhantomData}; use frame_support::{ dispatch::GetDispatchInfo, ensure, @@ -24,7 +28,6 @@ use frame_support::{ }; use sp_core::defer; use sp_io::hashing::blake2_128; -use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; use sp_weights::Weight; use xcm::latest::prelude::*; @@ -208,9 +211,12 @@ impl ExecuteXcm for XcmExecutor Outcome { let origin = origin.into(); - log::trace!( + tracing::trace!( target: "xcm::execute", - "origin: {origin:?}, message: {message:?}, weight_credit: {weight_credit:?}", + ?origin, + ?message, + ?weight_credit, + "Executing message", ); let mut properties = Properties { weight_credit, message_id: None }; @@ -226,10 +232,13 @@ impl ExecuteXcm for XcmExecutor ExecuteXcm for XcmExecutor for frame_benchmarking::BenchmarkError { fn from(error: ExecutorError) -> Self { - log::error!( - "XCM ERROR >> Index: {:?}, Error: {:?}, Weight: {:?}", - error.index, - error.xcm_error, - error.weight + tracing::error!( + index = ?error.index, + xcm_error = ?error.xcm_error, + weight = ?error.weight, + "XCM ERROR", ); Self::Stop("xcm executor error: see error logs") } @@ -326,10 +335,12 @@ impl XcmExecutor { let mut weight_used = xcm_weight.saturating_sub(self.total_surplus); if !self.holding.is_empty() { - log::trace!( + tracing::trace!( target: "xcm::post_process", - "Trapping assets in holding register: {:?}, context: {:?} (original_origin: {:?})", - self.holding, self.context, self.original_origin, + holding_register = ?self.holding, + context = ?self.context, + original_origin = ?self.original_origin, + "Trapping assets in holding register", ); let effective_origin = self.context.origin.as_ref().unwrap_or(&self.original_origin); let trap_weight = @@ -342,7 +353,13 @@ impl XcmExecutor { // TODO: #2841 #REALWEIGHT We should deduct the cost of any instructions following // the error which didn't end up being executed. Some((_i, e)) => { - log::trace!(target: "xcm::post_process", "Execution errored at {:?}: {:?} (original_origin: {:?})", _i, e, self.original_origin); + tracing::trace!( + target: "xcm::post_process", + instruction = ?_i, + error = ?e, + original_origin = ?self.original_origin, + "Execution failed", + ); Outcome::Incomplete { used: weight_used, error: e } }, } @@ -363,8 +380,12 @@ impl XcmExecutor { msg: Xcm<()>, reason: FeeReason, ) -> Result { - log::trace!( - target: "xcm::send", "Sending msg: {msg:?}, to destination: {dest:?}, (reason: {reason:?})" + tracing::trace!( + target: "xcm::send", + ?msg, + destination = ?dest, + reason = ?reason, + "Sending msg", ); let (ticket, fee) = validate_send::(dest, msg)?; self.take_fee(fee, reason)?; @@ -374,7 +395,7 @@ impl XcmExecutor { /// Remove the registered error handler and return it. Do not refund its weight. fn take_error_handler(&mut self) -> Xcm { let mut r = Xcm::(vec![]); - sp_std::mem::swap(&mut self.error_handler, &mut r); + core::mem::swap(&mut self.error_handler, &mut r); self.error_handler_weight = Weight::zero(); r } @@ -389,7 +410,7 @@ impl XcmExecutor { /// Remove the registered appendix and return it. fn take_appendix(&mut self) -> Xcm { let mut r = Xcm::(vec![]); - sp_std::mem::swap(&mut self.appendix, &mut r); + core::mem::swap(&mut self.appendix, &mut r); self.appendix_weight = Weight::zero(); r } @@ -400,7 +421,12 @@ impl XcmExecutor { // `holding_limit` items (which has a best case outcome of holding.len() == holding_limit), // then the operation is guaranteed to succeed. let worst_case_holding_len = self.holding.len() + assets_length; - log::trace!(target: "xcm::ensure_can_subsume_assets", "worst_case_holding_len: {:?}, holding_limit: {:?}", worst_case_holding_len, self.holding_limit); + tracing::trace!( + target: "xcm::ensure_can_subsume_assets", + ?worst_case_holding_len, + holding_limit = ?self.holding_limit, + "Ensuring subsume assets work", + ); ensure!(worst_case_holding_len <= self.holding_limit * 2, XcmError::HoldingWouldOverflow); Ok(()) } @@ -408,12 +434,12 @@ impl XcmExecutor { /// Refund any unused weight. fn refund_surplus(&mut self) -> Result<(), XcmError> { let current_surplus = self.total_surplus.saturating_sub(self.total_refunded); - log::trace!( + tracing::trace!( target: "xcm::refund_surplus", - "total_surplus: {:?}, total_refunded: {:?}, current_surplus: {:?}", - self.total_surplus, - self.total_refunded, - current_surplus, + total_surplus = ?self.total_surplus, + total_refunded = ?self.total_refunded, + ?current_surplus, + "Refunding surplus", ); if current_surplus.any_gt(Weight::zero()) { if let Some(w) = self.trader.refund_weight(current_surplus, &self.context) { @@ -426,7 +452,7 @@ impl XcmExecutor { .defensive_proof( "refund_weight returned an asset capable of buying weight; qed", ); - log::error!( + tracing::error!( target: "xcm::refund_surplus", "error: HoldingWouldOverflow", ); @@ -436,10 +462,9 @@ impl XcmExecutor { self.holding.subsume_assets(w.into()); } } - log::trace!( + tracing::trace!( target: "xcm::refund_surplus", - "total_refunded: {:?}", - self.total_refunded, + total_refunded = ?self.total_refunded, ); Ok(()) } @@ -448,13 +473,13 @@ impl XcmExecutor { if Config::FeeManager::is_waived(self.origin_ref(), reason.clone()) { return Ok(()) } - log::trace!( + tracing::trace!( target: "xcm::fees", - "taking fee: {:?} from origin_ref: {:?} in fees_mode: {:?} for a reason: {:?}", - fee, - self.origin_ref(), - self.fees_mode, - reason, + ?fee, + origin_ref = ?self.origin_ref(), + fees_mode = ?self.fees_mode, + ?reason, + "Taking fees", ); let paid = if self.fees_mode.jit_withdraw { let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?; @@ -507,7 +532,7 @@ impl XcmExecutor { let reanchor_context = Config::UniversalLocation::get(); let reanchored = reanchorable.reanchored(&destination, &reanchor_context).map_err(|error| { - log::error!(target: "xcm::reanchor", "Failed reanchoring with error {error:?}"); + tracing::error!(target: "xcm::reanchor", ?error, "Failed reanchoring with error"); XcmError::ReanchorFailed })?; Ok((reanchored, reanchor_context)) @@ -530,13 +555,12 @@ impl XcmExecutor { } fn process(&mut self, xcm: Xcm) -> Result<(), ExecutorError> { - log::trace!( + tracing::trace!( target: "xcm::process", - "origin: {:?}, total_surplus/refunded: {:?}/{:?}, error_handler_weight: {:?}", - self.origin_ref(), - self.total_surplus, - self.total_refunded, - self.error_handler_weight, + origin = ?self.origin_ref(), + total_surplus = ?self.total_surplus, + total_refunded = ?self.total_refunded, + error_handler_weight = ?self.error_handler_weight, ); let mut result = Ok(()); for (i, instr) in xcm.0.into_iter().enumerate() { @@ -566,7 +590,7 @@ impl XcmExecutor { self.process_instruction(instr) }); if let Err(e) = inst_res { - log::trace!(target: "xcm::execute", "!!! ERROR: {:?}", e); + tracing::trace!(target: "xcm::execute", "!!! ERROR: {:?}", e); *r = Err(ExecutorError { index: i as u32, xcm_error: e, @@ -588,11 +612,12 @@ impl XcmExecutor { &mut self, instr: Instruction, ) -> Result<(), XcmError> { - log::trace!( + tracing::trace!( target: "xcm::process_instruction", - "=== {:?}", - instr + instruction = ?instr, + "Processing instruction", ); + match instr { WithdrawAsset(assets) => { let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?; @@ -694,7 +719,7 @@ impl XcmExecutor { Transact { origin_kind, require_weight_at_most, mut call } => { // We assume that the Relay-chain is allowed to use transact on this parachain. let origin = self.cloned_origin().ok_or_else(|| { - log::trace!( + tracing::trace!( target: "xcm::process_instruction::transact", "No origin provided", ); @@ -704,7 +729,7 @@ impl XcmExecutor { // TODO: #2841 #TRANSACTFILTER allow the trait to issue filters for the relay-chain let message_call = call.take_decoded().map_err(|_| { - log::trace!( + tracing::trace!( target: "xcm::process_instruction::transact", "Failed to decode call", ); @@ -712,13 +737,14 @@ impl XcmExecutor { XcmError::FailedToDecode })?; - log::trace!( + tracing::trace!( target: "xcm::process_instruction::transact", - "Processing call: {message_call:?}", + ?call, + "Processing call", ); if !Config::SafeCallFilter::contains(&message_call) { - log::trace!( + tracing::trace!( target: "xcm::process_instruction::transact", "Call filtered by `SafeCallFilter`", ); @@ -729,26 +755,31 @@ impl XcmExecutor { let dispatch_origin = Config::OriginConverter::convert_origin(origin.clone(), origin_kind).map_err( |_| { - log::trace!( + tracing::trace!( target: "xcm::process_instruction::transact", - "Failed to convert origin {origin:?} and origin kind {origin_kind:?} to a local origin." + ?origin, + ?origin_kind, + "Failed to convert origin to a local origin." ); XcmError::BadOrigin }, )?; - log::trace!( + tracing::trace!( target: "xcm::process_instruction::transact", - "Dispatching with origin: {dispatch_origin:?}", + origin = ?dispatch_origin, + "Dispatching with origin", ); let weight = message_call.get_dispatch_info().weight; if !weight.all_lte(require_weight_at_most) { - log::trace!( + tracing::trace!( target: "xcm::process_instruction::transact", - "Max {weight} bigger than require at most {require_weight_at_most}", + %weight, + %require_weight_at_most, + "Max weight bigger than require at most", ); return Err(XcmError::MaxWeightInvalid) @@ -757,17 +788,19 @@ impl XcmExecutor { let maybe_actual_weight = match Config::CallDispatcher::dispatch(message_call, dispatch_origin) { Ok(post_info) => { - log::trace!( + tracing::trace!( target: "xcm::process_instruction::transact", - "Dispatch successful: {post_info:?}" + ?post_info, + "Dispatch successful" ); self.transact_status = MaybeErrorCode::Success; post_info.actual_weight }, Err(error_and_info) => { - log::trace!( + tracing::trace!( target: "xcm::process_instruction::transact", - "Dispatch failed {error_and_info:?}" + ?error_and_info, + "Dispatch failed" ); self.transact_status = error_and_info.error.encode().into(); diff --git a/polkadot/xcm/xcm-executor/src/traits/asset_lock.rs b/polkadot/xcm/xcm-executor/src/traits/asset_lock.rs index b6270c529452133c011fef24b9ac63e057acb91a..b4e9f32983fd52f27eb66d31bb7098d780389de9 100644 --- a/polkadot/xcm/xcm-executor/src/traits/asset_lock.rs +++ b/polkadot/xcm/xcm-executor/src/traits/asset_lock.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use sp_std::convert::Infallible; +use core::convert::Infallible; use xcm::prelude::*; #[derive(Debug)] diff --git a/polkadot/xcm/xcm-executor/src/traits/conversion.rs b/polkadot/xcm/xcm-executor/src/traits/conversion.rs index 9e2f4c83997ac2b370536822454bcfbea41c4896..bc62ad655669756793327d23d3d24f5f2da1be9c 100644 --- a/polkadot/xcm/xcm-executor/src/traits/conversion.rs +++ b/polkadot/xcm/xcm-executor/src/traits/conversion.rs @@ -14,9 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +use core::{marker::PhantomData, result::Result}; use frame_support::traits::{Contains, OriginTrait}; use sp_runtime::{traits::Dispatchable, DispatchErrorWithPostInfo}; -use sp_std::{marker::PhantomData, result::Result}; use xcm::latest::prelude::*; /// Means of converting a location into an account identifier. @@ -88,19 +88,45 @@ pub trait ConvertOrigin { #[impl_trait_for_tuples::impl_for_tuples(30)] impl ConvertOrigin for Tuple { fn convert_origin(origin: impl Into, kind: OriginKind) -> Result { + let origin = origin.into(); + + tracing::trace!( + target: "xcm::convert_origin", + ?origin, + ?kind, + "Converting origin", + ); + for_tuples!( #( + let convert_origin = core::any::type_name::(); + let origin = match Tuple::convert_origin(origin, kind) { - Err(o) => o, - r => return r + Err(o) => { + tracing::trace!( + target: "xcm::convert_origin", + %convert_origin, + "Convert origin step failed", + ); + + o + }, + Ok(o) => { + tracing::trace!( + target: "xcm::convert_origin", + %convert_origin, + "Convert origin step succeeded", + ); + + return Ok(o) + } }; )* ); - let origin = origin.into(); - log::trace!( + + tracing::trace!( target: "xcm::convert_origin", - "could not convert: origin: {:?}, kind: {:?}", - origin, - kind, + "Converting origin failed", ); + Err(origin) } } diff --git a/polkadot/xcm/xcm-executor/src/traits/on_response.rs b/polkadot/xcm/xcm-executor/src/traits/on_response.rs index 5d2412d6137552db68d30cf61b25b10521afd966..a4ed6014b4fc8bc423bbc5cceb20cee15fe7890f 100644 --- a/polkadot/xcm/xcm-executor/src/traits/on_response.rs +++ b/polkadot/xcm/xcm-executor/src/traits/on_response.rs @@ -16,10 +16,9 @@ use crate::{Junctions::Here, Xcm}; use codec::{Decode, Encode}; -use core::result; +use core::{fmt::Debug, result}; use frame_support::{pallet_prelude::Get, parameter_types}; use sp_arithmetic::traits::Zero; -use sp_std::fmt::Debug; use xcm::latest::{ Error as XcmError, InteriorLocation, Location, QueryId, Response, Result as XcmResult, Weight, XcmContext, diff --git a/polkadot/xcm/xcm-executor/src/traits/should_execute.rs b/polkadot/xcm/xcm-executor/src/traits/should_execute.rs index e76d56bfe6164d16487f65ed79c1a1a58a9949fe..ec9ef70cc817e5a230ae843581fb736ce06770ee 100644 --- a/polkadot/xcm/xcm-executor/src/traits/should_execute.rs +++ b/polkadot/xcm/xcm-executor/src/traits/should_execute.rs @@ -14,8 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +use core::result::Result; use frame_support::traits::ProcessMessageError; -use sp_std::result::Result; use xcm::latest::{Instruction, Location, Weight, XcmHash}; /// Properties of an XCM message and its imminent execution. @@ -59,19 +59,35 @@ impl ShouldExecute for Tuple { properties: &mut Properties, ) -> Result<(), ProcessMessageError> { for_tuples!( #( - match Tuple::should_execute(origin, instructions, max_weight, properties) { - Ok(()) => return Ok(()), - _ => (), + let barrier = core::any::type_name::(); + match Tuple::should_execute(origin, instructions, max_weight, properties) { + Ok(()) => { + tracing::trace!( + target: "xcm::should_execute", + ?origin, + ?instructions, + ?max_weight, + ?properties, + %barrier, + "pass barrier", + ); + return Ok(()) + }, + Err(error) => { + tracing::trace!( + target: "xcm::should_execute", + ?origin, + ?instructions, + ?max_weight, + ?properties, + ?error, + %barrier, + "did not pass barrier", + ); + }, } )* ); - log::trace!( - target: "xcm::should_execute", - "did not pass barrier: origin: {:?}, instructions: {:?}, max_weight: {:?}, properties: {:?}", - origin, - instructions, - max_weight, - properties, - ); + Err(ProcessMessageError::Unsupported) } } diff --git a/polkadot/xcm/xcm-executor/src/traits/token_matching.rs b/polkadot/xcm/xcm-executor/src/traits/token_matching.rs index e9a7e3ad845daf2f3f0a8da05c7d9d3d3711a291..aa44aee4f9de39cd7bcda09e3ce3b4e294d8ee6d 100644 --- a/polkadot/xcm/xcm-executor/src/traits/token_matching.rs +++ b/polkadot/xcm/xcm-executor/src/traits/token_matching.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use sp_std::result; +use core::result; use xcm::latest::prelude::*; pub trait MatchesFungible { @@ -27,7 +27,7 @@ impl MatchesFungible for Tuple { for_tuples!( #( match Tuple::matches_fungible(a) { o @ Some(_) => return o, _ => () } )* ); - log::trace!(target: "xcm::matches_fungible", "did not match fungible asset: {:?}", &a); + tracing::trace!(target: "xcm::matches_fungible", asset = ?a, "did not match fungible asset"); None } } @@ -42,7 +42,7 @@ impl MatchesNonFungible for Tuple { for_tuples!( #( match Tuple::matches_nonfungible(a) { o @ Some(_) => return o, _ => () } )* ); - log::trace!(target: "xcm::matches_non_fungible", "did not match non-fungible asset: {:?}", &a); + tracing::trace!(target: "xcm::matches_non_fungible", asset = ?a, "did not match non-fungible asset"); None } } @@ -86,7 +86,7 @@ impl MatchesFungibles for Tuple { for_tuples!( #( match Tuple::matches_fungibles(a) { o @ Ok(_) => return o, _ => () } )* ); - log::trace!(target: "xcm::matches_fungibles", "did not match fungibles asset: {:?}", &a); + tracing::trace!(target: "xcm::matches_fungibles", asset = ?a, "did not match fungibles asset"); Err(Error::AssetNotHandled) } } @@ -101,7 +101,7 @@ impl MatchesNonFungibles for Tuple { for_tuples!( #( match Tuple::matches_nonfungibles(a) { o @ Ok(_) => return o, _ => () } )* ); - log::trace!(target: "xcm::matches_non_fungibles", "did not match fungibles asset: {:?}", &a); + tracing::trace!(target: "xcm::matches_non_fungibles", asset = ?a, "did not match fungibles asset"); Err(Error::AssetNotHandled) } } diff --git a/polkadot/xcm/xcm-executor/src/traits/transact_asset.rs b/polkadot/xcm/xcm-executor/src/traits/transact_asset.rs index e8a52d8256851b4baf9565ba5ddeb47ae28667a7..c2331f805b4bddd51493fa7d9ec8c384baa20f14 100644 --- a/polkadot/xcm/xcm-executor/src/traits/transact_asset.rs +++ b/polkadot/xcm/xcm-executor/src/traits/transact_asset.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see . use crate::AssetsInHolding; -use sp_std::result::Result; +use core::result::Result; use xcm::latest::{Asset, Error as XcmError, Location, Result as XcmResult, XcmContext}; /// Facility for asset transacting. @@ -148,12 +148,12 @@ impl TransactAsset for Tuple { r => return r, } )* ); - log::trace!( + tracing::trace!( target: "xcm::TransactAsset::can_check_in", - "asset not found: what: {:?}, origin: {:?}, context: {:?}", - what, - origin, - context, + ?what, + ?origin, + ?context, + "asset not found", ); Err(XcmError::AssetNotFound) } @@ -171,12 +171,12 @@ impl TransactAsset for Tuple { r => return r, } )* ); - log::trace!( + tracing::trace!( target: "xcm::TransactAsset::can_check_out", - "asset not found: what: {:?}, dest: {:?}, context: {:?}", - what, - dest, - context, + ?what, + ?dest, + ?context, + "asset not found", ); Err(XcmError::AssetNotFound) } @@ -194,12 +194,12 @@ impl TransactAsset for Tuple { r => return r, } )* ); - log::trace!( + tracing::trace!( target: "xcm::TransactAsset::deposit_asset", - "did not deposit asset: what: {:?}, who: {:?}, context: {:?}", - what, - who, - context, + ?what, + ?who, + ?context, + "did not deposit asset", ); Err(XcmError::AssetNotFound) } @@ -215,12 +215,12 @@ impl TransactAsset for Tuple { r => return r, } )* ); - log::trace!( + tracing::trace!( target: "xcm::TransactAsset::withdraw_asset", - "did not withdraw asset: what: {:?}, who: {:?}, maybe_context: {:?}", - what, - who, - maybe_context, + ?what, + ?who, + ?maybe_context, + "did not withdraw asset", ); Err(XcmError::AssetNotFound) } @@ -237,13 +237,13 @@ impl TransactAsset for Tuple { r => return r, } )* ); - log::trace!( + tracing::trace!( target: "xcm::TransactAsset::internal_transfer_asset", - "did not transfer asset: what: {:?}, from: {:?}, to: {:?}, context: {:?}", - what, - from, - to, - context, + ?what, + ?from, + ?to, + ?context, + "did not transfer asset", ); Err(XcmError::AssetNotFound) } diff --git a/polkadot/xcm/xcm-executor/src/traits/weight.rs b/polkadot/xcm/xcm-executor/src/traits/weight.rs index efb9a2dfb6efdf65a074f631c691c0bfec88d600..72de3e0f433b96ed1718be70e3c0feb20340453a 100644 --- a/polkadot/xcm/xcm-executor/src/traits/weight.rs +++ b/polkadot/xcm/xcm-executor/src/traits/weight.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see . use crate::AssetsInHolding; -use sp_std::result::Result; +use core::result::Result; use xcm::latest::{prelude::*, Weight}; /// Determine the weight of an XCM message. @@ -80,18 +80,38 @@ impl WeightTrader for Tuple { let mut too_expensive_error_found = false; let mut last_error = None; for_tuples!( #( + let weight_trader = core::any::type_name::(); + match Tuple.buy_weight(weight, payment.clone(), context) { - Ok(assets) => return Ok(assets), - Err(e) => { - if let XcmError::TooExpensive = e { + Ok(assets) => { + tracing::trace!( + target: "xcm::buy_weight", + %weight_trader, + "Buy weight succeeded", + ); + + return Ok(assets) + }, + Err(error) => { + if let XcmError::TooExpensive = error { too_expensive_error_found = true; } - last_error = Some(e) + last_error = Some(error); + + tracing::trace!( + target: "xcm::buy_weight", + ?error, + %weight_trader, + "Weight trader failed", + ); } } )* ); - log::trace!(target: "xcm::buy_weight", "last_error: {:?}, too_expensive_error_found: {}", last_error, too_expensive_error_found); + tracing::trace!( + target: "xcm::buy_weight", + "Buy weight failed", + ); // if we have multiple traders, and first one returns `TooExpensive` and others fail e.g. // `AssetNotFound` then it is more accurate to return `TooExpensive` then `AssetNotFound` diff --git a/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml b/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml deleted file mode 100644 index 6fa0236dfb41d5e2a4ec2749a402a8f73be60eb4..0000000000000000000000000000000000000000 --- a/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml +++ /dev/null @@ -1,71 +0,0 @@ -[package] -name = "xcm-fee-payment-runtime-api" -version = "0.1.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -repository.workspace = true -description = "XCM fee payment runtime API" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ - "derive", -] } - -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -scale-info = { version = "2.11.1", default-features = false, features = [ - "derive", - "serde", -] } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-weights = { path = "../../../substrate/primitives/weights", default-features = false } -xcm = { package = "staging-xcm", path = "../", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false } - -[dev-dependencies] -frame-system = { path = "../../../substrate/frame/system", default-features = false } -pallet-xcm = { path = "../pallet-xcm", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } -pallet-assets = { path = "../../../substrate/frame/assets", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } -frame-executive = { path = "../../../substrate/frame/executive", default-features = false } -log = { workspace = true } -env_logger = "0.9.0" - -[features] -default = ["std"] -std = [ - "codec/std", - "frame-executive/std", - "frame-support/std", - "frame-system/std", - "log/std", - "pallet-assets/std", - "pallet-balances/std", - "pallet-xcm/std", - "scale-info/std", - "sp-api/std", - "sp-io/std", - "sp-runtime/std", - "sp-std/std", - "sp-weights/std", - "xcm-builder/std", - "xcm-executor/std", - "xcm/std", -] -runtime-benchmarks = [ - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-assets/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "pallet-xcm/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", - "xcm-builder/runtime-benchmarks", - "xcm-executor/runtime-benchmarks", -] diff --git a/polkadot/xcm/xcm-runtime-apis/Cargo.toml b/polkadot/xcm/xcm-runtime-apis/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..748d5af68a1fdee6c62873370d33387d55a06e6f --- /dev/null +++ b/polkadot/xcm/xcm-runtime-apis/Cargo.toml @@ -0,0 +1,63 @@ +[package] +name = "xcm-runtime-apis" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +repository.workspace = true +description = "XCM runtime APIs" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive", "serde"], workspace = true } + +frame-support = { workspace = true } +sp-api = { workspace = true } +sp-weights = { workspace = true } +xcm = { workspace = true } +xcm-executor = { workspace = true } + +[dev-dependencies] +frame-system = { workspace = true } +sp-io = { workspace = true } +xcm-builder = { workspace = true } +hex-literal = { workspace = true } +pallet-xcm = { workspace = true } +pallet-balances = { workspace = true } +pallet-assets = { workspace = true } +xcm-executor = { workspace = true } +frame-executive = { workspace = true } +log = { workspace = true } +env_logger = { workspace = true } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-executive/std", + "frame-support/std", + "frame-system/std", + "log/std", + "pallet-assets/std", + "pallet-balances/std", + "pallet-xcm/std", + "scale-info/std", + "sp-api/std", + "sp-io/std", + "sp-weights/std", + "xcm-builder/std", + "xcm-executor/std", + "xcm/std", +] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", +] diff --git a/polkadot/xcm/xcm-runtime-apis/src/conversions.rs b/polkadot/xcm/xcm-runtime-apis/src/conversions.rs new file mode 100644 index 0000000000000000000000000000000000000000..e5eeac013fee6e8b7222429dfd0ed93afa9384c9 --- /dev/null +++ b/polkadot/xcm/xcm-runtime-apis/src/conversions.rs @@ -0,0 +1,56 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Contains runtime APIs for useful conversions, such as between XCM `Location` and `AccountId`. + +use codec::{Decode, Encode}; +use scale_info::TypeInfo; +use xcm::VersionedLocation; +use xcm_executor::traits::ConvertLocation; + +sp_api::decl_runtime_apis! { + /// API for useful conversions between XCM `Location` and `AccountId`. + pub trait LocationToAccountApi where AccountId: Decode { + /// Converts `Location` to `AccountId`. + fn convert_location(location: VersionedLocation) -> Result; + } +} + +#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] +pub enum Error { + /// Requested `Location` is not supported by the local conversion. + #[codec(index = 0)] + Unsupported, + + /// Converting a versioned data structure from one version to another failed. + #[codec(index = 1)] + VersionedConversionFailed, +} + +/// A helper implementation that can be used for `LocationToAccountApi` implementations. +/// It is useful when you already have a `ConvertLocation` implementation and a default +/// `Ss58Prefix`. +pub struct LocationToAccountHelper( + core::marker::PhantomData<(AccountId, Conversion)>, +); +impl> + LocationToAccountHelper +{ + pub fn convert_location(location: VersionedLocation) -> Result { + let location = location.try_into().map_err(|_| Error::VersionedConversionFailed)?; + Conversion::convert_location(&location).ok_or(Error::Unsupported) + } +} diff --git a/polkadot/xcm/xcm-fee-payment-runtime-api/src/dry_run.rs b/polkadot/xcm/xcm-runtime-apis/src/dry_run.rs similarity index 99% rename from polkadot/xcm/xcm-fee-payment-runtime-api/src/dry_run.rs rename to polkadot/xcm/xcm-runtime-apis/src/dry_run.rs index 9828acab402300a55abf2ece820cf8871c76a858..2a1a0daf0d5d5d0bae868e973df56f7e35b41592 100644 --- a/polkadot/xcm/xcm-fee-payment-runtime-api/src/dry_run.rs +++ b/polkadot/xcm/xcm-runtime-apis/src/dry_run.rs @@ -18,9 +18,9 @@ //! This API can be used to simulate XCMs and, for example, find the fees //! that need to be paid. +use alloc::vec::Vec; use codec::{Decode, Encode}; use frame_support::pallet_prelude::{DispatchResultWithPostInfo, TypeInfo}; -use sp_std::vec::Vec; use xcm::prelude::*; /// Effects of dry-running an extrinsic. diff --git a/polkadot/xcm/xcm-fee-payment-runtime-api/src/fees.rs b/polkadot/xcm/xcm-runtime-apis/src/fees.rs similarity index 99% rename from polkadot/xcm/xcm-fee-payment-runtime-api/src/fees.rs rename to polkadot/xcm/xcm-runtime-apis/src/fees.rs index 572d4edf533865e66299eba7bd0d22a890547603..3445d42ecab3bda1a212e60f2be5583a31e04b58 100644 --- a/polkadot/xcm/xcm-fee-payment-runtime-api/src/fees.rs +++ b/polkadot/xcm/xcm-runtime-apis/src/fees.rs @@ -16,9 +16,9 @@ //! Runtime API definition for getting XCM fees. +use alloc::vec::Vec; use codec::{Decode, Encode}; use frame_support::pallet_prelude::TypeInfo; -use sp_std::vec::Vec; use sp_weights::Weight; use xcm::{Version, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}; diff --git a/polkadot/xcm/xcm-fee-payment-runtime-api/src/lib.rs b/polkadot/xcm/xcm-runtime-apis/src/lib.rs similarity index 74% rename from polkadot/xcm/xcm-fee-payment-runtime-api/src/lib.rs rename to polkadot/xcm/xcm-runtime-apis/src/lib.rs index 616ee4c2eccb0aeed1cdb5e2aa524855d8b2df82..b106836c1132b253acdc01e8b9fd63a7c4ff828b 100644 --- a/polkadot/xcm/xcm-fee-payment-runtime-api/src/lib.rs +++ b/polkadot/xcm/xcm-runtime-apis/src/lib.rs @@ -14,19 +14,19 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Runtime APIs for estimating xcm fee payment. -//! This crate offers two APIs, one for estimating fees, -//! which can be used for any type of message, and another one -//! for returning the specific messages used for transfers, a common -//! feature. -//! Users of these APIs should call the transfers API and pass the result to the -//! fees API. +//! Various runtime APIs to support XCM processing and manipulation. #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + +/// Exposes runtime APIs for various XCM-related conversions. +pub mod conversions; + /// Dry-run API. /// Given an extrinsic or an XCM program, it returns the outcome of its execution. pub mod dry_run; + /// Fee estimation API. /// Given an XCM program, it will return the fees needed to execute it properly or send it. pub mod fees; diff --git a/polkadot/xcm/xcm-runtime-apis/tests/conversions.rs b/polkadot/xcm/xcm-runtime-apis/tests/conversions.rs new file mode 100644 index 0000000000000000000000000000000000000000..7f0f0923b092116e0ad10f4b287dda8c93f5357f --- /dev/null +++ b/polkadot/xcm/xcm-runtime-apis/tests/conversions.rs @@ -0,0 +1,83 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +mod mock; + +use frame_support::{ + assert_err, assert_ok, + sp_runtime::{ + testing::H256, + traits::{IdentifyAccount, Verify}, + AccountId32, MultiSignature, + }, +}; +use mock::*; +use sp_api::ProvideRuntimeApi; +use xcm::prelude::*; +use xcm_runtime_apis::conversions::{ + Error as LocationToAccountApiError, LocationToAccountApi, LocationToAccountHelper, +}; + +#[test] +fn convert_location_to_account_works() { + sp_io::TestExternalities::default().execute_with(|| { + let client = TestClient {}; + let runtime_api = client.runtime_api(); + + // Test unknown conversion for `Here` location + assert_err!( + runtime_api + .convert_location(H256::zero(), VersionedLocation::from(Location::here())) + .unwrap(), + LocationToAccountApiError::Unsupported + ); + + // Test known conversion for sibling parachain location + assert_ok!( + runtime_api + .convert_location(H256::zero(), VersionedLocation::from((Parent, Parachain(1000)))) + .unwrap(), + 1000_u64 + ); + }) +} + +#[test] +fn location_to_account_helper_with_multi_signature_works() { + type Signature = MultiSignature; + type AccountIdForConversions = <::Signer as IdentifyAccount>::AccountId; + // We alias only `Location::parent()` + pub type LocationToAccountIdForConversions = + (xcm_builder::ParentIsPreset,); + + // Test unknown conversion for `Here` location + assert_err!( + LocationToAccountHelper::< + AccountIdForConversions, + LocationToAccountIdForConversions, + >::convert_location(Location::here().into_versioned()), + LocationToAccountApiError::Unsupported + ); + + // Test known conversion for `Parent` location + assert_ok!( + LocationToAccountHelper::< + AccountIdForConversions, + LocationToAccountIdForConversions, + >::convert_location(Location::parent().into_versioned()), + AccountId32::from(hex_literal::hex!("506172656e740000000000000000000000000000000000000000000000000000")) + ); +} diff --git a/polkadot/xcm/xcm-fee-payment-runtime-api/tests/fee_estimation.rs b/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs similarity index 99% rename from polkadot/xcm/xcm-fee-payment-runtime-api/tests/fee_estimation.rs rename to polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs index 33611c8a471c03a34c125a921b24a51880dfbb3f..59ee17973805621ce360546afb0b1583abfbdc9a 100644 --- a/polkadot/xcm/xcm-fee-payment-runtime-api/tests/fee_estimation.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs @@ -16,11 +16,11 @@ //! Tests for using both the XCM fee payment API and the dry-run API. +use frame_support::sp_runtime::testing::H256; use frame_system::RawOrigin; use sp_api::ProvideRuntimeApi; -use sp_runtime::testing::H256; use xcm::prelude::*; -use xcm_fee_payment_runtime_api::{dry_run::DryRunApi, fees::XcmPaymentApi}; +use xcm_runtime_apis::{dry_run::DryRunApi, fees::XcmPaymentApi}; mod mock; use mock::{ diff --git a/polkadot/xcm/xcm-fee-payment-runtime-api/tests/mock.rs b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs similarity index 95% rename from polkadot/xcm/xcm-fee-payment-runtime-api/tests/mock.rs rename to polkadot/xcm/xcm-runtime-apis/tests/mock.rs index aa6c1422b608c955fc74934811f4f136212507cb..c76b26fcd2a337545450da4d77cb0103c3e8eb8c 100644 --- a/polkadot/xcm/xcm-fee-payment-runtime-api/tests/mock.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs @@ -18,8 +18,13 @@ //! Implements both runtime APIs for fee estimation and getting the messages for transfers. use codec::Encode; +use core::{cell::RefCell, marker::PhantomData}; use frame_support::{ - construct_runtime, derive_impl, parameter_types, + construct_runtime, derive_impl, parameter_types, sp_runtime, + sp_runtime::{ + traits::{Dispatchable, Get, IdentityLookup, MaybeEquivalence, TryConvert}, + BuildStorage, SaturatedConversion, + }, traits::{ AsEnsureOriginWithArg, ConstU128, ConstU32, Contains, ContainsPair, Everything, Nothing, OriginTrait, @@ -28,11 +33,6 @@ use frame_support::{ }; use frame_system::{EnsureRoot, RawOrigin as SystemRawOrigin}; use pallet_xcm::TestWeightInfo; -use sp_runtime::{ - traits::{Dispatchable, Get, IdentityLookup, MaybeEquivalence, TryConvert}, - BuildStorage, SaturatedConversion, -}; -use sp_std::{cell::RefCell, marker::PhantomData}; use xcm::{prelude::*, Version as XcmVersion}; use xcm_builder::{ AllowTopLevelPaidExecutionFrom, ConvertedConcreteId, EnsureXcmOrigin, FixedRateOfFungible, @@ -44,7 +44,8 @@ use xcm_executor::{ XcmExecutor, }; -use xcm_fee_payment_runtime_api::{ +use xcm_runtime_apis::{ + conversions::{Error as LocationToAccountApiError, LocationToAccountApi}, dry_run::{CallDryRunEffects, DryRunApi, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::{Error as XcmPaymentApiError, XcmPaymentApi}, }; @@ -352,6 +353,7 @@ impl pallet_xcm::Config for TestRuntime { type WeightInfo = TestWeightInfo; } +#[allow(dead_code)] pub fn new_test_ext_with_balances(balances: Vec<(AccountId, Balance)>) -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); @@ -364,6 +366,7 @@ pub fn new_test_ext_with_balances(balances: Vec<(AccountId, Balance)>) -> sp_io: ext } +#[allow(dead_code)] pub fn new_test_ext_with_balances_and_assets( balances: Vec<(AccountId, Balance)>, assets: Vec<(AssetIdForAssetsPallet, AccountId, Balance)>, @@ -386,6 +389,7 @@ pub fn new_test_ext_with_balances_and_assets( (1, "Relay Token".into(), "RLY".into(), 12), ], accounts: assets, + next_asset_id: None, } .assimilate_storage(&mut t) .unwrap(); @@ -410,6 +414,14 @@ impl sp_api::ProvideRuntimeApi for TestClient { } sp_api::mock_impl_runtime_apis! { + impl LocationToAccountApi for RuntimeApi { + fn convert_location(location: VersionedLocation) -> Result { + let location = location.try_into().map_err(|_| LocationToAccountApiError::VersionedConversionFailed)?; + LocationToAccountId::convert_location(&location) + .ok_or(LocationToAccountApiError::Unsupported) + } + } + impl XcmPaymentApi for RuntimeApi { fn query_acceptable_payment_assets(xcm_version: XcmVersion) -> Result, XcmPaymentApiError> { Ok(vec![ diff --git a/polkadot/xcm/xcm-simulator/Cargo.toml b/polkadot/xcm/xcm-simulator/Cargo.toml index fc09b5e31861c0cb6470e7d7c121e8c94e1f60f8..c7caa49393ed5c7fa505b38d1a2eaac208d63465 100644 --- a/polkadot/xcm/xcm-simulator/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/Cargo.toml @@ -10,20 +10,20 @@ license.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12" } -scale-info = { version = "2.6.0", default-features = false } -paste = "1.0.7" +codec = { workspace = true, default-features = true } +scale-info = { workspace = true } +paste = { workspace = true, default-features = true } -frame-support = { path = "../../../substrate/frame/support" } -frame-system = { path = "../../../substrate/frame/system" } -sp-io = { path = "../../../substrate/primitives/io" } -sp-std = { path = "../../../substrate/primitives/std" } -sp-runtime = { path = "../../../substrate/primitives/runtime" } +frame-support = { workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } -xcm = { package = "staging-xcm", path = ".." } -xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor" } -xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder" } -polkadot-primitives = { path = "../../primitives" } -polkadot-core-primitives = { path = "../../core-primitives" } -polkadot-parachain-primitives = { path = "../../parachain" } -polkadot-runtime-parachains = { path = "../../runtime/parachains" } +xcm = { workspace = true, default-features = true } +xcm-executor = { workspace = true, default-features = true } +xcm-builder = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-core-primitives = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } diff --git a/polkadot/xcm/xcm-simulator/example/Cargo.toml b/polkadot/xcm/xcm-simulator/example/Cargo.toml index 8b04170e3032f90adb6f4c3c5d3954729e009b20..e0aff9b7782a7e4fa8c73dc5cfaae51af2035533 100644 --- a/polkadot/xcm/xcm-simulator/example/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/example/Cargo.toml @@ -10,29 +10,29 @@ version = "7.0.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12" } -scale-info = { version = "2.11.1", features = ["derive"] } +codec = { workspace = true, default-features = true } +scale-info = { features = ["derive"], workspace = true, default-features = true } log = { workspace = true } -frame-system = { path = "../../../../substrate/frame/system" } -frame-support = { path = "../../../../substrate/frame/support" } -pallet-balances = { path = "../../../../substrate/frame/balances" } -pallet-message-queue = { path = "../../../../substrate/frame/message-queue" } -pallet-uniques = { path = "../../../../substrate/frame/uniques" } -sp-std = { path = "../../../../substrate/primitives/std" } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-runtime = { path = "../../../../substrate/primitives/runtime" } -sp-io = { path = "../../../../substrate/primitives/io" } -sp-tracing = { path = "../../../../substrate/primitives/tracing" } +frame-system = { workspace = true, default-features = true } +frame-support = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +pallet-message-queue = { workspace = true, default-features = true } +pallet-uniques = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } -xcm = { package = "staging-xcm", path = "../.." } -xcm-simulator = { path = ".." } -xcm-executor = { package = "staging-xcm-executor", path = "../../xcm-executor" } -xcm-builder = { package = "staging-xcm-builder", path = "../../xcm-builder" } -pallet-xcm = { path = "../../pallet-xcm" } -polkadot-core-primitives = { path = "../../../core-primitives" } -polkadot-runtime-parachains = { path = "../../../runtime/parachains" } -polkadot-parachain-primitives = { path = "../../../parachain" } +xcm = { workspace = true, default-features = true } +xcm-simulator = { workspace = true, default-features = true } +xcm-executor = { workspace = true, default-features = true } +xcm-builder = { workspace = true, default-features = true } +pallet-xcm = { workspace = true, default-features = true } +polkadot-core-primitives = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } [features] default = [] diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs index 93c8302757cb061bc1f97d003ce8b7de2374448e..bfb455aba3f9302200d58bcd6b7c074d1053468f 100644 --- a/polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs +++ b/polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs @@ -31,7 +31,6 @@ use sp_runtime::{ traits::{Get, IdentityLookup}, AccountId32, }; -use sp_std::prelude::*; use xcm::latest::prelude::*; use xcm_builder::{EnsureXcmOrigin, SignedToAccountId32}; use xcm_executor::{traits::ConvertLocation, XcmExecutor}; @@ -101,7 +100,7 @@ impl EnsureOriginWithArg for ForeignCreators { fn try_origin( o: RuntimeOrigin, a: &Location, - ) -> sp_std::result::Result { + ) -> core::result::Result { let origin_location = pallet_xcm::EnsureXcm::::try_origin(o.clone())?; if !a.starts_with(&origin_location) { return Err(o); diff --git a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml index 6b3b4018d9fbb30862eee8fa5ea1408c96b2f68e..04f8ba115173465b14127cb277bcc74776ea1a5b 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml @@ -11,30 +11,30 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12" } -honggfuzz = "0.5.55" -arbitrary = "1.3.2" -scale-info = { version = "2.11.1", features = ["derive"] } +codec = { workspace = true, default-features = true } +honggfuzz = { workspace = true } +arbitrary = { workspace = true } +scale-info = { features = ["derive"], workspace = true, default-features = true } -frame-system = { path = "../../../../substrate/frame/system" } -frame-support = { path = "../../../../substrate/frame/support" } -frame-executive = { path = "../../../../substrate/frame/executive" } -frame-try-runtime = { path = "../../../../substrate/frame/try-runtime" } -pallet-balances = { path = "../../../../substrate/frame/balances" } -pallet-message-queue = { path = "../../../../substrate/frame/message-queue" } -sp-std = { path = "../../../../substrate/primitives/std" } -sp-core = { path = "../../../../substrate/primitives/core" } -sp-runtime = { path = "../../../../substrate/primitives/runtime" } -sp-io = { path = "../../../../substrate/primitives/io" } +frame-system = { workspace = true, default-features = true } +frame-support = { workspace = true, default-features = true } +frame-executive = { workspace = true, default-features = true } +frame-try-runtime = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +pallet-message-queue = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } -xcm = { package = "staging-xcm", path = "../.." } -xcm-simulator = { path = ".." } -xcm-executor = { package = "staging-xcm-executor", path = "../../xcm-executor" } -xcm-builder = { package = "staging-xcm-builder", path = "../../xcm-builder" } -pallet-xcm = { path = "../../pallet-xcm" } -polkadot-core-primitives = { path = "../../../core-primitives" } -polkadot-runtime-parachains = { path = "../../../runtime/parachains" } -polkadot-parachain-primitives = { path = "../../../parachain" } +xcm = { workspace = true, default-features = true } +xcm-simulator = { workspace = true, default-features = true } +xcm-executor = { workspace = true, default-features = true } +xcm-builder = { workspace = true, default-features = true } +pallet-xcm = { workspace = true, default-features = true } +polkadot-core-primitives = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } [features] try-runtime = [ diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs index 11435868d4682ae4229b7939f2a8685316c7e296..616329a2f06b43f73d059a3471f49c2d7fa82e95 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs @@ -29,7 +29,6 @@ use sp_runtime::{ traits::{AccountIdLookup, BlakeTwo256, Hash, IdentifyAccount, Verify}, MultiAddress, MultiSignature, }; -use sp_std::prelude::*; use pallet_xcm::XcmPassthrough; use polkadot_core_primitives::BlockNumber as RelayBlockNumber; diff --git a/polkadot/xcm/xcm-simulator/src/lib.rs b/polkadot/xcm/xcm-simulator/src/lib.rs index a6747a4789edf8065462b831893ebc8b0284dd18..59df394406ea00fd3a3d0edb5e78efe1475e77bc 100644 --- a/polkadot/xcm/xcm-simulator/src/lib.rs +++ b/polkadot/xcm/xcm-simulator/src/lib.rs @@ -20,15 +20,18 @@ /// Used for sending messages. pub mod mock_message_queue; +extern crate alloc; + pub use codec::Encode; pub use paste; +pub use alloc::collections::vec_deque::VecDeque; +pub use core::{cell::RefCell, marker::PhantomData}; pub use frame_support::{ traits::{EnqueueMessage, Get, ProcessMessage, ProcessMessageError, ServiceQueues}, weights::{Weight, WeightMeter}, }; pub use sp_io::{hashing::blake2_256, TestExternalities}; -pub use sp_std::{cell::RefCell, collections::vec_deque::VecDeque, marker::PhantomData}; pub use polkadot_core_primitives::BlockNumber as RelayBlockNumber; pub use polkadot_parachain_primitives::primitives::{ diff --git a/polkadot/xcm/xcm-simulator/src/mock_message_queue.rs b/polkadot/xcm/xcm-simulator/src/mock_message_queue.rs index 96b47999fe952145b09faa93aaf2cefd5143acb9..bf7b0e15967c027738751cff3edaa27c29f41a0c 100644 --- a/polkadot/xcm/xcm-simulator/src/mock_message_queue.rs +++ b/polkadot/xcm/xcm-simulator/src/mock_message_queue.rs @@ -24,7 +24,6 @@ use polkadot_parachain_primitives::primitives::{ use polkadot_primitives::BlockNumber as RelayBlockNumber; use sp_runtime::traits::{Get, Hash}; -use sp_std::prelude::*; use xcm::{latest::prelude::*, VersionedXcm}; pub use pallet::*; diff --git a/polkadot/zombienet_tests/elastic_scaling/0001-basic-3cores-6s-blocks.toml b/polkadot/zombienet_tests/elastic_scaling/0001-basic-3cores-6s-blocks.toml index 83f5434edddb19afefcba93a9ce7bb305909c07f..611978a33a5f145274dd3c6c158e0de69a1c436a 100644 --- a/polkadot/zombienet_tests/elastic_scaling/0001-basic-3cores-6s-blocks.toml +++ b/polkadot/zombienet_tests/elastic_scaling/0001-basic-3cores-6s-blocks.toml @@ -7,11 +7,9 @@ timeout = 1000 [relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] max_validators_per_core = 1 - scheduling_lookahead = 2 num_cores = 3 [relaychain.genesis.runtimeGenesis.patch.configuration.config.approval_voting_params] - needed_approvals = 3 max_approval_coalesce_count = 5 [relaychain] @@ -48,4 +46,4 @@ addToGenesis = true [types.Header] number = "u64" parent_hash = "Hash" -post_state = "Hash" \ No newline at end of file +post_state = "Hash" diff --git a/polkadot/zombienet_tests/smoke/0005-precompile-pvf-smoke.js b/polkadot/zombienet_tests/smoke/0005-precompile-pvf-smoke.js new file mode 100644 index 0000000000000000000000000000000000000000..9963ce74d64e8c81d38c0ce8a141346e979f7c30 --- /dev/null +++ b/polkadot/zombienet_tests/smoke/0005-precompile-pvf-smoke.js @@ -0,0 +1,46 @@ +const assert = require("assert"); + +function nameCase(string) { + return string.charAt(0).toUpperCase() + string.slice(1); +} + +async function run(nodeName, networkInfo, jsArgs) { + const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + const action = jsArgs[0] === "register" ? "registerValidators" : "deregisterValidators" + const validatorName = jsArgs[1]; // used as seed + + await zombie.util.cryptoWaitReady(); + + // account to submit tx + const keyring = new zombie.Keyring({ type: "sr25519" }); + const alice = keyring.addFromUri("//Alice"); + const validatorStash = keyring.createFromUri(`//${nameCase(validatorName)}//stash`); + + await new Promise(async (resolve, reject) => { + const unsub = await api.tx.sudo + .sudo(api.tx.validatorManager[action]([validatorStash.address])) + .signAndSend(alice, (result) => { + console.log(`Current status is ${result.status}`); + if (result.status.isInBlock) { + console.log( + `Transaction included at blockHash ${result.status.asInBlock}` + ); + } else if (result.status.isFinalized) { + console.log( + `Transaction finalized at blockHash ${result.status.asFinalized}` + ); + unsub(); + return resolve(); + } else if (result.isError) { + console.log(`Transaction Error`); + unsub(); + return reject(); + } + }); + }); + + return 0; +} + +module.exports = { run } diff --git a/polkadot/zombienet_tests/smoke/0005-precompile-pvf-smoke.toml b/polkadot/zombienet_tests/smoke/0005-precompile-pvf-smoke.toml new file mode 100644 index 0000000000000000000000000000000000000000..2baf21b96cc1aa076173840c34e2d96aa3a5f76a --- /dev/null +++ b/polkadot/zombienet_tests/smoke/0005-precompile-pvf-smoke.toml @@ -0,0 +1,32 @@ +[settings] +timeout = 1000 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" +command = "polkadot" + + [[relaychain.nodes]] + name = "alice" + args = ["-lruntime=debug,parachain=trace" ] + + [[relaychain.nodes]] + name = "bob" + args = [ "-lruntime=debug,parachain=trace" ] + + [[relaychain.nodes]] + name = "charlie" + args = [ "-lruntime=debug,parachain=trace" ] + + [[relaychain.nodes]] + name = "dave" + args = [ "-lruntime=debug,parachain=trace" ] + +[[parachains]] +id = 100 +add_to_genesis = true + + [parachains.collator] + name = "collator-100" + image = "{{CUMULUS_IMAGE}}" + command = "polkadot-parachain" diff --git a/polkadot/zombienet_tests/smoke/0005-precompile-pvf-smoke.zndsl b/polkadot/zombienet_tests/smoke/0005-precompile-pvf-smoke.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..3ac68caf7e1bf3115e883708da95cbe6cf485175 --- /dev/null +++ b/polkadot/zombienet_tests/smoke/0005-precompile-pvf-smoke.zndsl @@ -0,0 +1,43 @@ +Description: PVF precompilation +Network: ./0005-precompile-pvf-smoke.toml +Creds: config + +# Ensure the calidator is in the validator set +dave: reports polkadot_node_is_parachain_validator is 1 within 240 secs +dave: reports polkadot_node_is_active_validator is 1 within 240 secs + +# Deregister the validator +alice: js-script ./0005-register-deregister-validator.js with "deregister,dave" return is 0 within 30 secs + +# Wait 2 sessions. The authority set change is enacted at curent_session + 2. +sleep 120 seconds +dave: reports polkadot_node_is_parachain_validator is 0 within 180 secs +dave: reports polkadot_node_is_active_validator is 0 within 180 secs + +# register the parachain +alice: js-script ./0005-register-para.js with "100" return is 0 within 600 seconds + +# Ensure the parachain made progress. +alice: parachain 100 block height is at least 10 within 300 seconds + +# Ensure the validator didn't prepare pvf +dave: reports polkadot_pvf_preparation_time_count is 1 within 30 seconds + +# Register the validator again +alice: js-script ./0005-register-deregister-validator.js with "register,dave" return is 0 within 30 secs + +# Wait 1 session and check the pvf preparation +sleep 60 seconds +dave: reports polkadot_pvf_preparation_time_count is 1 within 30 seconds + +# Check the validator is still not in the validator set +dave: reports polkadot_node_is_parachain_validator is 0 within 30 secs +dave: reports polkadot_node_is_active_validator is 0 within 30 secs + +# Check the validator is in the validator set +dave: reports polkadot_node_is_parachain_validator is 1 within 60 secs +dave: reports polkadot_node_is_active_validator is 1 within 60 secs + +# Check the pvf preparation again. The authority set change is enacted at curent_session + 2. +sleep 60 seconds +dave: reports polkadot_pvf_preparation_time_count is 1 within 60 seconds diff --git a/polkadot/zombienet_tests/smoke/0005-register-deregister-validator.js b/polkadot/zombienet_tests/smoke/0005-register-deregister-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..16e7d87d0ffc499981565ad12743ea665edccf42 --- /dev/null +++ b/polkadot/zombienet_tests/smoke/0005-register-deregister-validator.js @@ -0,0 +1,44 @@ +function nameCase(string) { + return string.charAt(0).toUpperCase() + string.slice(1); +} + +async function run(nodeName, networkInfo, args) { + const { wsUri, userDefinedTypes } = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + const action = args[0] === "register" ? "registerValidators" : "deregisterValidators" + const validatorName = args[1]; // used as seed + + await zombie.util.cryptoWaitReady(); + + // account to submit tx + const keyring = new zombie.Keyring({ type: "sr25519" }); + const alice = keyring.addFromUri("//Alice"); + const validatorStash = keyring.createFromUri(`//${nameCase(validatorName)}//stash`); + + await new Promise(async (resolve, reject) => { + const unsub = await api.tx.sudo + .sudo(api.tx.validatorManager[action]([validatorStash.address])) + .signAndSend(alice, (result) => { + console.log(`Current status is ${result.status}`); + if (result.status.isInBlock) { + console.log( + `Transaction included at blockHash ${result.status.asInBlock}` + ); + } else if (result.status.isFinalized) { + console.log( + `Transaction finalized at blockHash ${result.status.asFinalized}` + ); + unsub(); + return resolve(); + } else if (result.isError) { + console.log(`Transaction Error`); + unsub(); + return reject(); + } + }); + }); + + return 0; +} + +module.exports = { run } diff --git a/polkadot/zombienet_tests/smoke/0005-register-para.js b/polkadot/zombienet_tests/smoke/0005-register-para.js new file mode 100644 index 0000000000000000000000000000000000000000..aba7bc3601fbe8c779a3f599d6680ed36f09b056 --- /dev/null +++ b/polkadot/zombienet_tests/smoke/0005-register-para.js @@ -0,0 +1,63 @@ +async function run(nodeName, networkInfo, args) { + const init = networkInfo.nodesByName[nodeName]; + let wsUri = init.wsUri; + let userDefinedTypes = init.userDefinedTypes; + const api = await zombie.connect(wsUri, userDefinedTypes); + + // account to submit tx + const keyring = new zombie.Keyring({ type: "sr25519" }); + const alice = keyring.addFromUri("//Alice"); + + let calls = []; + + for (let i = 0; i < args.length; i++) { + let para = args[i]; + const sec = networkInfo.nodesByName["collator-" + para]; + const api_collator = await zombie.connect(sec.wsUri, sec.userDefinedTypes); + + await zombie.util.cryptoWaitReady(); + + // Get the genesis header and the validation code of the parachain + const genesis_header = await api_collator.rpc.chain.getHeader(); + const validation_code = await api_collator.rpc.state.getStorage("0x3A636F6465"); + + calls.push( + api.tx.paras.addTrustedValidationCode(validation_code.toHex()) + ); + calls.push( + api.tx.registrar.forceRegister( + alice.address, + 0, + Number(para), + genesis_header.toHex(), + validation_code.toHex(), + ) + ); + } + + const sudo_batch = api.tx.sudo.sudo(api.tx.utility.batch(calls)); + + await new Promise(async (resolve, reject) => { + const unsub = await sudo_batch + .signAndSend(alice, ({ status, isError }) => { + if (status.isInBlock) { + console.log( + `Transaction included at blockhash ${status.asInBlock}`, + ); + } else if (status.isFinalized) { + console.log( + `Transaction finalized at blockHash ${status.asFinalized}`, + ); + unsub(); + return resolve(); + } else if (isError) { + console.log(`Transaction error`); + reject(`Transaction error`); + } + }); + }); + + return 0; +} + +module.exports = { run }; diff --git a/prdoc/1.14.0/pr_1631.prdoc b/prdoc/1.14.0/pr_1631.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..f73d00968552a4b0c589a68079971d0dcac503bc --- /dev/null +++ b/prdoc/1.14.0/pr_1631.prdoc @@ -0,0 +1,39 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Upgrade libp2p to 0.52.4 + +doc: + - audience: [Node Dev, Node Operator] + description: | + Upgrade libp2p from 0.51.4 to 0.52.4 + +crates: + - name: sc-authority-discovery + bump: minor + - name: sc-cli + bump: minor + - name: sc-mixnet + bump: minor + - name: sc-network + bump: minor + - name: sc-network-gossip + bump: minor + - name: sc-network-common + bump: minor + - name: sc-network-light + bump: minor + - name: sc-network-statement + bump: minor + - name: sc-network-sync + bump: minor + - name: sc-network-test + bump: minor + - name: sc-network-transactions + bump: minor + - name: sc-network-types + bump: minor + - name: sc-offchain + bump: major + - name: sc-telemetry + bump: major diff --git a/prdoc/pr_3374.prdoc b/prdoc/1.14.0/pr_3374.prdoc similarity index 100% rename from prdoc/pr_3374.prdoc rename to prdoc/1.14.0/pr_3374.prdoc diff --git a/prdoc/pr_3679.prdoc b/prdoc/1.14.0/pr_3679.prdoc similarity index 100% rename from prdoc/pr_3679.prdoc rename to prdoc/1.14.0/pr_3679.prdoc diff --git a/prdoc/pr_3820.prdoc b/prdoc/1.14.0/pr_3820.prdoc similarity index 100% rename from prdoc/pr_3820.prdoc rename to prdoc/1.14.0/pr_3820.prdoc diff --git a/prdoc/1.14.0/pr_3828.prdoc b/prdoc/1.14.0/pr_3828.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..426625d5f23effb3fe889cacb767650d56921044 --- /dev/null +++ b/prdoc/1.14.0/pr_3828.prdoc @@ -0,0 +1,13 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "[FRAME] Remove storage migration type" + +doc: + - audience: Runtime Dev + description: | + Introduce migration type to remove data associated with a specific storage of a pallet. + +crates: + - name: frame-support + bump: minor diff --git a/prdoc/pr_3843.prdoc b/prdoc/1.14.0/pr_3843.prdoc similarity index 100% rename from prdoc/pr_3843.prdoc rename to prdoc/1.14.0/pr_3843.prdoc diff --git a/prdoc/1.14.0/pr_3940.prdoc b/prdoc/1.14.0/pr_3940.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..590afa77bb1ed8ec41958d87279e7be969f55ade --- /dev/null +++ b/prdoc/1.14.0/pr_3940.prdoc @@ -0,0 +1,31 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "RFC-5: Add request revenue info" + +doc: + - audience: Runtime Dev + description: | + Partially implemented RFC-5 in terms of revenue requests and notifications + - audience: Runtime User + description: | + Instantaneous Coretime sold on the relay chain now generates revenue for its provider. + The revenue may be claimed by its provider on the Coretime chain. + +crates: + - name: polkadot-runtime-parachains + bump: minor + - name: rococo-runtime + bump: minor + - name: westend-runtime + bump: minor + - name: pallet-broker + bump: minor + - name: rococo-runtime-constants + bump: minor + - name: westend-runtime-constants + bump: minor + - name: coretime-rococo-runtime + bump: minor + - name: coretime-westend-runtime + bump: minor diff --git a/prdoc/pr_3951.prdoc b/prdoc/1.14.0/pr_3951.prdoc similarity index 100% rename from prdoc/pr_3951.prdoc rename to prdoc/1.14.0/pr_3951.prdoc diff --git a/prdoc/1.14.0/pr_4513.prdoc b/prdoc/1.14.0/pr_4513.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..e7363d211c1700a9ec3a4b38799ad73da0b13038 --- /dev/null +++ b/prdoc/1.14.0/pr_4513.prdoc @@ -0,0 +1,14 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Removed `pallet::getter` usage from pallet-elections-phragmen + +doc: + - audience: Runtime Dev + description: | + This PR removed the `pallet::getter`s from `pallet-elections-phragmen`. + The syntax `StorageItem::::get()` should be used instead. + +crates: + - name: pallet-elections-phragmen + bump: major diff --git a/prdoc/pr_4596.prdoc b/prdoc/1.14.0/pr_4596.prdoc similarity index 100% rename from prdoc/pr_4596.prdoc rename to prdoc/1.14.0/pr_4596.prdoc diff --git a/prdoc/pr_4618.prdoc b/prdoc/1.14.0/pr_4618.prdoc similarity index 100% rename from prdoc/pr_4618.prdoc rename to prdoc/1.14.0/pr_4618.prdoc diff --git a/prdoc/pr_4662.prdoc b/prdoc/1.14.0/pr_4662.prdoc similarity index 100% rename from prdoc/pr_4662.prdoc rename to prdoc/1.14.0/pr_4662.prdoc diff --git a/prdoc/pr_4684.prdoc b/prdoc/1.14.0/pr_4684.prdoc similarity index 100% rename from prdoc/pr_4684.prdoc rename to prdoc/1.14.0/pr_4684.prdoc diff --git a/prdoc/1.14.0/pr_4685.prdoc b/prdoc/1.14.0/pr_4685.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..e212919ba2e5bcfede725c1afbdd27115dc5e229 --- /dev/null +++ b/prdoc/1.14.0/pr_4685.prdoc @@ -0,0 +1,16 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Chain-spec-builder supports `codeSubstitutes`. + +doc: + - audience: Node Operator + description: | + A new subcommand `add-code-substitute` is available for the `chain-spec-builder` binary. It allows users to provide a runtime that should be used from a given + block onwards. The `codeSubstitutes` field in the chain spec is used to force usage of a given runtime at a given block until the next runtime upgrade. It can be + used to progress chains that are stalled due to runtime bugs that prevent block-building. However, parachain usage is only possible in combination with an updated + validation function on the relay chain. + +crates: + - name: staging-chain-spec-builder + bump: minor diff --git a/prdoc/pr_4691.prdoc b/prdoc/1.14.0/pr_4691.prdoc similarity index 100% rename from prdoc/pr_4691.prdoc rename to prdoc/1.14.0/pr_4691.prdoc diff --git a/prdoc/pr_4710.prdoc b/prdoc/1.14.0/pr_4710.prdoc similarity index 100% rename from prdoc/pr_4710.prdoc rename to prdoc/1.14.0/pr_4710.prdoc diff --git a/prdoc/pr_4724.prdoc b/prdoc/1.14.0/pr_4724.prdoc similarity index 100% rename from prdoc/pr_4724.prdoc rename to prdoc/1.14.0/pr_4724.prdoc diff --git a/prdoc/pr_4728.prdoc b/prdoc/1.14.0/pr_4728.prdoc similarity index 100% rename from prdoc/pr_4728.prdoc rename to prdoc/1.14.0/pr_4728.prdoc diff --git a/prdoc/1.14.0/pr_4730.prdoc b/prdoc/1.14.0/pr_4730.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..9af14534bcbd28a600c1bb838ae6ff7f8512f563 --- /dev/null +++ b/prdoc/1.14.0/pr_4730.prdoc @@ -0,0 +1,25 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: rpc upgrade jsonrpsee to v0.23.1 + +doc: + - audience: Node Dev + description: | + Upgrade the rpc library jsonrpsee to v0.23.1 to utilize: + + - Add Extensions which we now is using to get the connection id (used by the rpc spec v2) + - Update hyper to v1.0, http v1.0, soketto and related crates (hyper::service::make_service_fn is removed) + - The subscription API for the client is modified to know why a subscription was closed. + +crates: + - name: sc-rpc-spec-v2 + bump: patch + - name: sc-rpc + bump: patch + - name: sc-rpc-server + bump: patch + - name: cumulus-relay-chain-rpc-interface + bump: patch + - name: frame-remote-externalities + bump: patch diff --git a/prdoc/pr_4733.prdoc b/prdoc/1.14.0/pr_4733.prdoc similarity index 100% rename from prdoc/pr_4733.prdoc rename to prdoc/1.14.0/pr_4733.prdoc diff --git a/prdoc/pr_4756.prdoc b/prdoc/1.14.0/pr_4756.prdoc similarity index 100% rename from prdoc/pr_4756.prdoc rename to prdoc/1.14.0/pr_4756.prdoc diff --git a/prdoc/1.14.0/pr_4757.prdoc b/prdoc/1.14.0/pr_4757.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..d94a20d7bb1a6ab4c79117f5f99f95eaaa1881d8 --- /dev/null +++ b/prdoc/1.14.0/pr_4757.prdoc @@ -0,0 +1,18 @@ +title: "pallet assets: optional auto-increment for the asset ID" + +doc: + - audience: Runtime Dev + description: | + Introduce an optional auto-increment setup for the IDs of new assets. + +crates: + - name: pallet-assets + bump: major + - name: staging-xcm-builder + bump: patch + - name: staging-xcm + bump: patch + - name: pallet-assets-freezer + bump: patch + - name: pallet-contracts + bump: patch diff --git a/prdoc/pr_4765.prdoc b/prdoc/1.14.0/pr_4765.prdoc similarity index 100% rename from prdoc/pr_4765.prdoc rename to prdoc/1.14.0/pr_4765.prdoc diff --git a/prdoc/1.14.0/pr_4769.prdoc b/prdoc/1.14.0/pr_4769.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..e9691ba6f89744f073f8b0e794706e755aa59f0a --- /dev/null +++ b/prdoc/1.14.0/pr_4769.prdoc @@ -0,0 +1,20 @@ +title: Use real rust type for pallet alias in `runtime` macro + +doc: + - audience: Runtime Dev + description: | + This PR adds the ability to use a real rust type for pallet alias in the new `runtime` macro: + ```rust + #[runtime::pallet_index(0)] + pub type System = frame_system::Pallet; + ``` + + Please note that the current syntax still continues to be supported. + +crates: + - name: frame-support-procedural + bump: patch + - name: frame-support + bump: patch + - name: minimal-template-runtime + bump: patch diff --git a/prdoc/1.14.0/pr_4799.prdoc b/prdoc/1.14.0/pr_4799.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..c4e68e316c22f8d805aceb20910f31dd3f7703fe --- /dev/null +++ b/prdoc/1.14.0/pr_4799.prdoc @@ -0,0 +1,24 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "network: Upgrade `litep2p` to v0.6.0" + +doc: + - audience: Node Operator + description: | + This PR brings the latest `litep2p` v0.6.0 to polkadot-sdk with stability improvements, + security fixes, and performance optimizations. + + Specifically: + - Incoming DHT records are now validated also with experimental litep2p network backend. + - Performance of TCP & WebSocket connections improved by setting `TCP_NODELAY` flag. + - Stability of secondary connection establishment improved. + - Multiple possible panics in litep2p library eliminated. + +crates: + - name: sc-authority-discovery + bump: patch + - name: sc-network + bump: patch + - name: sc-network-types + bump: patch diff --git a/prdoc/pr_4802.prdoc b/prdoc/1.14.0/pr_4802.prdoc similarity index 100% rename from prdoc/pr_4802.prdoc rename to prdoc/1.14.0/pr_4802.prdoc diff --git a/prdoc/1.14.0/pr_4807.prdoc b/prdoc/1.14.0/pr_4807.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..b60bfb524510a17f50df19fbbb985dc0d263a9d6 --- /dev/null +++ b/prdoc/1.14.0/pr_4807.prdoc @@ -0,0 +1,11 @@ +title: "pallet ranked collective: max member count per rank" + +doc: + - audience: Runtime Dev + description: | + Configuration for the maximum member count per rank, with the option for no limit. + +crates: + - name: pallet-ranked-collective + bump: major + diff --git a/prdoc/1.14.0/pr_4823.prdoc b/prdoc/1.14.0/pr_4823.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..a498b33f7bfa949078ca23ac196116b7f5b2f1f9 --- /dev/null +++ b/prdoc/1.14.0/pr_4823.prdoc @@ -0,0 +1,11 @@ +title: "`pallet-referenda`: Ensure to schedule referendas earliest at the next block" + +doc: + - audience: Runtime User + description: | + Ensure that referendas are scheduled earliest at the next block when they are enacted. + Otherwise the scheduling may fails and thus, the enactment of the referenda. + +crates: + - name: pallet-referenda + bump: patch diff --git a/prdoc/1.14.0/pr_4831.prdoc b/prdoc/1.14.0/pr_4831.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..8629ead6e81d80306bb69cf57ed14cea49313010 --- /dev/null +++ b/prdoc/1.14.0/pr_4831.prdoc @@ -0,0 +1,25 @@ +title: "treasury pallet: - remove unused config parameters" + +doc: + - audience: Runtime Dev + description: | + Remove unused config parameters `ApproveOrigin` and `OnSlash` from the treasury pallet. + Add `OnSlash` config parameter to the bounties and tips pallets. + +crates: + - name: pallet-treasury + bump: major + - name: pallet-bounties + bump: major + - name: pallet-tips + bump: major + - name: collectives-westend-runtime + bump: patch + - name: polkadot-runtime-common + bump: patch + - name: rococo-runtime + bump: patch + - name: westend-runtime + bump: patch + - name: kitchensink-runtime + bump: patch diff --git a/prdoc/1.14.0/pr_4833.prdoc b/prdoc/1.14.0/pr_4833.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..a5cf853696eee38fc2659a3357eb7be7fe5f860a --- /dev/null +++ b/prdoc/1.14.0/pr_4833.prdoc @@ -0,0 +1,12 @@ +title: "Reinitialize should allow to override existing config in collationGeneration" + +doc: + - audience: Node Dev + description: | + The Reinitialize collationGeneration subsystem message currently fails if no other config is already set. + As it is difficult to query the collationGeneration subsystem to check when to call Initialize or Reinitialize, this PR + proposes that Reinitialize overrides the configuration regardless if there was one already set. + +crates: + - name: polkadot-node-collation-generation + bump: minor diff --git a/prdoc/1.14.0/pr_4844.prdoc b/prdoc/1.14.0/pr_4844.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..999e63c84ed9a0491c6b4683a5ed3d5b25efa8c2 --- /dev/null +++ b/prdoc/1.14.0/pr_4844.prdoc @@ -0,0 +1,34 @@ +title: Make `Verifier::verify` and `BlockImport::check_block` use `&self` instead of `&mut self` + +doc: + - audience: Node Dev + description: | + `Verifier::verify` and `BlockImport::check_block` were refactored to use `&self` instead of `&mut self` + because there is no fundamental requirement for those operations to be exclusive in nature. + +crates: +- name: sc-consensus + bump: major + validate: false +- name: sc-consensus-aura + bump: major +- name: sc-consensus-babe + bump: major +- name: sc-consensus-beefy + bump: major +- name: sc-consensus-grandpa + bump: major +- name: sc-consensus-manual-seal + bump: major +- name: sc-consensus-pow + bump: major +- name: sc-service + bump: major +- name: cumulus-client-consensus-common + bump: major +- name: cumulus-client-consensus-aura + bump: major +- name: cumulus-client-consensus-relay-chain + bump: major +- name: polkadot-parachain-bin + validate: false diff --git a/prdoc/1.14.0/pr_4857.prdoc b/prdoc/1.14.0/pr_4857.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..d515e4257622e046c42b4de2638541397463374a --- /dev/null +++ b/prdoc/1.14.0/pr_4857.prdoc @@ -0,0 +1,50 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "[xcm] runtime api for LocationToAccount conversions" + +doc: + - audience: Runtime Dev + description: | + Introduces a new runtime API to help with conversions of XCM `Location` to the runtime's `AccountId`, + showing an Ss58 formatted address for easier verification. + + Besides that, the `xcm-fee-payment-runtime-api` module was merged into the new `xcm-runtime-apis`. + If you are using the `xcm-fee-payment-runtime-api` dependency, you just need to change it to `xcm-runtime-apis` + and update the imports from `use xcm_fee_payment_runtime_api::*` to `use xcm_runtime_apis::*`. + +crates: + - name: xcm-runtime-apis + bump: none + - name: polkadot-sdk + bump: patch + - name: pallet-xcm + bump: patch + - name: polkadot-service + bump: patch + - name: rococo-runtime + bump: patch + - name: westend-runtime + bump: patch + - name: asset-hub-rococo-runtime + bump: patch + - name: asset-hub-westend-runtime + bump: patch + - name: bridge-hub-rococo-runtime + bump: patch + - name: bridge-hub-westend-runtime + bump: patch + - name: collectives-westend-runtime + bump: patch + - name: people-rococo-runtime + bump: patch + - name: people-westend-runtime + bump: patch + - name: penpal-runtime + bump: patch + - name: contracts-rococo-runtime + bump: patch + - name: coretime-rococo-runtime + bump: patch + - name: coretime-westend-runtime + bump: none diff --git a/prdoc/1.14.0/pr_4865.prdoc b/prdoc/1.14.0/pr_4865.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..48ffd04219cf5ab48bb45bae7449a0176d28ec7e --- /dev/null +++ b/prdoc/1.14.0/pr_4865.prdoc @@ -0,0 +1,13 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Implement trait `ContainsLengthBound` for pallet-membership + +doc: + - audience: Runtime Dev + description: | + Implement trait ContainsLengthBound for pallet membership otherwise we can't use it with pallet-tips without wrapper + +crates: + - name: pallet-membership + bump: minor diff --git a/prdoc/1.14.0/pr_4877.prdoc b/prdoc/1.14.0/pr_4877.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..ede536aee450257aaff732870f01d1dfa9106e49 --- /dev/null +++ b/prdoc/1.14.0/pr_4877.prdoc @@ -0,0 +1,13 @@ +title: "Core-Fellowship: new promote_fast call" + +doc: + - audience: Runtime User + description: | + Adds the ability to quickly promote someone within a collective by bypassing the promotion + cooldown. This can help in special situations and comes with a new origin: `FastPromoteOrigin`. + +crates: + - name: pallet-core-fellowship + bump: major + - name: collectives-westend-runtime + bump: major diff --git a/prdoc/pr_2923.prdoc b/prdoc/pr_2923.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..88bf1d48dd84be6e64f107a4a5a308bd64d92c2f --- /dev/null +++ b/prdoc/pr_2923.prdoc @@ -0,0 +1,16 @@ +title: "Use `console` crate instead of `ansi_term`" + +doc: + - audience: Node Dev + description: | + This PR replace obsoleted `ansi_term` to `console`. + +crates: + - name: relay-utils + bump: patch + - name: sc-informant + bump: patch + - name: sc-tracing + bump: patch + - name: sc-service + bump: major diff --git a/prdoc/pr_3286.prdoc b/prdoc/pr_3286.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..3433f63f30295a57d8889eea12aedf731f8471cf --- /dev/null +++ b/prdoc/pr_3286.prdoc @@ -0,0 +1,17 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "Assets: can_decrease/increase for destroying asset is not successful" + +doc: + - audience: Runtime Dev + description: | + Functions `can_decrease` and `can_increase` do not return successful consequence results + for assets undergoing destruction; instead, they return the `UnknownAsset` consequence variant. + This update aligns their behavior with similar functions, such as `reducible_balance`, + `increase_balance`, `decrease_balance`, and `burn`, which return an `AssetNotLive` error + for assets in the process of being destroyed. + +crates: + - name: pallet-assets + bump: patch diff --git a/prdoc/pr_3786.prdoc b/prdoc/pr_3786.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..0bb9e6c23f75b79db37ab73d7ba997ef810efaa4 --- /dev/null +++ b/prdoc/pr_3786.prdoc @@ -0,0 +1,22 @@ +title: Make changing of peer-id while active a bit more robust + +doc: + - audience: Node Dev + description: | + Implemetation of https://github.com/polkadot-fellows/RFCs/pull/91, to use `creation_time` field to determine + the newest DHT record and to update nodes known to have the old record. + + Gossip-support is modified to try to re-resolve new address authorithies every 5 minutes instead of each session, + so that we pick autorithies that changed their address faster and try to connect to them. + +crates: +- name: sc-authority-discovery + bump: major +- name: polkadot-gossip-support + bump: major +- name: polkadot-network-bridge + bump: major +- name: polkadot-node-subsystem-types + bump: major +- name: sc-network + bump: minor \ No newline at end of file diff --git a/prdoc/pr_4097.prdoc b/prdoc/pr_4097.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..2804a9571c79e5449111affb2e3117f635e0051d --- /dev/null +++ b/prdoc/pr_4097.prdoc @@ -0,0 +1,45 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Introduce experimental slot-based collator + +doc: + - audience: Node Operator + description: | + Introduces an experimental collator that is fit fot elastic-scaling. + It can be activated on `test-parachain` and `polkadot-parachain` binaries via + `--experimental-use-slot-based` flag. The current implementation is MVP status and purely + for testing. Behaviour can change any time and should not be relied upon in environments with + any stability requirements. + +crates: + - name: cumulus-client-consensus-aura + bump: major + - name: cumulus-client-consensus-common + bump: minor + - name: cumulus-client-pov-recovery + bump: none + validate: false + - name: cumulus-pallet-aura-ext + bump: patch + - name: cumulus-relay-chain-interface + bump: major + validate: false + - name: sc-consensus-slots + bump: minor + - name: sc-basic-authorship + bump: patch + - name: cumulus-client-network + bump: none + validate: false + - name: cumulus-relay-chain-inprocess-interface + bump: minor + - name: sc-consensus-aura + bump: patch + - name: cumulus-relay-chain-rpc-interface + bump: minor + - name: polkadot-parachain-bin + bump: patch + - name: polkadot + bump: none + validate: false diff --git a/prdoc/pr_4488.prdoc b/prdoc/pr_4488.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..d0b6a877be6b1ecbdfbf94e364cc9c836cb8dd32 --- /dev/null +++ b/prdoc/pr_4488.prdoc @@ -0,0 +1,25 @@ +title: "Tx Payment: drop ED requirements for tx payments with exchangeable asset" + +doc: + - audience: Runtime Dev + description: | + Drop the Existential Deposit requirement for the asset amount exchangeable for the fee asset + (eg. DOT/KSM) during transaction payments. + + This achieved by using `SwapCredit` implementation of asset conversion, which works with + imbalances and does not require a temporary balance account within the transaction payment. + + This is a breaking change for the `pallet-asset-conversion-tx-payment` pallet, use examples + from PR for the migration. + +crates: + - name: pallet-asset-conversion-tx-payment + bump: major + - name: pallet-transaction-payment + bump: patch + - name: pallet-asset-conversion + bump: patch + - name: asset-hub-rococo-runtime + bump: patch + - name: asset-hub-westend-runtime + bump: patch diff --git a/prdoc/pr_4522.prdoc b/prdoc/pr_4522.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..c8fdcfa51a419665ea00ad37051994e73089295b --- /dev/null +++ b/prdoc/pr_4522.prdoc @@ -0,0 +1,39 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Added runtime support for reporting BEEFY fork voting + +doc: + - audience: + - Runtime Dev + - Runtime User + description: | + This PR adds the `report_fork_voting`, `report_future_voting` extrinsics to `pallet-beefy` + and renames the `report_equivocation` extrinsic to `report_double_voting`. + `report_fork_voting` can't be called yet, since it uses `Weight::MAX` weight. We will + add benchmarks for it and set the proper weight in a future PR. + Also a new `AncestryHelper` associated trait was added to `pallet_beefy::Config`. + - audience: Node Dev + description: | + This PR renames the `submit_report_equivocation_unsigned_extrinsic` in `BeefyApi` to + `submit_report_double_voting_unsigned_extrinsic`and bumps the `BeefyApi` version from 3 to 4. + +crates: + - name: pallet-beefy + bump: major + - name: pallet-beefy-mmr + bump: minor + - name: pallet-mmr + bump: major + - name: sc-consensus-beefy + bump: patch + - name: kitchensink-runtime + bump: major + - name: rococo-runtime + bump: major + - name: westend-runtime + bump: major + - name: sp-consensus-beefy + bump: major + - name: polkadot-service + bump: patch diff --git a/prdoc/pr_4563.prdoc b/prdoc/pr_4563.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..3780eee5898b555f44f9d7c7d6670e2c06ff4702 --- /dev/null +++ b/prdoc/pr_4563.prdoc @@ -0,0 +1,12 @@ +title: Try State Hook for Bounties. + +doc: + - audience: Runtime User + description: | + Invariants for storage items in the bounties pallet. Enforces the following Invariants: + 1.`BountyCount` should be greater or equals to the length of the number of items in `Bounties`. + 2.`BountyCount` should be greater or equals to the length of the number of items in `BountyDescriptions`. + 3. Number of items in `Bounties` should be the same as `BountyDescriptions` length. +crates: +- name: pallet-bounties + bump: minor diff --git a/prdoc/pr_4564.prdoc b/prdoc/pr_4564.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..896e49ee6b9ff404ccb2d616564d3e0be116476b --- /dev/null +++ b/prdoc/pr_4564.prdoc @@ -0,0 +1,32 @@ +title: "Make `OnUnbalanced::on_unbalanceds` work with `fungibles` `imbalances`" + +doc: + - audience: Runtime Dev + description: | + The `on_unbalanceds` function of `OnUnbalanced` trait accepts the `fungibles` `imbalances` + imbalances. This is done by replacing the `Imbalance` trait bound on imbalance type with + the `TryMerge` trait bound. The `TryMerge` trait is implemented for all imbalance types. + + ### Migration for `OnUnbalanced` trait implementations: + In case if you have a custom implementation of `on_unbalanceds` trait function, remove + it's `` type argument. + + ### Migration for custom imbalance types: + If you have your own imbalance types implementations, implement the `TryMerge` trait for it + introduced with this update. + +crates: + - name: frame-support + bump: major + - name: pallet-balances + bump: minor + - name: pallet-asset-conversion-tx-payment + bump: patch + - name: pallet-transaction-payment + bump: patch + - name: kitchensink-runtime + bump: patch + - name: polkadot-runtime-common + bump: patch + - name: parachains-common + bump: minor diff --git a/prdoc/pr_4566.prdoc b/prdoc/pr_4566.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..ea2979bb363aa2c26313f4e0b2d1108e99437492 --- /dev/null +++ b/prdoc/pr_4566.prdoc @@ -0,0 +1,23 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "[pallet_contracts] Add support for transient storage in contracts host functions" + +doc: + - audience: Runtime User + description: | + This PR implements transient storage, which behaves identically to regular storage + but is kept only in memory and discarded after every transaction. + This functionality is similar to the `TSTORE` and `TLOAD` operations used in Ethereum. + The following new host functions have been introduced: `get_transient_storage`, + `set_transient_storage`, `take_transient_storage`, `clear_transient_storage` and + `contains_transient_storage`. + These functions are declared as unstable and thus are not activated. + +crates: + - name: pallet-contracts + bump: major + - name: pallet-contracts-uapi + bump: major + - name: contracts-rococo-runtime + bump: minor diff --git a/prdoc/pr_4586.prdoc b/prdoc/pr_4586.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..46d166d0f9773cddaf0a867943d70c0e9fc53930 --- /dev/null +++ b/prdoc/pr_4586.prdoc @@ -0,0 +1,22 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Removed `pallet::getter` usage from pallet-identity + +doc: + - audience: Runtime Dev + description: | + This PR removed the `pallet::getter`s from `pallet-identity`. + The syntax `StorageItem::::get()` should be used instead. + +crates: + - name: pallet-identity + bump: minor + - name: pallet-alliance + bump: none + - name: kitchensink-runtime + bump: none + - name: people-rococo-integration-tests + bump: none + - name: people-westend-integration-tests + bump: none diff --git a/prdoc/pr_4613.prdoc b/prdoc/pr_4613.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..e6b2e6adc612ac0d867a0e5557cc2790f4a175cb --- /dev/null +++ b/prdoc/pr_4613.prdoc @@ -0,0 +1,10 @@ +title: "pallet-conviction-voting: Include events for vote and remove vote" + +doc: + - audience: Runtime User + description: | + Introduce event called `Voted: { who: T::AccountId, vote: AccountVote> }` and `VoteRemoved: { who: T::AccountId, vote: AccountVote> }` + +crates: + - name: pallet-conviction-voting + bump: major diff --git a/prdoc/pr_4640.prdoc b/prdoc/pr_4640.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..52abc8f4baa5dbefe370ea3ed7b5992afa376924 --- /dev/null +++ b/prdoc/pr_4640.prdoc @@ -0,0 +1,20 @@ +title: Introduce tool for validating PoVs locally + +doc: + - audience: + - Runtime Dev + - Node Dev + description: | + Introduces the `cumulus-pov-validator` for running PoVs locally. This can be helpful for debugging issues that are + only happening when the PoV gets validated on the relay chain or for example to profile the validation code. + Besides that the `polkadot-parachain` was extended with the CLI flag `--export-pov-to-path` to let a collator export + all its build PoV's to the given directory. These PoV's can then be feed into the `cumulus-pov-validator`. + +crates: + - name: polkadot-parachain-bin + bump: minor + - name: cumulus-client-consensus-aura + bump: minor + - name: cumulus-pov-validator + bump: patch + validate: false diff --git a/prdoc/pr_4663.prdoc b/prdoc/pr_4663.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..74b1274828d5c9fb31014c37b39798600f6c25fa --- /dev/null +++ b/prdoc/pr_4663.prdoc @@ -0,0 +1,14 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Add elastic scaling MVP guide + +doc: + - audience: Node Operator + description: | + Adds a guide for parachains that want to use the experimental elastic scaling MVP. + Will be viewable at: https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/guides/enable_elastic_scaling_mvp/index.html + +crates: + - name: polkadot-parachain-bin + bump: none diff --git a/prdoc/pr_4665.prdoc b/prdoc/pr_4665.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..7a8ec7398e644a161cd9a57231559147a256f91f --- /dev/null +++ b/prdoc/pr_4665.prdoc @@ -0,0 +1,21 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "Remove runtime collator signature checks" + +doc: + - audience: [Runtime Dev, Node Dev] + description: | + Removes runtime collator signature checks, but these are still being done on the node. Remove collator + and signature from the `ProspectiveCandidate` definition in the inclusion emulator. Add + `CandidateReceiptV2` node feature bit. + +crates: +- name: polkadot-primitives + bump: minor +- name: polkadot-node-subsystem-util + bump: minor +- name: polkadot-node-core-prospective-parachains + bump: patch +- name: polkadot-runtime-parachains + bump: patch diff --git a/prdoc/pr_4706.prdoc b/prdoc/pr_4706.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..ab235768b10db5789a0e116b2fe49c9a217431db --- /dev/null +++ b/prdoc/pr_4706.prdoc @@ -0,0 +1,17 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "Rename `assigner_on_demand` pallet to `on_demand`" + +doc: + - audience: Runtime Dev + description: | + Renames `assigner_on_demand` pallet to `on_demand` + +crates: +- name: polkadot-runtime-parachains + bump: major +- name: rococo-runtime + bump: patch +- name: westend-runtime + bump: patch \ No newline at end of file diff --git a/prdoc/pr_4738.prdoc b/prdoc/pr_4738.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..751f318e64f34355f009e6105f9f9d4d657ab1f2 --- /dev/null +++ b/prdoc/pr_4738.prdoc @@ -0,0 +1,18 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Add CheckMetadata SignedExtension to Rococo and Westend Coretime chains + +doc: + - audience: Runtime User + description: | + This brings support for the new Ledger app and similar hardware wallets to the Coretime + Chain on Rococo and Westend. These hardware wallets will be able to decode the transaction + using the metadata. The runtime will ensure that the metadata used for this decoding process + is correct and that the online wallet did not try to trick you. + +crates: + - name: coretime-rococo-runtime + bump: major + - name: coretime-westend-runtime + bump: major diff --git a/prdoc/pr_4751.prdoc b/prdoc/pr_4751.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..5a2c42209088039a3b570995121d661e620a9a2c --- /dev/null +++ b/prdoc/pr_4751.prdoc @@ -0,0 +1,22 @@ +title: "Use all parachain heads for BEEFY MMR extra data" + +doc: + - audience: Runtime Dev + description: | + Previously, the extra data in an MMR leaf nodes was only computed based on lease-based parachain heads. + This PR extends the extra data to include others, including on-demand parachain heads. + Currently, the number of heads is limited to the first 1024 heads sorted by para id. + +crates: + - name: polkadot-runtime-parachains + bump: minor + - name: rococo-runtime + bump: minor + - name: westend-runtime + bump: minor + - name: pallet-mmr + bump: major + - name: pallet-beefy-mmr + bump: minor + - name: polkadot-sdk + bump: minor diff --git a/prdoc/pr_4755.prdoc b/prdoc/pr_4755.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..1018446cb67e7e20a77ce1780c7157fdeed3db56 --- /dev/null +++ b/prdoc/pr_4755.prdoc @@ -0,0 +1,24 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Send PeerViewChange with high priority + +doc: + - audience: Node Dev + description: | + - orchestra updated to 0.4.0, which introduces support for prioritizing system messages. + - PeerViewChange sent with high priority and should be processed first in a queue. + - To count them in tests added tracker to TestSender and TestOverseer. It acts more like a smoke test though. + + +crates: + - name: polkadot-overseer + bump: minor + - name: polkadot-network-bridge + bump: patch + - name: polkadot-availability-distribution + bump: patch + - name: polkadot-test-malus + bump: patch + - name: polkadot-node-subsystem-test-helpers + bump: patch diff --git a/prdoc/pr_4777.prdoc b/prdoc/pr_4777.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..07fa8decebe08bfaad0fe0c621bbda8e016502ab --- /dev/null +++ b/prdoc/pr_4777.prdoc @@ -0,0 +1,27 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: XCM builder pattern allows clear_origin before buy_execution. + +doc: + - audience: Runtime Dev + description: | + Added clear_origin as an allowed command after commands that load the holdings register, in the safe xcm builder. + Previously, although it's logically allowed, an XCM could not be built like this: + ```rust + let xcm = Xcm::builder() + .withdraw_asset((Parent, 100u128)) + .clear_origin() + .buy_execution((Parent, 1u128)) + .deposit_asset(All, [0u8; 32]) + .build(); + ``` + You had to use the unsafe_builder. + Now, it's allowed using the default builder. + +crates: +- name: "xcm-procedural" + bump: minor +- name: "staging-xcm" + bump: minor + diff --git a/prdoc/pr_4791.prdoc b/prdoc/pr_4791.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..9a7a9ca44e1672fcad796e5c00dfde4ca447ad96 --- /dev/null +++ b/prdoc/pr_4791.prdoc @@ -0,0 +1,19 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Prepare PVFs if node is a validator in the next session + +doc: + - audience: Node Operator + description: | + - On every active leaf candidate-validation subsystem checks if the node is the next session authority. + - If it is, it fetches backed candidates and prepares unknown PVFs. + - Number of PVF preparations per block is limited to not overload subsystem. + +crates: + - name: polkadot + bump: patch + - name: polkadot-service + bump: patch + - name: polkadot-node-core-candidate-validation + bump: major diff --git a/prdoc/pr_4839.prdoc b/prdoc/pr_4839.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..84bb393d4c45425f2dd691e16668957d45813313 --- /dev/null +++ b/prdoc/pr_4839.prdoc @@ -0,0 +1,14 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Removed `pallet::getter` usage from pallet-insecure-randomness-collective-flip + +doc: + - audience: Runtime Dev + description: | + This PR removed the `pallet::getter`s from `pallet-insecure-randomness-collective-flip`. + The syntax `StorageItem::::get()` should be used instead. + +crates: + - name: pallet-insecure-randomness-collective-flip + bump: patch diff --git a/prdoc/pr_4840.prdoc b/prdoc/pr_4840.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..265e1f41c3f384c1c0aa3721ec0727d63b7cd96e --- /dev/null +++ b/prdoc/pr_4840.prdoc @@ -0,0 +1,14 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Removed `pallet::getter` usage from pallet-membership + +doc: + - audience: Runtime Dev + description: | + This PR removed the `pallet::getter`s from `pallet-membership`. + The syntax `StorageItem::::get()` should be used instead. + +crates: + - name: pallet-membership + bump: minor \ No newline at end of file diff --git a/prdoc/pr_4848.prdoc b/prdoc/pr_4848.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..cbc0c8322d7722678922ef8ba53056aba7836319 --- /dev/null +++ b/prdoc/pr_4848.prdoc @@ -0,0 +1,14 @@ +title: Optimize logic for gossiping assignments + +doc: + - audience: Node Dev + description: | + Optimize the logic for gossiping assignments by obtaining the list of peer ids + from the topology instead of iterating through all connected validators, this + gives us a 15% to 20% reduction in cpu usage. + +crates: +- name: polkadot-approval-distribution + bump: minor +- name: polkadot-node-network-protocol + bump: minor \ No newline at end of file diff --git a/prdoc/pr_4863.prdoc b/prdoc/pr_4863.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..eb43b67a45c5c10cda58e84ff94d6e4815e888b4 --- /dev/null +++ b/prdoc/pr_4863.prdoc @@ -0,0 +1,10 @@ +title: "Make `tracing::log` work in the runtime" + +doc: + - audience: Runtime Dev + description: | + Make `tracing::log` work in the runtime as `log` works in the runtime. + +crates: + - name: sp-runtime + bump: patch diff --git a/prdoc/pr_4871.prdoc b/prdoc/pr_4871.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..6ff36f59d70085f3dfff23678b9d64946d4f75de --- /dev/null +++ b/prdoc/pr_4871.prdoc @@ -0,0 +1,14 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Removed `pallet::getter` usage from the pallet-tips + +doc: + - audience: Runtime Dev + description: | + This PR removed `pallet::getter`s from `pallet-tips`s storage items. + When accessed inside the pallet, use the syntax `StorageItem::::get()`. + +crates: + - name: pallet-tips + bump: minor diff --git a/prdoc/pr_4885.prdoc b/prdoc/pr_4885.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..50dc31bc1b8fad8886a7ca39a1f4c7fda7e5592e --- /dev/null +++ b/prdoc/pr_4885.prdoc @@ -0,0 +1,14 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Removed `pallet::getter` usage from the pallet-transaction-storage + +doc: + - audience: Runtime Dev + description: | + This PR removed `pallet::getter`s from `pallet-transaction-storage`s storage items. + When accessed inside the pallet, use the syntax `StorageItem::::get()`. + +crates: + - name: pallet-transaction-storage + bump: minor diff --git a/prdoc/pr_4888.prdoc b/prdoc/pr_4888.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..e8cfb25d924d23fe05a44b6a7f076f70dc999e68 --- /dev/null +++ b/prdoc/pr_4888.prdoc @@ -0,0 +1,35 @@ +title: "Allow any asset over the bridge lane between the two Asset Hubs" + +doc: + - audience: Runtime User + description: | + Allow all Rococo-native, Westend-native and Ethereum-native assets to flow over + the bridge between the Rococo and Westend AssetHubs. + + On Rococo Asset Hub, we allow Westend Asset Hub to act as reserve for any asset + native to the Westend ecosystem. + We also allow Ethereum contracts to act as reserves for the foreign assets + identified by the same respective contracts locations (on the other side of Snowbridge). + + On Westend Asset Hub, we allow Rococo Asset Hub to act as reserve for any asset + native to the Rococo or Ethereum ecosystems (practically providing Westend access + to Ethereum assets through double bridging: Ethereum <> Rococo <> Westend). + +crates: + - name: assets-common + bump: major + - name: asset-hub-rococo-runtime + bump: major + - name: asset-hub-westend-runtime + bump: major + - name: asset-hub-rococo-emulated-chain + bump: minor + - name: asset-hub-rococo-integration-tests + bump: minor + - name: bridge-hub-rococo-integration-tests + bump: minor + - name: bridge-hub-westend-integration-tests + bump: minor + - name: emulated-integration-tests-common + bump: minor + diff --git a/prdoc/pr_4902.prdoc b/prdoc/pr_4902.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..19fe168a74abe316ee7e5acae7f1dfd0912c1486 --- /dev/null +++ b/prdoc/pr_4902.prdoc @@ -0,0 +1,14 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Removed `pallet::getter` usage from the pallet-vesting + +doc: + - audience: Runtime Dev + description: | + This PR removed `pallet::getter`s from `pallet-vesting`s storage items. + When accessed inside the pallet, use the syntax `StorageItem::::get()`. + +crates: + - name: pallet-vesting + bump: minor diff --git a/prdoc/pr_4912.prdoc b/prdoc/pr_4912.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..dd96054b81fa3853d695b4baa4c9474ec4ea8338 --- /dev/null +++ b/prdoc/pr_4912.prdoc @@ -0,0 +1,15 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Removed `pallet::getter` usage from the pallet-babe + +doc: + - audience: Runtime Dev + description: | + This PR removed `pallet::getter`s from `pallet-babe`s storage items. + When accessed inside the pallet, use the syntax `StorageItem::::get()`. + When accessed outside the pallet, use the public functions of storage. + +crates: + - name: pallet-babe + bump: minor diff --git a/prdoc/pr_4922.prdoc b/prdoc/pr_4922.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..2e2dd26947c0d486fa92023c3021cdcb52128938 --- /dev/null +++ b/prdoc/pr_4922.prdoc @@ -0,0 +1,15 @@ +title: Optimize finalization performance + +doc: + - audience: Node Dev + description: | + Finalization algorithm was replaced with a more efficient version, data structures refactored to be faster and do + fewer memory allocations. As the result some APIs have changed in a minor, but incompatible way. + +crates: +- name: sc-client-api + bump: major +- name: sc-client-db + bump: major +- name: sp-blockchain + bump: major diff --git a/prdoc/pr_4930.prdoc b/prdoc/pr_4930.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..a7c9a302b11852815b6665370da72097074bedea --- /dev/null +++ b/prdoc/pr_4930.prdoc @@ -0,0 +1,15 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Add test macro to emulated chains + +doc: + - audience: Runtime Dev + description: | + This PR adds a portable test macro that can be used to test trapped assets can be + claimed in an emulated chain. + + +crates: +- name: emulated-integration-tests-common + bump: minor diff --git a/prdoc/pr_4932.prdoc b/prdoc/pr_4932.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..94af00d9249eb15c9b9c372cfb96a6a7f48862bc --- /dev/null +++ b/prdoc/pr_4932.prdoc @@ -0,0 +1,15 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Remove relay-chain consensus authoring support for asset-hub chains from polkadot-parachain. + +doc: + - audience: Node Operator + description: | + The polkadot-parachain node had special handling for asset-hub parachains. They started out + using relay-chain consensus and later migrated to Aura as soon as it became available. The codepath for authoring + with relay chain consensus has been removed, since all asset hub chains have long migrated. + +crates: + - name: polkadot-parachain-bin + bump: major diff --git a/prdoc/pr_4935.prdoc b/prdoc/pr_4935.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..2b06899b63398353209eb38ad5410e24fc3e4f6d --- /dev/null +++ b/prdoc/pr_4935.prdoc @@ -0,0 +1,75 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "Bridges V2 refactoring backport and `pallet_bridge_messages` simplifications" + +doc: + - audience: Runtime Dev + description: | + This introduces several simplifications to the pallet_bridge_messages::Config configuration. + Types like `BridgedChainId`, `MaxUnrewardedRelayerEntriesAtInboundLane`, `MaxUnconfirmedMessagesAtInboundLane`, `MaximalOutboundPayloadSize`, + `InboundRelayer`, `TargetHeaderChain`, and `SourceHeaderChain` were removed. + Now, you only need to provide specific bridging chain configurations for `ThisChain`, `BridgedChain`, and `BridgedHeaderChain`. + + If you previously specified implementations for the bp_runtime::Chain* traits, those will fit here exactly, for example: + ``` + type ThisChain = bp_bridge_hub_rococo::BridgeHubRococo; + type BridgedChain = bp_bridge_hub_westend::BridgeHubWestend; + type BridgedHeaderChain = pallet_bridge_parachains::ParachainHeaders< + Runtime, + BridgeParachainWestendInstance, + bp_bridge_hub_westend::BridgeHubWestend, + >; + ``` + +crates: + - name: pallet-bridge-messages + bump: major + - name: bridge-runtime-common + bump: major + - name: bp-header-chain + bump: major + - name: bp-runtime + bump: major + - name: bp-messages + bump: major + - name: bp-polkadot-core + bump: patch + - name: bp-bridge-hub-kusama + bump: minor + - name: bp-bridge-hub-polkadot + bump: minor + - name: bp-bridge-hub-rococo + bump: minor + - name: bp-bridge-hub-westend + bump: minor + - name: bp-kusama + bump: minor + - name: bp-polkadot + bump: minor + - name: bp-polkadot-bulletin + bump: minor + - name: bp-rococo + bump: minor + - name: bp-test-utils + bump: patch + - name: bp-westend + bump: minor + - name: bridge-hub-test-utils + bump: major + - name: pallet-bridge-grandpa + bump: patch + - name: pallet-bridge-parachains + bump: patch + - name: pallet-bridge-relayers + bump: patch + - name: pallet-xcm-bridge-hub + bump: patch + - name: asset-hub-rococo-runtime + bump: patch + - name: asset-hub-westend-runtime + bump: patch + - name: bridge-hub-rococo-runtime + bump: major + - name: bridge-hub-westend-runtime + bump: major diff --git a/prdoc/pr_4936.prdoc b/prdoc/pr_4936.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..f9b7ee506a7ac6eb09014943ec5ce47e427f34e0 --- /dev/null +++ b/prdoc/pr_4936.prdoc @@ -0,0 +1,13 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "Balances Pallet: Emit events when TI is updated in currency impl" + +doc: + - audience: Runtime Dev + description: | + Previously, in the Currency impl, the implementation of pallet_balances was not emitting any instances of Issued and Rescinded events, even though the Fungible equivalent was. This PR adds the Issued and Rescinded events in appropriate places in impl_currency along with tests. + +crates: +- name: pallet-balances + bump: patch diff --git a/prdoc/pr_4938.prdoc b/prdoc/pr_4938.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..acc2a7c98e0ea2f2eb0a2d9efc231d3792cead8a --- /dev/null +++ b/prdoc/pr_4938.prdoc @@ -0,0 +1,21 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: introduce pallet-parameters to Westend to parameterize inflation + +doc: + - audience: Runtime User + description: | + This PR adds `pallet-parameters` to the Westend runtime, and makes the inflation formula be + adjustable based on this. + + Moreover, the old `era_payout` function has been removed from `polkadot_runtime_common` and is + replaced by `relay_era_payout`. This function is only meant to be used in the Polkadot relay + chains, and other users are encouraged to provide their own implementation of `type + EraPayout`. + +crates: + - name: westend-runtime + bump: major + - name: polkadot-runtime-common + bump: major diff --git a/prdoc/pr_4943.prdoc b/prdoc/pr_4943.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..a8db0f9e1ea10f59654c62122a79dfb69477f375 --- /dev/null +++ b/prdoc/pr_4943.prdoc @@ -0,0 +1,13 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Update definition of frozen balance (docs PR) + +doc: + - audience: Runtime Dev + description: | + This PR fixes a bug in the docs located in the definition of frozen balances. In addition, it extends that definition for completeness. + +crates: +- name: frame-support + bump: patch diff --git a/prdoc/pr_4959.prdoc b/prdoc/pr_4959.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..4891a97917956b2326871fda30e74e8a1a15b8b3 --- /dev/null +++ b/prdoc/pr_4959.prdoc @@ -0,0 +1,45 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: relax XcmFeeToAccount trait bound on AccountId + +doc: + - audience: Runtime Dev + description: | + This PR relaxes the trait bound on AccountId for the XcmFeeToAccount struct by introducing a new struct called `SendXcmFeeToAccount`. + The old one (`XcmFeeToAccount`) will be deprecated at January 2025. + +crates: + - name: staging-xcm-builder + bump: minor + - name: staging-xcm + bump: minor + - name: pallet-xcm + bump: minor + - name: asset-hub-rococo-runtime + bump: minor + - name: asset-hub-westend-runtime + bump: minor + - name: bridge-hub-rococo-runtime + bump: minor + - name: bridge-hub-westend-runtime + bump: minor + - name: collectives-westend-runtime + bump: minor + - name: contracts-rococo-runtime + bump: minor + - name: coretime-rococo-runtime + bump: minor + - name: coretime-westend-runtime + bump: minor + - name: people-rococo-runtime + bump: minor + - name: people-westend-runtime + bump: minor + - name: penpal-runtime + bump: minor + - name: rococo-runtime + bump: minor + - name: westend-runtime + bump: minor + diff --git a/prdoc/pr_4970.prdoc b/prdoc/pr_4970.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..d86f1af1e86028b8434af06ec2d578ff100d88a7 --- /dev/null +++ b/prdoc/pr_4970.prdoc @@ -0,0 +1,14 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "Remove `pallet::getter` usage from the transaction-payment pallet" + +doc: + - audience: Runtime Dev + description: | + This PR removes the `pallet::getter`s from `pallet-transaction-payment`. + The syntax `StorageItem::::get()` should be used instead. + +crates: + - name: pallet-transaction-payment + bump: minor diff --git a/prdoc/pr_4972.prdoc b/prdoc/pr_4972.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..dd9f1b531aad1a8a36fbc4b2ba19469ceccdb898 --- /dev/null +++ b/prdoc/pr_4972.prdoc @@ -0,0 +1,14 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "Remove `pallet::getter` usage from pallet-session" + +doc: + - audience: Runtime Dev + description: | + This PR removes the `pallet::getter`s from `pallet-session`. + The syntax `StorageItem::::get()` should be used instead. + +crates: + - name: pallet-session + bump: minor diff --git a/prdoc/pr_4976.prdoc b/prdoc/pr_4976.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..72b7b92bc47f711a564046349e0b351b08884287 --- /dev/null +++ b/prdoc/pr_4976.prdoc @@ -0,0 +1,15 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Add pub to xcm::v4::PalletInfo + +doc: + - audience: Runtime Dev + description: | + Forgot to make v4 PalletInfo fields public. Without them we cannot make use of the struct. + +crates: + - name: staging-xcm + bump: patch + validate: false + diff --git a/prdoc/pr_4978.prdoc b/prdoc/pr_4978.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..1f86d512f2c78aa3910ace03a1216eb04faf517b --- /dev/null +++ b/prdoc/pr_4978.prdoc @@ -0,0 +1,18 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Add MAX_INSTRUCTIONS_TO_DECODE to XCMv2 + +doc: + - audience: Runtime User + description: | + Added a max number of instructions to XCMv2. If using XCMv2, you'll have to take this limit into account. + It was set to 100. + - audience: Runtime Dev + description: | + Added a max number of instructions to XCMv2. If using XCMv2, you'll have to take this limit into account. + It was set to 100. + +crates: + - name: staging-xcm + bump: minor diff --git a/prdoc/pr_4993.prdoc b/prdoc/pr_4993.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..d822d5cd6c76899a47e440bd2f5aa0fa4c97a181 --- /dev/null +++ b/prdoc/pr_4993.prdoc @@ -0,0 +1,27 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Added BEEFY equivocation-related methods to BeefyApi + +doc: + - audience: Node Dev + description: | + This PR adds the `generate_ancestry_proof`, `submit_report_fork_voting_unsigned_extrinsic` and + `submit_report_future_block_voting_unsigned_extrinsic` to `BeefyApi` and bumps the `BeefyApi` version + from 4 to 5. + +crates: + - name: pallet-beefy + bump: minor + - name: pallet-beefy-mmr + bump: minor + - name: kitchensink-runtime + bump: major + - name: rococo-runtime + bump: major + - name: westend-runtime + bump: major + - name: sp-consensus-beefy + bump: minor + - name: polkadot-service + bump: patch diff --git a/prdoc/pr_4997.prdoc b/prdoc/pr_4997.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..25620a7e63ea817e9009cf557748deb63d921f2e --- /dev/null +++ b/prdoc/pr_4997.prdoc @@ -0,0 +1,20 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Do not crash on block gap in displaced_leaves_after_finalizing + +doc: + - audience: + - Node Operator + - Node Dev + description: | + After recent changes, crashes where occuring when calculating displaced branches after a block was finalized. + The reason are block gaps in the finalized chain. When encountering unknown blocks, the node was panicking. + This PR introduces changes to tolerate unknown blocks. Leafs that are separated by a gap from the to-be-finalized + block are not marked as displaced. + +crates: +- name: sc-client-db + bump: none +- name: sp-blockchain + bump: patch diff --git a/prdoc/pr_5011.prdoc b/prdoc/pr_5011.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..cb827bae6c591155087ad9a96095c1f3d716844f --- /dev/null +++ b/prdoc/pr_5011.prdoc @@ -0,0 +1,29 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "Use `BadOrigin` from `sp_runtime`" + +doc: + - audience: Runtime Dev + description: | + This PR refactor usages of deprecated `frame_support::error::BadOrigin` to `sp_runtime::traits::BadOrigin` + +crates: +- name: pallet-collective-content + bump: patch +- name: polkadot-runtime-common + bump: patch +- name: polkadot-runtime-parachains + bump: patch +- name: pallet-alliance + bump: patch +- name: pallet-contracts + bump: patch +- name: pallet-democracy + bump: patch +- name: pallet-nomination-pools + bump: patch +- name: pallet-ranked-collective + bump: patch +- name: pallet-utility + bump: patch diff --git a/prdoc/pr_5040.prdoc b/prdoc/pr_5040.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..62b175c1d64806fc2a916811af8cf3845eb8051a --- /dev/null +++ b/prdoc/pr_5040.prdoc @@ -0,0 +1,11 @@ +title: Update libp2p-websocket to v0.42.2 + +doc: + - audience: Node Operator + description: | + Fixes a panic coming from the libp2p-websocket which stops the node. + This fix ensures that polling multiple time after error results in an error instead of panics. + +crates: +- name: sc-network + bump: minor diff --git a/prdoc/pr_5103.prdoc b/prdoc/pr_5103.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..b0f72bf531f183c7dc1bb4e0d57836778bd8d1b1 --- /dev/null +++ b/prdoc/pr_5103.prdoc @@ -0,0 +1,18 @@ +title: Skip genesis leaf to unblock syncing + +doc: + - audience: + - Node Operator + - Node Dev + description: | + This PR skips over the genesis block reported as leaf when calculating displaced branches. + In those cases, when the genesis block is reported as leaf, the node would compute the path + from the current finalized block to the genesis block. This operation is time consuming and + is enough to block syncing. In the current state, the genesis block is assumed to always be + part of the finalized chain. + +crates: +- name: sc-client-db + bump: none +- name: sp-blockchain + bump: patch diff --git a/prdoc/pr_5114.prdoc b/prdoc/pr_5114.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..d57141490a3ed65d56f00a93ef8c1410f4361977 --- /dev/null +++ b/prdoc/pr_5114.prdoc @@ -0,0 +1,16 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "Remove not-audited warning" + +doc: + - audience: Runtime Dev + description: | + Pallets `tx-pause` and `safe-mode` have passed audit, this just removes a warning in the docs + to not use them. + +crates: + - name: pallet-safe-mode + bump: patch + - name: pallet-tx-pause + bump: patch diff --git a/prdoc/pr_5124.prdoc b/prdoc/pr_5124.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..966761721fc7599be50ca7a6652d3eba56f0ffb1 --- /dev/null +++ b/prdoc/pr_5124.prdoc @@ -0,0 +1,20 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Add Polkadot Chain genesis chainspec + +doc: + - audience: Node Operator + description: | + The Polkadot People Chain can now be run as all other system parachains without specifying a + chainspec. However this will soon be deprecated and `--chain ./chainspec.json` should continue + to be used instead. + + - audience: Runtime User + description: | + The Polkadot People Chain chainspecs have been added to the polkadot-sdk repo and can now be + pulled from there along with all other system chains. + +crates: + - name: polkadot-parachain-bin + bump: minor diff --git a/prdoc/schema_user.json b/prdoc/schema_user.json index e6c0468aaf8517956501324dc4ba087b444bb424..5f7d460a5cc080b1feb1f744b05e07addbb8cd51 100644 --- a/prdoc/schema_user.json +++ b/prdoc/schema_user.json @@ -148,7 +148,8 @@ } }, "required": [ - "name" + "name", + "bump" ] }, "migration_db": { diff --git a/scripts/getting-started.sh b/scripts/getting-started.sh new file mode 100755 index 0000000000000000000000000000000000000000..57806280914bd8289b253a69c669f941bbc8dabf --- /dev/null +++ b/scripts/getting-started.sh @@ -0,0 +1,147 @@ +#!/usr/bin/env sh + +set -e + +prompt() { + while true; do + echo "$1 [y/N]" + read yn + case $yn in + [Yy]* ) return 0;; # Yes, return 0 (true) + [Nn]* ) return 1;; # No, return 1 (false) + "" ) return 1;; # Default to no if user just presses Enter + * ) echo "Please answer yes or no.";; + esac + done +} + +prompt_default_yes() { + while true; do + echo "$1 [Y/n]" + read yn + case $yn in + [Yy]* ) return 0;; # Yes, return 0 (true) + [Nn]* ) return 1;; # No, return 1 (false) + "" ) return 0;; # Default to yes if user just presses Enter + * ) echo "Please answer yes or no.";; + esac + done +} + +cat </dev/null 2>&1; then + echo "\nโœ…๏ธŽ๐Ÿบ Homebrew already installed." + else + if prompt_default_yes "\n๐Ÿบ Homebrew is not installed. Install it?"; then + echo "๐Ÿบ Installing Homebrew." + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" + else + echo "โŒ Cannot continue without homebrew. Aborting." + exit 1 + fi + fi + + brew update + if command -v git >/dev/null 2>&1; then + echo "\nโœ…๏ธŽ๐Ÿบ git already installed." + else + if prompt_default_yes "\n๐Ÿบ git seems to be missing but we will need it; install git?"; then + brew install git + else + echo "โŒ Cannot continue without git. Aborting." + exit 1 + fi + fi + + if prompt "\n๐Ÿบ Install cmake, openssl and protobuf?"; then + brew install cmake openssl protobuf + else + echo "๐Ÿบ Assuming cmake, openssl and protobuf are present." + fi +elif [ "$os_name" = "Linux" ]; then + # find the distro name in the release files + distro=$( cat /etc/*-release | tr '[:upper:]' '[:lower:]' | grep -Poi '(debian|ubuntu|arch|fedora|opensuse)' | uniq | head -n 1 ) + + if [ "$distro" = "ubuntu" ]; then + echo "\n๐Ÿง Detected Ubuntu. Using apt to install dependencies." + sudo apt install --assume-yes git clang curl libssl-dev protobuf-compiler + elif [ "$distro" = "debian" ]; then + echo "\n๐Ÿง Detected Debian. Using apt to install dependencies." + sudo apt install --assume-yes git clang curl libssl-dev llvm libudev-dev make protobuf-compiler + elif [ "$distro" = "arch" ]; then + echo "\n๐Ÿง Detected Arch Linux. Using pacman to install dependencies." + pacman -Syu --needed --noconfirm curl git clang make protobuf + elif [ "$distro" = "fedora" ]; then + echo "\n๐Ÿง Detected Fedora. Using dnf to install dependencies." + sudo dnf update + sudo dnf install clang curl git openssl-devel make protobuf-compiler + elif [ "$distro" = "opensuse" ]; then + echo "\n๐Ÿง Detected openSUSE. Using zypper to install dependencies." + sudo zypper install clang curl git openssl-devel llvm-devel libudev-devel make protobuf + else + if prompt "\n๐Ÿง Unknown Linux distribution. Unable to install dependencies. Continue anyway?"; then + echo "\n๐Ÿง Proceeding with unknown linux distribution..." + else + exit 1 + fi + fi +else + echo "โŒ Unknown operating system. Aborting." + exit 1 +fi + +# Check if rust is installed +if command -v rustc >/dev/null 2>&1; then + echo "\nโœ…๏ธŽ๐Ÿฆ€ Rust already installed." +else + if prompt_default_yes "\n๐Ÿฆ€ Rust is not installed. Install it?"; then + echo "๐Ÿฆ€ Installing via rustup." + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + else + echo "Aborting." + exit 1 + fi +fi + +# Ensure that we have wasm support +if prompt_default_yes "\n๐Ÿฆ€ Setup the Rust environment (e.g. WASM support)?"; then + echo "๐Ÿฆ€ Setting up Rust environment." + rustup default stable + rustup update + rustup target add wasm32-unknown-unknown + rustup component add rust-src +fi + +if [ -d "minimal-template" ]; then + echo "\nโœ…๏ธŽ minimal-template directory already exists. -> Entering." +else + echo "\nโ†“ Let's grab the minimal template from github." + git clone https://github.com/paritytech/polkadot-sdk-minimal-template.git minimal-template +fi +cd minimal-template + +echo "\nโš™๏ธ Let's compile the node." +cargo build --release + +if prompt_default_yes "\n๐Ÿš€ Everything ready to go, let's run the node?"; then + cargo run --release -- --dev +fi diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index b756f3504655bf44f0b5e51699026dcd82afaca3..6b061955184ea3ef982352011733616a9bb0520a 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -15,33 +15,33 @@ workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -array-bytes = "6.2.2" -clap = { version = "4.5.3", features = ["derive"] } +array-bytes = { workspace = true, default-features = true } +clap = { features = ["derive"], workspace = true } log = { workspace = true, default-features = true } -node-primitives = { path = "../primitives" } -node-testing = { path = "../testing" } -kitchensink-runtime = { path = "../runtime" } -sc-client-api = { path = "../../../client/api" } -sp-runtime = { path = "../../../primitives/runtime" } -sp-state-machine = { path = "../../../primitives/state-machine" } +node-primitives = { workspace = true, default-features = true } +node-testing = { workspace = true } +kitchensink-runtime = { workspace = true } +sc-client-api = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } serde = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } -derive_more = { version = "0.99.17", default-features = false, features = ["display"] } -kvdb = "0.13.0" -kvdb-rocksdb = "0.19.0" -sp-trie = { path = "../../../primitives/trie" } -sp-core = { path = "../../../primitives/core" } -sp-consensus = { path = "../../../primitives/consensus/common" } -sc-basic-authorship = { path = "../../../client/basic-authorship" } -sp-inherents = { path = "../../../primitives/inherents" } -sp-timestamp = { path = "../../../primitives/timestamp", default-features = false } -sp-tracing = { path = "../../../primitives/tracing" } -hash-db = "0.16.0" -tempfile = "3.1.0" -fs_extra = "1" -rand = { version = "0.8.5", features = ["small_rng"] } -lazy_static = "1.4.0" -parity-db = "0.4.12" -sc-transaction-pool = { path = "../../../client/transaction-pool" } -sc-transaction-pool-api = { path = "../../../client/transaction-pool/api" } -futures = { version = "0.3.30", features = ["thread-pool"] } +derive_more = { features = ["display"], workspace = true } +kvdb = { workspace = true } +kvdb-rocksdb = { workspace = true } +sp-trie = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sc-basic-authorship = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-timestamp = { workspace = true } +sp-tracing = { workspace = true, default-features = true } +hash-db = { workspace = true, default-features = true } +tempfile = { workspace = true } +fs_extra = { workspace = true } +rand = { features = ["small_rng"], workspace = true, default-features = true } +lazy_static = { workspace = true } +parity-db = { workspace = true } +sc-transaction-pool = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } +futures = { features = ["thread-pool"], workspace = true } diff --git a/substrate/bin/node/bench/src/import.rs b/substrate/bin/node/bench/src/import.rs index e340869dea0281092b41c94d107e65e4831c7e95..0b972650ef5a0fee317f040513bbb54ceb09bdd5 100644 --- a/substrate/bin/node/bench/src/import.rs +++ b/substrate/bin/node/bench/src/import.rs @@ -121,22 +121,23 @@ impl core::Benchmark for ImportBenchmark { .inspect_state(|| { match self.block_type { BlockType::RandomTransfersKeepAlive => { - // should be 8 per signed extrinsic + 1 per unsigned + // should be 9 per signed extrinsic + 1 per unsigned // we have 2 unsigned (timestamp and glutton bloat) while the rest are // signed in the block. - // those 8 events per signed are: + // those 9 events per signed are: // - transaction paid for the transaction payment // - withdraw (Balances::Withdraw) for charging the transaction fee // - new account (System::NewAccount) as we always transfer fund to // non-existent account // - endowed (Balances::Endowed) for this new account + // - issued (Balances::Issued) as total issuance is increased // - successful transfer (Event::Transfer) for this transfer operation // - 2x deposit (Balances::Deposit and Treasury::Deposit) for depositing // the transaction fee into the treasury // - extrinsic success assert_eq!( kitchensink_runtime::System::events().len(), - (self.block.extrinsics.len() - 2) * 8 + 2, + (self.block.extrinsics.len() - 2) * 9 + 2, ); }, BlockType::Noop => { diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 929cd6a29e3889dbd93d6e31277406cf61176114..1856487ac9cac88ef3a812cbe89bd9341d232ca2 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -37,53 +37,54 @@ crate-type = ["cdylib", "rlib"] [dependencies] # third-party dependencies -array-bytes = "6.1" -clap = { version = "4.5.3", features = ["derive"], optional = true } -codec = { package = "parity-scale-codec", version = "3.6.12" } +array-bytes = { workspace = true, default-features = true } +clap = { features = ["derive"], optional = true, workspace = true } +codec = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } -jsonrpsee = { version = "0.22", features = ["server"] } -futures = "0.3.30" +jsonrpsee = { features = ["server"], workspace = true } +futures = { workspace = true } log = { workspace = true, default-features = true } -rand = "0.8" +rand = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } # The Polkadot-SDK: -polkadot-sdk = { path = "../../../../umbrella", features = ["node"] } +polkadot-sdk = { features = ["node"], workspace = true, default-features = true } # Shared code between the staging node and kitchensink runtime: -kitchensink-runtime = { path = "../runtime" } -node-rpc = { path = "../rpc" } -node-primitives = { path = "../primitives" } -node-inspect = { package = "staging-node-inspect", path = "../inspect", optional = true } +kitchensink-runtime = { workspace = true } +node-rpc = { workspace = true } +node-primitives = { workspace = true, default-features = true } +node-inspect = { optional = true, workspace = true, default-features = true } [dev-dependencies] -futures = "0.3.30" -tempfile = "3.1.0" -assert_cmd = "2.0.2" -nix = { version = "0.28.0", features = ["signal"] } -regex = "1.6.0" -platforms = "3.0" -soketto = "0.7.1" -criterion = { version = "0.5.1", features = ["async_tokio"] } -tokio = { version = "1.22.0", features = ["macros", "parking_lot", "time"] } -tokio-util = { version = "0.7.4", features = ["compat"] } -wait-timeout = "0.2" -wat = "1.0" +futures = { workspace = true } +tempfile = { workspace = true } +assert_cmd = { workspace = true } +nix = { features = ["signal"], workspace = true } +regex = { workspace = true } +platforms = { workspace = true } +soketto = { workspace = true } +criterion = { features = ["async_tokio"], workspace = true, default-features = true } +tokio = { features = ["macros", "parking_lot", "time"], workspace = true, default-features = true } +tokio-util = { features = ["compat"], workspace = true } +wait-timeout = { workspace = true } +wat = { workspace = true } serde_json = { workspace = true, default-features = true } -scale-info = { version = "2.11.1", features = ["derive", "serde"] } +scale-info = { features = ["derive", "serde"], workspace = true, default-features = true } +pretty_assertions.workspace = true # These testing-only dependencies are not exported by the Polkadot-SDK crate: -node-testing = { path = "../testing" } -substrate-cli-test-utils = { path = "../../../test-utils/cli" } -sc-service-test = { path = "../../../client/service/test" } +node-testing = { workspace = true } +substrate-cli-test-utils = { workspace = true } +sc-service-test = { workspace = true } [build-dependencies] -clap = { version = "4.5.3", optional = true } -clap_complete = { version = "4.0.2", optional = true } +clap = { optional = true, workspace = true } +clap_complete = { optional = true, workspace = true } -node-inspect = { package = "staging-node-inspect", path = "../inspect", optional = true } +node-inspect = { optional = true, workspace = true, default-features = true } -polkadot-sdk = { path = "../../../../umbrella", features = ["frame-benchmarking-cli", "sc-cli", "sc-storage-monitor", "substrate-build-script-utils"], optional = true } +polkadot-sdk = { features = ["frame-benchmarking-cli", "sc-cli", "sc-storage-monitor", "substrate-build-script-utils"], optional = true, workspace = true, default-features = true } [features] default = ["cli"] diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index c16b25187e5f58a218fa22fc55cfdc58a214c6bf..8239637b3a9f3236fc746bab887a58f17b578242 100644 --- a/substrate/bin/node/cli/benches/block_production.rs +++ b/substrate/bin/node/cli/benches/block_production.rs @@ -104,7 +104,6 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { announce_block: true, data_path: base_path.path().into(), base_path, - informant_output_format: Default::default(), wasm_runtime_overrides: None, }; diff --git a/substrate/bin/node/cli/benches/transaction_pool.rs b/substrate/bin/node/cli/benches/transaction_pool.rs index 6618f4b1132e031cd7e6c69451e3ff8997e86684..9a71a4ec585d4621f5cfd141f55ad9fb2a5ab76a 100644 --- a/substrate/bin/node/cli/benches/transaction_pool.rs +++ b/substrate/bin/node/cli/benches/transaction_pool.rs @@ -99,7 +99,6 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { announce_block: true, data_path: base_path.path().into(), base_path, - informant_output_format: Default::default(), wasm_runtime_overrides: None, }; diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index e57ca04f3b743ff3fab2f492e90a2d92cfdf8fd5..d58ca888d419bb1a6350d73b904dc3e4d13ff601 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -441,8 +441,10 @@ pub fn new_full_base::Hash>>( let auth_disc_publish_non_global_ips = config.network.allow_non_globals_in_dht; let auth_disc_public_addresses = config.network.public_addresses.clone(); - let mut net_config = - sc_network::config::FullNetworkConfiguration::<_, _, N>::new(&config.network); + let mut net_config = sc_network::config::FullNetworkConfiguration::<_, _, N>::new( + &config.network, + config.prometheus_config.as_ref().map(|cfg| cfg.registry.clone()), + ); let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"); let peer_store_handle = net_config.peer_store_handle(); diff --git a/substrate/bin/node/cli/tests/basic.rs b/substrate/bin/node/cli/tests/basic.rs index b1f737ce399b32de652abd8c26bad1811727fcff..0a2e3fd25047f39c51ca75c59a0791fe5e040a56 100644 --- a/substrate/bin/node/cli/tests/basic.rs +++ b/substrate/bin/node/cli/tests/basic.rs @@ -35,6 +35,7 @@ use kitchensink_runtime::{ }; use node_primitives::{Balance, Hash}; use node_testing::keyring::*; +use pretty_assertions::assert_eq; use wat; pub mod common; @@ -380,6 +381,13 @@ fn full_native_block_import_works() { }), topics: vec![], }, + EventRecord { + phase: Phase::ApplyExtrinsic(1), + event: RuntimeEvent::Balances(pallet_balances::Event::Rescinded { + amount: fees * 2 / 10, + }), + topics: vec![], + }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: RuntimeEvent::TransactionPayment( @@ -465,6 +473,13 @@ fn full_native_block_import_works() { }), topics: vec![], }, + EventRecord { + phase: Phase::ApplyExtrinsic(1), + event: RuntimeEvent::Balances(pallet_balances::Event::Rescinded { + amount: fees - fees * 8 / 10, + }), + topics: vec![], + }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: RuntimeEvent::TransactionPayment( @@ -515,6 +530,13 @@ fn full_native_block_import_works() { }), topics: vec![], }, + EventRecord { + phase: Phase::ApplyExtrinsic(2), + event: RuntimeEvent::Balances(pallet_balances::Event::Rescinded { + amount: fees - fees * 8 / 10, + }), + topics: vec![], + }, EventRecord { phase: Phase::ApplyExtrinsic(2), event: RuntimeEvent::TransactionPayment( diff --git a/substrate/bin/node/cli/tests/res/default_genesis_config.json b/substrate/bin/node/cli/tests/res/default_genesis_config.json index d8713764ab21d516851fddff04734f37e03c9bfe..b63e5ff549ef9d0a5742e26fe03a6167821cc97e 100644 --- a/substrate/bin/node/cli/tests/res/default_genesis_config.json +++ b/substrate/bin/node/cli/tests/res/default_genesis_config.json @@ -16,6 +16,7 @@ "balances": { "balances": [] }, + "broker": {}, "transactionPayment": { "multiplier": "1000000000000000000" }, @@ -80,12 +81,14 @@ "assets": { "assets": [], "metadata": [], - "accounts": [] + "accounts": [], + "nextAssetId": null }, "poolAssets": { "assets": [], "metadata": [], - "accounts": [] + "accounts": [], + "nextAssetId": null }, "transactionStorage": { "byteFee": 10, diff --git a/substrate/bin/node/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index e23a4c4f37e59b8b0e6e37169dfb03e676b7f2d8..68769ffb4fa44794d98bfd56657d8cb7219f8a7c 100644 --- a/substrate/bin/node/inspect/Cargo.toml +++ b/substrate/bin/node/inspect/Cargo.toml @@ -15,17 +15,17 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.5.3", features = ["derive"] } -codec = { package = "parity-scale-codec", version = "3.6.12" } +clap = { features = ["derive"], workspace = true } +codec = { workspace = true, default-features = true } thiserror = { workspace = true } -sc-cli = { path = "../../../client/cli", default-features = false } -sc-client-api = { path = "../../../client/api" } -sc-service = { path = "../../../client/service", default-features = false } -sp-blockchain = { path = "../../../primitives/blockchain" } -sp-core = { path = "../../../primitives/core" } -sp-io = { path = "../../../primitives/io" } -sp-runtime = { path = "../../../primitives/runtime" } -sp-statement-store = { path = "../../../primitives/statement-store" } +sc-cli = { workspace = true } +sc-client-api = { workspace = true, default-features = true } +sc-service = { workspace = true } +sp-blockchain = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-statement-store = { workspace = true, default-features = true } [features] runtime-benchmarks = [ diff --git a/substrate/bin/node/primitives/Cargo.toml b/substrate/bin/node/primitives/Cargo.toml index 24279ad09c3d9f4576a212d7c67ac24be27b8e22..de295fd59d45a73fee8736259ed91038dd2d40aa 100644 --- a/substrate/bin/node/primitives/Cargo.toml +++ b/substrate/bin/node/primitives/Cargo.toml @@ -16,8 +16,8 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { path = "../../../primitives/core", default-features = false } -sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-core = { workspace = true } +sp-runtime = { workspace = true } [features] default = ["std"] diff --git a/substrate/bin/node/rpc/Cargo.toml b/substrate/bin/node/rpc/Cargo.toml index 6ae80eb578596490753d903d253c01af2660ef4f..fa1e96e67e98250a1c3da6b6298307f00cb85acb 100644 --- a/substrate/bin/node/rpc/Cargo.toml +++ b/substrate/bin/node/rpc/Cargo.toml @@ -16,33 +16,33 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.22", features = ["server"] } -node-primitives = { path = "../primitives" } -pallet-transaction-payment-rpc = { path = "../../../frame/transaction-payment/rpc" } -mmr-rpc = { path = "../../../client/merkle-mountain-range/rpc" } -sc-chain-spec = { path = "../../../client/chain-spec" } -sc-client-api = { path = "../../../client/api" } -sc-consensus-babe = { path = "../../../client/consensus/babe" } -sc-consensus-babe-rpc = { path = "../../../client/consensus/babe/rpc" } -sc-consensus-beefy = { path = "../../../client/consensus/beefy" } -sc-consensus-beefy-rpc = { path = "../../../client/consensus/beefy/rpc" } -sp-consensus-beefy = { path = "../../../primitives/consensus/beefy" } -sc-consensus-grandpa = { path = "../../../client/consensus/grandpa" } -sc-consensus-grandpa-rpc = { path = "../../../client/consensus/grandpa/rpc" } -sc-mixnet = { path = "../../../client/mixnet" } -sc-rpc = { path = "../../../client/rpc" } -sc-rpc-api = { path = "../../../client/rpc-api" } -sc-rpc-spec-v2 = { path = "../../../client/rpc-spec-v2" } -sc-sync-state-rpc = { path = "../../../client/sync-state-rpc" } -sc-transaction-pool-api = { path = "../../../client/transaction-pool/api" } -sp-api = { path = "../../../primitives/api" } -sp-block-builder = { path = "../../../primitives/block-builder" } -sp-blockchain = { path = "../../../primitives/blockchain" } -sp-consensus = { path = "../../../primitives/consensus/common" } -sp-consensus-babe = { path = "../../../primitives/consensus/babe" } -sp-keystore = { path = "../../../primitives/keystore" } -sp-runtime = { path = "../../../primitives/runtime" } -sp-application-crypto = { path = "../../../primitives/application-crypto" } -sp-statement-store = { path = "../../../primitives/statement-store" } -substrate-frame-rpc-system = { path = "../../../utils/frame/rpc/system" } -substrate-state-trie-migration-rpc = { path = "../../../utils/frame/rpc/state-trie-migration-rpc" } +jsonrpsee = { features = ["server"], workspace = true } +node-primitives = { workspace = true, default-features = true } +pallet-transaction-payment-rpc = { workspace = true, default-features = true } +mmr-rpc = { workspace = true, default-features = true } +sc-chain-spec = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-consensus-babe = { workspace = true, default-features = true } +sc-consensus-babe-rpc = { workspace = true, default-features = true } +sc-consensus-beefy = { workspace = true, default-features = true } +sc-consensus-beefy-rpc = { workspace = true, default-features = true } +sp-consensus-beefy = { workspace = true, default-features = true } +sc-consensus-grandpa = { workspace = true, default-features = true } +sc-consensus-grandpa-rpc = { workspace = true, default-features = true } +sc-mixnet = { workspace = true, default-features = true } +sc-rpc = { workspace = true, default-features = true } +sc-rpc-api = { workspace = true, default-features = true } +sc-rpc-spec-v2 = { workspace = true, default-features = true } +sc-sync-state-rpc = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-block-builder = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-statement-store = { workspace = true, default-features = true } +substrate-frame-rpc-system = { workspace = true, default-features = true } +substrate-state-trie-migration-rpc = { workspace = true, default-features = true } diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index e8cc7b3482b66ef8e850871670430b23f2923396..c1c470f1dcd6dfc7bf755d25609c68d6cb18fa03 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -19,29 +19,29 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # third-party dependencies -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ +codec = { features = [ "derive", "max-encoded-len", -] } -scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } -static_assertions = "1.1.0" +], workspace = true } +scale-info = { features = ["derive", "serde"], workspace = true } +static_assertions = { workspace = true, default-features = true } log = { workspace = true } serde_json = { features = ["alloc", "arbitrary_precision"], workspace = true } # pallet-asset-conversion: turn on "num-traits" feature -primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "num-traits", "scale-info"] } +primitive-types = { features = ["codec", "num-traits", "scale-info"], workspace = true } -polkadot-sdk = { path = "../../../../umbrella", features = ["runtime", "tuples-96"], default-features = false } +polkadot-sdk = { features = ["runtime", "tuples-96"], workspace = true } # shared code between runtime and node -node-primitives = { path = "../primitives", default-features = false } +node-primitives = { workspace = true } # Example pallets that are not published: -pallet-example-mbm = { path = "../../../frame/examples/multi-block-migrations", default-features = false } -pallet-example-tasks = { path = "../../../frame/examples/tasks", default-features = false } +pallet-example-mbm = { workspace = true } +pallet-example-tasks = { workspace = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/bin/node/runtime/src/assets_api.rs b/substrate/bin/node/runtime/src/assets_api.rs index 38ec56507113f561721887689a5f4540121e2403..98187e7391f3e2d316c53da6b52ebdaea97f85fc 100644 --- a/substrate/bin/node/runtime/src/assets_api.rs +++ b/substrate/bin/node/runtime/src/assets_api.rs @@ -20,8 +20,8 @@ use polkadot_sdk::*; +use alloc::vec::Vec; use codec::Codec; -use sp_std::vec::Vec; sp_api::decl_runtime_apis! { pub trait AssetsApi diff --git a/substrate/bin/node/runtime/src/impls.rs b/substrate/bin/node/runtime/src/impls.rs index dbe562857c99fcdd4730edd0aa5d985ab2e6dd51..43e7a766e0e80c78f46f8f38772b90654e3aae19 100644 --- a/substrate/bin/node/runtime/src/impls.rs +++ b/substrate/bin/node/runtime/src/impls.rs @@ -17,8 +17,7 @@ //! Some configurable implementations as associated type for the substrate runtime. -use polkadot_sdk::*; - +use alloc::boxed::Box; use frame_support::{ pallet_prelude::*, traits::{ @@ -29,7 +28,7 @@ use frame_support::{ use pallet_alliance::{IdentityVerifier, ProposalIndex, ProposalProvider}; use pallet_asset_tx_payment::HandleCredit; use pallet_identity::legacy::IdentityField; -use sp_std::prelude::*; +use polkadot_sdk::*; use crate::{ AccountId, AllianceCollective, AllianceMotion, Assets, Authorship, Balances, Hash, @@ -64,8 +63,8 @@ impl IdentityVerifier for AllianceIdentityVerifier { } fn has_good_judgement(who: &AccountId) -> bool { - use pallet_identity::Judgement; - crate::Identity::identity(who) + use pallet_identity::{IdentityOf, Judgement}; + IdentityOf::::get(who) .map(|(registration, _)| registration.judgements) .map_or(false, |judgements| { judgements @@ -75,7 +74,8 @@ impl IdentityVerifier for AllianceIdentityVerifier { } fn super_account_id(who: &AccountId) -> Option { - crate::Identity::super_of(who).map(|parent| parent.0) + use pallet_identity::SuperOf; + SuperOf::::get(who).map(|parent| parent.0) } } diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index d683c4e086ed0a427d660cee6300d574a0f6a877..8792744eb80d284208d353022e94a617fd703d83 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -22,8 +22,11 @@ // `construct_runtime!` does a lot of recursion and requires us to increase the limits. #![recursion_limit = "1024"] +extern crate alloc; + use polkadot_sdk::*; +use alloc::{vec, vec::Vec}; use codec::{Decode, Encode, MaxEncodedLen}; use frame_election_provider_support::{ bounds::{ElectionBounds, ElectionBoundsBuilder}, @@ -66,6 +69,7 @@ use frame_system::{ pub use node_primitives::{AccountId, Signature}; use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Moment, Nonce}; use pallet_asset_conversion::{AccountIdConverter, Ascending, Chain, WithFirstAsset}; +use pallet_asset_conversion_tx_payment::SwapAssetAdapter; use pallet_broker::{CoreAssignment, CoreIndex, CoretimeInterface, PartsOf57600}; use pallet_election_provider_multi_phase::{GeometricDepositBase, SolutionAccuracyOf}; use pallet_identity::legacy::IdentityInfo; @@ -100,7 +104,6 @@ use sp_runtime::{ ApplyExtrinsicResult, FixedPointNumber, FixedU128, Perbill, Percent, Permill, Perquintill, RuntimeDebug, }; -use sp_std::prelude::*; #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -121,7 +124,7 @@ pub use sp_runtime::BuildStorage; pub mod impls; #[cfg(not(feature = "runtime-benchmarks"))] use impls::AllianceIdentityVerifier; -use impls::{AllianceProposalProvider, Author, CreditToBlockAuthor}; +use impls::{AllianceProposalProvider, Author}; /// Constant values used within the runtime. pub mod constants; @@ -187,7 +190,7 @@ type NegativeImbalance = >::NegativeImbalance; pub struct DealWithFees; impl OnUnbalanced for DealWithFees { - fn on_unbalanceds(mut fees_then_tips: impl Iterator) { + fn on_unbalanceds(mut fees_then_tips: impl Iterator) { if let Some(fees) = fees_then_tips.next() { // for fees, 80% to treasury, 20% to author let mut split = fees.ration(80, 20); @@ -572,22 +575,14 @@ impl pallet_transaction_payment::Config for Runtime { >; } -impl pallet_asset_tx_payment::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Fungibles = Assets; - type OnChargeAssetTransaction = pallet_asset_tx_payment::FungiblesAdapter< - pallet_assets::BalanceToAssetBalance, - CreditToBlockAuthor, - >; -} - impl pallet_asset_conversion_tx_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Fungibles = Assets; - type OnChargeAssetTransaction = pallet_asset_conversion_tx_payment::AssetConversionAdapter< - Balances, - AssetConversion, + type AssetId = NativeOrWithId; + type OnChargeAssetTransaction = SwapAssetAdapter< Native, + NativeAndAssets, + AssetConversion, + ResolveAssetTo, >; } @@ -857,7 +852,7 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type SignedDepositWeight = (); type SignedMaxWeight = MinerMaxWeight; type SlashHandler = (); // burn slashes - type RewardHandler = (); // nothing to do upon rewards + type RewardHandler = (); // rewards are minted from the void type DataProvider = Staking; type Fallback = onchain::OnChainExecution; type GovernanceFallback = onchain::OnChainExecution; @@ -1038,6 +1033,7 @@ impl pallet_ranked_collective::Config for Runtime { type MinRankOfClass = traits::Identity; type VoteWeight = pallet_ranked_collective::Geometric; type MemberSwappedHandler = (CoreFellowship, Salary); + type MaxMemberCount = (); #[cfg(feature = "runtime-benchmarks")] type BenchmarkSetup = (CoreFellowship, Salary); } @@ -1228,16 +1224,11 @@ parameter_types! { impl pallet_treasury::Config for Runtime { type PalletId = TreasuryPalletId; type Currency = Balances; - type ApproveOrigin = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionAtLeast, - >; type RejectOrigin = EitherOfDiverse< EnsureRoot, pallet_collective::EnsureProportionMoreThan, >; type RuntimeEvent = RuntimeEvent; - type OnSlash = (); type SpendPeriod = SpendPeriod; type Burn = Burn; type BurnDestination = (); @@ -1291,6 +1282,7 @@ impl pallet_bounties::Config for Runtime { type MaximumReasonLength = MaximumReasonLength; type WeightInfo = pallet_bounties::weights::SubstrateWeight; type ChildBountyManager = ChildBounties; + type OnSlash = Treasury; } parameter_types! { @@ -1335,6 +1327,7 @@ impl pallet_tips::Config for Runtime { type TipReportDepositBase = TipReportDepositBase; type MaxTipAmount = ConstU128<{ 500 * DOLLARS }>; type WeightInfo = pallet_tips::weights::SubstrateWeight; + type OnSlash = Treasury; } parameter_types! { @@ -1373,6 +1366,7 @@ impl pallet_contracts::Config for Runtime { type UploadOrigin = EnsureSigned; type InstantiateOrigin = EnsureSigned; type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; + type MaxTransientStorageSize = ConstU32<{ 1 * 1024 * 1024 }>; type RuntimeHoldReason = RuntimeHoldReason; #[cfg(not(feature = "runtime-benchmarks"))] type Migrations = (); @@ -1604,6 +1598,8 @@ impl pallet_mmr::Config for Runtime { type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest; type BlockHashProvider = pallet_mmr::DefaultBlockHashProvider; type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } parameter_types! { @@ -1702,12 +1698,15 @@ parameter_types! { pub const Native: NativeOrWithId = NativeOrWithId::Native; } +pub type NativeAndAssets = + UnionOf, AccountId>; + impl pallet_asset_conversion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = u128; type HigherPrecisionBalance = sp_core::U256; type AssetKind = NativeOrWithId; - type Assets = UnionOf, AccountId>; + type Assets = NativeAndAssets; type PoolId = (Self::AssetKind, Self::AssetKind); type PoolLocator = Chain< WithFirstAsset< @@ -1869,6 +1868,7 @@ impl pallet_core_fellowship::Config for Runtime { type InductOrigin = pallet_core_fellowship::EnsureInducted; type ApproveOrigin = EnsureRootWithSuccess>; type PromoteOrigin = EnsureRootWithSuccess>; + type FastPromoteOrigin = Self::PromoteOrigin; type EvidenceSize = ConstU32<16_384>; type MaxRank = ConstU32<9>; } @@ -2098,10 +2098,6 @@ impl OnUnbalanced> for IntoAuthor { } } -parameter_types! { - pub storage CoretimeRevenue: Option<(BlockNumber, Balance)> = None; -} - pub struct CoretimeProvider; impl CoretimeInterface for CoretimeProvider { type AccountId = AccountId; @@ -2117,15 +2113,6 @@ impl CoretimeInterface for CoretimeProvider { _end_hint: Option, ) { } - fn check_notify_revenue_info() -> Option<(u32, Self::Balance)> { - let revenue = CoretimeRevenue::get(); - CoretimeRevenue::set(&None); - revenue - } - #[cfg(feature = "runtime-benchmarks")] - fn ensure_notify_revenue_info(when: u32, revenue: Self::Balance) { - CoretimeRevenue::set(&Some((when, revenue))); - } } impl pallet_broker::Config for Runtime { @@ -2243,248 +2230,245 @@ mod runtime { pub struct Runtime; #[runtime::pallet_index(0)] - pub type System = frame_system; + pub type System = frame_system::Pallet; #[runtime::pallet_index(1)] - pub type Utility = pallet_utility; + pub type Utility = pallet_utility::Pallet; #[runtime::pallet_index(2)] - pub type Babe = pallet_babe; + pub type Babe = pallet_babe::Pallet; #[runtime::pallet_index(3)] - pub type Timestamp = pallet_timestamp; + pub type Timestamp = pallet_timestamp::Pallet; // Authorship must be before session in order to note author in the correct session and era // for im-online and staking. #[runtime::pallet_index(4)] - pub type Authorship = pallet_authorship; + pub type Authorship = pallet_authorship::Pallet; #[runtime::pallet_index(5)] - pub type Indices = pallet_indices; + pub type Indices = pallet_indices::Pallet; #[runtime::pallet_index(6)] - pub type Balances = pallet_balances; + pub type Balances = pallet_balances::Pallet; #[runtime::pallet_index(7)] - pub type TransactionPayment = pallet_transaction_payment; - - #[runtime::pallet_index(8)] - pub type AssetTxPayment = pallet_asset_tx_payment; + pub type TransactionPayment = pallet_transaction_payment::Pallet; #[runtime::pallet_index(9)] - pub type AssetConversionTxPayment = pallet_asset_conversion_tx_payment; + pub type AssetConversionTxPayment = pallet_asset_conversion_tx_payment::Pallet; #[runtime::pallet_index(10)] - pub type ElectionProviderMultiPhase = pallet_election_provider_multi_phase; + pub type ElectionProviderMultiPhase = pallet_election_provider_multi_phase::Pallet; #[runtime::pallet_index(11)] - pub type Staking = pallet_staking; + pub type Staking = pallet_staking::Pallet; #[runtime::pallet_index(12)] - pub type Session = pallet_session; + pub type Session = pallet_session::Pallet; #[runtime::pallet_index(13)] - pub type Democracy = pallet_democracy; + pub type Democracy = pallet_democracy::Pallet; #[runtime::pallet_index(14)] - pub type Council = pallet_collective; + pub type Council = pallet_collective::Pallet; #[runtime::pallet_index(15)] - pub type TechnicalCommittee = pallet_collective; + pub type TechnicalCommittee = pallet_collective::Pallet; #[runtime::pallet_index(16)] - pub type Elections = pallet_elections_phragmen; + pub type Elections = pallet_elections_phragmen::Pallet; #[runtime::pallet_index(17)] - pub type TechnicalMembership = pallet_membership; + pub type TechnicalMembership = pallet_membership::Pallet; #[runtime::pallet_index(18)] - pub type Grandpa = pallet_grandpa; + pub type Grandpa = pallet_grandpa::Pallet; #[runtime::pallet_index(19)] - pub type Treasury = pallet_treasury; + pub type Treasury = pallet_treasury::Pallet; #[runtime::pallet_index(20)] - pub type AssetRate = pallet_asset_rate; + pub type AssetRate = pallet_asset_rate::Pallet; #[runtime::pallet_index(21)] - pub type Contracts = pallet_contracts; + pub type Contracts = pallet_contracts::Pallet; #[runtime::pallet_index(22)] - pub type Sudo = pallet_sudo; + pub type Sudo = pallet_sudo::Pallet; #[runtime::pallet_index(23)] - pub type ImOnline = pallet_im_online; + pub type ImOnline = pallet_im_online::Pallet; #[runtime::pallet_index(24)] - pub type AuthorityDiscovery = pallet_authority_discovery; + pub type AuthorityDiscovery = pallet_authority_discovery::Pallet; #[runtime::pallet_index(25)] - pub type Offences = pallet_offences; + pub type Offences = pallet_offences::Pallet; #[runtime::pallet_index(26)] - pub type Historical = pallet_session_historical; + pub type Historical = pallet_session_historical::Pallet; #[runtime::pallet_index(27)] - pub type RandomnessCollectiveFlip = pallet_insecure_randomness_collective_flip; + pub type RandomnessCollectiveFlip = pallet_insecure_randomness_collective_flip::Pallet; #[runtime::pallet_index(28)] - pub type Identity = pallet_identity; + pub type Identity = pallet_identity::Pallet; #[runtime::pallet_index(29)] - pub type Society = pallet_society; + pub type Society = pallet_society::Pallet; #[runtime::pallet_index(30)] - pub type Recovery = pallet_recovery; + pub type Recovery = pallet_recovery::Pallet; #[runtime::pallet_index(31)] - pub type Vesting = pallet_vesting; + pub type Vesting = pallet_vesting::Pallet; #[runtime::pallet_index(32)] - pub type Scheduler = pallet_scheduler; + pub type Scheduler = pallet_scheduler::Pallet; #[runtime::pallet_index(33)] - pub type Glutton = pallet_glutton; + pub type Glutton = pallet_glutton::Pallet; #[runtime::pallet_index(34)] - pub type Preimage = pallet_preimage; + pub type Preimage = pallet_preimage::Pallet; #[runtime::pallet_index(35)] - pub type Proxy = pallet_proxy; + pub type Proxy = pallet_proxy::Pallet; #[runtime::pallet_index(36)] - pub type Multisig = pallet_multisig; + pub type Multisig = pallet_multisig::Pallet; #[runtime::pallet_index(37)] - pub type Bounties = pallet_bounties; + pub type Bounties = pallet_bounties::Pallet; #[runtime::pallet_index(38)] - pub type Tips = pallet_tips; + pub type Tips = pallet_tips::Pallet; #[runtime::pallet_index(39)] - pub type Assets = pallet_assets; + pub type Assets = pallet_assets::Pallet; #[runtime::pallet_index(40)] - pub type PoolAssets = pallet_assets; + pub type PoolAssets = pallet_assets::Pallet; #[runtime::pallet_index(41)] - pub type Beefy = pallet_beefy; + pub type Beefy = pallet_beefy::Pallet; // MMR leaf construction must be after session in order to have a leaf's next_auth_set // refer to block. See issue polkadot-fellows/runtimes#160 for details. #[runtime::pallet_index(42)] - pub type Mmr = pallet_mmr; + pub type Mmr = pallet_mmr::Pallet; #[runtime::pallet_index(43)] - pub type MmrLeaf = pallet_beefy_mmr; + pub type MmrLeaf = pallet_beefy_mmr::Pallet; #[runtime::pallet_index(44)] - pub type Lottery = pallet_lottery; + pub type Lottery = pallet_lottery::Pallet; #[runtime::pallet_index(45)] - pub type Nis = pallet_nis; + pub type Nis = pallet_nis::Pallet; #[runtime::pallet_index(46)] - pub type Uniques = pallet_uniques; + pub type Uniques = pallet_uniques::Pallet; #[runtime::pallet_index(47)] - pub type Nfts = pallet_nfts; + pub type Nfts = pallet_nfts::Pallet; #[runtime::pallet_index(48)] - pub type NftFractionalization = pallet_nft_fractionalization; + pub type NftFractionalization = pallet_nft_fractionalization::Pallet; #[runtime::pallet_index(49)] - pub type Salary = pallet_salary; + pub type Salary = pallet_salary::Pallet; #[runtime::pallet_index(50)] - pub type CoreFellowship = pallet_core_fellowship; + pub type CoreFellowship = pallet_core_fellowship::Pallet; #[runtime::pallet_index(51)] - pub type TransactionStorage = pallet_transaction_storage; + pub type TransactionStorage = pallet_transaction_storage::Pallet; #[runtime::pallet_index(52)] - pub type VoterList = pallet_bags_list; + pub type VoterList = pallet_bags_list::Pallet; #[runtime::pallet_index(53)] - pub type StateTrieMigration = pallet_state_trie_migration; + pub type StateTrieMigration = pallet_state_trie_migration::Pallet; #[runtime::pallet_index(54)] - pub type ChildBounties = pallet_child_bounties; + pub type ChildBounties = pallet_child_bounties::Pallet; #[runtime::pallet_index(55)] - pub type Referenda = pallet_referenda; + pub type Referenda = pallet_referenda::Pallet; #[runtime::pallet_index(56)] - pub type Remark = pallet_remark; + pub type Remark = pallet_remark::Pallet; #[runtime::pallet_index(57)] - pub type RootTesting = pallet_root_testing; + pub type RootTesting = pallet_root_testing::Pallet; #[runtime::pallet_index(58)] - pub type ConvictionVoting = pallet_conviction_voting; + pub type ConvictionVoting = pallet_conviction_voting::Pallet; #[runtime::pallet_index(59)] - pub type Whitelist = pallet_whitelist; + pub type Whitelist = pallet_whitelist::Pallet; #[runtime::pallet_index(60)] - pub type AllianceMotion = pallet_collective; + pub type AllianceMotion = pallet_collective::Pallet; #[runtime::pallet_index(61)] - pub type Alliance = pallet_alliance; + pub type Alliance = pallet_alliance::Pallet; #[runtime::pallet_index(62)] - pub type NominationPools = pallet_nomination_pools; + pub type NominationPools = pallet_nomination_pools::Pallet; #[runtime::pallet_index(63)] - pub type RankedPolls = pallet_referenda; + pub type RankedPolls = pallet_referenda::Pallet; #[runtime::pallet_index(64)] - pub type RankedCollective = pallet_ranked_collective; + pub type RankedCollective = pallet_ranked_collective::Pallet; #[runtime::pallet_index(65)] - pub type AssetConversion = pallet_asset_conversion; + pub type AssetConversion = pallet_asset_conversion::Pallet; #[runtime::pallet_index(66)] - pub type FastUnstake = pallet_fast_unstake; + pub type FastUnstake = pallet_fast_unstake::Pallet; #[runtime::pallet_index(67)] - pub type MessageQueue = pallet_message_queue; + pub type MessageQueue = pallet_message_queue::Pallet; #[runtime::pallet_index(68)] - pub type Pov = frame_benchmarking_pallet_pov; + pub type Pov = frame_benchmarking_pallet_pov::Pallet; #[runtime::pallet_index(69)] - pub type TxPause = pallet_tx_pause; + pub type TxPause = pallet_tx_pause::Pallet; #[runtime::pallet_index(70)] - pub type SafeMode = pallet_safe_mode; + pub type SafeMode = pallet_safe_mode::Pallet; #[runtime::pallet_index(71)] - pub type Statement = pallet_statement; + pub type Statement = pallet_statement::Pallet; #[runtime::pallet_index(72)] - pub type MultiBlockMigrations = pallet_migrations; + pub type MultiBlockMigrations = pallet_migrations::Pallet; #[runtime::pallet_index(73)] - pub type Broker = pallet_broker; + pub type Broker = pallet_broker::Pallet; #[runtime::pallet_index(74)] - pub type TasksExample = pallet_example_tasks; + pub type TasksExample = pallet_example_tasks::Pallet; #[runtime::pallet_index(75)] - pub type Mixnet = pallet_mixnet; + pub type Mixnet = pallet_mixnet::Pallet; #[runtime::pallet_index(76)] - pub type Parameters = pallet_parameters; + pub type Parameters = pallet_parameters::Pallet; #[runtime::pallet_index(77)] - pub type SkipFeelessPayment = pallet_skip_feeless_payment; + pub type SkipFeelessPayment = pallet_skip_feeless_payment::Pallet; #[runtime::pallet_index(78)] - pub type PalletExampleMbms = pallet_example_mbm; + pub type PalletExampleMbms = pallet_example_mbm::Pallet; #[runtime::pallet_index(79)] - pub type AssetConversionMigration = pallet_asset_conversion_ops; + pub type AssetConversionMigration = pallet_asset_conversion_ops::Pallet; } /// The address format for describing accounts. @@ -2562,6 +2546,7 @@ impl pallet_beefy::Config for Runtime { type MaxNominators = ConstU32<0>; type MaxSetIdSessionEntries = BeefySetIdSessionEntries; type OnNewValidatorSet = MmrLeaf; + type AncestryHelper = MmrLeaf; type WeightInfo = (); type KeyOwnerProof = >::Proof; type EquivocationReportSystem = @@ -2673,7 +2658,7 @@ impl_runtime_apis! { Runtime::metadata_at_version(version) } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { Runtime::metadata_versions() } } @@ -3046,7 +3031,7 @@ impl_runtime_apis! { } } - #[api_version(3)] + #[api_version(5)] impl sp_consensus_beefy::BeefyApi for Runtime { fn beefy_genesis() -> Option { pallet_beefy::GenesisBlock::::get() @@ -3056,7 +3041,7 @@ impl_runtime_apis! { Beefy::validator_set() } - fn submit_report_equivocation_unsigned_extrinsic( + fn submit_report_double_voting_unsigned_extrinsic( equivocation_proof: sp_consensus_beefy::DoubleVotingProof< BlockNumber, BeefyId, @@ -3066,12 +3051,37 @@ impl_runtime_apis! { ) -> Option<()> { let key_owner_proof = key_owner_proof.decode()?; - Beefy::submit_unsigned_equivocation_report( + Beefy::submit_unsigned_double_voting_report( equivocation_proof, key_owner_proof, ) } + fn submit_report_fork_voting_unsigned_extrinsic( + equivocation_proof: + sp_consensus_beefy::ForkVotingProof< + ::Header, + BeefyId, + sp_runtime::OpaqueValue + >, + key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof, + ) -> Option<()> { + Beefy::submit_unsigned_fork_voting_report( + equivocation_proof.try_into()?, + key_owner_proof.decode()?, + ) + } + + fn submit_report_future_block_voting_unsigned_extrinsic( + equivocation_proof: sp_consensus_beefy::FutureBlockVotingProof, + key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof, + ) -> Option<()> { + Beefy::submit_unsigned_future_block_voting_report( + equivocation_proof, + key_owner_proof.decode()?, + ) + } + fn generate_key_ownership_proof( _set_id: sp_consensus_beefy::ValidatorSetId, authority_id: BeefyId, @@ -3080,6 +3090,17 @@ impl_runtime_apis! { .map(|p| p.encode()) .map(sp_consensus_beefy::OpaqueKeyOwnershipProof::new) } + + fn generate_ancestry_proof( + prev_block_number: BlockNumber, + best_known_block_number: Option, + ) -> Option { + use sp_consensus_beefy::AncestryHelper; + + MmrLeaf::generate_proof(prev_block_number, best_known_block_number) + .map(|p| p.encode()) + .map(sp_runtime::OpaqueValue::new) + } } impl pallet_mmr::primitives::MmrApi< diff --git a/substrate/bin/node/testing/Cargo.toml b/substrate/bin/node/testing/Cargo.toml index 3ba3f07510e006458cf23b246e293af4e288c624..90c9ee0555cf496dcc371b4f697e64855b6d79f0 100644 --- a/substrate/bin/node/testing/Cargo.toml +++ b/substrate/bin/node/testing/Cargo.toml @@ -16,36 +16,36 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12" } -fs_extra = "1" -futures = "0.3.30" +codec = { workspace = true, default-features = true } +fs_extra = { workspace = true } +futures = { workspace = true } log = { workspace = true, default-features = true } -tempfile = "3.1.0" -frame-metadata-hash-extension = { path = "../../../frame/metadata-hash-extension" } -frame-system = { path = "../../../frame/system" } -node-cli = { package = "staging-node-cli", path = "../cli" } -node-primitives = { path = "../primitives" } -kitchensink-runtime = { path = "../runtime" } -pallet-asset-conversion = { path = "../../../frame/asset-conversion" } -pallet-assets = { path = "../../../frame/assets" } -pallet-asset-conversion-tx-payment = { path = "../../../frame/transaction-payment/asset-conversion-tx-payment" } -pallet-asset-tx-payment = { path = "../../../frame/transaction-payment/asset-tx-payment" } -pallet-skip-feeless-payment = { path = "../../../frame/transaction-payment/skip-feeless-payment" } -sc-block-builder = { path = "../../../client/block-builder" } -sc-client-api = { path = "../../../client/api" } -sc-client-db = { path = "../../../client/db", features = ["rocksdb"] } -sc-consensus = { path = "../../../client/consensus/common" } -sc-executor = { path = "../../../client/executor" } -sc-service = { path = "../../../client/service", features = ["rocksdb", "test-helpers"] } -sp-api = { path = "../../../primitives/api" } -sp-block-builder = { path = "../../../primitives/block-builder" } -sp-blockchain = { path = "../../../primitives/blockchain" } -sp-consensus = { path = "../../../primitives/consensus/common" } -sp-core = { path = "../../../primitives/core" } -sp-crypto-hashing = { path = "../../../primitives/crypto/hashing" } -sp-inherents = { path = "../../../primitives/inherents" } -sp-io = { path = "../../../primitives/io" } -sp-keyring = { path = "../../../primitives/keyring" } -sp-runtime = { path = "../../../primitives/runtime" } -sp-timestamp = { path = "../../../primitives/timestamp", default-features = false } -substrate-test-client = { path = "../../../test-utils/client" } +tempfile = { workspace = true } +frame-metadata-hash-extension = { workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } +node-cli = { workspace = true } +node-primitives = { workspace = true, default-features = true } +kitchensink-runtime = { workspace = true } +pallet-asset-conversion = { workspace = true, default-features = true } +pallet-assets = { workspace = true, default-features = true } +pallet-asset-conversion-tx-payment = { workspace = true, default-features = true } +pallet-asset-tx-payment = { workspace = true, default-features = true } +pallet-skip-feeless-payment = { workspace = true, default-features = true } +sc-block-builder = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-client-db = { features = ["rocksdb"], workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sc-executor = { workspace = true, default-features = true } +sc-service = { features = ["rocksdb", "test-helpers"], workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-block-builder = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-timestamp = { workspace = true } +substrate-test-client = { workspace = true } diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index 88585649acfe015e2e1e7ca6285c1a3565ca6f78..083f2191f3c5a9a9b3b41639ed20808173d3a3a4 100644 --- a/substrate/bin/utils/chain-spec-builder/Cargo.toml +++ b/substrate/bin/utils/chain-spec-builder/Cargo.toml @@ -24,8 +24,8 @@ name = "chain-spec-builder" crate-type = ["rlib"] [dependencies] -clap = { version = "4.5.3", features = ["derive"] } +clap = { features = ["derive"], workspace = true } log = { workspace = true, default-features = true } -sc-chain-spec = { path = "../../../client/chain-spec", features = ["clap"] } +sc-chain-spec = { features = ["clap"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } -sp-tracing = { path = "../../../primitives/tracing" } +sp-tracing = { workspace = true, default-features = true } diff --git a/substrate/bin/utils/chain-spec-builder/bin/main.rs b/substrate/bin/utils/chain-spec-builder/bin/main.rs index 18da3c30691bd895c833454cb6cd9f6fda91531d..39fa054b4806d396acd557947a957c6cfdd519f7 100644 --- a/substrate/bin/utils/chain-spec-builder/bin/main.rs +++ b/substrate/bin/utils/chain-spec-builder/bin/main.rs @@ -17,16 +17,19 @@ // along with this program. If not, see . use chain_spec_builder::{ - generate_chain_spec_for_runtime, ChainSpecBuilder, ChainSpecBuilderCmd, ConvertToRawCmd, - DisplayPresetCmd, ListPresetsCmd, UpdateCodeCmd, VerifyCmd, + generate_chain_spec_for_runtime, AddCodeSubstituteCmd, ChainSpecBuilder, ChainSpecBuilderCmd, + ConvertToRawCmd, DisplayPresetCmd, ListPresetsCmd, UpdateCodeCmd, VerifyCmd, }; use clap::Parser; use sc_chain_spec::{ - update_code_in_json_chain_spec, GenericChainSpec, GenesisConfigBuilderRuntimeCaller, + set_code_substitute_in_json_chain_spec, update_code_in_json_chain_spec, GenericChainSpec, + GenesisConfigBuilderRuntimeCaller, }; use staging_chain_spec_builder as chain_spec_builder; use std::fs; +type ChainSpec = GenericChainSpec<(), ()>; + //avoid error message escaping fn main() { match inner_main() { @@ -50,7 +53,7 @@ fn inner_main() -> Result<(), String> { ref input_chain_spec, ref runtime_wasm_path, }) => { - let chain_spec = GenericChainSpec::<()>::from_json_file(input_chain_spec.clone())?; + let chain_spec = ChainSpec::from_json_file(input_chain_spec.clone())?; let mut chain_spec_json = serde_json::from_str::(&chain_spec.as_json(false)?) @@ -65,8 +68,29 @@ fn inner_main() -> Result<(), String> { .map_err(|e| format!("to pretty failed: {e}"))?; fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string())?; }, + ChainSpecBuilderCmd::AddCodeSubstitute(AddCodeSubstituteCmd { + ref input_chain_spec, + ref runtime_wasm_path, + block_height, + }) => { + let chain_spec = ChainSpec::from_json_file(input_chain_spec.clone())?; + + let mut chain_spec_json = + serde_json::from_str::(&chain_spec.as_json(false)?) + .map_err(|e| format!("Conversion to json failed: {e}"))?; + + set_code_substitute_in_json_chain_spec( + &mut chain_spec_json, + &fs::read(runtime_wasm_path.as_path()) + .map_err(|e| format!("Wasm blob file could not be read: {e}"))?[..], + block_height, + ); + let chain_spec_json = serde_json::to_string_pretty(&chain_spec_json) + .map_err(|e| format!("to pretty failed: {e}"))?; + fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string())?; + }, ChainSpecBuilderCmd::ConvertToRaw(ConvertToRawCmd { ref input_chain_spec }) => { - let chain_spec = GenericChainSpec::<()>::from_json_file(input_chain_spec.clone())?; + let chain_spec = ChainSpec::from_json_file(input_chain_spec.clone())?; let chain_spec_json = serde_json::from_str::(&chain_spec.as_json(true)?) @@ -77,7 +101,7 @@ fn inner_main() -> Result<(), String> { fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string())?; }, ChainSpecBuilderCmd::Verify(VerifyCmd { ref input_chain_spec }) => { - let chain_spec = GenericChainSpec::<()>::from_json_file(input_chain_spec.clone())?; + let chain_spec = ChainSpec::from_json_file(input_chain_spec.clone())?; let _ = serde_json::from_str::(&chain_spec.as_json(true)?) .map_err(|e| format!("Conversion to json failed: {e}"))?; }, diff --git a/substrate/bin/utils/chain-spec-builder/src/lib.rs b/substrate/bin/utils/chain-spec-builder/src/lib.rs index 4c00bb3551b39fbe810db2ce324d69aea1092387..6c679f109a002401bb6b25718979c2e8fc58d2a9 100644 --- a/substrate/bin/utils/chain-spec-builder/src/lib.rs +++ b/substrate/bin/utils/chain-spec-builder/src/lib.rs @@ -143,6 +143,7 @@ pub enum ChainSpecBuilderCmd { ConvertToRaw(ConvertToRawCmd), ListPresets(ListPresetsCmd), DisplayPreset(DisplayPresetCmd), + AddCodeSubstitute(AddCodeSubstituteCmd), } /// Create a new chain spec by interacting with the provided runtime wasm blob. @@ -222,6 +223,25 @@ pub struct UpdateCodeCmd { pub runtime_wasm_path: PathBuf, } +/// Add a code substitute in the chain spec. +/// +/// The `codeSubstitute` object of the chain spec will be updated with the block height as key and +/// runtime code as value. This operation supports both plain and raw formats. The `codeSubstitute` +/// field instructs the node to use the provided runtime code at the given block height. This is +/// useful when the chain can not progress on its own due to a bug that prevents block-building. +/// +/// Note: For parachains, the validation function on the relaychain needs to be adjusted too, +/// otherwise blocks built using the substituted parachain runtime will be rejected. +#[derive(Parser, Debug, Clone)] +pub struct AddCodeSubstituteCmd { + /// Chain spec to be updated. + pub input_chain_spec: PathBuf, + /// New runtime wasm blob that should replace the existing code. + pub runtime_wasm_path: PathBuf, + /// The block height at which the code should be substituted. + pub block_height: u64, +} + /// Converts the given chain spec into the raw format. #[derive(Parser, Debug, Clone)] pub struct ConvertToRawCmd { diff --git a/substrate/bin/utils/subkey/Cargo.toml b/substrate/bin/utils/subkey/Cargo.toml index 8dc4bf254b2d44e1f6b5c96ca16a2e8586e0333c..5aa013097c150add192d25c2b658c61720e39bd8 100644 --- a/substrate/bin/utils/subkey/Cargo.toml +++ b/substrate/bin/utils/subkey/Cargo.toml @@ -20,5 +20,5 @@ path = "src/main.rs" name = "subkey" [dependencies] -clap = { version = "4.5.3", features = ["derive"] } -sc-cli = { path = "../../../client/cli" } +clap = { features = ["derive"], workspace = true } +sc-cli = { workspace = true, default-features = true } diff --git a/substrate/client/allocator/Cargo.toml b/substrate/client/allocator/Cargo.toml index 2c268b548ea9c32fabdc82226c77e82a7ef59cea..5a3b05aa8a98d8366433d574e158a8cd9a2f3a64 100644 --- a/substrate/client/allocator/Cargo.toml +++ b/substrate/client/allocator/Cargo.toml @@ -19,5 +19,5 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { workspace = true, default-features = true } thiserror = { workspace = true } -sp-core = { path = "../../primitives/core" } -sp-wasm-interface = { path = "../../primitives/wasm-interface" } +sp-core = { workspace = true, default-features = true } +sp-wasm-interface = { workspace = true, default-features = true } diff --git a/substrate/client/api/Cargo.toml b/substrate/client/api/Cargo.toml index 147ea2bfbf5df83716c4a7f1f5fb2ade0c41d3f8..a64ee3ab4ce1944672ec87aac34119720834ef59 100644 --- a/substrate/client/api/Cargo.toml +++ b/substrate/client/api/Cargo.toml @@ -17,30 +17,30 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ +codec = { features = [ "derive", -] } -fnv = "1.0.6" -futures = "0.3.30" +], workspace = true } +fnv = { workspace = true } +futures = { workspace = true } log = { workspace = true, default-features = true } -parking_lot = "0.12.1" -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } -sc-executor = { path = "../executor" } -sc-transaction-pool-api = { path = "../transaction-pool/api" } -sc-utils = { path = "../utils" } -sp-api = { path = "../../primitives/api" } -sp-blockchain = { path = "../../primitives/blockchain" } -sp-consensus = { path = "../../primitives/consensus/common" } -sp-core = { path = "../../primitives/core", default-features = false } -sp-database = { path = "../../primitives/database" } -sp-externalities = { path = "../../primitives/externalities" } -sp-runtime = { path = "../../primitives/runtime", default-features = false } -sp-state-machine = { path = "../../primitives/state-machine" } -sp-statement-store = { path = "../../primitives/statement-store" } -sp-storage = { path = "../../primitives/storage" } -sp-trie = { path = "../../primitives/trie" } +parking_lot = { workspace = true, default-features = true } +prometheus-endpoint = { workspace = true, default-features = true } +sc-executor = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } +sc-utils = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-core = { workspace = true } +sp-database = { workspace = true, default-features = true } +sp-externalities = { workspace = true, default-features = true } +sp-runtime = { workspace = true } +sp-state-machine = { workspace = true, default-features = true } +sp-statement-store = { workspace = true, default-features = true } +sp-storage = { workspace = true, default-features = true } +sp-trie = { workspace = true, default-features = true } [dev-dependencies] thiserror = { workspace = true } -sp-test-primitives = { path = "../../primitives/test-primitives" } -substrate-test-runtime = { path = "../../test-utils/runtime" } +sp-test-primitives = { workspace = true } +substrate-test-runtime = { workspace = true } diff --git a/substrate/client/api/src/backend.rs b/substrate/client/api/src/backend.rs index 31b100433c7086719737275bfaa6b3931bffc88a..0b2a349524018d33b8003b6832363286b77d8503 100644 --- a/substrate/client/api/src/backend.rs +++ b/substrate/client/api/src/backend.rs @@ -217,7 +217,8 @@ pub trait BlockImportOperation { where I: IntoIterator, Option>)>; - /// Mark a block as finalized. + /// Mark a block as finalized, if multiple blocks are finalized in the same operation then they + /// must be marked in ascending order. fn mark_finalized( &mut self, hash: Block::Hash, diff --git a/substrate/client/api/src/leaves.rs b/substrate/client/api/src/leaves.rs index e129de8bf3fad30a0bb76569957c93138c631db8..70efe8b19c627d03741a3ea11b8889332b5a567c 100644 --- a/substrate/client/api/src/leaves.rs +++ b/substrate/client/api/src/leaves.rs @@ -45,33 +45,20 @@ pub struct RemoveOutcome { } /// Removed leaves after a finalization action. -pub struct FinalizationOutcome { - removed: BTreeMap, Vec>, +pub struct FinalizationOutcome +where + I: Iterator, +{ + removed: I, } -impl FinalizationOutcome { - /// Merge with another. This should only be used for displaced items that - /// are produced within one transaction of each other. - pub fn merge(&mut self, mut other: Self) { - // this will ignore keys that are in duplicate, however - // if these are actually produced correctly via the leaf-set within - // one transaction, then there will be no overlap in the keys. - self.removed.append(&mut other.removed); - } - - /// Iterate over all displaced leaves. - pub fn leaves(&self) -> impl Iterator { - self.removed.values().flatten() - } - +impl FinalizationOutcome +where + I: Iterator, +{ /// Constructor - pub fn new(new_displaced: impl Iterator) -> Self { - let mut removed = BTreeMap::, Vec>::new(); - for (hash, number) in new_displaced { - removed.entry(Reverse(number)).or_default().push(hash); - } - - FinalizationOutcome { removed } + pub fn new(new_displaced: I) -> Self { + FinalizationOutcome { removed: new_displaced } } } @@ -86,7 +73,7 @@ pub struct LeafSet { impl LeafSet where H: Clone + PartialEq + Decode + Encode, - N: std::fmt::Debug + Clone + AtLeast32Bit + Decode + Encode, + N: std::fmt::Debug + Copy + AtLeast32Bit + Decode + Encode, { /// Construct a new, blank leaf set. pub fn new() -> Self { @@ -117,13 +104,13 @@ where let number = Reverse(number); let removed = if number.0 != N::zero() { - let parent_number = Reverse(number.0.clone() - N::one()); + let parent_number = Reverse(number.0 - N::one()); self.remove_leaf(&parent_number, &parent_hash).then(|| parent_hash) } else { None }; - self.insert_leaf(number.clone(), hash.clone()); + self.insert_leaf(number, hash.clone()); ImportOutcome { inserted: LeafSetItem { hash, number }, removed } } @@ -150,7 +137,7 @@ where let inserted = parent_hash.and_then(|parent_hash| { if number.0 != N::zero() { - let parent_number = Reverse(number.0.clone() - N::one()); + let parent_number = Reverse(number.0 - N::one()); self.insert_leaf(parent_number, parent_hash.clone()); Some(parent_hash) } else { @@ -162,11 +149,12 @@ where } /// Remove all leaves displaced by the last block finalization. - pub fn remove_displaced_leaves(&mut self, displaced_leaves: &FinalizationOutcome) { - for (number, hashes) in &displaced_leaves.removed { - for hash in hashes.iter() { - self.remove_leaf(number, hash); - } + pub fn remove_displaced_leaves(&mut self, displaced_leaves: FinalizationOutcome) + where + I: Iterator, + { + for (number, hash) in displaced_leaves.removed { + self.remove_leaf(&Reverse(number), &hash); } } @@ -186,13 +174,13 @@ where let items = self .storage .iter() - .flat_map(|(number, hashes)| hashes.iter().map(move |h| (h.clone(), number.clone()))) + .flat_map(|(number, hashes)| hashes.iter().map(move |h| (h.clone(), *number))) .collect::>(); - for (hash, number) in &items { + for (hash, number) in items { if number.0 > best_number { assert!( - self.remove_leaf(number, hash), + self.remove_leaf(&number, &hash), "item comes from an iterator over storage; qed", ); } @@ -207,7 +195,7 @@ where // we need to make sure that the best block exists in the leaf set as // this is an invariant of regular block import. if !leaves_contains_best { - self.insert_leaf(best_number.clone(), best_hash.clone()); + self.insert_leaf(best_number, best_hash.clone()); } } @@ -229,7 +217,7 @@ where column: u32, prefix: &[u8], ) { - let leaves: Vec<_> = self.storage.iter().map(|(n, h)| (n.0.clone(), h.clone())).collect(); + let leaves: Vec<_> = self.storage.iter().map(|(n, h)| (n.0, h.clone())).collect(); tx.set_from_vec(column, prefix, leaves.encode()); } @@ -274,7 +262,7 @@ where /// Returns the highest leaf and all hashes associated to it. pub fn highest_leaf(&self) -> Option<(N, &[H])> { - self.storage.iter().next().map(|(k, v)| (k.0.clone(), &v[..])) + self.storage.iter().next().map(|(k, v)| (k.0, &v[..])) } } @@ -286,13 +274,13 @@ pub struct Undo<'a, H: 'a, N: 'a> { impl<'a, H: 'a, N: 'a> Undo<'a, H, N> where H: Clone + PartialEq + Decode + Encode, - N: std::fmt::Debug + Clone + AtLeast32Bit + Decode + Encode, + N: std::fmt::Debug + Copy + AtLeast32Bit + Decode + Encode, { /// Undo an imported block by providing the import operation outcome. /// No additional operations should be performed between import and undo. pub fn undo_import(&mut self, outcome: ImportOutcome) { if let Some(removed_hash) = outcome.removed { - let removed_number = Reverse(outcome.inserted.number.0.clone() - N::one()); + let removed_number = Reverse(outcome.inserted.number.0 - N::one()); self.inner.insert_leaf(removed_number, removed_hash); } self.inner.remove_leaf(&outcome.inserted.number, &outcome.inserted.hash); @@ -302,7 +290,7 @@ where /// No additional operations should be performed between remove and undo. pub fn undo_remove(&mut self, outcome: RemoveOutcome) { if let Some(inserted_hash) = outcome.inserted { - let inserted_number = Reverse(outcome.removed.number.0.clone() - N::one()); + let inserted_number = Reverse(outcome.removed.number.0 - N::one()); self.inner.remove_leaf(&inserted_number, &inserted_hash); } self.inner.insert_leaf(outcome.removed.number, outcome.removed.hash); @@ -310,8 +298,13 @@ where /// Undo a finalization operation by providing the displaced leaves. /// No additional operations should be performed between finalization and undo. - pub fn undo_finalization(&mut self, mut outcome: FinalizationOutcome) { - self.inner.storage.append(&mut outcome.removed); + pub fn undo_finalization(&mut self, outcome: FinalizationOutcome) + where + I: Iterator, + { + for (number, hash) in outcome.removed { + self.inner.storage.entry(Reverse(number)).or_default().push(hash); + } } } diff --git a/substrate/client/authority-discovery/Cargo.toml b/substrate/client/authority-discovery/Cargo.toml index 435ca88a80079c9da9510b0f505d21677afb52cf..309c9c542a0b10fa8c7fbff14a07c5622634e8f2 100644 --- a/substrate/client/authority-discovery/Cargo.toml +++ b/substrate/client/authority-discovery/Cargo.toml @@ -17,38 +17,33 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.12.4" +prost-build = { workspace = true } [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } -futures = "0.3.30" -futures-timer = "3.0.1" -ip_network = "0.4.1" -libp2p = { version = "0.51.4", features = ["ed25519", "kad"] } -multihash = { version = "0.17.0", default-features = false, features = ["sha2", "std"] } -linked_hash_set = "0.1.4" +codec = { workspace = true } +futures = { workspace = true } +futures-timer = { workspace = true } +ip_network = { workspace = true } +libp2p = { features = ["ed25519", "kad"], workspace = true } +multihash = { workspace = true } +linked_hash_set = { workspace = true } log = { workspace = true, default-features = true } -prost = "0.12.4" -rand = "0.8.5" +prost = { workspace = true } +rand = { workspace = true, default-features = true } thiserror = { workspace = true } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } -sc-client-api = { path = "../api" } -sc-network = { path = "../network" } -sc-network-types = { path = "../network/types" } -sp-api = { path = "../../primitives/api" } -sp-authority-discovery = { path = "../../primitives/authority-discovery" } -sp-blockchain = { path = "../../primitives/blockchain" } -sp-core = { path = "../../primitives/core" } -sp-keystore = { path = "../../primitives/keystore" } -sp-runtime = { path = "../../primitives/runtime" } -async-trait = "0.1.79" -multihash-codetable = { version = "0.1.1", features = [ - "digest", - "serde", - "sha2", -] } +prometheus-endpoint = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-network-types = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-authority-discovery = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +async-trait = { workspace = true } [dev-dependencies] -quickcheck = { version = "1.0.3", default-features = false } -sp-tracing = { path = "../../primitives/tracing" } -substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } +quickcheck = { workspace = true } +sp-tracing = { workspace = true, default-features = true } +substrate-test-runtime-client = { workspace = true } diff --git a/substrate/client/authority-discovery/build.rs b/substrate/client/authority-discovery/build.rs index 83076ac8c893736cf9c2e0852d515339f8bde7a5..cdabc1a74427def80e03e5717ea429dfeff09055 100644 --- a/substrate/client/authority-discovery/build.rs +++ b/substrate/client/authority-discovery/build.rs @@ -18,7 +18,11 @@ fn main() { prost_build::compile_protos( - &["src/worker/schema/dht-v1.proto", "src/worker/schema/dht-v2.proto"], + &[ + "src/worker/schema/dht-v1.proto", + "src/worker/schema/dht-v2.proto", + "src/worker/schema/dht-v3.proto", + ], &["src/worker/schema"], ) .unwrap(); diff --git a/substrate/client/authority-discovery/src/service.rs b/substrate/client/authority-discovery/src/service.rs index 60c7a2b990378f0c91a16854bdb815de8661c53a..852d3ab80c9b8926d291f5a83249515b1c8fabc6 100644 --- a/substrate/client/authority-discovery/src/service.rs +++ b/substrate/client/authority-discovery/src/service.rs @@ -55,7 +55,7 @@ impl Service { /// [`crate::Worker`] failed. /// /// Note: [`Multiaddr`]s returned always include a [`PeerId`] via a - /// [`libp2p::core::multiaddr::Protocol::P2p`] component. Equality of + /// [`sc_network_types::multiaddr::Protocol::P2p`] component. Equality of /// [`PeerId`]s across [`Multiaddr`]s returned by a single call is not /// enforced today, given that there are still authorities out there /// publishing the addresses of their sentry nodes on the DHT. In the future diff --git a/substrate/client/authority-discovery/src/worker.rs b/substrate/client/authority-discovery/src/worker.rs index f20cf6aa2121204063982bc7717bf094ac561c53..42994bbc7ea89e7a9eca2296b7d3c5153c85a658 100644 --- a/substrate/client/authority-discovery/src/worker.rs +++ b/substrate/client/authority-discovery/src/worker.rs @@ -26,7 +26,7 @@ use std::{ collections::{HashMap, HashSet}, marker::PhantomData, sync::Arc, - time::Duration, + time::{Duration, Instant, SystemTime, UNIX_EPOCH}, }; use futures::{channel::mpsc, future, stream::Fuse, FutureExt, Stream, StreamExt}; @@ -34,21 +34,19 @@ use futures::{channel::mpsc, future, stream::Fuse, FutureExt, Stream, StreamExt} use addr_cache::AddrCache; use codec::{Decode, Encode}; use ip_network::IpNetwork; +use libp2p::kad::{PeerRecord, Record}; use linked_hash_set::LinkedHashSet; -use log::{debug, error, log_enabled}; +use log::{debug, error}; use prometheus_endpoint::{register, Counter, CounterVec, Gauge, Opts, U64}; use prost::Message; use rand::{seq::SliceRandom, thread_rng}; use sc_network::{ - event::DhtEvent, multiaddr, KademliaKey, Multiaddr, NetworkDHTProvider, NetworkSigner, - NetworkStateInfo, -}; -use sc_network_types::{ - multihash::{Code, Multihash}, - PeerId, + config::DEFAULT_KADEMLIA_REPLICATION_FACTOR, event::DhtEvent, multiaddr, KademliaKey, + Multiaddr, NetworkDHTProvider, NetworkSigner, NetworkStateInfo, }; +use sc_network_types::{multihash::Code, PeerId}; use schema::PeerSignature; use sp_api::{ApiError, ProvideRuntimeApi}; use sp_authority_discovery::{ @@ -65,7 +63,7 @@ mod schema { #[cfg(test)] mod tests; - include!(concat!(env!("OUT_DIR"), "/authority_discovery_v2.rs")); + include!(concat!(env!("OUT_DIR"), "/authority_discovery_v3.rs")); } #[cfg(test)] pub mod tests; @@ -162,6 +160,16 @@ pub struct Worker { /// Set of in-flight lookups. in_flight_lookups: HashMap, + /// Set of lookups we can still receive records. + /// These are the entries in the `in_flight_lookups` for which + /// we got at least one successfull result. + known_lookups: HashMap, + + /// Last known record by key, here we always keep the record with + /// the highest creation time and we don't accept records older than + /// that. + last_known_records: HashMap, + addr_cache: addr_cache::AddrCache, metrics: Option, @@ -171,6 +179,17 @@ pub struct Worker { phantom: PhantomData, } +#[derive(Debug, Clone)] +struct RecordInfo { + /// Time since UNIX_EPOCH in nanoseconds. + creation_time: u128, + /// Peers that we know have this record, bounded to no more than + /// DEFAULT_KADEMLIA_REPLICATION_FACTOR(20). + peers_with_record: HashSet, + /// The record itself. + record: Record, +} + /// Wrapper for [`AuthorityDiscoveryApi`](sp_authority_discovery::AuthorityDiscoveryApi). Can be /// be implemented by any struct without dependency on the runtime. #[async_trait::async_trait] @@ -247,14 +266,14 @@ where }; let public_addresses = { - let local_peer_id: Multihash = network.local_peer_id().into(); + let local_peer_id = network.local_peer_id(); config .public_addresses .into_iter() .map(|mut address| { if let Some(multiaddr::Protocol::P2p(peer_id)) = address.iter().last() { - if peer_id != local_peer_id { + if peer_id != *local_peer_id.as_ref() { error!( target: LOG_TARGET, "Discarding invalid local peer ID in public address {address}.", @@ -286,10 +305,12 @@ where query_interval, pending_lookups: Vec::new(), in_flight_lookups: HashMap::new(), + known_lookups: HashMap::new(), addr_cache, role, metrics, phantom: PhantomData, + last_known_records: HashMap::new(), } } @@ -397,14 +418,13 @@ where debug!( target: LOG_TARGET, - "Authority DHT record peer_id='{local_peer_id}' addresses='{addresses:?}'", + "Publishing authority DHT record peer_id='{local_peer_id}' addresses='{addresses:?}'", ); // The address must include the local peer id. - let local_peer_id: Multihash = local_peer_id.into(); addresses .into_iter() - .map(move |a| a.with(multiaddr::Protocol::P2p(local_peer_id))) + .map(move |a| a.with(multiaddr::Protocol::P2p(*local_peer_id.as_ref()))) } /// Publish own public addresses. @@ -448,7 +468,7 @@ where .set(addresses.len().try_into().unwrap_or(std::u64::MAX)); } - let serialized_record = serialize_authority_record(addresses)?; + let serialized_record = serialize_authority_record(addresses, Some(build_creation_time()))?; let peer_signature = sign_record_with_peer_id(&serialized_record, &self.network)?; let keys_vec = keys.iter().cloned().collect::>(); @@ -499,12 +519,17 @@ where self.authorities_queried_at = Some(best_hash); self.addr_cache.retain_ids(&authorities); + let now = Instant::now(); + self.last_known_records.retain(|k, value| { + self.known_authorities.contains_key(k) && !value.record.is_expired(now) + }); authorities.shuffle(&mut thread_rng()); self.pending_lookups = authorities; // Ignore all still in-flight lookups. Those that are still in-flight are likely stalled as // query interval ticks are far enough apart for all lookups to succeed. self.in_flight_lookups.clear(); + self.known_lookups.clear(); if let Some(metrics) = &self.metrics { metrics @@ -542,16 +567,12 @@ where metrics.dht_event_received.with_label_values(&["value_found"]).inc(); } - if log_enabled!(log::Level::Debug) { - let hashes: Vec<_> = v.iter().map(|(hash, _value)| hash.clone()).collect(); - debug!(target: LOG_TARGET, "Value for hash '{:?}' found on Dht.", hashes); - } + debug!(target: LOG_TARGET, "Value for hash '{:?}' found on Dht.", v.record.key); if let Err(e) = self.handle_dht_value_found_event(v) { if let Some(metrics) = &self.metrics { metrics.handle_value_found_event_failure.inc(); } - debug!(target: LOG_TARGET, "Failed to handle Dht value found event: {}", e); } }, @@ -655,6 +676,31 @@ where publisher, authority_id, )?; + + let records_creation_time: u128 = + schema::AuthorityRecord::decode(signed_record.record.as_slice()) + .map_err(Error::DecodingProto)? + .creation_time + .map(|creation_time| { + u128::decode(&mut &creation_time.timestamp[..]).unwrap_or_default() + }) + .unwrap_or_default(); // 0 is a sane default for records that do not have creation time present. + + let current_record_info = self.last_known_records.get(&record_key); + // If record creation time is older than the current record creation time, + // we don't store it since we want to give higher priority to newer records. + if let Some(current_record_info) = current_record_info { + if records_creation_time < current_record_info.creation_time { + debug!( + target: LOG_TARGET, + "Skip storing because record creation time {:?} is older than the current known record {:?}", + records_creation_time, + current_record_info.creation_time + ); + return Ok(()); + } + } + self.network.store_record(record_key, record_value, Some(publisher), expires); Ok(()) } @@ -705,67 +751,88 @@ where Ok(()) } - fn handle_dht_value_found_event(&mut self, values: Vec<(KademliaKey, Vec)>) -> Result<()> { + fn handle_dht_value_found_event(&mut self, peer_record: PeerRecord) -> Result<()> { // Ensure `values` is not empty and all its keys equal. - let remote_key = single(values.iter().map(|(key, _)| key.clone())) - .map_err(|_| Error::ReceivingDhtValueFoundEventWithDifferentKeys)? - .ok_or(Error::ReceivingDhtValueFoundEventWithNoRecords)?; - - let authority_id: AuthorityId = self - .in_flight_lookups - .remove(&remote_key) - .ok_or(Error::ReceivingUnexpectedRecord)?; + let remote_key = peer_record.record.key.clone(); + + let authority_id: AuthorityId = + if let Some(authority_id) = self.in_flight_lookups.remove(&remote_key) { + self.known_lookups.insert(remote_key.clone(), authority_id.clone()); + authority_id + } else if let Some(authority_id) = self.known_lookups.get(&remote_key) { + authority_id.clone() + } else { + return Err(Error::ReceivingUnexpectedRecord); + }; let local_peer_id = self.network.local_peer_id(); - let remote_addresses: Vec = values - .into_iter() - .map(|(_k, v)| { - let schema::SignedAuthorityRecord { record, peer_signature, .. } = - Self::check_record_signed_with_authority_id(&v, &authority_id)?; - - let addresses: Vec = schema::AuthorityRecord::decode(record.as_slice()) - .map(|a| a.addresses) - .map_err(Error::DecodingProto)? - .into_iter() - .map(|a| a.try_into()) - .collect::>() - .map_err(Error::ParsingMultiaddress)?; - - let get_peer_id = |a: &Multiaddr| match a.iter().last() { - Some(multiaddr::Protocol::P2p(key)) => PeerId::from_multihash(key).ok(), - _ => None, - }; - - // Ignore [`Multiaddr`]s without [`PeerId`] or with own addresses. - let addresses: Vec = addresses - .into_iter() - .filter(|a| get_peer_id(a).filter(|p| *p != local_peer_id).is_some()) - .collect(); - - let remote_peer_id = single(addresses.iter().map(get_peer_id)) - .map_err(|_| Error::ReceivingDhtValueFoundEventWithDifferentPeerIds)? // different peer_id in records - .flatten() - .ok_or(Error::ReceivingDhtValueFoundEventWithNoPeerIds)?; // no records with peer_id in them - - // At this point we know all the valid multiaddresses from the record, know that - // each of them belong to the same PeerId, we just need to check if the record is - // properly signed by the owner of the PeerId - self.check_record_signed_with_network_key( - &record, - peer_signature, - remote_peer_id, - &authority_id, - )?; - Ok(addresses) + let schema::SignedAuthorityRecord { record, peer_signature, .. } = + Self::check_record_signed_with_authority_id( + peer_record.record.value.as_slice(), + &authority_id, + )?; + + let authority_record = + schema::AuthorityRecord::decode(record.as_slice()).map_err(Error::DecodingProto)?; + + let records_creation_time: u128 = authority_record + .creation_time + .as_ref() + .map(|creation_time| { + u128::decode(&mut &creation_time.timestamp[..]).unwrap_or_default() }) - .collect::>>>()? + .unwrap_or_default(); // 0 is a sane default for records that do not have creation time present. + + let addresses: Vec = authority_record + .addresses .into_iter() - .flatten() - .take(MAX_ADDRESSES_PER_AUTHORITY) + .map(|a| a.try_into()) + .collect::>() + .map_err(Error::ParsingMultiaddress)?; + + let get_peer_id = |a: &Multiaddr| match a.iter().last() { + Some(multiaddr::Protocol::P2p(key)) => PeerId::from_multihash(key).ok(), + _ => None, + }; + + // Ignore [`Multiaddr`]s without [`PeerId`] or with own addresses. + let addresses: Vec = addresses + .into_iter() + .filter(|a| get_peer_id(&a).filter(|p| *p != local_peer_id).is_some()) .collect(); - if !remote_addresses.is_empty() { + let remote_peer_id = single(addresses.iter().map(|a| get_peer_id(&a))) + .map_err(|_| Error::ReceivingDhtValueFoundEventWithDifferentPeerIds)? // different peer_id in records + .flatten() + .ok_or(Error::ReceivingDhtValueFoundEventWithNoPeerIds)?; // no records with peer_id in them + + // At this point we know all the valid multiaddresses from the record, know that + // each of them belong to the same PeerId, we just need to check if the record is + // properly signed by the owner of the PeerId + self.check_record_signed_with_network_key( + &record, + peer_signature, + remote_peer_id, + &authority_id, + )?; + + let remote_addresses: Vec = + addresses.into_iter().take(MAX_ADDRESSES_PER_AUTHORITY).collect(); + + let answering_peer_id = peer_record.peer.map(|peer| peer.into()); + + let addr_cache_needs_update = self.handle_new_record( + &authority_id, + remote_key.clone(), + RecordInfo { + creation_time: records_creation_time, + peers_with_record: answering_peer_id.into_iter().collect(), + record: peer_record.record, + }, + ); + + if !remote_addresses.is_empty() && addr_cache_needs_update { self.addr_cache.insert(authority_id, remote_addresses); if let Some(metrics) = &self.metrics { metrics @@ -776,6 +843,68 @@ where Ok(()) } + // Handles receiving a new DHT record for the authorithy. + // Returns true if the record was new, false if the record was older than the current one. + fn handle_new_record( + &mut self, + authority_id: &AuthorityId, + kademlia_key: KademliaKey, + new_record: RecordInfo, + ) -> bool { + let current_record_info = self + .last_known_records + .entry(kademlia_key.clone()) + .or_insert_with(|| new_record.clone()); + + if new_record.creation_time > current_record_info.creation_time { + let peers_that_need_updating = current_record_info.peers_with_record.clone(); + self.network.put_record_to( + new_record.record.clone(), + peers_that_need_updating.clone(), + // If this is empty it means we received the answer from our node local + // storage, so we need to update that as well. + current_record_info.peers_with_record.is_empty(), + ); + debug!( + target: LOG_TARGET, + "Found a newer record for {:?} new record creation time {:?} old record creation time {:?}", + authority_id, new_record.creation_time, current_record_info.creation_time + ); + self.last_known_records.insert(kademlia_key, new_record); + return true + } + + if new_record.creation_time == current_record_info.creation_time { + // Same record just update in case this is a record from old nodes that don't have + // timestamp. + debug!( + target: LOG_TARGET, + "Found same record for {:?} record creation time {:?}", + authority_id, new_record.creation_time + ); + if current_record_info.peers_with_record.len() + new_record.peers_with_record.len() <= + DEFAULT_KADEMLIA_REPLICATION_FACTOR + { + current_record_info.peers_with_record.extend(new_record.peers_with_record); + } + return true + } + + debug!( + target: LOG_TARGET, + "Found old record for {:?} received record creation time {:?} current record creation time {:?}", + authority_id, new_record.creation_time, current_record_info.creation_time, + ); + self.network.put_record_to( + current_record_info.record.clone(), + new_record.peers_with_record.clone(), + // If this is empty it means we received the answer from our node local + // storage, so we need to update that as well. + new_record.peers_with_record.is_empty(), + ); + return false + } + /// Retrieve our public keys within the current and next authority set. // A node might have multiple authority discovery keys within its keystore, e.g. an old one and // one for the upcoming session. In addition it could be participating in the current and (/ or) @@ -842,9 +971,21 @@ fn serialize_addresses(addresses: impl Iterator) -> Vec>) -> Result> { +fn build_creation_time() -> schema::TimestampInfo { + let creation_time = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|time| time.as_nanos()) + .unwrap_or_default(); + schema::TimestampInfo { timestamp: creation_time.encode() } +} + +fn serialize_authority_record( + addresses: Vec>, + creation_time: Option, +) -> Result> { let mut serialized_record = vec![]; - schema::AuthorityRecord { addresses } + + schema::AuthorityRecord { addresses, creation_time } .encode(&mut serialized_record) .map_err(Error::EncodingProto)?; Ok(serialized_record) @@ -880,7 +1021,6 @@ fn sign_record_with_authority_ids( // Scale encode let auth_signature = auth_signature.encode(); - let signed_record = schema::SignedAuthorityRecord { record: serialized_record.clone(), auth_signature, diff --git a/substrate/client/authority-discovery/src/worker/addr_cache.rs b/substrate/client/authority-discovery/src/worker/addr_cache.rs index 77cdfbd4f1502574cd5a1aa2434d3c0fd392fd51..13bb990bf8b9908a5ec9a11e205a4a380c5954b4 100644 --- a/substrate/client/authority-discovery/src/worker/addr_cache.rs +++ b/substrate/client/authority-discovery/src/worker/addr_cache.rs @@ -177,7 +177,7 @@ mod tests { use super::*; use quickcheck::{Arbitrary, Gen, QuickCheck, TestResult}; - use sc_network_types::multihash::Multihash; + use sc_network_types::multihash::{Code, Multihash}; use sp_authority_discovery::{AuthorityId, AuthorityPair}; use sp_core::crypto::Pair; @@ -198,10 +198,9 @@ mod tests { impl Arbitrary for TestMultiaddr { fn arbitrary(g: &mut Gen) -> Self { let seed = (0..32).map(|_| u8::arbitrary(g)).collect::>(); - let peer_id = PeerId::from_multihash( - Multihash::wrap(multihash::Code::Sha2_256.into(), &seed).unwrap(), - ) - .unwrap(); + let peer_id = + PeerId::from_multihash(Multihash::wrap(Code::Sha2_256.into(), &seed).unwrap()) + .unwrap(); let multiaddr = "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333" .parse::() .unwrap() @@ -217,10 +216,9 @@ mod tests { impl Arbitrary for TestMultiaddrsSamePeerCombo { fn arbitrary(g: &mut Gen) -> Self { let seed = (0..32).map(|_| u8::arbitrary(g)).collect::>(); - let peer_id = PeerId::from_multihash( - Multihash::wrap(multihash::Code::Sha2_256.into(), &seed).unwrap(), - ) - .unwrap(); + let peer_id = + PeerId::from_multihash(Multihash::wrap(Code::Sha2_256.into(), &seed).unwrap()) + .unwrap(); let multiaddr1 = "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333" .parse::() .unwrap() diff --git a/substrate/client/authority-discovery/src/worker/schema/dht-v3.proto b/substrate/client/authority-discovery/src/worker/schema/dht-v3.proto new file mode 100644 index 0000000000000000000000000000000000000000..547237573af298125573b9156bcc89adb3188ec7 --- /dev/null +++ b/substrate/client/authority-discovery/src/worker/schema/dht-v3.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; + +package authority_discovery_v3; + +// First we need to serialize the addresses in order to be able to sign them. +message AuthorityRecord { + // Possibly multiple `MultiAddress`es through which the node can be reached. + repeated bytes addresses = 1; + // Information about the creation time of the record + TimestampInfo creation_time = 2; +} + +message PeerSignature { + bytes signature = 1; + bytes public_key = 2; +} + +// Information regarding the creation data of the record +message TimestampInfo { + // Time since UNIX_EPOCH in nanoseconds, scale encoded + bytes timestamp = 1; +} + +// Then we need to serialize the authority record and signature to send them over the wire. +message SignedAuthorityRecord { + bytes record = 1; + bytes auth_signature = 2; + // Even if there are multiple `record.addresses`, all of them have the same peer id. + // Old versions are missing this field. It is optional in order to provide compatibility both ways. + PeerSignature peer_signature = 3; +} diff --git a/substrate/client/authority-discovery/src/worker/schema/tests.rs b/substrate/client/authority-discovery/src/worker/schema/tests.rs index ef06ed7d336b0894f54511dfc87561a7b5d68d54..557fa9641f97b0953760e5f407cf819d617be939 100644 --- a/substrate/client/authority-discovery/src/worker/schema/tests.rs +++ b/substrate/client/authority-discovery/src/worker/schema/tests.rs @@ -20,7 +20,12 @@ mod schema_v1 { include!(concat!(env!("OUT_DIR"), "/authority_discovery_v1.rs")); } +mod schema_v2 { + include!(concat!(env!("OUT_DIR"), "/authority_discovery_v2.rs")); +} + use super::*; +use codec::Encode; use libp2p::identity::Keypair; use prost::Message; use sc_network::{Multiaddr, PeerId}; @@ -65,7 +70,7 @@ fn v1_decodes_v2() { let vec_auth_signature = b"Totally valid signature, I promise!".to_vec(); let vec_peer_signature = b"Surprisingly hard to crack crypto".to_vec(); - let record_v2 = AuthorityRecord { addresses: vec_addresses.clone() }; + let record_v2 = schema_v2::AuthorityRecord { addresses: vec_addresses.clone() }; let mut vec_record_v2 = vec![]; record_v2.encode(&mut vec_record_v2).unwrap(); let vec_peer_public = peer_public.encode_protobuf(); @@ -85,6 +90,82 @@ fn v1_decodes_v2() { assert_eq!(&signed_addresses_v1_decoded.addresses, &vec_record_v2); assert_eq!(&signed_addresses_v1_decoded.signature, &vec_auth_signature); - let addresses_v2_decoded = AuthorityRecord::decode(vec_record_v2.as_slice()).unwrap(); + let addresses_v2_decoded = + schema_v2::AuthorityRecord::decode(vec_record_v2.as_slice()).unwrap(); + assert_eq!(&addresses_v2_decoded.addresses, &vec_addresses); +} + +#[test] +fn v1_decodes_v3() { + let peer_secret = Keypair::generate_ed25519(); + let peer_public = peer_secret.public(); + let peer_id = peer_public.to_peer_id(); + let multiaddress: Multiaddr = + format!("/ip4/127.0.0.1/tcp/3003/p2p/{}", peer_id).parse().unwrap(); + let vec_addresses = vec![multiaddress.to_vec()]; + let vec_auth_signature = b"Totally valid signature, I promise!".to_vec(); + let vec_peer_signature = b"Surprisingly hard to crack crypto".to_vec(); + + let record_v3 = AuthorityRecord { + addresses: vec_addresses.clone(), + creation_time: Some(TimestampInfo { timestamp: Encode::encode(&55) }), + }; + let mut vec_record_v3 = vec![]; + record_v3.encode(&mut vec_record_v3).unwrap(); + let vec_peer_public = peer_public.encode_protobuf(); + let peer_signature_v3 = + PeerSignature { public_key: vec_peer_public, signature: vec_peer_signature }; + let signed_record_v3 = SignedAuthorityRecord { + record: vec_record_v3.clone(), + auth_signature: vec_auth_signature.clone(), + peer_signature: Some(peer_signature_v3.clone()), + }; + let mut vec_signed_record_v3 = vec![]; + signed_record_v3.encode(&mut vec_signed_record_v3).unwrap(); + + let signed_addresses_v1_decoded = + schema_v1::SignedAuthorityAddresses::decode(vec_signed_record_v3.as_slice()).unwrap(); + + assert_eq!(&signed_addresses_v1_decoded.addresses, &vec_record_v3); + assert_eq!(&signed_addresses_v1_decoded.signature, &vec_auth_signature); + + let addresses_v2_decoded = + schema_v2::AuthorityRecord::decode(vec_record_v3.as_slice()).unwrap(); assert_eq!(&addresses_v2_decoded.addresses, &vec_addresses); } + +#[test] +fn v3_decodes_v2() { + let peer_secret = Keypair::generate_ed25519(); + let peer_public = peer_secret.public(); + let peer_id = peer_public.to_peer_id(); + let multiaddress: Multiaddr = + format!("/ip4/127.0.0.1/tcp/3003/p2p/{}", peer_id).parse().unwrap(); + let vec_addresses = vec![multiaddress.to_vec()]; + let vec_auth_signature = b"Totally valid signature, I promise!".to_vec(); + let vec_peer_signature = b"Surprisingly hard to crack crypto".to_vec(); + + let record_v2 = schema_v2::AuthorityRecord { addresses: vec_addresses.clone() }; + let mut vec_record_v2 = vec![]; + record_v2.encode(&mut vec_record_v2).unwrap(); + let vec_peer_public = peer_public.encode_protobuf(); + let peer_signature_v2 = + schema_v2::PeerSignature { public_key: vec_peer_public, signature: vec_peer_signature }; + let signed_record_v2 = schema_v2::SignedAuthorityRecord { + record: vec_record_v2.clone(), + auth_signature: vec_auth_signature.clone(), + peer_signature: Some(peer_signature_v2.clone()), + }; + let mut vec_signed_record_v2 = vec![]; + signed_record_v2.encode(&mut vec_signed_record_v2).unwrap(); + + let signed_addresses_v3_decoded = + SignedAuthorityRecord::decode(vec_signed_record_v2.as_slice()).unwrap(); + + assert_eq!(&signed_addresses_v3_decoded.record, &vec_record_v2); + assert_eq!(&signed_addresses_v3_decoded.auth_signature, &vec_auth_signature); + + let addresses_v3_decoded = AuthorityRecord::decode(vec_record_v2.as_slice()).unwrap(); + assert_eq!(&addresses_v3_decoded.addresses, &vec_addresses); + assert_eq!(&addresses_v3_decoded.creation_time, &None); +} diff --git a/substrate/client/authority-discovery/src/worker/tests.rs b/substrate/client/authority-discovery/src/worker/tests.rs index de7443d634fa79e7761b39b3c2fab3e16adb4a0b..b49615382b8a2b2734185da50fd5b9515d42b1d7 100644 --- a/substrate/client/authority-discovery/src/worker/tests.rs +++ b/substrate/client/authority-discovery/src/worker/tests.rs @@ -119,6 +119,7 @@ sp_api::mock_impl_runtime_apis! { pub enum TestNetworkEvent { GetCalled(KademliaKey), PutCalled(KademliaKey, Vec), + PutToCalled(Record, HashSet, bool), StoreRecordCalled(KademliaKey, Vec, Option, Option), } @@ -129,6 +130,7 @@ pub struct TestNetwork { // Whenever functions on `TestNetwork` are called, the function arguments are added to the // vectors below. pub put_value_call: Arc)>>>, + pub put_value_to_call: Arc, bool)>>>, pub get_value_call: Arc>>, pub store_value_call: Arc, Option, Option)>>>, @@ -153,6 +155,7 @@ impl Default for TestNetwork { external_addresses: vec!["/ip6/2001:db8::/tcp/30333".parse().unwrap()], put_value_call: Default::default(), get_value_call: Default::default(), + put_value_to_call: Default::default(), store_value_call: Default::default(), event_sender: tx, event_receiver: Some(rx), @@ -200,6 +203,23 @@ impl NetworkDHTProvider for TestNetwork { .unwrap(); } + fn put_record_to( + &self, + record: Record, + peers: HashSet, + update_local_storage: bool, + ) { + self.put_value_to_call.lock().unwrap().push(( + record.clone(), + peers.clone(), + update_local_storage, + )); + self.event_sender + .clone() + .unbounded_send(TestNetworkEvent::PutToCalled(record, peers, update_local_storage)) + .unwrap(); + } + fn store_record( &self, key: KademliaKey, @@ -262,9 +282,11 @@ fn build_dht_event( public_key: AuthorityId, key_store: &MemoryKeystore, network: Option<&Signer>, + creation_time: Option, ) -> Vec<(KademliaKey, Vec)> { let serialized_record = - serialize_authority_record(serialize_addresses(addresses.into_iter())).unwrap(); + serialize_authority_record(serialize_addresses(addresses.into_iter()), creation_time) + .unwrap(); let peer_signature = network.map(|n| sign_record_with_peer_id(&serialized_record, n).unwrap()); let kv_pairs = sign_record_with_authority_ids( @@ -372,7 +394,10 @@ fn publish_discover_cycle() { let dht_event = { let (key, value) = network.put_value_call.lock().unwrap().pop().unwrap(); - DhtEvent::ValueFound(vec![(key, value)]) + DhtEvent::ValueFound(PeerRecord { + peer: None, + record: Record { key, value, publisher: None, expires: None }, + }) }; // Node B discovering node A's address. @@ -515,21 +540,39 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() { // Send an event that should generate an error dht_event_tx - .send(DhtEvent::ValueFound(Default::default())) + .send(DhtEvent::ValueFound(PeerRecord { + peer: None, + record: Record { + key: vec![0x9u8].into(), + value: Default::default(), + publisher: None, + expires: None, + }, + })) .await .expect("Channel has capacity of 1."); // Make previously triggered lookup succeed. - let dht_event = { - let kv_pairs = build_dht_event::( - vec![remote_multiaddr.clone()], - remote_public_key.clone(), - &remote_key_store, - None, - ); - DhtEvent::ValueFound(kv_pairs) - }; - dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1."); + let kv_pairs: Vec = build_dht_event::( + vec![remote_multiaddr.clone()], + remote_public_key.clone(), + &remote_key_store, + None, + Some(build_creation_time()), + ) + .into_iter() + .map(|(key, value)| PeerRecord { + peer: None, + record: Record { key, value, publisher: None, expires: None }, + }) + .collect(); + + for kv_pair in kv_pairs { + dht_event_tx + .send(DhtEvent::ValueFound(kv_pair)) + .await + .expect("Channel has capacity of 1."); + } // Expect authority discovery to function normally, now knowing the // address for the remote node. @@ -581,37 +624,51 @@ impl DhtValueFoundTester { &mut self, strict_record_validation: bool, values: Vec<(KademliaKey, Vec)>, - ) -> Option<&HashSet> { + ) -> (Option>, Option>) { let (_dht_event_tx, dht_event_rx) = channel(1); let local_test_api = Arc::new(TestApi { authorities: vec![self.remote_authority_public.into()] }); - let local_network: Arc = Arc::new(Default::default()); let local_key_store = MemoryKeystore::new(); let (_to_worker, from_service) = mpsc::channel(0); - let mut local_worker = Worker::new( - from_service, - local_test_api, - local_network.clone(), - Box::pin(dht_event_rx), - Role::PublishAndDiscover(Arc::new(local_key_store)), - None, - WorkerConfig { strict_record_validation, ..Default::default() }, - ); + let (local_worker, local_network) = if let Some(local_work) = self.local_worker.as_mut() { + (local_work, None) + } else { + let local_network: Arc = Arc::new(Default::default()); + + self.local_worker = Some(Worker::new( + from_service, + local_test_api, + local_network.clone(), + Box::pin(dht_event_rx), + Role::PublishAndDiscover(Arc::new(local_key_store)), + None, + WorkerConfig { strict_record_validation, ..Default::default() }, + )); + (self.local_worker.as_mut().unwrap(), Some(local_network)) + }; block_on(local_worker.refill_pending_lookups_queue()).unwrap(); local_worker.start_new_lookups(); - drop(local_worker.handle_dht_value_found_event(values)); - - self.local_worker = Some(local_worker); + for record in values.into_iter().map(|(key, value)| PeerRecord { + peer: Some(PeerId::random().into()), + record: Record { key, value, publisher: None, expires: None }, + }) { + drop(local_worker.handle_dht_value_found_event(record)) + } - self.local_worker - .as_ref() - .map(|w| { - w.addr_cache.get_addresses_by_authority_id(&self.remote_authority_public.into()) - }) - .unwrap() + ( + self.local_worker + .as_ref() + .map(|w| { + w.addr_cache + .get_addresses_by_authority_id(&self.remote_authority_public.into()) + .cloned() + }) + .unwrap(), + local_network, + ) } } @@ -625,9 +682,10 @@ fn limit_number_of_addresses_added_to_cache_per_authority() { tester.remote_authority_public.into(), &tester.remote_key_store, None, + Some(build_creation_time()), ); - let cached_remote_addresses = tester.process_value_found(false, kv_pairs); + let cached_remote_addresses = tester.process_value_found(false, kv_pairs).0; assert_eq!(MAX_ADDRESSES_PER_AUTHORITY, cached_remote_addresses.unwrap().len()); } @@ -640,17 +698,242 @@ fn strict_accept_address_with_peer_signature() { tester.remote_authority_public.into(), &tester.remote_key_store, Some(&TestSigner { keypair: &tester.remote_node_key }), + Some(build_creation_time()), ); - let cached_remote_addresses = tester.process_value_found(true, kv_pairs); + let cached_remote_addresses = tester.process_value_found(true, kv_pairs).0; assert_eq!( - Some(&HashSet::from([addr])), + Some(HashSet::from([addr])), cached_remote_addresses, "Expect worker to only cache `Multiaddr`s with `PeerId`s.", ); } +#[test] +fn strict_accept_address_without_creation_time() { + let mut tester = DhtValueFoundTester::new(); + let addr = tester.multiaddr_with_peer_id(1); + let kv_pairs = build_dht_event( + vec![addr.clone()], + tester.remote_authority_public.into(), + &tester.remote_key_store, + Some(&TestSigner { keypair: &tester.remote_node_key }), + None, + ); + + let cached_remote_addresses = tester.process_value_found(true, kv_pairs).0; + + assert_eq!( + Some(HashSet::from([addr])), + cached_remote_addresses, + "Expect worker to cache address without creation time", + ); +} + +#[test] +fn keep_last_received_if_no_creation_time() { + let mut tester: DhtValueFoundTester = DhtValueFoundTester::new(); + let addr = tester.multiaddr_with_peer_id(1); + let kv_pairs = build_dht_event( + vec![addr.clone()], + tester.remote_authority_public.into(), + &tester.remote_key_store, + Some(&TestSigner { keypair: &tester.remote_node_key }), + None, + ); + + let (cached_remote_addresses, network) = tester.process_value_found(true, kv_pairs); + + assert_eq!( + Some(HashSet::from([addr])), + cached_remote_addresses, + "Expect worker to cache address without creation time", + ); + + assert!(network + .as_ref() + .map(|network| network.put_value_to_call.lock().unwrap().is_empty()) + .unwrap_or_default()); + + let addr2 = tester.multiaddr_with_peer_id(2); + let kv_pairs = build_dht_event( + vec![addr2.clone()], + tester.remote_authority_public.into(), + &tester.remote_key_store, + Some(&TestSigner { keypair: &tester.remote_node_key }), + None, + ); + + let cached_remote_addresses = tester.process_value_found(true, kv_pairs).0; + + assert_eq!( + Some(HashSet::from([addr2])), + cached_remote_addresses, + "Expect worker to cache last received when no creation time", + ); + assert!(network + .as_ref() + .map(|network| network.put_value_to_call.lock().unwrap().is_empty()) + .unwrap_or_default()); +} + +#[test] +fn records_with_incorrectly_signed_creation_time_are_ignored() { + let mut tester: DhtValueFoundTester = DhtValueFoundTester::new(); + let addr = tester.multiaddr_with_peer_id(1); + let kv_pairs = build_dht_event( + vec![addr.clone()], + tester.remote_authority_public.into(), + &tester.remote_key_store, + Some(&TestSigner { keypair: &tester.remote_node_key }), + Some(build_creation_time()), + ); + + let (cached_remote_addresses, network) = tester.process_value_found(true, kv_pairs); + + assert_eq!( + Some(HashSet::from([addr.clone()])), + cached_remote_addresses, + "Expect worker to cache record with creation time", + ); + assert!(network + .as_ref() + .map(|network| network.put_value_to_call.lock().unwrap().is_empty()) + .unwrap_or_default()); + + let alternative_key = tester + .remote_key_store + .sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None) + .unwrap(); + + let addr2 = tester.multiaddr_with_peer_id(2); + let mut kv_pairs = build_dht_event( + vec![addr2.clone()], + alternative_key.into(), + &tester.remote_key_store, + Some(&TestSigner { keypair: &tester.remote_node_key }), + Some(build_creation_time()), + ); + let kademlia_key = hash_authority_id(tester.remote_authority_public.as_slice()); + for key in kv_pairs.iter_mut() { + key.0 = kademlia_key.clone(); + } + let cached_remote_addresses = tester.process_value_found(true, kv_pairs).0; + + assert_eq!( + Some(HashSet::from([addr])), + cached_remote_addresses, + "Expect `Multiaddr` to remain the same", + ); + assert!(network + .as_ref() + .map(|network| network.put_value_to_call.lock().unwrap().is_empty()) + .unwrap_or_default()); +} + +#[test] +fn newer_records_overwrite_older_ones() { + let mut tester: DhtValueFoundTester = DhtValueFoundTester::new(); + let old_record = tester.multiaddr_with_peer_id(1); + let kv_pairs = build_dht_event( + vec![old_record.clone()], + tester.remote_authority_public.into(), + &tester.remote_key_store, + Some(&TestSigner { keypair: &tester.remote_node_key }), + Some(build_creation_time()), + ); + + let (cached_remote_addresses, network) = tester.process_value_found(true, kv_pairs); + + assert_eq!( + Some(HashSet::from([old_record])), + cached_remote_addresses, + "Expect worker to cache record with creation time", + ); + + let nothing_updated = network + .as_ref() + .map(|network| network.put_value_to_call.lock().unwrap().is_empty()) + .unwrap(); + assert!(nothing_updated); + + let new_record = tester.multiaddr_with_peer_id(2); + let kv_pairs = build_dht_event( + vec![new_record.clone()], + tester.remote_authority_public.into(), + &tester.remote_key_store, + Some(&TestSigner { keypair: &tester.remote_node_key }), + Some(build_creation_time()), + ); + + let cached_remote_addresses = tester.process_value_found(true, kv_pairs).0; + + assert_eq!( + Some(HashSet::from([new_record])), + cached_remote_addresses, + "Expect worker to store the newest recrod", + ); + + let result = network + .as_ref() + .map(|network| network.put_value_to_call.lock().unwrap().first().unwrap().clone()) + .unwrap(); + assert!(matches!(result, (_, _, false))); + assert_eq!(result.1.len(), 1); +} + +#[test] +fn older_records_dont_affect_newer_ones() { + let mut tester: DhtValueFoundTester = DhtValueFoundTester::new(); + let old_record = tester.multiaddr_with_peer_id(1); + let old_kv_pairs = build_dht_event( + vec![old_record.clone()], + tester.remote_authority_public.into(), + &tester.remote_key_store, + Some(&TestSigner { keypair: &tester.remote_node_key }), + Some(build_creation_time()), + ); + + let new_record = tester.multiaddr_with_peer_id(2); + let kv_pairs = build_dht_event( + vec![new_record.clone()], + tester.remote_authority_public.into(), + &tester.remote_key_store, + Some(&TestSigner { keypair: &tester.remote_node_key }), + Some(build_creation_time()), + ); + + let (cached_remote_addresses, network) = tester.process_value_found(true, kv_pairs); + + assert_eq!( + Some(HashSet::from([new_record.clone()])), + cached_remote_addresses, + "Expect worker to store new record", + ); + + let nothing_updated = network + .as_ref() + .map(|network| network.put_value_to_call.lock().unwrap().is_empty()) + .unwrap(); + assert!(nothing_updated); + + let cached_remote_addresses = tester.process_value_found(true, old_kv_pairs).0; + + assert_eq!( + Some(HashSet::from([new_record])), + cached_remote_addresses, + "Expect worker to not update stored record", + ); + + let update_peers_info = network + .as_ref() + .map(|network| network.put_value_to_call.lock().unwrap().remove(0)) + .unwrap(); + assert!(matches!(update_peers_info, (_, _, false))); + assert_eq!(update_peers_info.1.len(), 1); +} + #[test] fn reject_address_with_rogue_peer_signature() { let mut tester = DhtValueFoundTester::new(); @@ -660,9 +943,10 @@ fn reject_address_with_rogue_peer_signature() { tester.remote_authority_public.into(), &tester.remote_key_store, Some(&TestSigner { keypair: &rogue_remote_node_key }), + Some(build_creation_time()), ); - let cached_remote_addresses = tester.process_value_found(false, kv_pairs); + let cached_remote_addresses = tester.process_value_found(false, kv_pairs).0; assert!( cached_remote_addresses.is_none(), @@ -678,13 +962,14 @@ fn reject_address_with_invalid_peer_signature() { tester.remote_authority_public.into(), &tester.remote_key_store, Some(&TestSigner { keypair: &tester.remote_node_key }), + Some(build_creation_time()), ); // tamper with the signature let mut record = schema::SignedAuthorityRecord::decode(kv_pairs[0].1.as_slice()).unwrap(); record.peer_signature.as_mut().map(|p| p.signature[1] = !p.signature[1]); record.encode(&mut kv_pairs[0].1).unwrap(); - let cached_remote_addresses = tester.process_value_found(false, kv_pairs); + let cached_remote_addresses = tester.process_value_found(false, kv_pairs).0; assert!( cached_remote_addresses.is_none(), @@ -700,9 +985,10 @@ fn reject_address_without_peer_signature() { tester.remote_authority_public.into(), &tester.remote_key_store, None, + Some(build_creation_time()), ); - let cached_remote_addresses = tester.process_value_found(true, kv_pairs); + let cached_remote_addresses = tester.process_value_found(true, kv_pairs).0; assert!(cached_remote_addresses.is_none(), "Expected worker to ignore unsigned record.",); } @@ -718,12 +1004,13 @@ fn do_not_cache_addresses_without_peer_id() { tester.remote_authority_public.into(), &tester.remote_key_store, None, + Some(build_creation_time()), ); - let cached_remote_addresses = tester.process_value_found(false, kv_pairs); + let cached_remote_addresses = tester.process_value_found(false, kv_pairs).0; assert_eq!( - Some(&HashSet::from([multiaddr_with_peer_id])), + Some(HashSet::from([multiaddr_with_peer_id])), cached_remote_addresses, "Expect worker to only cache `Multiaddr`s with `PeerId`s.", ); @@ -861,16 +1148,24 @@ fn lookup_throttling() { // Make first lookup succeed. let remote_hash = network.get_value_call.lock().unwrap().pop().unwrap(); let remote_key: AuthorityId = remote_hash_to_key.get(&remote_hash).unwrap().clone(); - let dht_event = { - let kv_pairs = build_dht_event::( - vec![remote_multiaddr.clone()], - remote_key, - &remote_key_store, - None, - ); - DhtEvent::ValueFound(kv_pairs) - }; - dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1."); + let kv_pairs = build_dht_event::( + vec![remote_multiaddr.clone()], + remote_key, + &remote_key_store, + None, + Some(build_creation_time()), + ) + .into_iter() + .map(|(key, value)| PeerRecord { + peer: None, + record: Record { key, value, publisher: None, expires: None }, + }); + for kv_pair in kv_pairs { + dht_event_tx + .send(DhtEvent::ValueFound(kv_pair)) + .await + .expect("Channel has capacity of 1."); + } // Assert worker to trigger another lookup. assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_)))); @@ -899,14 +1194,17 @@ fn lookup_throttling() { #[test] fn test_handle_put_record_request() { - let network = TestNetwork::default(); - let peer_id = network.peer_id; + let local_node_network = TestNetwork::default(); + let remote_node_network = TestNetwork::default(); + let peer_id = remote_node_network.peer_id; let remote_multiaddr = { let address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap(); - address.with(multiaddr::Protocol::P2p(peer_id.into())) + address.with(multiaddr::Protocol::P2p(remote_node_network.peer_id.into())) }; + + println!("{:?}", remote_multiaddr); let remote_key_store = MemoryKeystore::new(); let remote_public_keys: Vec = (0..20) .map(|_| { @@ -928,7 +1226,7 @@ fn test_handle_put_record_request() { let (_dht_event_tx, dht_event_rx) = channel(1); let (_to_worker, from_service) = mpsc::channel(0); - let network = Arc::new(network); + let network = Arc::new(local_node_network); let mut worker = Worker::new( from_service, Arc::new(TestApi { authorities: remote_public_keys.clone() }), @@ -944,10 +1242,11 @@ fn test_handle_put_record_request() { let valid_authorithy_key = remote_public_keys.first().unwrap().clone(); let kv_pairs = build_dht_event( - vec![remote_multiaddr], - valid_authorithy_key.into(), + vec![remote_multiaddr.clone()], + valid_authorithy_key.clone().into(), &remote_key_store, - Some(&TestSigner { keypair: &network.identity }), + Some(&TestSigner { keypair: &remote_node_network.identity }), + Some(build_creation_time()), ); pool.run_until( @@ -986,7 +1285,7 @@ fn test_handle_put_record_request() { let key = hash_authority_id(another_authorithy_id.as_ref()); // Valid record signed with a different key should return error. - for (_, value) in kv_pairs { + for (_, value) in kv_pairs.clone() { assert!(matches!( worker .handle_put_record_requested(key.clone(), value, Some(peer_id), None) @@ -995,6 +1294,57 @@ fn test_handle_put_record_request() { )); } assert_eq!(network.store_value_call.lock().unwrap().len(), 1); + let newer_kv_pairs = build_dht_event( + vec![remote_multiaddr], + valid_authorithy_key.clone().into(), + &remote_key_store, + Some(&TestSigner { keypair: &remote_node_network.identity }), + Some(build_creation_time()), + ); + + // Valid old authority, should not throw error, but it should not be stored since a + // newer one already exists. + for (new_key, new_value) in newer_kv_pairs.clone() { + worker.in_flight_lookups.insert(new_key.clone(), valid_authorithy_key.clone()); + + let found = PeerRecord { + peer: Some(peer_id.into()), + record: Record { + key: new_key, + value: new_value, + publisher: Some(peer_id.into()), + expires: None, + }, + }; + assert!(worker.handle_dht_value_found_event(found).is_ok()); + } + + for (key, value) in kv_pairs.clone() { + assert!(worker + .handle_put_record_requested(key, value, Some(peer_id), None) + .await + .is_ok()); + } + assert_eq!(network.store_value_call.lock().unwrap().len(), 1); + + // Newer kv pairs should always be stored. + for (key, value) in newer_kv_pairs.clone() { + assert!(worker + .handle_put_record_requested(key, value, Some(peer_id), None) + .await + .is_ok()); + } + + assert_eq!(network.store_value_call.lock().unwrap().len(), 2); + + worker.refill_pending_lookups_queue().await.unwrap(); + assert_eq!(worker.last_known_records.len(), 1); + + // Check known records gets clean up, when an authorithy gets out of the + // active set. + worker.client = Arc::new(TestApi { authorities: Default::default() }); + worker.refill_pending_lookups_queue().await.unwrap(); + assert_eq!(worker.last_known_records.len(), 0); } .boxed_local(), ); diff --git a/substrate/client/basic-authorship/Cargo.toml b/substrate/client/basic-authorship/Cargo.toml index b75cb463b1a874c48a7b8c4511929eade4245704..e3ae80e14f6ffd3f554f59f3debb45a3b0c04431 100644 --- a/substrate/client/basic-authorship/Cargo.toml +++ b/substrate/client/basic-authorship/Cargo.toml @@ -16,24 +16,24 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12" } -futures = "0.3.30" -futures-timer = "3.0.1" +codec = { workspace = true, default-features = true } +futures = { workspace = true } +futures-timer = { workspace = true } log = { workspace = true, default-features = true } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } -sc-block-builder = { path = "../block-builder" } -sc-proposer-metrics = { path = "../proposer-metrics" } -sc-telemetry = { path = "../telemetry" } -sc-transaction-pool-api = { path = "../transaction-pool/api" } -sp-api = { path = "../../primitives/api" } -sp-blockchain = { path = "../../primitives/blockchain" } -sp-consensus = { path = "../../primitives/consensus/common" } -sp-core = { path = "../../primitives/core" } -sp-inherents = { path = "../../primitives/inherents" } -sp-runtime = { path = "../../primitives/runtime" } +prometheus-endpoint = { workspace = true, default-features = true } +sc-block-builder = { workspace = true, default-features = true } +sc-proposer-metrics = { workspace = true, default-features = true } +sc-telemetry = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } [dev-dependencies] -parking_lot = "0.12.1" -sc-client-api = { path = "../api" } -sc-transaction-pool = { path = "../transaction-pool" } -substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } +parking_lot = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-transaction-pool = { workspace = true, default-features = true } +substrate-test-runtime-client = { workspace = true } diff --git a/substrate/client/basic-authorship/src/basic_authorship.rs b/substrate/client/basic-authorship/src/basic_authorship.rs index 1519c76c42c0efab1fa59c7e53bed41c5e104f9b..74805488792ad5f1eb810d9c22f00d719f1b1b21 100644 --- a/substrate/client/basic-authorship/src/basic_authorship.rs +++ b/substrate/client/basic-authorship/src/basic_authorship.rs @@ -205,7 +205,11 @@ where ) -> Proposer { let parent_hash = parent_header.hash(); - info!("๐Ÿ™Œ Starting consensus session on top of parent {:?}", parent_hash); + info!( + "๐Ÿ™Œ Starting consensus session on top of parent {:?} (#{})", + parent_hash, + parent_header.number() + ); let proposer = Proposer::<_, _, _, PR> { spawn_handle: self.spawn_handle.clone(), diff --git a/substrate/client/block-builder/Cargo.toml b/substrate/client/block-builder/Cargo.toml index 62efe977e989c13bfc6e3fe0fb11d13ac3aca298..47e3fc39c289997bdcdfa094ce65193295ab0220 100644 --- a/substrate/client/block-builder/Cargo.toml +++ b/substrate/client/block-builder/Cargo.toml @@ -16,17 +16,17 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", features = [ +codec = { features = [ "derive", -] } -sp-api = { path = "../../primitives/api" } -sp-block-builder = { path = "../../primitives/block-builder" } -sp-blockchain = { path = "../../primitives/blockchain" } -sp-core = { path = "../../primitives/core" } -sp-trie = { path = "../../primitives/trie" } -sp-inherents = { path = "../../primitives/inherents" } -sp-runtime = { path = "../../primitives/runtime" } +], workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-block-builder = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-trie = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } [dev-dependencies] -sp-state-machine = { path = "../../primitives/state-machine" } -substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } +sp-state-machine = { workspace = true, default-features = true } +substrate-test-runtime-client = { workspace = true } diff --git a/substrate/client/chain-spec/Cargo.toml b/substrate/client/chain-spec/Cargo.toml index 5b411b642a0e3aa410517621d99f4ab3cd245a74..b3cd4bd57db86c0384c56316315550edda962f24 100644 --- a/substrate/client/chain-spec/Cargo.toml +++ b/substrate/client/chain-spec/Cargo.toml @@ -16,31 +16,31 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.5.3", features = ["derive"], optional = true } -codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } -memmap2 = "0.9.3" +clap = { features = ["derive"], optional = true, workspace = true } +codec = { features = ["derive"], workspace = true } +memmap2 = { workspace = true } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } -sc-client-api = { path = "../api" } -sc-chain-spec-derive = { path = "derive" } -sc-executor = { path = "../executor" } -sp-io = { default-features = false, path = "../../primitives/io" } -sc-network = { path = "../network" } -sc-telemetry = { path = "../telemetry" } -sp-blockchain = { path = "../../primitives/blockchain" } -sp-core = { path = "../../primitives/core" } -sp-crypto-hashing = { path = "../../primitives/crypto/hashing" } -sp-genesis-builder = { path = "../../primitives/genesis-builder" } -sp-runtime = { path = "../../primitives/runtime" } -sp-state-machine = { path = "../../primitives/state-machine" } +sc-client-api = { workspace = true, default-features = true } +sc-chain-spec-derive = { workspace = true, default-features = true } +sc-executor = { workspace = true, default-features = true } +sp-io = { workspace = true } +sc-network = { workspace = true, default-features = true } +sc-telemetry = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true, default-features = true } +sp-genesis-builder = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } log = { workspace = true } -sp-tracing = { path = "../../primitives/tracing" } -array-bytes = "6.2.2" -docify = "0.2.8" +sp-tracing = { workspace = true, default-features = true } +array-bytes = { workspace = true, default-features = true } +docify = { workspace = true } [dev-dependencies] -substrate-test-runtime = { path = "../../test-utils/runtime" } -sp-keyring = { path = "../../primitives/keyring" } -sp-application-crypto = { default-features = false, path = "../../primitives/application-crypto", features = ["serde"] } -sp-consensus-babe = { default-features = false, path = "../../primitives/consensus/babe", features = ["serde"] } -regex = "1.6.0" +substrate-test-runtime = { workspace = true } +sp-keyring = { workspace = true, default-features = true } +sp-application-crypto = { features = ["serde"], workspace = true } +sp-consensus-babe = { features = ["serde"], workspace = true } +regex = { workspace = true } diff --git a/substrate/client/chain-spec/derive/Cargo.toml b/substrate/client/chain-spec/derive/Cargo.toml index 521eee578ecae3b03cf86a3b4e3630bb7cd22f02..4ab8c849cc7feb6368c5f74fbbd77703434b7675 100644 --- a/substrate/client/chain-spec/derive/Cargo.toml +++ b/substrate/client/chain-spec/derive/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -proc-macro-crate = "3.0.0" -proc-macro2 = "1.0.56" +proc-macro-crate = { workspace = true } +proc-macro2 = { workspace = true } quote = { workspace = true } syn = { workspace = true } diff --git a/substrate/client/chain-spec/src/chain_spec.rs b/substrate/client/chain-spec/src/chain_spec.rs index 883cd19adfd1c7543ee919a6e436df1838c6efe2..aa3c1ba3e6f132f2b400b6c1dd8a7af2ad1aa9b9 100644 --- a/substrate/client/chain-spec/src/chain_spec.rs +++ b/substrate/client/chain-spec/src/chain_spec.rs @@ -325,7 +325,7 @@ impl ChainSpecBuilder { name: "Development".to_string(), id: "dev".to_string(), chain_type: ChainType::Local, - genesis_build_action: GenesisBuildAction::Patch(Default::default()), + genesis_build_action: GenesisBuildAction::Patch(json::json!({})), boot_nodes: None, telemetry_endpoints: None, protocol_id: None, @@ -766,6 +766,16 @@ pub fn update_code_in_json_chain_spec(chain_spec: &mut json::Value, code: &[u8]) } } +/// This function sets a codeSubstitute in the chain spec. +pub fn set_code_substitute_in_json_chain_spec( + chain_spec: &mut json::Value, + code: &[u8], + block_height: u64, +) { + let substitutes = json::json!({"codeSubstitutes":{ &block_height.to_string(): sp_core::bytes::to_hex(code, false) }}); + crate::json_patch::merge(chain_spec, substitutes); +} + #[cfg(test)] mod tests { use super::*; diff --git a/substrate/client/chain-spec/src/lib.rs b/substrate/client/chain-spec/src/lib.rs index b59ad68610ecee8fc78ea15eb7cd717fe2bb4d40..c43f9e89b8a993f6a349b3eb612b41346acc62ec 100644 --- a/substrate/client/chain-spec/src/lib.rs +++ b/substrate/client/chain-spec/src/lib.rs @@ -333,8 +333,8 @@ pub mod json_patch; pub use self::{ chain_spec::{ - update_code_in_json_chain_spec, ChainSpec as GenericChainSpec, ChainSpecBuilder, - NoExtension, + set_code_substitute_in_json_chain_spec, update_code_in_json_chain_spec, + ChainSpec as GenericChainSpec, ChainSpecBuilder, NoExtension, }, extension::{get_extension, get_extension_mut, Extension, Fork, Forks, GetExtension, Group}, genesis_block::{ diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 169ed72c96e489ee35dca02edc6e098c2426eadb..1e4017c23af231baf0946ed26cc37e7767276cbb 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -16,46 +16,46 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -array-bytes = "6.2.2" -chrono = "0.4.31" -clap = { version = "4.5.3", features = ["derive", "string", "wrap_help"] } -fdlimit = "0.3.0" -futures = "0.3.30" -itertools = "0.11" -libp2p-identity = { version = "0.1.3", features = ["ed25519", "peerid"] } +array-bytes = { workspace = true, default-features = true } +chrono = { workspace = true } +clap = { features = ["derive", "string", "wrap_help"], workspace = true } +fdlimit = { workspace = true } +futures = { workspace = true } +itertools = { workspace = true } +libp2p-identity = { features = ["ed25519", "peerid"], workspace = true } log = { workspace = true, default-features = true } -names = { version = "0.14.0", default-features = false } -codec = { package = "parity-scale-codec", version = "3.6.12" } -rand = "0.8.5" -regex = "1.6.0" -rpassword = "7.0.0" +names = { workspace = true } +codec = { workspace = true, default-features = true } +rand = { workspace = true, default-features = true } +regex = { workspace = true } +rpassword = { workspace = true } serde = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } thiserror = { workspace = true } # personal fork here as workaround for: https://github.com/rust-bitcoin/rust-bip39/pull/64 bip39 = { package = "parity-bip39", version = "2.0.1", features = ["rand"] } -tokio = { version = "1.22.0", features = ["parking_lot", "rt-multi-thread", "signal"] } -sc-client-api = { path = "../api" } -sc-client-db = { path = "../db", default-features = false } -sc-keystore = { path = "../keystore" } -sc-mixnet = { path = "../mixnet" } -sc-network = { path = "../network" } -sc-service = { path = "../service", default-features = false } -sc-telemetry = { path = "../telemetry" } -sc-tracing = { path = "../tracing" } -sc-utils = { path = "../utils" } -sp-blockchain = { path = "../../primitives/blockchain" } -sp-core = { path = "../../primitives/core" } -sp-keyring = { path = "../../primitives/keyring" } -sp-keystore = { path = "../../primitives/keystore" } -sp-panic-handler = { path = "../../primitives/panic-handler" } -sp-runtime = { path = "../../primitives/runtime" } -sp-version = { path = "../../primitives/version" } +tokio = { features = ["parking_lot", "rt-multi-thread", "signal"], workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-client-db = { workspace = true } +sc-keystore = { workspace = true, default-features = true } +sc-mixnet = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-service = { workspace = true } +sc-telemetry = { workspace = true, default-features = true } +sc-tracing = { workspace = true, default-features = true } +sc-utils = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-panic-handler = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-version = { workspace = true, default-features = true } [dev-dependencies] -tempfile = "3.1.0" -futures-timer = "3.0.1" -sp-tracing = { path = "../../primitives/tracing" } +tempfile = { workspace = true } +futures-timer = { workspace = true } +sp-tracing = { workspace = true, default-features = true } [features] default = ["rocksdb"] diff --git a/substrate/client/cli/src/config.rs b/substrate/client/cli/src/config.rs index 783c9313121fef1a199705e8a6508688e51b67ca..283148a6d6adbb1ec9051682086879ac0614ec5e 100644 --- a/substrate/client/cli/src/config.rs +++ b/substrate/client/cli/src/config.rs @@ -27,7 +27,7 @@ use names::{Generator, Name}; use sc_service::{ config::{ BasePath, Configuration, DatabaseSource, IpNetwork, KeystoreConfig, NetworkConfiguration, - NodeKeyConfig, OffchainWorkerConfig, OutputFormat, PrometheusConfig, PruningMode, Role, + NodeKeyConfig, OffchainWorkerConfig, PrometheusConfig, PruningMode, Role, RpcBatchRequestConfig, RpcMethods, TelemetryEndpoints, TransactionPoolOptions, WasmExecutionMethod, }, @@ -550,7 +550,6 @@ pub trait CliConfiguration: Sized { announce_block: self.announce_block()?, role, base_path, - informant_output_format: OutputFormat { enable_color: !self.disable_log_color()? }, runtime_cache_size, }) } diff --git a/substrate/client/cli/src/lib.rs b/substrate/client/cli/src/lib.rs index 104e8ec8b798ee5b8eb6c9561c6ef0729d7a7b2a..1bb9fec0e27690f9b7ec21918f3dce329100de3a 100644 --- a/substrate/client/cli/src/lib.rs +++ b/substrate/client/cli/src/lib.rs @@ -58,11 +58,11 @@ pub trait SubstrateCli: Sized { /// Implementation version. /// - /// By default this will look like this: + /// By default, it will look like this: /// /// `2.0.0-b950f731c` /// - /// Where the hash is the short commit hash of the commit of in the Git repository. + /// Where the hash is the short hash of the commit in the Git repository. fn impl_version() -> String; /// Executable file name. @@ -199,17 +199,8 @@ pub trait SubstrateCli: Sized { fn create_runner, DVC: DefaultConfigurationValues>( &self, command: &T, - ) -> error::Result> { - let tokio_runtime = build_runtime()?; - - // `capture` needs to be called in a tokio context. - // Also capture them as early as possible. - let signals = tokio_runtime.block_on(async { Signals::capture() })?; - - let config = command.create_configuration(self, tokio_runtime.handle().clone())?; - - command.init(&Self::support_url(), &Self::impl_version(), |_, _| {}, &config)?; - Runner::new(config, tokio_runtime, signals) + ) -> Result> { + self.create_runner_with_logger_hook(command, |_, _| {}) } /// Create a runner for the command provided in argument. The `logger_hook` can be used to setup @@ -231,11 +222,15 @@ pub trait SubstrateCli: Sized { /// } /// } /// ``` - fn create_runner_with_logger_hook( + fn create_runner_with_logger_hook< + T: CliConfiguration, + DVC: DefaultConfigurationValues, + F, + >( &self, command: &T, logger_hook: F, - ) -> error::Result> + ) -> Result> where F: FnOnce(&mut LoggerBuilder, &Configuration), { diff --git a/substrate/client/cli/src/runner.rs b/substrate/client/cli/src/runner.rs index 6d986e38d2fb563abcbdf80fd1d79eecaef6ea4c..b0dbccfa634c881afe7b90b5e3a98a2fdbab6904 100644 --- a/substrate/client/cli/src/runner.rs +++ b/substrate/client/cli/src/runner.rs @@ -291,7 +291,6 @@ mod tests { announce_block: true, base_path: sc_service::BasePath::new(root.clone()), data_path: root, - informant_output_format: Default::default(), runtime_cache_size: 2, }, runtime, diff --git a/substrate/client/consensus/aura/Cargo.toml b/substrate/client/consensus/aura/Cargo.toml index d1460c45356d7ec86204b52c42c08ee28e9c5faf..3a3d7ae18d711e0c9b952e4f1383ae8ecb28fbc3 100644 --- a/substrate/client/consensus/aura/Cargo.toml +++ b/substrate/client/consensus/aura/Cargo.toml @@ -16,37 +16,37 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.12" } -futures = "0.3.30" +async-trait = { workspace = true } +codec = { workspace = true, default-features = true } +futures = { workspace = true } log = { workspace = true, default-features = true } thiserror = { workspace = true } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } -sc-block-builder = { path = "../../block-builder" } -sc-client-api = { path = "../../api" } -sc-consensus = { path = "../common" } -sc-consensus-slots = { path = "../slots" } -sc-telemetry = { path = "../../telemetry" } -sp-api = { path = "../../../primitives/api" } -sp-application-crypto = { path = "../../../primitives/application-crypto" } -sp-block-builder = { path = "../../../primitives/block-builder" } -sp-blockchain = { path = "../../../primitives/blockchain" } -sp-consensus = { path = "../../../primitives/consensus/common" } -sp-consensus-aura = { path = "../../../primitives/consensus/aura" } -sp-consensus-slots = { path = "../../../primitives/consensus/slots" } -sp-core = { path = "../../../primitives/core" } -sp-inherents = { path = "../../../primitives/inherents" } -sp-keystore = { path = "../../../primitives/keystore" } -sp-runtime = { path = "../../../primitives/runtime" } +prometheus-endpoint = { workspace = true, default-features = true } +sc-block-builder = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sc-consensus-slots = { workspace = true, default-features = true } +sc-telemetry = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-block-builder = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-consensus-aura = { workspace = true, default-features = true } +sp-consensus-slots = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } [dev-dependencies] -parking_lot = "0.12.1" -tempfile = "3.1.0" -sc-keystore = { path = "../../keystore" } -sc-network = { path = "../../network" } -sc-network-test = { path = "../../network/test" } -sp-keyring = { path = "../../../primitives/keyring" } -sp-timestamp = { path = "../../../primitives/timestamp" } -sp-tracing = { path = "../../../primitives/tracing" } -substrate-test-runtime-client = { path = "../../../test-utils/runtime/client" } -tokio = { version = "1.22.0" } +parking_lot = { workspace = true, default-features = true } +tempfile = { workspace = true } +sc-keystore = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-network-test = { workspace = true } +sp-keyring = { workspace = true, default-features = true } +sp-timestamp = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +substrate-test-runtime-client = { workspace = true } +tokio = { workspace = true, default-features = true } diff --git a/substrate/client/consensus/aura/src/import_queue.rs b/substrate/client/consensus/aura/src/import_queue.rs index a8777ef8788cc3a247d6d09c146f61bf4cb23e62..79f4faa5ebf97657b0f6d02933a1e7f8421d4f56 100644 --- a/substrate/client/consensus/aura/src/import_queue.rs +++ b/substrate/client/consensus/aura/src/import_queue.rs @@ -174,7 +174,7 @@ where CIDP::InherentDataProviders: InherentDataProviderExt + Send + Sync, { async fn verify( - &mut self, + &self, mut block: BlockImportParams, ) -> Result, String> { // Skip checks that include execution, if being told so or when importing only state. diff --git a/substrate/client/consensus/aura/src/standalone.rs b/substrate/client/consensus/aura/src/standalone.rs index 0f9b8668d4478bfe4dedfc56e234b79acdf14674..c1536d9ef73f38561e9944928b1c7a6c1e985ab6 100644 --- a/substrate/client/consensus/aura/src/standalone.rs +++ b/substrate/client/consensus/aura/src/standalone.rs @@ -24,7 +24,7 @@ use log::trace; use codec::Codec; -use sc_client_api::{backend::AuxStore, UsageProvider}; +use sc_client_api::UsageProvider; use sp_api::{Core, ProvideRuntimeApi}; use sp_application_crypto::{AppCrypto, AppPublic}; use sp_blockchain::Result as CResult; @@ -48,7 +48,7 @@ pub fn slot_duration(client: &C) -> CResult where A: Codec, B: BlockT, - C: AuxStore + ProvideRuntimeApi + UsageProvider, + C: ProvideRuntimeApi + UsageProvider, C::Api: AuraApi, { slot_duration_at(client, client.usage_info().chain.best_hash) @@ -59,7 +59,7 @@ pub fn slot_duration_at(client: &C, block_hash: B::Hash) -> CResult, + C: ProvideRuntimeApi, C::Api: AuraApi, { client.runtime_api().slot_duration(block_hash).map_err(|err| err.into()) diff --git a/substrate/client/consensus/babe/Cargo.toml b/substrate/client/consensus/babe/Cargo.toml index c51082a018b5cfd558efe0b76985d6add890057d..bba60bc45ea50d5c14b2d6a742de690ea95c98d6 100644 --- a/substrate/client/consensus/babe/Cargo.toml +++ b/substrate/client/consensus/babe/Cargo.toml @@ -17,41 +17,41 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } -futures = "0.3.30" +async-trait = { workspace = true } +codec = { features = ["derive"], workspace = true, default-features = true } +futures = { workspace = true } log = { workspace = true, default-features = true } -num-bigint = "0.4.3" -num-rational = "0.4.1" -num-traits = "0.2.17" -parking_lot = "0.12.1" +num-bigint = { workspace = true } +num-rational = { workspace = true } +num-traits = { workspace = true, default-features = true } +parking_lot = { workspace = true, default-features = true } thiserror = { workspace = true } -fork-tree = { path = "../../../utils/fork-tree" } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } -sc-client-api = { path = "../../api" } -sc-consensus = { path = "../common" } -sc-consensus-epochs = { path = "../epochs" } -sc-consensus-slots = { path = "../slots" } -sc-telemetry = { path = "../../telemetry" } -sc-transaction-pool-api = { path = "../../transaction-pool/api" } -sp-api = { path = "../../../primitives/api" } -sp-application-crypto = { path = "../../../primitives/application-crypto" } -sp-block-builder = { path = "../../../primitives/block-builder" } -sp-blockchain = { path = "../../../primitives/blockchain" } -sp-consensus = { path = "../../../primitives/consensus/common" } -sp-consensus-babe = { path = "../../../primitives/consensus/babe" } -sp-consensus-slots = { path = "../../../primitives/consensus/slots" } -sp-core = { path = "../../../primitives/core" } -sp-crypto-hashing = { path = "../../../primitives/crypto/hashing" } -sp-inherents = { path = "../../../primitives/inherents" } -sp-keystore = { path = "../../../primitives/keystore" } -sp-runtime = { path = "../../../primitives/runtime" } +fork-tree = { workspace = true, default-features = true } +prometheus-endpoint = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sc-consensus-epochs = { workspace = true, default-features = true } +sc-consensus-slots = { workspace = true, default-features = true } +sc-telemetry = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-block-builder = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-consensus-slots = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } [dev-dependencies] -sc-block-builder = { path = "../../block-builder" } -sp-keyring = { path = "../../../primitives/keyring" } -sc-network-test = { path = "../../network/test" } -sp-timestamp = { path = "../../../primitives/timestamp" } -sp-tracing = { path = "../../../primitives/tracing" } -substrate-test-runtime-client = { path = "../../../test-utils/runtime/client" } -tokio = "1.37" +sc-block-builder = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sc-network-test = { workspace = true } +sp-timestamp = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +substrate-test-runtime-client = { workspace = true } +tokio = { workspace = true, default-features = true } diff --git a/substrate/client/consensus/babe/rpc/Cargo.toml b/substrate/client/consensus/babe/rpc/Cargo.toml index 4c755df541d70315dea241092145e17c2bd28800..1ef049c3dbcc412ae94bc849b066e2ff154ae57c 100644 --- a/substrate/client/consensus/babe/rpc/Cargo.toml +++ b/substrate/client/consensus/babe/rpc/Cargo.toml @@ -16,27 +16,27 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.22.5", features = ["client-core", "macros", "server-core"] } -futures = "0.3.30" +jsonrpsee = { features = ["client-core", "macros", "server-core"], workspace = true } +futures = { workspace = true } serde = { features = ["derive"], workspace = true, default-features = true } thiserror = { workspace = true } -sc-consensus-babe = { path = ".." } -sc-consensus-epochs = { path = "../../epochs" } -sc-rpc-api = { path = "../../../rpc-api" } -sp-api = { path = "../../../../primitives/api" } -sp-application-crypto = { path = "../../../../primitives/application-crypto" } -sp-blockchain = { path = "../../../../primitives/blockchain" } -sp-consensus = { path = "../../../../primitives/consensus/common" } -sp-consensus-babe = { path = "../../../../primitives/consensus/babe" } -sp-core = { path = "../../../../primitives/core" } -sp-keystore = { path = "../../../../primitives/keystore" } -sp-runtime = { path = "../../../../primitives/runtime" } +sc-consensus-babe = { workspace = true, default-features = true } +sc-consensus-epochs = { workspace = true, default-features = true } +sc-rpc-api = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } [dev-dependencies] serde_json = { workspace = true, default-features = true } -tokio = "1.37" -sc-consensus = { path = "../../common" } -sc-keystore = { path = "../../../keystore" } -sc-transaction-pool-api = { path = "../../../transaction-pool/api" } -sp-keyring = { path = "../../../../primitives/keyring" } -substrate-test-runtime-client = { path = "../../../../test-utils/runtime/client" } +tokio = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sc-keystore = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +substrate-test-runtime-client = { workspace = true } diff --git a/substrate/client/consensus/babe/src/lib.rs b/substrate/client/consensus/babe/src/lib.rs index 0c85de24004031fce96be35bc413506069093eb1..0c1eb88758644c0d661c25c4feb670c6054781f4 100644 --- a/substrate/client/consensus/babe/src/lib.rs +++ b/substrate/client/consensus/babe/src/lib.rs @@ -1128,7 +1128,7 @@ where CIDP::InherentDataProviders: InherentDataProviderExt + Send + Sync, { async fn verify( - &mut self, + &self, mut block: BlockImportParams, ) -> Result, String> { trace!( @@ -1681,7 +1681,7 @@ where } async fn check_block( - &mut self, + &self, block: BlockCheckParams, ) -> Result { self.inner.check_block(block).await.map_err(Into::into) diff --git a/substrate/client/consensus/babe/src/tests.rs b/substrate/client/consensus/babe/src/tests.rs index 716067ae4000661beab6aeb90772087720d0a5ae..6f805188b9a42d806f45c01715f1a088770c3bfe 100644 --- a/substrate/client/consensus/babe/src/tests.rs +++ b/substrate/client/consensus/babe/src/tests.rs @@ -143,11 +143,11 @@ thread_local! { pub struct PanickingBlockImport(B); #[async_trait::async_trait] -impl> BlockImport for PanickingBlockImport +impl BlockImport for PanickingBlockImport where - B: Send, + BI: BlockImport + Send + Sync, { - type Error = B::Error; + type Error = BI::Error; async fn import_block( &mut self, @@ -157,7 +157,7 @@ where } async fn check_block( - &mut self, + &self, block: BlockCheckParams, ) -> Result { Ok(self.0.check_block(block).await.expect("checking block failed")) @@ -198,7 +198,7 @@ impl Verifier for TestVerifier { /// new set of validators to import. If not, err with an Error-Message /// presented to the User in the logs. async fn verify( - &mut self, + &self, mut block: BlockImportParams, ) -> Result, String> { // apply post-sealing mutations (i.e. stripping seal, if desired). diff --git a/substrate/client/consensus/beefy/Cargo.toml b/substrate/client/consensus/beefy/Cargo.toml index f5528ec5931dbc5d77321e903b57e4ef70349afc..b2031e0d1e077ef1d793faf570698499487aa4b2 100644 --- a/substrate/client/consensus/beefy/Cargo.toml +++ b/substrate/client/consensus/beefy/Cargo.toml @@ -12,46 +12,46 @@ homepage = "https://substrate.io" workspace = true [dependencies] -array-bytes = "6.2.2" -async-channel = "1.8.0" -async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } -fnv = "1.0.6" -futures = "0.3.30" +array-bytes = { workspace = true, default-features = true } +async-channel = { workspace = true } +async-trait = { workspace = true } +codec = { features = ["derive"], workspace = true, default-features = true } +fnv = { workspace = true } +futures = { workspace = true } log = { workspace = true, default-features = true } -parking_lot = "0.12.1" +parking_lot = { workspace = true, default-features = true } thiserror = { workspace = true } -wasm-timer = "0.2.5" -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } -sc-client-api = { path = "../../api" } -sc-consensus = { path = "../common" } -sc-network = { path = "../../network" } -sc-network-gossip = { path = "../../network-gossip" } -sc-network-sync = { path = "../../network/sync" } -sc-network-types = { path = "../../network/types" } -sc-utils = { path = "../../utils" } -sp-api = { path = "../../../primitives/api" } -sp-application-crypto = { path = "../../../primitives/application-crypto" } -sp-arithmetic = { path = "../../../primitives/arithmetic" } -sp-blockchain = { path = "../../../primitives/blockchain" } -sp-consensus = { path = "../../../primitives/consensus/common" } -sp-consensus-beefy = { path = "../../../primitives/consensus/beefy" } -sp-core = { path = "../../../primitives/core" } -sp-crypto-hashing = { path = "../../../primitives/crypto/hashing" } -sp-keystore = { path = "../../../primitives/keystore" } -sp-runtime = { path = "../../../primitives/runtime" } -tokio = "1.37" +wasm-timer = { workspace = true } +prometheus-endpoint = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-network-gossip = { workspace = true, default-features = true } +sc-network-sync = { workspace = true, default-features = true } +sc-network-types = { workspace = true, default-features = true } +sc-utils = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-arithmetic = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-consensus-beefy = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +tokio = { workspace = true, default-features = true } [dev-dependencies] serde = { workspace = true, default-features = true } -tempfile = "3.1.0" -sc-block-builder = { path = "../../block-builder" } -sc-network-test = { path = "../../network/test" } -sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa" } -sp-keyring = { path = "../../../primitives/keyring" } -sp-mmr-primitives = { path = "../../../primitives/merkle-mountain-range" } -sp-tracing = { path = "../../../primitives/tracing" } -substrate-test-runtime-client = { path = "../../../test-utils/runtime/client" } +tempfile = { workspace = true } +sc-block-builder = { workspace = true, default-features = true } +sc-network-test = { workspace = true } +sp-consensus-grandpa = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-mmr-primitives = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +substrate-test-runtime-client = { workspace = true } [features] # This feature adds BLS crypto primitives. It should not be used in production since diff --git a/substrate/client/consensus/beefy/rpc/Cargo.toml b/substrate/client/consensus/beefy/rpc/Cargo.toml index 84f90622b5c14f8b7cba19749c877a6ce53ec226..7869f5a336b1135bb471fc584b8f826e17fb9d02 100644 --- a/substrate/client/consensus/beefy/rpc/Cargo.toml +++ b/substrate/client/consensus/beefy/rpc/Cargo.toml @@ -12,22 +12,22 @@ homepage = "https://substrate.io" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } -futures = "0.3.30" -jsonrpsee = { version = "0.22.5", features = ["client-core", "macros", "server-core"] } +codec = { features = ["derive"], workspace = true, default-features = true } +futures = { workspace = true } +jsonrpsee = { features = ["client-core", "macros", "server-core"], workspace = true } log = { workspace = true, default-features = true } -parking_lot = "0.12.1" +parking_lot = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } thiserror = { workspace = true } -sc-consensus-beefy = { path = ".." } -sp-consensus-beefy = { path = "../../../../primitives/consensus/beefy" } -sc-rpc = { path = "../../../rpc" } -sp-core = { path = "../../../../primitives/core" } -sp-runtime = { path = "../../../../primitives/runtime" } -sp-application-crypto = { path = "../../../../primitives/application-crypto" } +sc-consensus-beefy = { workspace = true, default-features = true } +sp-consensus-beefy = { workspace = true, default-features = true } +sc-rpc = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } [dev-dependencies] serde_json = { workspace = true, default-features = true } -sc-rpc = { path = "../../../rpc", features = ["test-helpers"] } -substrate-test-runtime-client = { path = "../../../../test-utils/runtime/client" } -tokio = { version = "1.22.0", features = ["macros"] } +sc-rpc = { features = ["test-helpers"], workspace = true, default-features = true } +substrate-test-runtime-client = { workspace = true } +tokio = { features = ["macros"], workspace = true, default-features = true } diff --git a/substrate/client/consensus/beefy/src/communication/peers.rs b/substrate/client/consensus/beefy/src/communication/peers.rs index 2d801aceaa8a76bf1c31820493bbd20b4f93f8da..929cc0c650b3e26e90016512042d620cc40c6408 100644 --- a/substrate/client/consensus/beefy/src/communication/peers.rs +++ b/substrate/client/consensus/beefy/src/communication/peers.rs @@ -75,6 +75,11 @@ impl KnownPeers { pub fn contains(&self, peer: &PeerId) -> bool { self.live.contains_key(peer) } + + /// Number of peers in the set. + pub fn len(&self) -> usize { + self.live.len() + } } #[cfg(test)] diff --git a/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs b/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs index e127e5a895905b212fda73b109714618b76367d9..95ecf35557a5189fae4cc117e71126d8c8076536 100644 --- a/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs +++ b/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -249,9 +249,16 @@ impl OnDemandJustificationsEngine OnDemandJustificationsEngine(&proof) { + if !check_double_voting_proof::<_, _, BeefySignatureHasher>(&proof) { debug!(target: LOG_TARGET, "๐Ÿฅฉ Skipping report for bad equivocation {:?}", proof); return Ok(()); } @@ -155,7 +155,7 @@ where for ProvedValidator { key_owner_proof, .. } in key_owner_proofs { self.runtime .runtime_api() - .submit_report_equivocation_unsigned_extrinsic( + .submit_report_double_voting_unsigned_extrinsic( best_block_hash, proof.clone(), key_owner_proof, diff --git a/substrate/client/consensus/beefy/src/import.rs b/substrate/client/consensus/beefy/src/import.rs index c01fb3db4845eb9e413e0dbe781ae395a3b31217..8480268529338fe09333719a2e26141e37c792ea 100644 --- a/substrate/client/consensus/beefy/src/import.rs +++ b/substrate/client/consensus/beefy/src/import.rs @@ -192,7 +192,7 @@ where } async fn check_block( - &mut self, + &self, block: BlockCheckParams, ) -> Result { self.inner.check_block(block).await diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index 8daf3440c7d2c745cc0ef85bc3d7436a6d91e1f4..888a11db89cbe55165de8f34c5bbaed422f13806 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -20,7 +20,7 @@ use log::warn; use sp_application_crypto::{key_types::BEEFY as BEEFY_KEY_TYPE, AppCrypto, RuntimeAppPublic}; #[cfg(feature = "bls-experimental")] -use sp_core::ecdsa_bls377; +use sp_core::ecdsa_bls381; use sp_core::{ecdsa, keccak_256}; use sp_keystore::KeystorePtr; @@ -100,13 +100,13 @@ impl BeefyKeystore { }, #[cfg(feature = "bls-experimental")] - ecdsa_bls377::CRYPTO_ID => { - let public: ecdsa_bls377::Public = - ecdsa_bls377::Public::try_from(public.as_slice()).unwrap(); + ecdsa_bls381::CRYPTO_ID => { + let public: ecdsa_bls381::Public = + ecdsa_bls381::Public::try_from(public.as_slice()).unwrap(); let sig = store - .ecdsa_bls377_sign_with_keccak256(BEEFY_KEY_TYPE, &public, &message) + .ecdsa_bls381_sign_with_keccak256(BEEFY_KEY_TYPE, &public, &message) .map_err(|e| error::Error::Keystore(e.to_string()))? - .ok_or_else(|| error::Error::Signature("bls377_sign() failed".to_string()))?; + .ok_or_else(|| error::Error::Signature("bls381_sign() failed".to_string()))?; let sig_ref: &[u8] = sig.as_ref(); sig_ref.to_vec() }, @@ -146,8 +146,8 @@ impl BeefyKeystore { }), #[cfg(feature = "bls-experimental")] - ecdsa_bls377::CRYPTO_ID => store - .ecdsa_bls377_public_keys(BEEFY_KEY_TYPE) + ecdsa_bls381::CRYPTO_ID => store + .ecdsa_bls381_public_keys(BEEFY_KEY_TYPE) .drain(..) .map(|pk| AuthorityId::try_from(pk.as_ref())) .collect::, _>>() @@ -254,9 +254,9 @@ pub mod tests { AuthorityId::decode(&mut pk.as_ref()).unwrap() }, #[cfg(feature = "bls-experimental")] - ecdsa_bls377::CRYPTO_ID => { + ecdsa_bls381::CRYPTO_ID => { let pk = store - .ecdsa_bls377_generate_new(key_type, optional_seed.as_deref()) + .ecdsa_bls381_generate_new(key_type, optional_seed.as_deref()) .ok() .unwrap(); AuthorityId::decode(&mut pk.as_ref()).unwrap() @@ -452,7 +452,7 @@ pub mod tests { #[cfg(feature = "bls-experimental")] #[test] fn sign_error_for_ecdsa_n_bls() { - sign_error::("bls377_sign() failed"); + sign_error::("bls381_sign() failed"); } #[test] diff --git a/substrate/client/consensus/beefy/src/tests.rs b/substrate/client/consensus/beefy/src/tests.rs index 681e11a0c5310f7bfa67aab824e861ef447f3941..d8f5b39dbbaaacc3094bcef31dfd8af618917990 100644 --- a/substrate/client/consensus/beefy/src/tests.rs +++ b/substrate/client/consensus/beefy/src/tests.rs @@ -314,7 +314,7 @@ sp_api::mock_impl_runtime_apis! { self.inner.validator_set.clone() } - fn submit_report_equivocation_unsigned_extrinsic( + fn submit_report_double_voting_unsigned_extrinsic( proof: DoubleVotingProof, AuthorityId, Signature>, _dummy: OpaqueKeyOwnershipProof, ) -> Option<()> { diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 3ce4da7ecd56adea78b92a905546c4fa619403d7..4a9f7a2d0e3b0afd6d8ed8b6f3237fcd1c209a49 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -1039,7 +1039,7 @@ pub(crate) mod tests { ecdsa_crypto, known_payloads, known_payloads::MMR_ROOT_ID, mmr::MmrRootProvider, - test_utils::{generate_equivocation_proof, Keyring}, + test_utils::{generate_double_voting_proof, Keyring}, ConsensusLog, Payload, SignedCommitment, }; use sp_runtime::traits::{Header as HeaderT, One}; @@ -1586,7 +1586,7 @@ pub(crate) mod tests { let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); // generate an equivocation proof, with Bob as perpetrator - let good_proof = generate_equivocation_proof( + let good_proof = generate_double_voting_proof( (block_num, payload1.clone(), set_id, &Keyring::Bob), (block_num, payload2.clone(), set_id, &Keyring::Bob), ); @@ -1618,7 +1618,7 @@ pub(crate) mod tests { assert!(api_alice.reported_equivocations.as_ref().unwrap().lock().is_empty()); // now let's try reporting a self-equivocation - let self_proof = generate_equivocation_proof( + let self_proof = generate_double_voting_proof( (block_num, payload1.clone(), set_id, &Keyring::Alice), (block_num, payload2.clone(), set_id, &Keyring::Alice), ); diff --git a/substrate/client/consensus/common/Cargo.toml b/substrate/client/consensus/common/Cargo.toml index 6d642ec78fefa88692503152595f8548d715426c..a6f59e600f269c67ab87f295c268f3d185dafcf4 100644 --- a/substrate/client/consensus/common/Cargo.toml +++ b/substrate/client/consensus/common/Cargo.toml @@ -16,24 +16,23 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.79" -futures = { version = "0.3.30", features = ["thread-pool"] } -futures-timer = "3.0.1" +async-trait = { workspace = true } +futures = { features = ["thread-pool"], workspace = true } log = { workspace = true, default-features = true } -mockall = "0.11.3" -parking_lot = "0.12.1" +mockall = { workspace = true } +parking_lot = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } thiserror = { workspace = true } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } -sc-client-api = { path = "../../api" } -sc-network-types = { path = "../../network/types" } -sc-utils = { path = "../../utils" } -sp-api = { path = "../../../primitives/api" } -sp-blockchain = { path = "../../../primitives/blockchain" } -sp-consensus = { path = "../../../primitives/consensus/common" } -sp-core = { path = "../../../primitives/core" } -sp-runtime = { path = "../../../primitives/runtime" } -sp-state-machine = { path = "../../../primitives/state-machine" } +prometheus-endpoint = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-network-types = { workspace = true, default-features = true } +sc-utils = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } [dev-dependencies] -sp-test-primitives = { path = "../../../primitives/test-primitives" } +sp-test-primitives = { workspace = true } diff --git a/substrate/client/consensus/common/src/block_import.rs b/substrate/client/consensus/common/src/block_import.rs index d91851aea62cf4564464b67bcd0bdcd5d712e139..c5adbb5a5fca0634b1cdb038c569a1de312cf859 100644 --- a/substrate/client/consensus/common/src/block_import.rs +++ b/substrate/client/consensus/common/src/block_import.rs @@ -307,10 +307,7 @@ pub trait BlockImport { type Error: std::error::Error + Send + 'static; /// Check block preconditions. - async fn check_block( - &mut self, - block: BlockCheckParams, - ) -> Result; + async fn check_block(&self, block: BlockCheckParams) -> Result; /// Import a block. async fn import_block( @@ -324,10 +321,7 @@ impl BlockImport for crate::import_queue::BoxBlockImport { type Error = sp_consensus::error::Error; /// Check block preconditions. - async fn check_block( - &mut self, - block: BlockCheckParams, - ) -> Result { + async fn check_block(&self, block: BlockCheckParams) -> Result { (**self).check_block(block).await } @@ -348,10 +342,7 @@ where { type Error = E; - async fn check_block( - &mut self, - block: BlockCheckParams, - ) -> Result { + async fn check_block(&self, block: BlockCheckParams) -> Result { (&**self).check_block(block).await } diff --git a/substrate/client/consensus/common/src/import_queue.rs b/substrate/client/consensus/common/src/import_queue.rs index 371465536c35a5feea5d6e157eb3ee8b019b94db..35fc8ad4a402e72d9f6c8d110a468bea5f3c5195 100644 --- a/substrate/client/consensus/common/src/import_queue.rs +++ b/substrate/client/consensus/common/src/import_queue.rs @@ -28,6 +28,10 @@ //! queues to be instantiated simply. use log::{debug, trace}; +use std::{ + fmt, + time::{Duration, Instant}, +}; use sp_consensus::{error::Error as ConsensusError, BlockOrigin}; use sp_runtime::{ @@ -93,18 +97,18 @@ pub struct IncomingBlock { /// Verify a justification of a block #[async_trait::async_trait] -pub trait Verifier: Send { +pub trait Verifier: Send + Sync { /// Verify the given block data and return the `BlockImportParams` to /// continue the block import process. - async fn verify(&mut self, block: BlockImportParams) - -> Result, String>; + async fn verify(&self, block: BlockImportParams) -> Result, String>; } /// Blocks import queue API. /// /// The `import_*` methods can be called in order to send elements for the import queue to verify. pub trait ImportQueueService: Send { - /// Import bunch of blocks. + /// Import bunch of blocks, every next block must be an ancestor of the previous block in the + /// list. fn import_blocks(&mut self, origin: BlockOrigin, blocks: Vec>); /// Import block justifications. @@ -165,16 +169,16 @@ pub trait Link: Send { /// Block import successful result. #[derive(Debug, PartialEq)] -pub enum BlockImportStatus { +pub enum BlockImportStatus { /// Imported known block. - ImportedKnown(N, Option), + ImportedKnown(BlockNumber, Option), /// Imported unknown block. - ImportedUnknown(N, ImportedAux, Option), + ImportedUnknown(BlockNumber, ImportedAux, Option), } -impl BlockImportStatus { +impl BlockImportStatus { /// Returns the imported block number. - pub fn number(&self) -> &N { + pub fn number(&self) -> &BlockNumber { match self { BlockImportStatus::ImportedKnown(n, _) | BlockImportStatus::ImportedUnknown(n, _, _) => n, @@ -223,44 +227,30 @@ pub async fn import_single_block>( block: IncomingBlock, verifier: &mut V, ) -> BlockImportResult { - import_single_block_metered(import_handle, block_origin, block, verifier, None).await + match verify_single_block_metered(import_handle, block_origin, block, verifier, None).await? { + SingleBlockVerificationOutcome::Imported(import_status) => Ok(import_status), + SingleBlockVerificationOutcome::Verified(import_parameters) => + import_single_block_metered(import_handle, import_parameters, None).await, + } } -/// Single block import function with metering. -pub(crate) async fn import_single_block_metered>( - import_handle: &mut impl BlockImport, - block_origin: BlockOrigin, - block: IncomingBlock, - verifier: &mut V, - metrics: Option, -) -> BlockImportResult { - let peer = block.origin; - - let (header, justifications) = match (block.header, block.justifications) { - (Some(header), justifications) => (header, justifications), - (None, _) => { - if let Some(ref peer) = peer { - debug!(target: LOG_TARGET, "Header {} was not provided by {} ", block.hash, peer); - } else { - debug!(target: LOG_TARGET, "Header {} was not provided ", block.hash); - } - return Err(BlockImportError::IncompleteHeader(peer)) - }, - }; - - trace!(target: LOG_TARGET, "Header {} has {:?} logs", block.hash, header.digest().logs().len()); - - let number = *header.number(); - let hash = block.hash; - let parent_hash = *header.parent_hash(); - - let import_handler = |import| match import { +fn import_handler( + number: NumberFor, + hash: Block::Hash, + parent_hash: Block::Hash, + block_origin: Option, + import: Result, +) -> Result>, BlockImportError> +where + Block: BlockT, +{ + match import { Ok(ImportResult::AlreadyInChain) => { trace!(target: LOG_TARGET, "Block already in chain {}: {:?}", number, hash); - Ok(BlockImportStatus::ImportedKnown(number, peer)) + Ok(BlockImportStatus::ImportedKnown(number, block_origin)) }, Ok(ImportResult::Imported(aux)) => - Ok(BlockImportStatus::ImportedUnknown(number, aux, peer)), + Ok(BlockImportStatus::ImportedUnknown(number, aux, block_origin)), Ok(ImportResult::MissingState) => { debug!( target: LOG_TARGET, @@ -277,15 +267,60 @@ pub(crate) async fn import_single_block_metered>( }, Ok(ImportResult::KnownBad) => { debug!(target: LOG_TARGET, "Peer gave us a bad block {}: {:?}", number, hash); - Err(BlockImportError::BadBlock(peer)) + Err(BlockImportError::BadBlock(block_origin)) }, Err(e) => { debug!(target: LOG_TARGET, "Error importing block {}: {:?}: {}", number, hash, e); Err(BlockImportError::Other(e)) }, + } +} + +pub(crate) enum SingleBlockVerificationOutcome { + /// Block is already imported. + Imported(BlockImportStatus>), + /// Block is verified, but needs to be imported. + Verified(SingleBlockImportParameters), +} + +pub(crate) struct SingleBlockImportParameters { + import_block: BlockImportParams, + hash: Block::Hash, + block_origin: Option, + verification_time: Duration, +} + +/// Single block import function with metering. +pub(crate) async fn verify_single_block_metered>( + import_handle: &impl BlockImport, + block_origin: BlockOrigin, + block: IncomingBlock, + verifier: &mut V, + metrics: Option<&Metrics>, +) -> Result, BlockImportError> { + let peer = block.origin; + let justifications = block.justifications; + + let Some(header) = block.header else { + if let Some(ref peer) = peer { + debug!(target: LOG_TARGET, "Header {} was not provided by {peer} ", block.hash); + } else { + debug!(target: LOG_TARGET, "Header {} was not provided ", block.hash); + } + return Err(BlockImportError::IncompleteHeader(peer)) }; - match import_handler( + trace!(target: LOG_TARGET, "Header {} has {:?} logs", block.hash, header.digest().logs().len()); + + let number = *header.number(); + let hash = block.hash; + let parent_hash = *header.parent_hash(); + + match import_handler::( + number, + hash, + parent_hash, + peer, import_handle .check_block(BlockCheckParams { hash, @@ -298,10 +333,13 @@ pub(crate) async fn import_single_block_metered>( .await, )? { BlockImportStatus::ImportedUnknown { .. } => (), - r => return Ok(r), // Any other successful result means that the block is already imported. + r => { + // Any other successful result means that the block is already imported. + return Ok(SingleBlockVerificationOutcome::Imported(r)) + }, } - let started = std::time::Instant::now(); + let started = Instant::now(); let mut import_block = BlockImportParams::new(block_origin, header); import_block.body = block.body; @@ -332,19 +370,42 @@ pub(crate) async fn import_single_block_metered>( } else { trace!(target: LOG_TARGET, "Verifying {}({}) failed: {}", number, hash, msg); } - if let Some(metrics) = metrics.as_ref() { + if let Some(metrics) = metrics { metrics.report_verification(false, started.elapsed()); } BlockImportError::VerificationFailed(peer, msg) })?; - if let Some(metrics) = metrics.as_ref() { - metrics.report_verification(true, started.elapsed()); + let verification_time = started.elapsed(); + if let Some(metrics) = metrics { + metrics.report_verification(true, verification_time); } + Ok(SingleBlockVerificationOutcome::Verified(SingleBlockImportParameters { + import_block, + hash, + block_origin: peer, + verification_time, + })) +} + +pub(crate) async fn import_single_block_metered( + import_handle: &mut impl BlockImport, + import_parameters: SingleBlockImportParameters, + metrics: Option<&Metrics>, +) -> BlockImportResult { + let started = Instant::now(); + + let SingleBlockImportParameters { import_block, hash, block_origin, verification_time } = + import_parameters; + + let number = *import_block.header.number(); + let parent_hash = *import_block.header.parent_hash(); + let imported = import_handle.import_block(import_block).await; - if let Some(metrics) = metrics.as_ref() { - metrics.report_verification_and_import(started.elapsed()); + if let Some(metrics) = metrics { + metrics.report_verification_and_import(started.elapsed() + verification_time); } - import_handler(imported) + + import_handler::(number, hash, parent_hash, block_origin, imported) } diff --git a/substrate/client/consensus/common/src/import_queue/basic_queue.rs b/substrate/client/consensus/common/src/import_queue/basic_queue.rs index f4f618d1b31825e17987130b20a96c21e475b098..05f2b252796146f62ba7c258b208fa4c2eb4a3d1 100644 --- a/substrate/client/consensus/common/src/import_queue/basic_queue.rs +++ b/substrate/client/consensus/common/src/import_queue/basic_queue.rs @@ -19,7 +19,6 @@ use futures::{ prelude::*, task::{Context, Poll}, }; -use futures_timer::Delay; use log::{debug, trace}; use prometheus_endpoint::Registry; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; @@ -28,14 +27,14 @@ use sp_runtime::{ traits::{Block as BlockT, Header as HeaderT, NumberFor}, Justification, Justifications, }; -use std::{pin::Pin, time::Duration}; +use std::pin::Pin; use crate::{ import_queue::{ buffered_link::{self, BufferedLinkReceiver, BufferedLinkSender}, - import_single_block_metered, BlockImportError, BlockImportStatus, BoxBlockImport, - BoxJustificationImport, ImportQueue, ImportQueueService, IncomingBlock, Link, - RuntimeOrigin, Verifier, LOG_TARGET, + import_single_block_metered, verify_single_block_metered, BlockImportError, + BlockImportStatus, BoxBlockImport, BoxJustificationImport, ImportQueue, ImportQueueService, + IncomingBlock, Link, RuntimeOrigin, SingleBlockVerificationOutcome, Verifier, LOG_TARGET, }, metrics::Metrics, }; @@ -61,13 +60,16 @@ impl BasicQueue { /// Instantiate a new basic queue, with given verifier. /// /// This creates a background task, and calls `on_start` on the justification importer. - pub fn new>( + pub fn new( verifier: V, block_import: BoxBlockImport, justification_import: Option>, spawner: &impl sp_core::traits::SpawnEssentialNamed, prometheus_registry: Option<&Registry>, - ) -> Self { + ) -> Self + where + V: Verifier + 'static, + { let (result_sender, result_port) = buffered_link::buffered_link(100_000); let metrics = prometheus_registry.and_then(|r| { @@ -224,7 +226,6 @@ async fn block_import_process( mut result_sender: BufferedLinkSender, mut block_import_receiver: TracingUnboundedReceiver>, metrics: Option, - delay_between_blocks: Duration, ) { loop { let worker_messages::ImportBlocks(origin, blocks) = match block_import_receiver.next().await @@ -239,15 +240,9 @@ async fn block_import_process( }, }; - let res = import_many_blocks( - &mut block_import, - origin, - blocks, - &mut verifier, - delay_between_blocks, - metrics.clone(), - ) - .await; + let res = + import_many_blocks(&mut block_import, origin, blocks, &mut verifier, metrics.clone()) + .await; result_sender.blocks_processed(res.imported, res.block_count, res.results); } @@ -260,7 +255,7 @@ struct BlockImportWorker { } impl BlockImportWorker { - fn new>( + fn new( result_sender: BufferedLinkSender, verifier: V, block_import: BoxBlockImport, @@ -270,19 +265,20 @@ impl BlockImportWorker { impl Future + Send, TracingUnboundedSender>, TracingUnboundedSender>, - ) { + ) + where + V: Verifier + 'static, + { use worker_messages::*; let (justification_sender, mut justification_port) = tracing_unbounded("mpsc_import_queue_worker_justification", 100_000); - let (block_import_sender, block_import_port) = + let (block_import_sender, block_import_receiver) = tracing_unbounded("mpsc_import_queue_worker_blocks", 100_000); let mut worker = BlockImportWorker { result_sender, justification_import, metrics }; - let delay_between_blocks = Duration::default(); - let future = async move { // Let's initialize `justification_import` if let Some(justification_import) = worker.justification_import.as_mut() { @@ -295,9 +291,8 @@ impl BlockImportWorker { block_import, verifier, worker.result_sender.clone(), - block_import_port, + block_import_receiver, worker.metrics.clone(), - delay_between_blocks, ); futures::pin_mut!(block_import_process); @@ -394,7 +389,6 @@ async fn import_many_blocks>( blocks_origin: BlockOrigin, blocks: Vec>, verifier: &mut V, - delay_between_blocks: Duration, metrics: Option, ) -> ImportManyBlocksResult { let count = blocks.len(); @@ -431,15 +425,22 @@ async fn import_many_blocks>( let import_result = if has_error { Err(BlockImportError::Cancelled) } else { - // The actual import. - import_single_block_metered( + let verification_fut = verify_single_block_metered( import_handle, blocks_origin, block, verifier, - metrics.clone(), - ) - .await + metrics.as_ref(), + ); + match verification_fut.await { + Ok(SingleBlockVerificationOutcome::Imported(import_status)) => Ok(import_status), + Ok(SingleBlockVerificationOutcome::Verified(import_parameters)) => { + // The actual import. + import_single_block_metered(import_handle, import_parameters, metrics.as_ref()) + .await + }, + Err(e) => Err(e), + } }; if let Some(metrics) = metrics.as_ref() { @@ -460,11 +461,7 @@ async fn import_many_blocks>( results.push((import_result, block_hash)); - if delay_between_blocks != Duration::default() && !has_error { - Delay::new(delay_between_blocks).await; - } else { - Yield::new().await - } + Yield::new().await } } @@ -510,7 +507,7 @@ mod tests { #[async_trait::async_trait] impl Verifier for () { async fn verify( - &mut self, + &self, block: BlockImportParams, ) -> Result, String> { Ok(BlockImportParams::new(block.origin, block.header)) @@ -522,7 +519,7 @@ mod tests { type Error = sp_consensus::Error; async fn check_block( - &mut self, + &self, _block: BlockCheckParams, ) -> Result { Ok(ImportResult::imported(false)) diff --git a/substrate/client/consensus/epochs/Cargo.toml b/substrate/client/consensus/epochs/Cargo.toml index e409e171e477c2452903a09ee78916808a210011..127cc9ebec207b27f9bf2f54c9e07184b290ebae 100644 --- a/substrate/client/consensus/epochs/Cargo.toml +++ b/substrate/client/consensus/epochs/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } -fork-tree = { path = "../../../utils/fork-tree" } -sc-client-api = { path = "../../api" } -sc-consensus = { path = "../common" } -sp-blockchain = { path = "../../../primitives/blockchain" } -sp-runtime = { path = "../../../primitives/runtime" } +codec = { features = ["derive"], workspace = true, default-features = true } +fork-tree = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } diff --git a/substrate/client/consensus/grandpa/Cargo.toml b/substrate/client/consensus/grandpa/Cargo.toml index b03a263ae0a37d3a304b54096ad71a06b89c99bd..e49c7c9f0d7a93e727453592d7f300d54bc96acf 100644 --- a/substrate/client/consensus/grandpa/Cargo.toml +++ b/substrate/client/consensus/grandpa/Cargo.toml @@ -17,51 +17,51 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -ahash = "0.8.2" -array-bytes = "6.2.2" -async-trait = "0.1.79" -dyn-clone = "1.0" -finality-grandpa = { version = "0.16.2", features = ["derive-codec"] } -futures = "0.3.30" -futures-timer = "3.0.1" +ahash = { workspace = true } +array-bytes = { workspace = true, default-features = true } +async-trait = { workspace = true } +dyn-clone = { workspace = true } +finality-grandpa = { features = ["derive-codec"], workspace = true, default-features = true } +futures = { workspace = true } +futures-timer = { workspace = true } log = { workspace = true, default-features = true } -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } -parking_lot = "0.12.1" -rand = "0.8.5" +codec = { features = ["derive"], workspace = true, default-features = true } +parking_lot = { workspace = true, default-features = true } +rand = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } thiserror = { workspace = true } -fork-tree = { path = "../../../utils/fork-tree" } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } -sc-block-builder = { path = "../../block-builder" } -sc-chain-spec = { path = "../../chain-spec" } -sc-client-api = { path = "../../api" } -sc-transaction-pool-api = { path = "../../transaction-pool/api" } -sc-consensus = { path = "../common" } -sc-network = { path = "../../network" } -sc-network-gossip = { path = "../../network-gossip" } -sc-network-common = { path = "../../network/common" } -sc-network-sync = { path = "../../network/sync" } -sc-network-types = { path = "../../network/types" } -sc-telemetry = { path = "../../telemetry" } -sc-utils = { path = "../../utils" } -sp-api = { path = "../../../primitives/api" } -sp-application-crypto = { path = "../../../primitives/application-crypto" } -sp-arithmetic = { path = "../../../primitives/arithmetic" } -sp-blockchain = { path = "../../../primitives/blockchain" } -sp-consensus = { path = "../../../primitives/consensus/common" } -sp-core = { path = "../../../primitives/core" } -sp-crypto-hashing = { path = "../../../primitives/crypto/hashing" } -sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa" } -sp-keystore = { path = "../../../primitives/keystore" } -sp-runtime = { path = "../../../primitives/runtime" } +fork-tree = { workspace = true, default-features = true } +prometheus-endpoint = { workspace = true, default-features = true } +sc-block-builder = { workspace = true, default-features = true } +sc-chain-spec = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-network-gossip = { workspace = true, default-features = true } +sc-network-common = { workspace = true, default-features = true } +sc-network-sync = { workspace = true, default-features = true } +sc-network-types = { workspace = true, default-features = true } +sc-telemetry = { workspace = true, default-features = true } +sc-utils = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-arithmetic = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true, default-features = true } +sp-consensus-grandpa = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } [dev-dependencies] -assert_matches = "1.3.0" -finality-grandpa = { version = "0.16.2", features = ["derive-codec", "test-helpers"] } +assert_matches = { workspace = true } +finality-grandpa = { features = ["derive-codec", "test-helpers"], workspace = true, default-features = true } serde = { workspace = true, default-features = true } -tokio = "1.37" -sc-network = { path = "../../network" } -sc-network-test = { path = "../../network/test" } -sp-keyring = { path = "../../../primitives/keyring" } -sp-tracing = { path = "../../../primitives/tracing" } -substrate-test-runtime-client = { path = "../../../test-utils/runtime/client" } +tokio = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-network-test = { workspace = true } +sp-keyring = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +substrate-test-runtime-client = { workspace = true } diff --git a/substrate/client/consensus/grandpa/rpc/Cargo.toml b/substrate/client/consensus/grandpa/rpc/Cargo.toml index a9437a9be07544060e2b05aff4a86e0edcc3dcc5..0215fe2e3e64244ac5143dff0b18237fedc23bba 100644 --- a/substrate/client/consensus/grandpa/rpc/Cargo.toml +++ b/substrate/client/consensus/grandpa/rpc/Cargo.toml @@ -13,25 +13,25 @@ homepage = "https://substrate.io" workspace = true [dependencies] -finality-grandpa = { version = "0.16.2", features = ["derive-codec"] } -futures = "0.3.30" -jsonrpsee = { version = "0.22.5", features = ["client-core", "macros", "server-core"] } +finality-grandpa = { features = ["derive-codec"], workspace = true, default-features = true } +futures = { workspace = true } +jsonrpsee = { features = ["client-core", "macros", "server-core"], workspace = true } log = { workspace = true, default-features = true } -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } +codec = { features = ["derive"], workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } thiserror = { workspace = true } -sc-client-api = { path = "../../../api" } -sc-consensus-grandpa = { path = ".." } -sc-rpc = { path = "../../../rpc" } -sp-blockchain = { path = "../../../../primitives/blockchain" } -sp-core = { path = "../../../../primitives/core" } -sp-runtime = { path = "../../../../primitives/runtime" } +sc-client-api = { workspace = true, default-features = true } +sc-consensus-grandpa = { workspace = true, default-features = true } +sc-rpc = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } [dev-dependencies] -sc-block-builder = { path = "../../../block-builder" } -sc-rpc = { path = "../../../rpc", features = ["test-helpers"] } -sp-core = { path = "../../../../primitives/core" } -sp-consensus-grandpa = { path = "../../../../primitives/consensus/grandpa" } -sp-keyring = { path = "../../../../primitives/keyring" } -substrate-test-runtime-client = { path = "../../../../test-utils/runtime/client" } -tokio = { version = "1.22.0", features = ["macros"] } +sc-block-builder = { workspace = true, default-features = true } +sc-rpc = { features = ["test-helpers"], workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-consensus-grandpa = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +substrate-test-runtime-client = { workspace = true } +tokio = { features = ["macros"], workspace = true, default-features = true } diff --git a/substrate/client/consensus/grandpa/src/import.rs b/substrate/client/consensus/grandpa/src/import.rs index b594c0f678cea64efae7980ee17a9876ce6d5013..8b7b02f180ecd582063c5b02e1f4217c0a507e13 100644 --- a/substrate/client/consensus/grandpa/src/import.rs +++ b/substrate/client/consensus/grandpa/src/import.rs @@ -518,7 +518,7 @@ where Client: ClientForGrandpa, Client::Api: GrandpaApi, for<'a> &'a Client: BlockImport, - SC: Send, + SC: Send + Sync, { type Error = ConsensusError; @@ -697,7 +697,7 @@ where } async fn check_block( - &mut self, + &self, block: BlockCheckParams, ) -> Result { self.inner.check_block(block).await diff --git a/substrate/client/consensus/manual-seal/Cargo.toml b/substrate/client/consensus/manual-seal/Cargo.toml index 33f5bf1f8c1501e0e366edab6c3606716aeb47ab..3d74eda8fa01f838b063c134163a61a8d98af081 100644 --- a/substrate/client/consensus/manual-seal/Cargo.toml +++ b/substrate/client/consensus/manual-seal/Cargo.toml @@ -16,37 +16,37 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.22.5", features = ["client-core", "macros", "server-core"] } -assert_matches = "1.3.0" -async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.12" } -futures = "0.3.30" -futures-timer = "3.0.1" +jsonrpsee = { features = ["client-core", "macros", "server-core"], workspace = true } +assert_matches = { workspace = true } +async-trait = { workspace = true } +codec = { workspace = true, default-features = true } +futures = { workspace = true } +futures-timer = { workspace = true } log = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } thiserror = { workspace = true } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } -sc-client-api = { path = "../../api" } -sc-consensus = { path = "../common" } -sc-consensus-aura = { path = "../aura" } -sc-consensus-babe = { path = "../babe" } -sc-consensus-epochs = { path = "../epochs" } -sc-transaction-pool = { path = "../../transaction-pool" } -sc-transaction-pool-api = { path = "../../transaction-pool/api" } -sp-api = { path = "../../../primitives/api" } -sp-blockchain = { path = "../../../primitives/blockchain" } -sp-consensus = { path = "../../../primitives/consensus/common" } -sp-consensus-aura = { path = "../../../primitives/consensus/aura" } -sp-consensus-babe = { path = "../../../primitives/consensus/babe" } -sp-consensus-slots = { path = "../../../primitives/consensus/slots" } -sp-core = { path = "../../../primitives/core" } -sp-inherents = { path = "../../../primitives/inherents" } -sp-keystore = { path = "../../../primitives/keystore" } -sp-runtime = { path = "../../../primitives/runtime" } -sp-timestamp = { path = "../../../primitives/timestamp" } +prometheus-endpoint = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sc-consensus-aura = { workspace = true, default-features = true } +sc-consensus-babe = { workspace = true, default-features = true } +sc-consensus-epochs = { workspace = true, default-features = true } +sc-transaction-pool = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-consensus-aura = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-consensus-slots = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-timestamp = { workspace = true, default-features = true } [dev-dependencies] -tokio = { version = "1.22.0", features = ["macros", "rt-multi-thread"] } -sc-basic-authorship = { path = "../../basic-authorship" } -substrate-test-runtime-client = { path = "../../../test-utils/runtime/client" } -substrate-test-runtime-transaction-pool = { path = "../../../test-utils/runtime/transaction-pool" } +tokio = { features = ["macros", "rt-multi-thread"], workspace = true, default-features = true } +sc-basic-authorship = { workspace = true, default-features = true } +substrate-test-runtime-client = { workspace = true } +substrate-test-runtime-transaction-pool = { workspace = true } diff --git a/substrate/client/consensus/manual-seal/src/consensus/babe.rs b/substrate/client/consensus/manual-seal/src/consensus/babe.rs index bc56ce0227142fee2c001c39ce8d31cd9e6fb9b5..a68e46f0134d655d1b034b2b4a40727627724164 100644 --- a/substrate/client/consensus/manual-seal/src/consensus/babe.rs +++ b/substrate/client/consensus/manual-seal/src/consensus/babe.rs @@ -96,7 +96,7 @@ where C: HeaderBackend + HeaderMetadata, { async fn verify( - &mut self, + &self, mut import_params: BlockImportParams, ) -> Result, String> { import_params.finalized = false; diff --git a/substrate/client/consensus/manual-seal/src/lib.rs b/substrate/client/consensus/manual-seal/src/lib.rs index 8fc7e7ecab2f45cf8359c2f449dde3b480bb3ad3..39f8f8609d8d7f35867cc8108ad6667263fe5b74 100644 --- a/substrate/client/consensus/manual-seal/src/lib.rs +++ b/substrate/client/consensus/manual-seal/src/lib.rs @@ -65,7 +65,7 @@ struct ManualSealVerifier; #[async_trait::async_trait] impl Verifier for ManualSealVerifier { async fn verify( - &mut self, + &self, mut block: BlockImportParams, ) -> Result, String> { block.finalized = false; diff --git a/substrate/client/consensus/pow/Cargo.toml b/substrate/client/consensus/pow/Cargo.toml index 51a2be1b6cf5d4be2d5a5c3af6b0e6ea2bc25406..f2a071ec25c2c3fb97e64229e2fac662532d5969 100644 --- a/substrate/client/consensus/pow/Cargo.toml +++ b/substrate/client/consensus/pow/Cargo.toml @@ -16,21 +16,21 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } -futures = "0.3.30" -futures-timer = "3.0.1" +async-trait = { workspace = true } +codec = { features = ["derive"], workspace = true, default-features = true } +futures = { workspace = true } +futures-timer = { workspace = true } log = { workspace = true, default-features = true } -parking_lot = "0.12.1" +parking_lot = { workspace = true, default-features = true } thiserror = { workspace = true } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } -sc-client-api = { path = "../../api" } -sc-consensus = { path = "../common" } -sp-api = { path = "../../../primitives/api" } -sp-block-builder = { path = "../../../primitives/block-builder" } -sp-blockchain = { path = "../../../primitives/blockchain" } -sp-consensus = { path = "../../../primitives/consensus/common" } -sp-consensus-pow = { path = "../../../primitives/consensus/pow" } -sp-core = { path = "../../../primitives/core" } -sp-inherents = { path = "../../../primitives/inherents" } -sp-runtime = { path = "../../../primitives/runtime" } +prometheus-endpoint = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-block-builder = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-consensus-pow = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } diff --git a/substrate/client/consensus/pow/src/lib.rs b/substrate/client/consensus/pow/src/lib.rs index ee5c1dfc6f11a26599c0f01efee9224caded43cd..50e9533abb36ab24e5d4942d154a378f84c4beec 100644 --- a/substrate/client/consensus/pow/src/lib.rs +++ b/substrate/client/consensus/pow/src/lib.rs @@ -312,10 +312,7 @@ where { type Error = ConsensusError; - async fn check_block( - &mut self, - block: BlockCheckParams, - ) -> Result { + async fn check_block(&self, block: BlockCheckParams) -> Result { self.inner.check_block(block).await.map_err(Into::into) } @@ -442,7 +439,7 @@ where Algorithm::Difficulty: 'static + Send, { async fn verify( - &mut self, + &self, mut block: BlockImportParams, ) -> Result, String> { let hash = block.header.hash(); diff --git a/substrate/client/consensus/slots/Cargo.toml b/substrate/client/consensus/slots/Cargo.toml index 8e88ee68d7d739a888f3b0e32b7a8fee3ac1e41c..2b795b13f8e338d6ed982ef2bd261e76336e683d 100644 --- a/substrate/client/consensus/slots/Cargo.toml +++ b/substrate/client/consensus/slots/Cargo.toml @@ -17,22 +17,22 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.12" } -futures = "0.3.30" -futures-timer = "3.0.1" +async-trait = { workspace = true } +codec = { workspace = true, default-features = true } +futures = { workspace = true } +futures-timer = { workspace = true } log = { workspace = true, default-features = true } -sc-client-api = { path = "../../api" } -sc-consensus = { path = "../common" } -sc-telemetry = { path = "../../telemetry" } -sp-arithmetic = { path = "../../../primitives/arithmetic" } -sp-blockchain = { path = "../../../primitives/blockchain" } -sp-consensus = { path = "../../../primitives/consensus/common" } -sp-consensus-slots = { path = "../../../primitives/consensus/slots" } -sp-core = { path = "../../../primitives/core" } -sp-inherents = { path = "../../../primitives/inherents" } -sp-runtime = { path = "../../../primitives/runtime" } -sp-state-machine = { path = "../../../primitives/state-machine" } +sc-client-api = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sc-telemetry = { workspace = true, default-features = true } +sp-arithmetic = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-consensus-slots = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } [dev-dependencies] -substrate-test-runtime-client = { path = "../../../test-utils/runtime/client" } +substrate-test-runtime-client = { workspace = true } diff --git a/substrate/client/consensus/slots/src/lib.rs b/substrate/client/consensus/slots/src/lib.rs index d9d792005312503f48bb2d628235794952104ccd..7cdf90877dffad20f91a1d1f846648cc22dfe4ea 100644 --- a/substrate/client/consensus/slots/src/lib.rs +++ b/substrate/client/consensus/slots/src/lib.rs @@ -29,8 +29,8 @@ mod aux_schema; mod slots; pub use aux_schema::{check_equivocation, MAX_SLOT_CAPACITY, PRUNING_BOUND}; -pub use slots::SlotInfo; use slots::Slots; +pub use slots::{time_until_next_slot, SlotInfo}; use futures::{future::Either, Future, TryFutureExt}; use futures_timer::Delay; diff --git a/substrate/client/db/Cargo.toml b/substrate/client/db/Cargo.toml index b10c42d50f0bcbf9aed764a2df85cffe7c6baf66..c8372701ac3290377ae54f0aed7c7eb8ed781511 100644 --- a/substrate/client/db/Cargo.toml +++ b/substrate/client/db/Cargo.toml @@ -16,38 +16,38 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.12", features = [ +codec = { features = [ "derive", -] } -hash-db = "0.16.0" -kvdb = "0.13.0" -kvdb-memorydb = "0.13.0" -kvdb-rocksdb = { version = "0.19.0", optional = true } -linked-hash-map = "0.5.4" +], workspace = true, default-features = true } +hash-db = { workspace = true, default-features = true } +kvdb = { workspace = true } +kvdb-memorydb = { workspace = true } +kvdb-rocksdb = { optional = true, workspace = true } +linked-hash-map = { workspace = true } log = { workspace = true, default-features = true } -parity-db = "0.4.12" -parking_lot = "0.12.1" -sc-client-api = { path = "../api" } -sc-state-db = { path = "../state-db" } -schnellru = "0.2.1" -sp-arithmetic = { path = "../../primitives/arithmetic" } -sp-blockchain = { path = "../../primitives/blockchain" } -sp-core = { path = "../../primitives/core" } -sp-database = { path = "../../primitives/database" } -sp-runtime = { path = "../../primitives/runtime" } -sp-state-machine = { path = "../../primitives/state-machine" } -sp-trie = { path = "../../primitives/trie" } +parity-db = { workspace = true } +parking_lot = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-state-db = { workspace = true, default-features = true } +schnellru = { workspace = true } +sp-arithmetic = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-database = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } +sp-trie = { workspace = true, default-features = true } [dev-dependencies] -criterion = "0.5.1" -kvdb-rocksdb = "0.19.0" -rand = "0.8.5" -tempfile = "3.1.0" -quickcheck = { version = "1.0.3", default-features = false } -kitchensink-runtime = { path = "../../bin/node/runtime" } -sp-tracing = { path = "../../primitives/tracing" } -substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } -array-bytes = "6.2.2" +criterion = { workspace = true, default-features = true } +kvdb-rocksdb = { workspace = true } +rand = { workspace = true, default-features = true } +tempfile = { workspace = true } +quickcheck = { workspace = true } +kitchensink-runtime = { workspace = true } +sp-tracing = { workspace = true, default-features = true } +substrate-test-runtime-client = { workspace = true } +array-bytes = { workspace = true, default-features = true } [features] default = [] diff --git a/substrate/client/db/src/lib.rs b/substrate/client/db/src/lib.rs index 8d8b7a2aff88f88a3f034845a3422bad51258e69..ba0cbc09d53dad38939efd4017da27ecd48f213a 100644 --- a/substrate/client/db/src/lib.rs +++ b/substrate/client/db/src/lib.rs @@ -1357,6 +1357,8 @@ impl Backend { Ok(()) } + /// `remove_displaced` can be set to `false` if this is not the last of many subsequent calls + /// for performance reasons. fn finalize_block_with_transaction( &self, transaction: &mut Transaction, @@ -1365,6 +1367,7 @@ impl Backend { last_finalized: Option, justification: Option, current_transaction_justifications: &mut HashMap, + remove_displaced: bool, ) -> ClientResult> { // TODO: ensure best chain contains this block. let number = *header.number(); @@ -1377,6 +1380,7 @@ impl Backend { hash, with_state, current_transaction_justifications, + remove_displaced, )?; if let Some(justification) = justification { @@ -1454,7 +1458,8 @@ impl Backend { let mut current_transaction_justifications: HashMap = HashMap::new(); - for (block_hash, justification) in operation.finalized_blocks { + let mut finalized_blocks = operation.finalized_blocks.into_iter().peekable(); + while let Some((block_hash, justification)) = finalized_blocks.next() { let block_header = self.blockchain.expect_header(block_hash)?; meta_updates.push(self.finalize_block_with_transaction( &mut transaction, @@ -1463,6 +1468,7 @@ impl Backend { Some(last_finalized_hash), justification, &mut current_transaction_justifications, + finalized_blocks.peek().is_none(), )?); last_finalized_hash = block_hash; last_finalized_num = *block_header.number(); @@ -1642,6 +1648,7 @@ impl Backend { hash, operation.commit_state, &mut current_transaction_justifications, + true, )?; } else { // canonicalize blocks which are old enough, regardless of finality. @@ -1766,9 +1773,10 @@ impl Backend { Ok(()) } - // write stuff to a transaction after a new block is finalized. - // this canonicalizes finalized blocks. Fails if called with a block which - // was not a child of the last finalized block. + // Write stuff to a transaction after a new block is finalized. This canonicalizes finalized + // blocks. Fails if called with a block which was not a child of the last finalized block. + /// `remove_displaced` can be set to `false` if this is not the last of many subsequent calls + /// for performance reasons. fn note_finalized( &self, transaction: &mut Transaction, @@ -1776,6 +1784,7 @@ impl Backend { f_hash: Block::Hash, with_state: bool, current_transaction_justifications: &mut HashMap, + remove_displaced: bool, ) -> ClientResult<()> { let f_num = *f_header.number(); @@ -1800,13 +1809,19 @@ impl Backend { apply_state_commit(transaction, commit); } - let new_displaced = self.blockchain.displaced_leaves_after_finalizing(f_hash, f_num)?; - let finalization_outcome = - FinalizationOutcome::new(new_displaced.displaced_leaves.clone().into_iter()); + if remove_displaced { + let new_displaced = self.blockchain.displaced_leaves_after_finalizing(f_hash, f_num)?; - self.blockchain.leaves.write().remove_displaced_leaves(&finalization_outcome); + self.blockchain.leaves.write().remove_displaced_leaves(FinalizationOutcome::new( + new_displaced.displaced_leaves.iter().copied(), + )); - self.prune_blocks(transaction, f_num, &new_displaced, current_transaction_justifications)?; + if !matches!(self.blocks_pruning, BlocksPruning::KeepAll) { + self.prune_displaced_branches(transaction, &new_displaced)?; + } + } + + self.prune_blocks(transaction, f_num, current_transaction_justifications)?; Ok(()) } @@ -1815,39 +1830,29 @@ impl Backend { &self, transaction: &mut Transaction, finalized_number: NumberFor, - displaced: &DisplacedLeavesAfterFinalization, current_transaction_justifications: &mut HashMap, ) -> ClientResult<()> { - match self.blocks_pruning { - BlocksPruning::KeepAll => {}, - BlocksPruning::Some(blocks_pruning) => { - // Always keep the last finalized block - let keep = std::cmp::max(blocks_pruning, 1); - if finalized_number >= keep.into() { - let number = finalized_number.saturating_sub(keep.into()); - - // Before we prune a block, check if it is pinned - if let Some(hash) = self.blockchain.hash(number)? { - self.blockchain.insert_persisted_body_if_pinned(hash)?; - - // If the block was finalized in this transaction, it will not be in the db - // yet. - if let Some(justification) = - current_transaction_justifications.remove(&hash) - { - self.blockchain.insert_justifications_if_pinned(hash, justification); - } else { - self.blockchain.insert_persisted_justifications_if_pinned(hash)?; - } - }; + if let BlocksPruning::Some(blocks_pruning) = self.blocks_pruning { + // Always keep the last finalized block + let keep = std::cmp::max(blocks_pruning, 1); + if finalized_number >= keep.into() { + let number = finalized_number.saturating_sub(keep.into()); + + // Before we prune a block, check if it is pinned + if let Some(hash) = self.blockchain.hash(number)? { + self.blockchain.insert_persisted_body_if_pinned(hash)?; + + // If the block was finalized in this transaction, it will not be in the db + // yet. + if let Some(justification) = current_transaction_justifications.remove(&hash) { + self.blockchain.insert_justifications_if_pinned(hash, justification); + } else { + self.blockchain.insert_persisted_justifications_if_pinned(hash)?; + } + }; - self.prune_block(transaction, BlockId::::number(number))?; - } - self.prune_displaced_branches(transaction, displaced)?; - }, - BlocksPruning::KeepFinalized => { - self.prune_displaced_branches(transaction, displaced)?; - }, + self.prune_block(transaction, BlockId::::number(number))?; + } } Ok(()) } @@ -1858,11 +1863,9 @@ impl Backend { displaced: &DisplacedLeavesAfterFinalization, ) -> ClientResult<()> { // Discard all blocks from displaced branches - for (_, tree_route) in displaced.tree_routes.iter() { - for r in tree_route.retracted() { - self.blockchain.insert_persisted_body_if_pinned(r.hash)?; - self.prune_block(transaction, BlockId::::hash(r.hash))?; - } + for &hash in displaced.displaced_blocks.iter() { + self.blockchain.insert_persisted_body_if_pinned(hash)?; + self.prune_block(transaction, BlockId::::hash(hash))?; } Ok(()) } @@ -2110,6 +2113,7 @@ impl sc_client_api::backend::Backend for Backend { None, justification, &mut current_transaction_justifications, + true, )?; self.storage.db.commit(transaction)?; @@ -2547,7 +2551,7 @@ pub(crate) mod tests { backend::{Backend as BTrait, BlockImportOperation as Op}, blockchain::Backend as BLBTrait, }; - use sp_blockchain::{lowest_common_ancestor, lowest_common_ancestor_multiblock, tree_route}; + use sp_blockchain::{lowest_common_ancestor, tree_route}; use sp_core::H256; use sp_runtime::{ testing::{Block as RawBlock, ExtrinsicWrapper, Header}, @@ -2609,6 +2613,35 @@ pub(crate) mod tests { Ok(header.hash()) } + pub fn insert_disconnected_header( + backend: &Backend, + number: u64, + parent_hash: H256, + extrinsics_root: H256, + best: bool, + ) -> H256 { + use sp_runtime::testing::Digest; + + let digest = Digest::default(); + let header = + Header { number, parent_hash, state_root: Default::default(), digest, extrinsics_root }; + + let mut op = backend.begin_operation().unwrap(); + + op.set_block_data( + header.clone(), + Some(vec![]), + None, + None, + if best { NewBlockState::Best } else { NewBlockState::Normal }, + ) + .unwrap(); + + backend.commit_operation(op).unwrap(); + + header.hash() + } + pub fn insert_header_no_head( backend: &Backend, number: u64, @@ -3109,121 +3142,244 @@ pub(crate) mod tests { } #[test] - fn lowest_common_ancestors_multiblock_works() { + fn displaced_leaves_after_finalizing_works_with_disconnect() { + // In this test we will create a situation that can typically happen after warp sync. + // The situation looks like this: + // g -> -> a3 -> a4 + // Basically there is a gap of unimported blocks at some point in the chain. let backend = Backend::::new_test(1000, 100); let blockchain = backend.blockchain(); - let block0 = insert_header(&backend, 0, Default::default(), None, Default::default()); - - // fork from genesis: 3 prong. - // block 0 -> a1 -> a2 -> a3 - // | - // -> b1 -> b2 -> c1 -> c2 - // | - // -> d1 -> d2 - let a1 = insert_header(&backend, 1, block0, None, Default::default()); - let a2 = insert_header(&backend, 2, a1, None, Default::default()); - let a3 = insert_header(&backend, 3, a2, None, Default::default()); - - // fork from genesis: 2 prong. - let b1 = insert_header(&backend, 1, block0, None, H256::from([1; 32])); - let b2 = insert_header(&backend, 2, b1, None, Default::default()); + let genesis_number = 0; + let genesis_hash = + insert_header(&backend, genesis_number, Default::default(), None, Default::default()); - // fork from b2. - let c1 = insert_header(&backend, 3, b2, None, H256::from([2; 32])); - let c2 = insert_header(&backend, 4, c1, None, Default::default()); + let a3_number = 3; + let a3_hash = insert_disconnected_header( + &backend, + a3_number, + H256::from([200; 32]), + H256::from([1; 32]), + true, + ); - // fork from b1. - let d1 = insert_header(&backend, 2, b1, None, H256::from([3; 32])); - let d2 = insert_header(&backend, 3, d1, None, Default::default()); + let a4_number = 4; + let a4_hash = + insert_disconnected_header(&backend, a4_number, a3_hash, H256::from([2; 32]), true); { - let lca = lowest_common_ancestor_multiblock(blockchain, vec![a3, b2]).unwrap().unwrap(); - - assert_eq!(lca.hash, block0); - assert_eq!(lca.number, 0); + let displaced = + blockchain.displaced_leaves_after_finalizing(a3_hash, a3_number).unwrap(); + assert_eq!(blockchain.leaves().unwrap(), vec![a4_hash, genesis_hash]); + assert_eq!(displaced.displaced_leaves, vec![(genesis_number, genesis_hash)]); + assert_eq!(displaced.displaced_blocks, vec![]); } { - let lca = lowest_common_ancestor_multiblock(blockchain, vec![a1, a3]).unwrap().unwrap(); - - assert_eq!(lca.hash, a1); - assert_eq!(lca.number, 1); + let displaced = + blockchain.displaced_leaves_after_finalizing(a4_hash, a4_number).unwrap(); + assert_eq!(blockchain.leaves().unwrap(), vec![a4_hash, genesis_hash]); + assert_eq!(displaced.displaced_leaves, vec![(genesis_number, genesis_hash)]); + assert_eq!(displaced.displaced_blocks, vec![]); } + // Import block a1 which has the genesis block as parent. + // g -> a1 -> -> a3(f) -> a4 + let a1_number = 1; + let a1_hash = insert_disconnected_header( + &backend, + a1_number, + genesis_hash, + H256::from([123; 32]), + false, + ); { - let lca = lowest_common_ancestor_multiblock(blockchain, vec![a3, a1]).unwrap().unwrap(); - - assert_eq!(lca.hash, a1); - assert_eq!(lca.number, 1); + let displaced = + blockchain.displaced_leaves_after_finalizing(a3_hash, a3_number).unwrap(); + assert_eq!(blockchain.leaves().unwrap(), vec![a4_hash, a1_hash]); + assert_eq!(displaced.displaced_leaves, vec![]); + assert_eq!(displaced.displaced_blocks, vec![]); } + // Import block b1 which has the genesis block as parent. + // g -> a1 -> -> a3(f) -> a4 + // \-> b1 + let b1_number = 1; + let b1_hash = insert_disconnected_header( + &backend, + b1_number, + genesis_hash, + H256::from([124; 32]), + false, + ); { - let lca = lowest_common_ancestor_multiblock(blockchain, vec![a2, a3]).unwrap().unwrap(); - - assert_eq!(lca.hash, a2); - assert_eq!(lca.number, 2); + let displaced = + blockchain.displaced_leaves_after_finalizing(a3_hash, a3_number).unwrap(); + assert_eq!(blockchain.leaves().unwrap(), vec![a4_hash, a1_hash, b1_hash]); + assert_eq!(displaced.displaced_leaves, vec![]); + assert_eq!(displaced.displaced_blocks, vec![]); } + // If branch of b blocks is higher in number than a branch, we + // should still not prune disconnected leafs. + // g -> a1 -> -> a3(f) -> a4 + // \-> b1 -> b2 ----------> b3 ----> b4 -> b5 + let b2_number = 2; + let b2_hash = + insert_disconnected_header(&backend, b2_number, b1_hash, H256::from([40; 32]), false); + let b3_number = 3; + let b3_hash = + insert_disconnected_header(&backend, b3_number, b2_hash, H256::from([41; 32]), false); + let b4_number = 4; + let b4_hash = + insert_disconnected_header(&backend, b4_number, b3_hash, H256::from([42; 32]), false); + let b5_number = 5; + let b5_hash = + insert_disconnected_header(&backend, b5_number, b4_hash, H256::from([43; 32]), false); { - let lca = lowest_common_ancestor_multiblock(blockchain, vec![a2, a1]).unwrap().unwrap(); - - assert_eq!(lca.hash, a1); - assert_eq!(lca.number, 1); + let displaced = + blockchain.displaced_leaves_after_finalizing(a3_hash, a3_number).unwrap(); + assert_eq!(blockchain.leaves().unwrap(), vec![b5_hash, a4_hash, a1_hash]); + assert_eq!(displaced.displaced_leaves, vec![]); + assert_eq!(displaced.displaced_blocks, vec![]); } + // Even though there is a disconnect, diplace should still detect + // branches above the block gap. + // /-> c4 + // g -> a1 -> -> a3 -> a4(f) + // \-> b1 -> b2 ----------> b3 -> b4 -> b5 + let c4_number = 4; + let c4_hash = + insert_disconnected_header(&backend, c4_number, a3_hash, H256::from([44; 32]), false); { - let lca = lowest_common_ancestor_multiblock(blockchain, vec![a2, a2]).unwrap().unwrap(); - - assert_eq!(lca.hash, a2); - assert_eq!(lca.number, 2); + let displaced = + blockchain.displaced_leaves_after_finalizing(a4_hash, a4_number).unwrap(); + assert_eq!(blockchain.leaves().unwrap(), vec![b5_hash, a4_hash, c4_hash, a1_hash]); + assert_eq!(displaced.displaced_leaves, vec![(c4_number, c4_hash)]); + assert_eq!(displaced.displaced_blocks, vec![c4_hash]); } + } + #[test] + fn displaced_leaves_after_finalizing_works() { + let backend = Backend::::new_test(1000, 100); + let blockchain = backend.blockchain(); + let genesis_number = 0; + let genesis_hash = + insert_header(&backend, genesis_number, Default::default(), None, Default::default()); + + // fork from genesis: 3 prong. + // block 0 -> a1 -> a2 -> a3 + // \ + // -> b1 -> b2 -> c1 -> c2 + // \ + // -> d1 -> d2 + let a1_number = 1; + let a1_hash = insert_header(&backend, a1_number, genesis_hash, None, Default::default()); + let a2_number = 2; + let a2_hash = insert_header(&backend, a2_number, a1_hash, None, Default::default()); + let a3_number = 3; + let a3_hash = insert_header(&backend, a3_number, a2_hash, None, Default::default()); { - let lca = lowest_common_ancestor_multiblock(blockchain, vec![a3, d2, c2]) - .unwrap() + let displaced = blockchain + .displaced_leaves_after_finalizing(genesis_hash, genesis_number) .unwrap(); - - assert_eq!(lca.hash, block0); - assert_eq!(lca.number, 0); + assert_eq!(displaced.displaced_leaves, vec![]); + assert_eq!(displaced.displaced_blocks, vec![]); } - { - let lca = lowest_common_ancestor_multiblock(blockchain, vec![c2, d2, b2]) - .unwrap() - .unwrap(); - - assert_eq!(lca.hash, b1); - assert_eq!(lca.number, 1); + let displaced_a1 = + blockchain.displaced_leaves_after_finalizing(a1_hash, a1_number).unwrap(); + assert_eq!(displaced_a1.displaced_leaves, vec![]); + assert_eq!(displaced_a1.displaced_blocks, vec![]); + + let displaced_a2 = + blockchain.displaced_leaves_after_finalizing(a2_hash, a3_number).unwrap(); + assert_eq!(displaced_a2.displaced_leaves, vec![]); + assert_eq!(displaced_a2.displaced_blocks, vec![]); + + let displaced_a3 = + blockchain.displaced_leaves_after_finalizing(a3_hash, a3_number).unwrap(); + assert_eq!(displaced_a3.displaced_leaves, vec![]); + assert_eq!(displaced_a3.displaced_blocks, vec![]); } - { - let lca = lowest_common_ancestor_multiblock(blockchain, vec![a1, a2, a3]) - .unwrap() - .unwrap(); - - assert_eq!(lca.hash, a1); - assert_eq!(lca.number, 1); + // Finalized block is above leaves and not imported yet. + // We will not be able to make a connection, + // nothing can be marked as displaced. + let displaced = + blockchain.displaced_leaves_after_finalizing(H256::from([57; 32]), 10).unwrap(); + assert_eq!(displaced.displaced_leaves, vec![]); + assert_eq!(displaced.displaced_blocks, vec![]); } - { - let lca = lowest_common_ancestor_multiblock(blockchain, vec![b1, b2, d1]) - .unwrap() - .unwrap(); + // fork from genesis: 2 prong. + let b1_number = 1; + let b1_hash = insert_header(&backend, b1_number, genesis_hash, None, H256::from([1; 32])); + let b2_number = 2; + let b2_hash = insert_header(&backend, b2_number, b1_hash, None, Default::default()); - assert_eq!(lca.hash, b1); - assert_eq!(lca.number, 1); - } + // fork from b2. + let c1_number = 3; + let c1_hash = insert_header(&backend, c1_number, b2_hash, None, H256::from([2; 32])); + let c2_number = 4; + let c2_hash = insert_header(&backend, c2_number, c1_hash, None, Default::default()); - { - let lca = lowest_common_ancestor_multiblock(blockchain, vec![]); + // fork from b1. + let d1_number = 2; + let d1_hash = insert_header(&backend, d1_number, b1_hash, None, H256::from([3; 32])); + let d2_number = 3; + let d2_hash = insert_header(&backend, d2_number, d1_hash, None, Default::default()); - assert_eq!(true, matches!(lca, Ok(None))); + { + let displaced_a1 = + blockchain.displaced_leaves_after_finalizing(a1_hash, a1_number).unwrap(); + assert_eq!( + displaced_a1.displaced_leaves, + vec![(c2_number, c2_hash), (d2_number, d2_hash)] + ); + let mut displaced_blocks = vec![b1_hash, b2_hash, c1_hash, c2_hash, d1_hash, d2_hash]; + displaced_blocks.sort(); + assert_eq!(displaced_a1.displaced_blocks, displaced_blocks); + + let displaced_a2 = + blockchain.displaced_leaves_after_finalizing(a2_hash, a2_number).unwrap(); + assert_eq!(displaced_a1.displaced_leaves, displaced_a2.displaced_leaves); + assert_eq!(displaced_a1.displaced_blocks, displaced_a2.displaced_blocks); + + let displaced_a3 = + blockchain.displaced_leaves_after_finalizing(a3_hash, a3_number).unwrap(); + assert_eq!(displaced_a1.displaced_leaves, displaced_a3.displaced_leaves); + assert_eq!(displaced_a1.displaced_blocks, displaced_a3.displaced_blocks); } - { - let lca = lowest_common_ancestor_multiblock(blockchain, vec![a1]).unwrap().unwrap(); - - assert_eq!(lca.hash, a1); - assert_eq!(lca.number, 1); + let displaced = + blockchain.displaced_leaves_after_finalizing(b1_hash, b1_number).unwrap(); + assert_eq!(displaced.displaced_leaves, vec![(a3_number, a3_hash)]); + let mut displaced_blocks = vec![a1_hash, a2_hash, a3_hash]; + displaced_blocks.sort(); + assert_eq!(displaced.displaced_blocks, displaced_blocks); + } + { + let displaced = + blockchain.displaced_leaves_after_finalizing(b2_hash, b2_number).unwrap(); + assert_eq!( + displaced.displaced_leaves, + vec![(a3_number, a3_hash), (d2_number, d2_hash)] + ); + let mut displaced_blocks = vec![a1_hash, a2_hash, a3_hash, d1_hash, d2_hash]; + displaced_blocks.sort(); + assert_eq!(displaced.displaced_blocks, displaced_blocks); + } + { + let displaced = + blockchain.displaced_leaves_after_finalizing(c2_hash, c2_number).unwrap(); + assert_eq!( + displaced.displaced_leaves, + vec![(a3_number, a3_hash), (d2_number, d2_hash)] + ); + let mut displaced_blocks = vec![a1_hash, a2_hash, a3_hash, d1_hash, d2_hash]; + displaced_blocks.sort(); + assert_eq!(displaced.displaced_blocks, displaced_blocks); } } diff --git a/substrate/client/executor/Cargo.toml b/substrate/client/executor/Cargo.toml index 1f54b82030ff226b179afe8f167e134417b859e9..c10c60822ff8dbec0b3ac800a1c3c2b0a3d8b0d8 100644 --- a/substrate/client/executor/Cargo.toml +++ b/substrate/client/executor/Cargo.toml @@ -17,43 +17,43 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -parking_lot = "0.12.1" -schnellru = "0.2.1" -tracing = "0.1.29" +parking_lot = { workspace = true, default-features = true } +schnellru = { workspace = true } +tracing = { workspace = true, default-features = true } -codec = { package = "parity-scale-codec", version = "3.6.12" } -sc-executor-common = { path = "common" } -sc-executor-polkavm = { path = "polkavm" } -sc-executor-wasmtime = { path = "wasmtime" } -sp-api = { path = "../../primitives/api" } -sp-core = { path = "../../primitives/core" } -sp-externalities = { path = "../../primitives/externalities" } -sp-io = { path = "../../primitives/io" } -sp-panic-handler = { path = "../../primitives/panic-handler" } -sp-runtime-interface = { path = "../../primitives/runtime-interface" } -sp-trie = { path = "../../primitives/trie" } -sp-version = { path = "../../primitives/version" } -sp-wasm-interface = { path = "../../primitives/wasm-interface" } +codec = { workspace = true, default-features = true } +sc-executor-common = { workspace = true, default-features = true } +sc-executor-polkavm = { workspace = true, default-features = true } +sc-executor-wasmtime = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-externalities = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-panic-handler = { workspace = true, default-features = true } +sp-runtime-interface = { workspace = true, default-features = true } +sp-trie = { workspace = true, default-features = true } +sp-version = { workspace = true, default-features = true } +sp-wasm-interface = { workspace = true, default-features = true } [dev-dependencies] -array-bytes = "6.2.2" -assert_matches = "1.3.0" -wat = "1.0" -sc-runtime-test = { path = "runtime-test" } -substrate-test-runtime = { path = "../../test-utils/runtime" } -sp-crypto-hashing = { path = "../../primitives/crypto/hashing" } -sp-state-machine = { path = "../../primitives/state-machine" } -sp-runtime = { path = "../../primitives/runtime" } -sp-maybe-compressed-blob = { path = "../../primitives/maybe-compressed-blob" } -sc-tracing = { path = "../tracing" } -sp-tracing = { path = "../../primitives/tracing" } +array-bytes = { workspace = true, default-features = true } +assert_matches = { workspace = true } +wat = { workspace = true } +sc-runtime-test = { workspace = true } +substrate-test-runtime = { workspace = true } +sp-crypto-hashing = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-maybe-compressed-blob = { workspace = true, default-features = true } +sc-tracing = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } tracing-subscriber = { workspace = true } -paste = "1.0" -regex = "1.6.0" -criterion = "0.5.1" -env_logger = "0.11" -num_cpus = "1.13.1" -tempfile = "3.3.0" +paste = { workspace = true, default-features = true } +regex = { workspace = true } +criterion = { workspace = true, default-features = true } +env_logger = { workspace = true } +num_cpus = { workspace = true } +tempfile = { workspace = true } [[bench]] name = "bench" diff --git a/substrate/client/executor/common/Cargo.toml b/substrate/client/executor/common/Cargo.toml index 8ff34c3709a5e486fb9036a638788a532c6f296c..e985c75ca908a669f0ff7e6cc7368269e0814343 100644 --- a/substrate/client/executor/common/Cargo.toml +++ b/substrate/client/executor/common/Cargo.toml @@ -18,10 +18,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] thiserror = { workspace = true } -wasm-instrument = "0.4" -sc-allocator = { path = "../../allocator" } -sp-maybe-compressed-blob = { path = "../../../primitives/maybe-compressed-blob" } -sp-wasm-interface = { path = "../../../primitives/wasm-interface" } +wasm-instrument = { workspace = true, default-features = true } +sc-allocator = { workspace = true, default-features = true } +sp-maybe-compressed-blob = { workspace = true, default-features = true } +sp-wasm-interface = { workspace = true, default-features = true } polkavm = { workspace = true } [features] diff --git a/substrate/client/executor/polkavm/Cargo.toml b/substrate/client/executor/polkavm/Cargo.toml index 9d0eb8ccf0ee072c86195068a589309edd132ba4..8b849209a07cf17838c89e32cc53fcb80fe3c6ab 100644 --- a/substrate/client/executor/polkavm/Cargo.toml +++ b/substrate/client/executor/polkavm/Cargo.toml @@ -19,5 +19,5 @@ targets = ["x86_64-unknown-linux-gnu"] log = { workspace = true } polkavm = { workspace = true } -sc-executor-common = { path = "../common" } -sp-wasm-interface = { path = "../../../primitives/wasm-interface" } +sc-executor-common = { workspace = true, default-features = true } +sp-wasm-interface = { workspace = true, default-features = true } diff --git a/substrate/client/executor/runtime-test/Cargo.toml b/substrate/client/executor/runtime-test/Cargo.toml index 82610c4f50c2841fea13c1f859cc242f8ae427c7..d132f47ff877f3c05580326e832a72c34676f7da 100644 --- a/substrate/client/executor/runtime-test/Cargo.toml +++ b/substrate/client/executor/runtime-test/Cargo.toml @@ -16,14 +16,13 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { path = "../../../primitives/core", default-features = false } -sp-io = { path = "../../../primitives/io", default-features = false, features = ["improved_panic_error_reporting"] } -sp-runtime = { path = "../../../primitives/runtime", default-features = false } -sp-runtime-interface = { path = "../../../primitives/runtime-interface", default-features = false } -sp-std = { path = "../../../primitives/std", default-features = false } +sp-core = { workspace = true } +sp-io = { features = ["improved_panic_error_reporting"], workspace = true } +sp-runtime = { workspace = true } +sp-runtime-interface = { workspace = true } [build-dependencies] -substrate-wasm-builder = { path = "../../../utils/wasm-builder", optional = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [features] default = ["std"] @@ -32,6 +31,5 @@ std = [ "sp-io/std", "sp-runtime-interface/std", "sp-runtime/std", - "sp-std/std", "substrate-wasm-builder", ] diff --git a/substrate/client/executor/runtime-test/src/lib.rs b/substrate/client/executor/runtime-test/src/lib.rs index 40683fbb664aadb6daf68595befcc68881322f05..08a5e39dff2cfdca2a2f3629caf939e836ef3144 100644 --- a/substrate/client/executor/runtime-test/src/lib.rs +++ b/substrate/client/executor/runtime-test/src/lib.rs @@ -32,7 +32,10 @@ pub fn wasm_binary_unwrap() -> &'static [u8] { } #[cfg(not(feature = "std"))] -use sp_std::{vec, vec::Vec}; +extern crate alloc; + +#[cfg(not(feature = "std"))] +use alloc::{vec, vec::Vec}; #[cfg(not(feature = "std"))] use sp_core::{ed25519, sr25519}; @@ -332,7 +335,7 @@ sp_core::wasm_export_functions! { let test_message = b"Hello invalid heap memory"; let ptr = (heap_base + offset) as *mut u8; - let message_slice = unsafe { sp_std::slice::from_raw_parts_mut(ptr, test_message.len()) }; + let message_slice = unsafe { alloc::slice::from_raw_parts_mut(ptr, test_message.len()) }; assert_ne!(test_message, message_slice); message_slice.copy_from_slice(test_message); diff --git a/substrate/client/executor/wasmtime/Cargo.toml b/substrate/client/executor/wasmtime/Cargo.toml index d3d670650db789b2b9b854a5fda8724a506833ee..e58b19bb12431a3ffb5b9fc77526b523e7cf4863 100644 --- a/substrate/client/executor/wasmtime/Cargo.toml +++ b/substrate/client/executor/wasmtime/Cargo.toml @@ -17,24 +17,24 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { workspace = true, default-features = true } -cfg-if = "1.0" -libc = "0.2.152" -parking_lot = "0.12.1" +cfg-if = { workspace = true } +libc = { workspace = true } +parking_lot = { workspace = true, default-features = true } # When bumping wasmtime do not forget to also bump rustix # to exactly the same version as used by wasmtime! -wasmtime = { version = "8.0.1", default-features = false, features = [ +wasmtime = { features = [ "cache", "cranelift", "jitdump", "parallel-compilation", "pooling-allocator", -] } -anyhow = "1.0.81" -sc-allocator = { path = "../../allocator" } -sc-executor-common = { path = "../common" } -sp-runtime-interface = { path = "../../../primitives/runtime-interface" } -sp-wasm-interface = { path = "../../../primitives/wasm-interface", features = ["wasmtime"] } +], workspace = true } +anyhow = { workspace = true } +sc-allocator = { workspace = true, default-features = true } +sc-executor-common = { workspace = true, default-features = true } +sp-runtime-interface = { workspace = true, default-features = true } +sp-wasm-interface = { features = ["wasmtime"], workspace = true, default-features = true } # Here we include the rustix crate in the exactly same semver-compatible version as used by # wasmtime and enable its 'use-libc' flag. @@ -42,13 +42,13 @@ sp-wasm-interface = { path = "../../../primitives/wasm-interface", features = [" # By default rustix directly calls the appropriate syscalls completely bypassing libc; # this doesn't have any actual benefits for us besides making it harder to debug memory # problems (since then `mmap` etc. cannot be easily hooked into). -rustix = { version = "0.36.7", default-features = false, features = ["fs", "mm", "param", "std", "use-libc"] } +rustix = { features = ["fs", "mm", "param", "std", "use-libc"], workspace = true } [dev-dependencies] -wat = "1.0" -sc-runtime-test = { path = "../runtime-test" } -sp-io = { path = "../../../primitives/io" } -tempfile = "3.3.0" -paste = "1.0" -codec = { package = "parity-scale-codec", version = "3.6.12" } -cargo_metadata = "0.15.4" +wat = { workspace = true } +sc-runtime-test = { workspace = true } +sp-io = { workspace = true, default-features = true } +tempfile = { workspace = true } +paste = { workspace = true, default-features = true } +codec = { workspace = true, default-features = true } +cargo_metadata = { workspace = true } diff --git a/substrate/client/informant/Cargo.toml b/substrate/client/informant/Cargo.toml index 191ef5f19f8df65b3c817129fe34c4db7438826d..aa54d9479f5c51038c5bbf0038b4b981e32e2806 100644 --- a/substrate/client/informant/Cargo.toml +++ b/substrate/client/informant/Cargo.toml @@ -16,13 +16,13 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -ansi_term = "0.12.1" -futures = "0.3.30" -futures-timer = "3.0.1" +console = { workspace = true } +futures = { workspace = true } +futures-timer = { workspace = true } log = { workspace = true, default-features = true } -sc-client-api = { path = "../api" } -sc-network-common = { path = "../network/common" } -sc-network-sync = { path = "../network/sync" } -sc-network = { path = "../network" } -sp-blockchain = { path = "../../primitives/blockchain" } -sp-runtime = { path = "../../primitives/runtime" } +sc-client-api = { workspace = true, default-features = true } +sc-network-common = { workspace = true, default-features = true } +sc-network-sync = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } diff --git a/substrate/client/informant/src/display.rs b/substrate/client/informant/src/display.rs index cdbb83b6596c2f235c5513d6e11a04fe4c6a793f..655bf21c71154a457320a1e7eda2783e70d686f0 100644 --- a/substrate/client/informant/src/display.rs +++ b/substrate/client/informant/src/display.rs @@ -16,8 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::OutputFormat; -use ansi_term::Colour; +use console::style; use log::info; use sc_client_api::ClientInfo; use sc_network::NetworkStatus; @@ -47,19 +46,16 @@ pub struct InformantDisplay { last_total_bytes_inbound: u64, /// The last seen total of bytes sent. last_total_bytes_outbound: u64, - /// The format to print output in. - format: OutputFormat, } impl InformantDisplay { /// Builds a new informant display system. - pub fn new(format: OutputFormat) -> InformantDisplay { + pub fn new() -> InformantDisplay { InformantDisplay { last_number: None, last_update: Instant::now(), last_total_bytes_inbound: 0, last_total_bytes_outbound: 0, - format, } } @@ -144,17 +140,17 @@ impl InformantDisplay { info!( target: "substrate", - "{} {}{} ({} peers), best: #{} ({}), finalized #{} ({}), {} {}", + "{} {}{} ({} peers), best: #{} ({}), finalized #{} ({}), โฌ‡ {} โฌ† {}", level, - self.format.print_with_color(Colour::White.bold(), status), + style(&status).white().bold(), target, - self.format.print_with_color(Colour::White.bold(), num_connected_peers), - self.format.print_with_color(Colour::White.bold(), best_number), + style(num_connected_peers).white().bold(), + style(best_number).white().bold(), best_hash, - self.format.print_with_color(Colour::White.bold(), finalized_number), + style(finalized_number).white().bold(), info.chain.finalized_hash, - self.format.print_with_color(Colour::Green, format!("โฌ‡ {}", TransferRateFormat(avg_bytes_per_sec_inbound))), - self.format.print_with_color(Colour::Red, format!("โฌ† {}", TransferRateFormat(avg_bytes_per_sec_outbound))), + style(TransferRateFormat(avg_bytes_per_sec_inbound)).green(), + style(TransferRateFormat(avg_bytes_per_sec_outbound)).red(), ) } } diff --git a/substrate/client/informant/src/lib.rs b/substrate/client/informant/src/lib.rs index af778529ffc58e13736352265b74856477f597eb..d44364539a291bb2bd1d149adaff8af9ce136735 100644 --- a/substrate/client/informant/src/lib.rs +++ b/substrate/client/informant/src/lib.rs @@ -18,7 +18,7 @@ //! Console informant. Prints sync progress and block events. Runs on the calling thread. -use ansi_term::{Colour, Style}; +use console::style; use futures::prelude::*; use futures_timer::Delay; use log::{debug, info, trace}; @@ -36,71 +36,15 @@ fn interval(duration: Duration) -> impl Stream + Unpin { futures::stream::unfold((), move |_| Delay::new(duration).map(|_| Some(((), ())))).map(drop) } -/// The format to print telemetry output in. -#[derive(Clone, Debug)] -pub struct OutputFormat { - /// Enable color output in logs. - /// - /// Is enabled by default. - pub enable_color: bool, -} - -impl Default for OutputFormat { - fn default() -> Self { - Self { enable_color: true } - } -} - -enum ColorOrStyle { - Color(Colour), - Style(Style), -} - -impl From for ColorOrStyle { - fn from(value: Colour) -> Self { - Self::Color(value) - } -} - -impl From