diff --git a/.config/zepter.yaml b/.config/zepter.yaml index 9b3bd9d618c14e41f1dbf420aff3fee1677e2830..24441e90b1a0510d8be95e48515c8b41371117c8 100644 --- a/.config/zepter.yaml +++ b/.config/zepter.yaml @@ -27,7 +27,7 @@ workflows: ] # The umbrella crate uses more features, so we to check those too: check_umbrella: - - [ $check.0, '--features=serde,experimental,with-tracing,tuples-96,with-tracing', '-p=polkadot-sdk' ] + - [ $check.0, '--features=serde,experimental,runtime,with-tracing,tuples-96,with-tracing', '-p=polkadot-sdk' ] # Same as `check_*`, but with the `--fix` flag. default: - [ $check.0, '--fix' ] diff --git a/.github/commands-readme.md b/.github/commands-readme.md index 20644c048c6035a0f92a1c0ed0e96db0896bb3bd..ce4e0fd0d789c808b9c6981e1eeb565c3404d1b7 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 Prdoc](https://github.com/paritytech/polkadot-sdk/actions/workflows/command-prdoc.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) @@ -25,12 +26,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. @@ -136,6 +161,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. @@ -174,6 +205,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. @@ -193,6 +230,45 @@ 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 +``` + +### PrDoc + +Generate a PrDoc with the crates populated by all modified crates. + +Options: +- `pr`: The PR number to generate the PrDoc for. +- `audience`: The audience of whom the changes may concern. +- `bump`: A default bump level for all crates. The PrDoc will likely need to be edited to reflect the actual changes after generation. +- `overwrite`: Whether to overwrite any existing PrDoc. + +### 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/scripts/common/lib.sh b/.github/scripts/common/lib.sh index f844e962c41def7625fa3d45ae3cbf81ecb57147..bfb3120ad9bba1d647ef8719d99ae885cee2dfb7 100755 --- a/.github/scripts/common/lib.sh +++ b/.github/scripts/common/lib.sh @@ -315,6 +315,7 @@ function import_gpg_keys() { ) & done wait + gpg -k $SEC } # Check the GPG signature for a given binary @@ -444,3 +445,28 @@ 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' +} + +validate_stable_tag() { + tag="$1" + pattern='^stable[0-9]+(-[0-9]+)?$' + + if [[ $tag =~ $pattern ]]; then + echo $tag + else + echo "The input '$tag' does not match the pattern." + exit 1 + fi +} diff --git a/.github/scripts/generate-prdoc.py b/.github/scripts/generate-prdoc.py new file mode 100644 index 0000000000000000000000000000000000000000..b7b2e6f970faa4812bf67a9e1a2fc28b8e75b84d --- /dev/null +++ b/.github/scripts/generate-prdoc.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 + +""" +Generate the PrDoc for a Pull Request with a specific number, audience and bump level. + +It downloads and parses the patch from the GitHub API to opulate the prdoc with all modified crates. +This will delete any prdoc that already exists for the PR if `--force` is passed. + +Usage: + python generate-prdoc.py --pr 1234 --audience "TODO" --bump "TODO" +""" + +import argparse +import os +import re +import sys +import subprocess +import toml +import yaml +import requests + +from github import Github +import whatthepatch +from cargo_workspace import Workspace + +# Download the patch and pass the info into `create_prdoc`. +def from_pr_number(n, audience, bump, force): + print(f"Fetching PR '{n}' from GitHub") + g = Github() + + repo = g.get_repo("paritytech/polkadot-sdk") + pr = repo.get_pull(n) + + patch_url = pr.patch_url + patch = requests.get(patch_url).text + + create_prdoc(n, audience, pr.title, pr.body, patch, bump, force) + +def create_prdoc(pr, audience, title, description, patch, bump, force): + path = f"prdoc/pr_{pr}.prdoc" + + if os.path.exists(path): + if force == True: + print(f"Overwriting existing PrDoc for PR {pr}") + else: + print(f"PrDoc already exists for PR {pr}. Use --force to overwrite.") + sys.exit(1) + else: + print(f"No preexisting PrDoc for PR {pr}") + + prdoc = { "doc": [{}], "crates": [] } + + prdoc["title"] = title + prdoc["doc"][0]["audience"] = audience + prdoc["doc"][0]["description"] = description + + workspace = Workspace.from_path(".") + + modified_paths = [] + for diff in whatthepatch.parse_patch(patch): + modified_paths.append(diff.header.new_path) + + modified_crates = {} + for p in modified_paths: + # Go up until we find a Cargo.toml + p = os.path.join(workspace.path, p) + while not os.path.exists(os.path.join(p, "Cargo.toml")): + p = os.path.dirname(p) + + with open(os.path.join(p, "Cargo.toml")) as f: + manifest = toml.load(f) + + if not "package" in manifest: + print(f"File was not in any crate: {p}") + continue + + crate_name = manifest["package"]["name"] + if workspace.crate_by_name(crate_name).publish: + modified_crates[crate_name] = True + else: + print(f"Skipping unpublished crate: {crate_name}") + + print(f"Modified crates: {modified_crates.keys()}") + + for crate_name in modified_crates.keys(): + entry = { "name": crate_name } + + if bump == 'silent' or bump == 'ignore' or bump == 'no change': + entry["validate"] = False + else: + entry["bump"] = bump + + print(f"Adding crate {entry}") + prdoc["crates"].append(entry) + + # write the parsed PR documentation back to the file + with open(path, "w") as f: + yaml.dump(prdoc, f) + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument("--pr", type=int, required=True) + parser.add_argument("--audience", type=str, default="TODO") + parser.add_argument("--bump", type=str, default="TODO") + parser.add_argument("--force", type=str) + return parser.parse_args() + +if __name__ == "__main__": + args = parse_args() + force = True if args.force.lower() == "true" else False + print(f"Args: {args}, force: {force}") + from_pr_number(args.pr, args.audience, args.bump, force) diff --git a/.github/scripts/update-wishlist-leaderboard.py b/.github/scripts/update-wishlist-leaderboard.py new file mode 100644 index 0000000000000000000000000000000000000000..82d1085144844f0fc9b46d94f668ba9a153400a3 --- /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|pull)/(\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-changed-files.yml b/.github/workflows/check-changed-files.yml deleted file mode 100644 index 657c05cd047db40af642886eb2710e7324dd40ce..0000000000000000000000000000000000000000 --- a/.github/workflows/check-changed-files.yml +++ /dev/null @@ -1,57 +0,0 @@ -# Reusable workflow to perform checks and generate conditions for other workflows. -# Currently it checks if any Rust (build-related) file is changed -# and if the current (caller) workflow file is changed. -# Example: -# -# jobs: -# changes: -# permissions: -# pull-requests: read -# uses: ./.github/workflows/check-changed-files.yml -# some-job: -# needs: changes -# if: ${{ needs.changes.outputs.rust }} -# ....... - -name: Check changes files - -on: - workflow_call: - # Map the workflow outputs to job outputs - outputs: - rust: - value: ${{ jobs.changes.outputs.rust }} - description: 'true if any of the build-related OR current (caller) workflow files have changed' - current-workflow: - value: ${{ jobs.changes.outputs.current-workflow }} - description: 'true if current (caller) workflow file has changed' - -jobs: - changes: - runs-on: ubuntu-latest - permissions: - pull-requests: read - outputs: - # true if current workflow (caller) file is changed - rust: ${{ steps.filter.outputs.rust == 'true' || steps.filter.outputs.current-workflow == 'true' }} - current-workflow: ${{ steps.filter.outputs.current-workflow }} - steps: - - id: current-file - run: echo "current-workflow-file=$(echo ${{ github.workflow_ref }} | sed -nE "s/.*(\.github\/workflows\/[a-zA-Z0-9_-]*\.y[a]?ml)@refs.*/\1/p")" >> $GITHUB_OUTPUT - - run: echo "${{ steps.current-file.outputs.current-workflow-file }}" - # For pull requests it's not necessary to checkout the code - - id: filter - uses: dorny/paths-filter@v3 - with: - predicate-quantifier: 'every' - # current-workflow - check if the current (caller) workflow file is changed - # rust - check if any Rust (build-related) file is changed - filters: | - current-workflow: - - '${{ steps.current-file.outputs.current-workflow-file }}' - rust: - - '**/*' - - '!.github/**/*' - - '!prdoc/**/*' - - '!docs/**/*' - # \ No newline at end of file diff --git a/.github/workflows/check-frame-omni-bencher.yml b/.github/workflows/check-frame-omni-bencher.yml new file mode 100644 index 0000000000000000000000000000000000000000..e9db2d9129797b1707a273122c5edf19542f9381 --- /dev/null +++ b/.github/workflows/check-frame-omni-bencher.yml @@ -0,0 +1,85 @@ +name: Short benchmarks (frame-omni-bencher) + +on: + push: + branches: + - master + pull_request: + types: [ opened, synchronize, reopened, ready_for_review, labeled ] + merge_group: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + ARTIFACTS_NAME: frame-omni-bencher-artifacts + +jobs: + changes: + # TODO: remove once migration is complete or this workflow is fully stable + if: contains(github.event.label.name, 'GHA-migration') + permissions: + pull-requests: read + uses: ./.github/workflows/reusable-check-changed-files.yml + + set-image: + # GitHub Actions allows using 'env' in a container context. + # However, env variables don't work for forks: https://github.com/orgs/community/discussions/44322 + # This workaround sets the container image for each job using 'set-image' job output. + runs-on: ubuntu-latest + needs: changes + if: ${{ needs.changes.outputs.rust }} + outputs: + IMAGE: ${{ steps.set_image.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - id: set_image + run: cat .github/env >> $GITHUB_OUTPUT + + run-frame-omni-bencher: + runs-on: arc-runners-polkadot-sdk-beefy + needs: [ set-image, changes ] # , build-frame-omni-bencher ] + if: ${{ needs.changes.outputs.rust }} + timeout-minutes: 30 + strategy: + fail-fast: false # keep running other workflows even if one fails, to see the logs of all possible failures + matrix: + runtime: + [ + westend-runtime, + rococo-runtime, + asset-hub-rococo-runtime, + asset-hub-westend-runtime, + bridge-hub-rococo-runtime, + bridge-hub-westend-runtime, + collectives-westend-runtime, + coretime-rococo-runtime, + coretime-westend-runtime, + people-rococo-runtime, + people-westend-runtime, + glutton-westend-runtime, + ] + container: + image: ${{ needs.set-image.outputs.IMAGE }} + env: + PACKAGE_NAME: ${{ matrix.runtime }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: script + run: | + RUNTIME_BLOB_NAME=$(echo $PACKAGE_NAME | sed 's/-/_/g').compact.compressed.wasm + RUNTIME_BLOB_PATH=./target/release/wbuild/$PACKAGE_NAME/$RUNTIME_BLOB_NAME + forklift cargo build --release --locked -p $PACKAGE_NAME -p frame-omni-bencher --features runtime-benchmarks + echo "Running short benchmarking for PACKAGE_NAME=$PACKAGE_NAME and RUNTIME_BLOB_PATH=$RUNTIME_BLOB_PATH" + ls -lrt $RUNTIME_BLOB_PATH + ./target/release/frame-omni-bencher v1 benchmark pallet --runtime $RUNTIME_BLOB_PATH --all --steps 2 --repeat 1 + confirm-frame-omni-benchers-passed: + runs-on: ubuntu-latest + name: All benchmarks passed + needs: run-frame-omni-bencher + steps: + - run: echo '### Good job! All the benchmarks passed 🚀' >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/check-licenses.yml b/.github/workflows/check-licenses.yml index 3bc95305f7467ebbede90526eadb156b89b1e7f9..a74986048976ecc0974285da3f14a9f8ee2b683d 100644 --- a/.github/workflows/check-licenses.yml +++ b/.github/workflows/check-licenses.yml @@ -16,8 +16,8 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/setup-node@v4.0.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - 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..d10f34e6faef4012b6348b20400f5c304f317df4 100644 --- a/.github/workflows/check-links.yml +++ b/.github/workflows/check-links.yml @@ -18,17 +18,17 @@ jobs: runs-on: ubuntu-latest steps: - name: Restore lychee cache - uses: actions/cache@e12d46a63a90f2fae62d114769bbf2a179198b5c # v3.3.2 (7. Sep 2023) + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v3.3.2 (7. Sep 2023) with: path: .lycheecache key: cache-lychee-${{ github.sha }} # This should restore from the most recent one: restore-keys: cache-lychee- - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.0 (22. Sep 2023) + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # 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 5df03f1044d88a7bcf9369c054235747f9f049b1..69311c41dd6f11800b7a0c23e9f7ab8416e80178 100644 --- a/.github/workflows/check-prdoc.yml +++ b/.github/workflows/check-prdoc.yml @@ -20,7 +20,7 @@ jobs: if: github.event.pull_request.number != '' steps: - name: Checkout repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.1.7 # we cannot show the version in this step (ie before checking out the repo) # due to https://github.com/paritytech/prdoc/issues/15 - name: Check if PRdoc is required diff --git a/.github/workflows/check-runtime-migration.yml b/.github/workflows/check-runtime-migration.yml index 33da5a8ecd591535eb0d4fe8b63cd8801699e988..9b7a6fafcd1545bb441a8ca593a32471340c9208 100644 --- a/.github/workflows/check-runtime-migration.yml +++ b/.github/workflows/check-runtime-migration.yml @@ -6,7 +6,12 @@ on: - master pull_request: types: [opened, synchronize, reopened, ready_for_review] + # Take a snapshot at 5am when most SDK devs are not working. + schedule: + - cron: '0 5 * * *' merge_group: + workflow_dispatch: + concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true @@ -27,7 +32,9 @@ jobs: # rococo and westend are disabled for now (no access to parity-chains.parity.io) check-runtime-migration: runs-on: arc-runners-polkadot-sdk-beefy - timeout-minutes: 40 + # We need to set this to rather long to allow the snapshot to be created, but the average time + # should be much lower. + timeout-minutes: 60 needs: [set-image] container: image: ${{ needs.set-image.outputs.IMAGE }} @@ -94,22 +101,45 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - - name: script - run: | - echo "Running ${{ matrix.network }} runtime migration check" - export RUST_LOG=remote-ext=debug,runtime=debug - echo "---------- Downloading try-runtime CLI ----------" - curl -sL https://github.com/paritytech/try-runtime-cli/releases/download/v0.5.4/try-runtime-x86_64-unknown-linux-musl -o try-runtime + - name: Download CLI + run: | + curl -sL https://github.com/paritytech/try-runtime-cli/releases/download/v0.7.0/try-runtime-x86_64-unknown-linux-musl -o try-runtime chmod +x ./try-runtime echo "Using try-runtime-cli version:" ./try-runtime --version + - name: Get Date + id: get-date + run: | + echo "today=$(/bin/date -u "+%Y%m%d")" >> $GITHUB_OUTPUT + shell: bash + + - name: Download Snapshot + uses: actions/cache@v4 + with: + path: snapshot.raw + key: try-runtime-snapshot-${{ matrix.network }}-${{ steps.get-date.outputs.today }} + save-always: true + + - name: Create Snapshot If Stale + if: ${{ hashFiles('snapshot.raw') == '' }} + run: | + echo "Creating new snapshot for today (${{ steps.get-date.outputs.today }})" + ./try-runtime create-snapshot --uri ${{ matrix.uri }} snapshot.raw + + - name: Build Runtime + run: | echo "---------- Building ${{ matrix.package }} runtime ----------" - time forklift cargo build --release --locked -p ${{ matrix.package }} --features try-runtime + time forklift cargo build --release --locked -p ${{ matrix.package }} --features try-runtime -q + + - name: Run Check + run: | + echo "Running ${{ matrix.network }} runtime migration check" + export RUST_LOG=remote-ext=debug,runtime=debug echo "---------- Executing on-runtime-upgrade for ${{ matrix.network }} ----------" time ./try-runtime ${{ matrix.command_extra_args }} \ --runtime ./target/release/wbuild/${{ matrix.package }}/${{ matrix.wasm }} \ - on-runtime-upgrade --disable-spec-version-check --checks=all ${{ matrix.subcommand_extra_args }} live --uri ${{ matrix.uri }} + on-runtime-upgrade --disable-spec-version-check --checks=all ${{ matrix.subcommand_extra_args }} snap -p snapshot.raw sleep 5 diff --git a/.github/workflows/check-semver.yml b/.github/workflows/check-semver.yml index 47f9e5061b4aec5be38937351ae072bd58f84f37..d9d918b44a23d705835615a23c1f25296a34bd4c 100644 --- a/.github/workflows/check-semver.yml +++ b/.github/workflows/check-semver.yml @@ -3,10 +3,15 @@ name: Check semver on: pull_request: types: [opened, synchronize, reopened, ready_for_review] - paths: - - prdoc/*.prdoc + workflow_dispatch: + +concurrency: + group: check-semver-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + env: - TOOLCHAIN: nightly-2024-03-01 + TOOLCHAIN: nightly-2024-06-01 + jobs: check-semver: @@ -14,34 +19,71 @@ jobs: container: image: docker.io/paritytech/ci-unified:bullseye-1.77.0-2024-04-10-v20240408 steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + - name: extra git setup + env: + BASE: ${{ github.event.pull_request.base.sha }} + run: | + git config --global --add safe.directory '*' + git fetch --no-tags --no-recurse-submodules --depth=1 origin $BASE + git branch old $BASE + + - name: Comment If Backport + if: ${{ startsWith(github.event.pull_request.base.ref, 'stable') }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR: ${{ github.event.pull_request.number }} + run: | + echo "This is a backport into stable." + + wget -q https://github.com/cli/cli/releases/download/v2.51.0/gh_2.51.0_linux_amd64.tar.gz -O gh.tar.gz && \ + tar -xzf gh.tar.gz && mv gh_2.51.0_linux_amd64/bin/gh /usr/local/bin/gh && rm gh.tar.gz + chmod +x /usr/local/bin/gh + + cat > msg.txt <Emergency Bypass +

+ + If you really need to bypass this check: add validate: false to each crate + in the Prdoc where a breaking change is introduced. This will release a new major + version of that crate and all its reverse dependencies and basically break the release. + +

+ + EOF + gh issue comment $PR --edit-last -F msg.txt || gh issue comment $PR -F msg.txt + + echo "PRDOC_EXTRA_ARGS=--max-bump minor" >> $GITHUB_ENV - name: Rust Cache uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 with: cache-on-failure: true - - name: install parity-publish - run: cargo install parity-publish@0.6.0 - - name: Rust compilation prerequisites run: | rustup default $TOOLCHAIN - rustup target add wasm32-unknown-unknown --toolchain $TOOLCHAIN rustup component add rust-src --toolchain $TOOLCHAIN - - name: extra git setup - run: | - git config --global --add safe.directory '*' - git fetch --no-tags --no-recurse-submodules --depth=1 origin master - git branch old origin/master + - name: install parity-publish + # Set the target dir to cache the build. + run: CARGO_TARGET_DIR=./target/ cargo install parity-publish@0.8.0 -q - name: check semver run: | 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 -v --toolchain $TOOLCHAIN; then + + if ! parity-publish --color always prdoc --since old --validate prdoc/pr_$PR.prdoc $PRDOC_EXTRA_ARGS -v --toolchain $TOOLCHAIN; then + cat <=1.2.4" toml - name: check umbrella correctness diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml new file mode 100644 index 0000000000000000000000000000000000000000..054c7d786ca979977e92ecc79ac58895374c2aba --- /dev/null +++ b/.github/workflows/checks.yml @@ -0,0 +1,90 @@ +name: checks + +on: + push: + branches: + - master + pull_request: + types: [opened, synchronize, reopened, ready_for_review, labeled] + merge_group: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: {} + +jobs: + changes: + # TODO: remove once migration is complete or this workflow is fully stable + if: contains(github.event.label.name, 'GHA-migration') + permissions: + pull-requests: read + uses: ./.github/workflows/reusable-check-changed-files.yml + set-image: + # GitHub Actions allows using 'env' in a container context. + # However, env variables don't work for forks: https://github.com/orgs/community/discussions/44322 + # This workaround sets the container image for each job using 'set-image' job output. + runs-on: ubuntu-latest + timeout-minutes: 20 + outputs: + IMAGE: ${{ steps.set_image.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - id: set_image + run: cat .github/env >> $GITHUB_OUTPUT + cargo-clippy: + runs-on: arc-runners-polkadot-sdk-beefy + needs: [set-image, changes] # , build-frame-omni-bencher ] + if: ${{ needs.changes.outputs.rust }} + timeout-minutes: 40 + container: + image: ${{ needs.set-image.outputs.IMAGE }} + env: + RUSTFLAGS: "-D warnings" + SKIP_WASM_BUILD: 1 + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - name: script + run: | + forklift cargo clippy --all-targets --locked --workspace + forklift cargo clippy --all-targets --all-features --locked --workspace + check-try-runtime: + runs-on: arc-runners-polkadot-sdk-beefy + needs: [set-image, changes] # , build-frame-omni-bencher ] + if: ${{ needs.changes.outputs.rust }} + timeout-minutes: 40 + container: + image: ${{ needs.set-image.outputs.IMAGE }} + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - name: script + run: | + forklift cargo check --locked --all --features try-runtime + # this is taken from cumulus + # Check that parachain-template will compile with `try-runtime` feature flag. + forklift cargo check --locked -p parachain-template-node --features try-runtime + # add after https://github.com/paritytech/substrate/pull/14502 is merged + # experimental code may rely on try-runtime and vice-versa + forklift cargo check --locked --all --features try-runtime,experimental + # check-core-crypto-features works fast without forklift + check-core-crypto-features: + runs-on: arc-runners-polkadot-sdk-beefy + needs: [set-image, changes] # , build-frame-omni-bencher ] + if: ${{ needs.changes.outputs.rust }} + timeout-minutes: 30 + container: + image: ${{ needs.set-image.outputs.IMAGE }} + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - name: script + run: | + cd substrate/primitives/core + ./check-features-variants.sh + cd - + cd substrate/primitives/application-crypto + ./check-features-variants.sh + cd - + cd substrate/primitives/keyring + ./check-features-variants.sh + cd - diff --git a/.github/workflows/command-fmt.yml b/.github/workflows/command-fmt.yml index 586b8c77f2745669a9d8f73c1dabb5b165be20ff..fc37a17ac549b06e6850ea8a209ec4b27db8fb3f 100644 --- a/.github/workflows/command-fmt.yml +++ b/.github/workflows/command-fmt.yml @@ -37,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 2825f4a604605fea8465ce0646d664c9ef5d38f5..afdcf4c1b7b9073762bfec0f0760137b3dba4506 100644 --- a/.github/workflows/command-inform.yml +++ b/.github/workflows/command-inform.yml @@ -7,7 +7,8 @@ on: jobs: comment: runs-on: ubuntu-latest - if: github.event.issue.pull_request && startsWith(github.event.comment.body, 'bot ') + # Temporary disable the bot until the new command bot works properly + if: github.event.issue.pull_request && startsWith(github.event.comment.body, 'bot ') && false steps: - name: Inform that the new command exist uses: actions/github-script@v7 diff --git a/.github/workflows/command-prdoc.yml b/.github/workflows/command-prdoc.yml new file mode 100644 index 0000000000000000000000000000000000000000..3a08b9a5fb286a7757715ac37006cf093b2b8b15 --- /dev/null +++ b/.github/workflows/command-prdoc.yml @@ -0,0 +1,90 @@ +name: Command PrDoc + +on: + workflow_dispatch: + inputs: + pr: + type: number + description: Number of the Pull Request + required: true + bump: + type: choice + description: Default bump level for all crates + default: "TODO" + required: true + options: + - "TODO" + - "no change" + - "patch" + - "minor" + - "major" + audience: + type: choice + description: Audience of the PrDoc + default: "TODO" + required: true + options: + - "TODO" + - "Runtime Dev" + - "Runtime User" + - "Node Dev" + - "Node User" + overwrite: + type: choice + description: Overwrite existing PrDoc + default: "true" + required: true + options: + - "true" + - "false" + +concurrency: + group: command-prdoc + cancel-in-progress: true + +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-prdoc: + 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 + - name: Install gh cli + id: gh + uses: ./.github/actions/set-up-gh + with: + pr-number: ${{ inputs.pr }} + GH_TOKEN: ${{ github.token }} + - name: Generate PrDoc + run: | + python3 -m pip install -q cargo-workspace PyGithub whatthepatch pyyaml toml + + python3 .github/scripts/generate-prdoc.py --pr "${{ inputs.pr }}" --bump "${{ inputs.bump }}" --audience "${{ inputs.audience }}" --force "${{ inputs.overwrite }}" + + - 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 }} + - name: Push Commit + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: Add PrDoc (auto generated) + branch: ${{ steps.gh.outputs.branch }} + file_pattern: 'prdoc/*.prdoc' diff --git a/.github/workflows/fork-sync-action.yml b/.github/workflows/fork-sync-action.yml new file mode 100644 index 0000000000000000000000000000000000000000..69e9e93bf54b023330232c0fe5df0430832a6e2b --- /dev/null +++ b/.github/workflows/fork-sync-action.yml @@ -0,0 +1,20 @@ +# This Workflow is not supposed to run in the paritytech/polkadot-sdk repo. +# This Workflow is supposed to run only in the forks of the repo, +# paritytech-release/polkadot-sdk specifically, +# to automatically maintain the critical fork synced with the upstream. +# This Workflow should be always disabled in the paritytech/polkadot-sdk repo. + +name: Sync the forked repo with the upstream +on: + schedule: + - cron: "0 0/4 * * *" + workflow_dispatch: + +jobs: + job_sync_branches: + uses: paritytech-release/sync-workflows/.github/workflows/sync-with-upstream.yml@latest + with: + fork_writer_app_id: ${{ vars.UPSTREAM_CONTENT_SYNC_APP_ID}} + fork_owner: ${{ vars.RELEASE_ORG}} + secrets: + fork_writer_app_key: ${{ secrets.UPSTREAM_CONTENT_SYNC_APP_KEY }} diff --git a/.github/workflows/misc-sync-templates.yml b/.github/workflows/misc-sync-templates.yml index d8027014863936ffd6c6a217f282dfa45bc2edd7..c06beb5e98eb7772f8f364c3a8a4121d40b7e522 100644 --- a/.github/workflows/misc-sync-templates.yml +++ b/.github/workflows/misc-sync-templates.yml @@ -18,11 +18,10 @@ on: # A manual dispatch for now - automatic on releases later. workflow_dispatch: inputs: - crate_release_version: - description: 'A release version to use, e.g. 1.9.0' + stable_release_branch: + description: 'Stable release branch, e.g. stable2407' required: true - jobs: sync-templates: runs-on: ubuntu-latest @@ -41,10 +40,10 @@ jobs: run: | git config --global user.name "Template Bot" git config --global user.email "163342540+paritytech-polkadotsdk-templatebot[bot]@users.noreply.github.com" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: path: polkadot-sdk - ref: "release-crates-io-v${{ github.event.inputs.crate_release_version }}" + ref: "${{ github.event.inputs.stable_release_branch }}" - name: Generate a token for the template repository id: app_token uses: actions/create-github-app-token@v1.9.3 @@ -53,7 +52,7 @@ jobs: repositories: "polkadot-sdk-${{ matrix.template }}-template" app-id: ${{ secrets.TEMPLATE_APP_ID }} private-key: ${{ secrets.TEMPLATE_APP_KEY }} - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: "paritytech/polkadot-sdk-${{ matrix.template }}-template" path: "${{ env.template-path }}" @@ -69,11 +68,11 @@ jobs: protobuf-compiler rustup target add wasm32-unknown-unknown rustup component add rustfmt clippy rust-src - + # 2. Yanking the template out of the monorepo workspace. - - name: Use psvm to replace git references with released creates. - run: find . -type f -name 'Cargo.toml' -exec psvm -o -v ${{ github.event.inputs.crate_release_version }} -p {} \; + - name: Replace dev-dependencies path references with workspace references + run: find . -type f -name 'Cargo.toml' -exec sed -i'' -E "s/path = \"\.\.\/.*\"/workspace = true/g" {} \; working-directory: polkadot-sdk/templates/${{ matrix.template }}/ - name: Create a new workspace Cargo.toml run: | @@ -81,7 +80,7 @@ jobs: [workspace.package] license = "MIT-0" authors = ["Parity Technologies "] - homepage = "https://substrate.io" + homepage = "https://paritytech.github.io/polkadot-sdk/" [workspace] members = [ @@ -90,7 +89,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 +120,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.stable_release_branch }} -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,18 +157,22 @@ 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 }} add-paths: | ./* - title: "[Don't merge] Update the ${{ matrix.template }} template to ${{ github.event.inputs.crate_release_version }}" + title: "[Don't merge] Update the ${{ matrix.template }} template to ${{ github.event.inputs.stable_release_branch }}" body: "The template has NOT been successfully built and needs to be inspected." - branch: "update-template/${{ github.event.inputs.crate_release_version }}" - - name: Push changes - run: | - git add -A . - git commit --allow-empty -m "Update to ${{ github.event.inputs.crate_release_version }} triggered by ${{ github.event_name }}" - git push - working-directory: "${{ env.template-path }}" + branch: "update-template/${{ github.event.inputs.stable_release_branch }}" + - name: Create PR on success + uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v5 + with: + path: "${{ env.template-path }}" + token: ${{ steps.app_token.outputs.token }} + add-paths: | + ./* + title: "Update the ${{ matrix.template }} template to ${{ github.event.inputs.stable_release_branch }}" + body: "This synchronizes the template to the ${{ github.event.inputs.stable_release_branch }} branch." + branch: "update-template/${{ github.event.inputs.stable_release_branch }}" diff --git a/.github/workflows/misc-update-wishlist-leaderboard.yml b/.github/workflows/misc-update-wishlist-leaderboard.yml new file mode 100644 index 0000000000000000000000000000000000000000..3261687176746841a57bf2d247aeb6f596310c8b --- /dev/null +++ b/.github/workflows/misc-update-wishlist-leaderboard.yml @@ -0,0 +1,37 @@ +name: Update wishlist leaderboard + +on: + schedule: + # Run every 3 hours + - cron: '0 */3 * * *' + +permissions: + contents: read + issues: write + +jobs: + update-wishlist-leaderboard: + if: github.repository == 'paritytech/polkadot-sdk' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + 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 33cf9316920048c65c70376557586d905fd7c9a6..9f96b92e0ce73eb1874ff7e11c9e43d820eaa649 100644 --- a/.github/workflows/publish-check-crates.yml +++ b/.github/workflows/publish-check-crates.yml @@ -12,7 +12,7 @@ jobs: check-publish: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Rust Cache uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 @@ -20,7 +20,7 @@ jobs: cache-on-failure: true - name: install parity-publish - run: cargo install parity-publish@0.6.0 + run: cargo install parity-publish@0.8.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 08c50638267ba3be596b5b563433fccf28c2652b..bee709a12076ed4a5ff212796f7691650f32ad7f 100644 --- a/.github/workflows/publish-claim-crates.yml +++ b/.github/workflows/publish-claim-crates.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest environment: master steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Rust Cache uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 @@ -18,7 +18,7 @@ jobs: cache-on-failure: true - name: install parity-publish - run: cargo install parity-publish@0.6.0 + run: cargo install parity-publish@0.8.0 - name: parity-publish claim env: diff --git a/.github/workflows/publish-subsystem-benchmarks.yml b/.github/workflows/publish-subsystem-benchmarks.yml index 1a726b669e9094e8be53ef5a1ddb1b3198210d33..e5b9db0836f3f6a944778a30df49ea7f98b3af34 100644 --- a/.github/workflows/publish-subsystem-benchmarks.yml +++ b/.github/workflows/publish-subsystem-benchmarks.yml @@ -23,7 +23,7 @@ jobs: echo "${{ github.event.inputs.output-file-path }}" | grep -P '^[a-z\-]+\.json' - name: Checkout Sources - uses: actions/checkout@v4.1.2 + uses: actions/checkout@v4 with: fetch-depth: 0 ref: "gh-pages" diff --git a/.github/workflows/release-10_rc-automation.yml b/.github/workflows/release-10_rc-automation.yml index 7231a8b75886d04ce18bb89fcef99029e3ab14c6..2d91850b82c180e25bbf87dfef529f8ab4667edd 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: @@ -21,32 +26,23 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 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-30_publish_release_draft.yml b/.github/workflows/release-30_publish_release_draft.yml index 20492f2d3a9104fd08af663d19aed9a301918e6c..6d31ca7a7365d77f6dd34c721b66acdc75ddbfa7 100644 --- a/.github/workflows/release-30_publish_release_draft.yml +++ b/.github/workflows/release-30_publish_release_draft.yml @@ -35,7 +35,7 @@ jobs: binary: [ [frame-omni-bencher, frame-omni-bencher], [staging-chain-spec-builder, chain-spec-builder] ] steps: - name: Checkout sources - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.0.0 - name: Install protobuf-compiler run: | @@ -62,10 +62,10 @@ jobs: asset_upload_url: ${{ steps.create-release.outputs.upload_url }} steps: - name: Checkout - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.0.0 - name: Download artifacts - uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 - name: Prepare tooling run: | @@ -133,10 +133,10 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.0.0 - name: Download artifacts - uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 - name: Get runtime info env: @@ -166,7 +166,7 @@ jobs: steps: - name: Download artifacts - uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: ${{ matrix.binary }} diff --git a/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml index 4679f58578f7906b75e4a3d6d623ebc1d55df40d..f09ecf1c79988c8c23c13f840e041f13f19ba457 100644 --- a/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -45,7 +45,7 @@ on: type: string default: docker.io - # The owner is often the same than the Docker Hub username but does ont have to be. + # The owner is often the same as the Docker Hub username but does ont have to be. # In our case, it is not. owner: description: Owner of the container image repo @@ -58,6 +58,10 @@ on: default: v0.9.18 required: true + stable_tag: + description: Tag matching the actual stable release version in the format stableYYMM or stableYYMM-X for patch releases + required: true + permissions: contents: write @@ -74,13 +78,36 @@ env: VERSION: ${{ inputs.version }} jobs: + validate-inputs: + runs-on: ubuntu-latest + outputs: + stable_tag: ${{ steps.validate_inputs.outputs.stable_tag }} + + steps: + - name: Checkout sources + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + - name: Validate inputs + id: validate_inputs + run: | + . ./.github/scripts/common/lib.sh + + VERSION=$(filter_version_from_input "${{ inputs.version }}") + echo "VERSION=${VERSION}" >> $GITHUB_ENV + + RELEASE_ID=$(check_release_id "${{ inputs.release_id }}") + echo "RELEASE_ID=${RELEASE_ID}" >> $GITHUB_ENV + + STABLE_TAG=$(validate_stable_tag ${{ inputs.stable_tag }}) + echo "stable_tag=${STABLE_TAG}" >> $GITHUB_OUTPUT + fetch-artifacts: # this job will be triggered for the polkadot-parachain rc and release or polkadot rc image build if: ${{ inputs.binary == 'polkadot-parachain' || inputs.binary == 'chain-spec-builder' || inputs.image_type == 'rc' }} runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 #TODO: this step will be needed when automated triggering will work #this step runs only if the workflow is triggered automatically when new release is published @@ -102,9 +129,6 @@ jobs: run: | . ./.github/scripts/common/lib.sh - VERSION=$(filter_version_from_input "${{ inputs.version }}") - echo "VERSION=${VERSION}" >> $GITHUB_ENV - fetch_release_artifacts_from_s3 - name: Fetch chain-spec-builder rc artifacts or release artifacts based on release id @@ -112,7 +136,7 @@ jobs: if: ${{ env.EVENT_NAME == 'workflow_dispatch' && inputs.binary == 'chain-spec-builder' }} run: | . ./.github/scripts/common/lib.sh - RELEASE_ID=$(check_release_id "${{ inputs.release_id }}") + fetch_release_artifacts - name: Upload artifacts @@ -124,15 +148,15 @@ jobs: build-container: # this job will be triggered for the polkadot-parachain rc and release or polkadot rc image build if: ${{ inputs.binary == 'polkadot-parachain' || inputs.binary == 'chain-spec-builder' || inputs.image_type == 'rc' }} runs-on: ubuntu-latest - needs: fetch-artifacts + needs: [fetch-artifacts, validate-inputs] environment: release steps: - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Download artifacts - uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 - name: Check sha256 ${{ env.BINARY }} if: ${{ inputs.binary == 'polkadot-parachain' || inputs.binary == 'polkadot' }} @@ -179,6 +203,7 @@ jobs: release=$( echo $VERSION | cut -f1 -d- ) echo "tag=latest" >> $GITHUB_OUTPUT echo "release=${release}" >> $GITHUB_OUTPUT + echo "stable=${{ needs.validate-inputs.outputs.stable_tag }}" >> $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 +234,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 }} @@ -256,17 +281,17 @@ jobs: build-polkadot-release-container: # this job will be triggered for polkadot release build if: ${{ inputs.binary == 'polkadot' && inputs.image_type == 'release' }} runs-on: ubuntu-latest - needs: fetch-latest-debian-package-version + needs: [fetch-latest-debian-package-version, validate-inputs] environment: release steps: - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 + uses: docker/setup-buildx-action@aa33708b10e362ff993539393ff100fa93ed6a27 # v3.5.0 - name: Cache Docker layers - uses: actions/cache@e12d46a63a90f2fae62d114769bbf2a179198b5c # v3.3.3 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: /tmp/.buildx-cache key: ${{ runner.os }}-buildx-${{ github.sha }} @@ -274,7 +299,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 +312,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:${{ needs.validate-inputs.outputs.stable_tag }} parity/polkadot:latest parity/polkadot:${{ needs.fetch-latest-debian-package-version.outputs.polkadot_container_tag }} build-args: | diff --git a/.github/workflows/release-check-runtimes.yml b/.github/workflows/release-check-runtimes.yml index 0e5ad104766a89aaa678cc5436475d95e3ab76fd..930b8da772d0b6d19c0a723f9de09ff8fa5cd0b2 100644 --- a/.github/workflows/release-check-runtimes.yml +++ b/.github/workflows/release-check-runtimes.yml @@ -35,7 +35,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Get list id: get-list @@ -56,7 +56,7 @@ jobs: steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Fetch release artifacts based on release id env: diff --git a/.github/workflows/release-clobber-stable.yml b/.github/workflows/release-clobber-stable.yml index 643c14daa15b1aa7501e27f272524e0ee010e781..50c20563b4347334aa591f0f4f2e544f17f12afe 100644 --- a/.github/workflows/release-clobber-stable.yml +++ b/.github/workflows/release-clobber-stable.yml @@ -24,7 +24,7 @@ jobs: AUDITED: audited steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Prechecks run: | diff --git a/.github/workflows/release-srtool.yml b/.github/workflows/release-srtool.yml index 69a4bdbdda9ae87a188a23bceb9185d813424a98..e1dc42afc6e98ded04c5689a28b224bb239114c0 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: @@ -31,7 +26,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.0.0 with: fetch-depth: 0 @@ -72,7 +67,7 @@ jobs: matrix: ${{ fromJSON(needs.find-runtimes.outputs.runtime) }} steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.0.0 with: fetch-depth: 0 diff --git a/.github/workflows/reusable-check-changed-files.yml b/.github/workflows/reusable-check-changed-files.yml new file mode 100644 index 0000000000000000000000000000000000000000..47f0620439c77f262c4fda1b68f0e250f2ec8ac6 --- /dev/null +++ b/.github/workflows/reusable-check-changed-files.yml @@ -0,0 +1,59 @@ +# Reusable workflow to perform checks and generate conditions for other workflows. +# Currently it checks if any Rust (build-related) file is changed +# and if the current (caller) workflow file is changed. +# Example: +# +# jobs: +# changes: +# permissions: +# pull-requests: read +# uses: ./.github/workflows/reusable-check-changed-files.yml +# some-job: +# needs: changes +# if: ${{ needs.changes.outputs.rust }} +# ....... + +name: Check changes files + +on: + workflow_call: + # Map the workflow outputs to job outputs + outputs: + rust: + value: ${{ jobs.changes.outputs.rust }} + description: "true if any of the build-related OR current (caller) workflow files have changed" + current-workflow: + value: ${{ jobs.changes.outputs.current-workflow }} + description: "true if current (caller) workflow file has changed" + +jobs: + changes: + runs-on: ubuntu-latest + permissions: + pull-requests: read + outputs: + # true if current workflow (caller) file is changed + rust: ${{ steps.filter.outputs.rust == 'true' || steps.filter.outputs.current-workflow == 'true' }} + current-workflow: ${{ steps.filter.outputs.current-workflow }} + steps: + - id: current-file + run: echo "current-workflow-file=$(echo ${{ github.workflow_ref }} | sed -nE "s/.*(\.github\/workflows\/[a-zA-Z0-9_-]*\.y[a]?ml)@refs.*/\1/p")" >> $GITHUB_OUTPUT + - run: echo "${{ steps.current-file.outputs.current-workflow-file }}" + # For pull requests it's not necessary to checkout the code + - name: Checkout + if: github.event_name != 'pull_request' + uses: actions/checkout@v4 + - id: filter + uses: dorny/paths-filter@v3 + with: + predicate-quantifier: "every" + # current-workflow - check if the current (caller) workflow file is changed + # rust - check if any Rust (build-related) file is changed + filters: | + current-workflow: + - '${{ steps.current-file.outputs.current-workflow-file }}' + rust: + - '**/*' + - '!.github/**/*' + - '!prdoc/**/*' + - '!docs/**/*' diff --git a/.github/workflows/review-bot.yml b/.github/workflows/review-bot.yml index f1401406ae47afd3230cc163f35df0e3bcbac7b7..80c96b0ef537fe3eaf368c7a39b2c5eddbb994e0 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.6.0 with: repo-token: ${{ steps.app_token.outputs.token }} team-token: ${{ steps.app_token.outputs.token }} diff --git a/.github/workflows/subsystem-benchmarks.yml b/.github/workflows/subsystem-benchmarks.yml new file mode 100644 index 0000000000000000000000000000000000000000..7c19b420a6acb42ed473bb2c4bd54c07cefdd0e4 --- /dev/null +++ b/.github/workflows/subsystem-benchmarks.yml @@ -0,0 +1,82 @@ +on: + push: + branches: + - master + pull_request: + types: [ opened, synchronize, reopened, closed, labeled ] + merge_group: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + pull-requests: write + +jobs: + set-image: + # TODO: remove once migration is complete or this workflow is fully stable + if: contains(github.event.label.name, 'GHA-migration') + # GitHub Actions allows using 'env' in a container context. + # However, env variables don't work for forks: https://github.com/orgs/community/discussions/44322 + # This workaround sets the container image for each job using 'set-image' job output. + 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 + + build: + needs: [ set-image ] + runs-on: arc-runners-polkadot-sdk-benchmark + container: + image: ${{ needs.set-image.outputs.IMAGE }} + env: + BENCH_DIR: ./charts/bench/${{ matrix.features.bench }} + BENCH_FILE_NAME: ${{ matrix.features.bench }} + strategy: + fail-fast: false + matrix: + features: [ + { name: "polkadot-availability-recovery", bench: "availability-recovery-regression-bench" }, + { name: "polkadot-availability-distribution", bench: "availability-distribution-regression-bench" }, + { name: "polkadot-node-core-approval-voting", bench: "approval-voting-regression-bench" }, + { name: "polkadot-statement-distribution", bench: "statement-distribution-regression-bench" } + ] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Check Rust + run: | + rustup show + rustup +nightly show + + - name: Run Benchmarks + continue-on-error: true + id: run-benchmarks + run: | + cargo bench -p ${{ matrix.features.name }} --bench ${{ matrix.features.bench }} --features subsystem-benchmarks || echo "Benchmarks failed" + ls -lsa ./charts + mkdir -p $BENCH_DIR || echo "Directory exists" + cp charts/${BENCH_FILE_NAME}.json $BENCH_DIR + ls -lsa $BENCH_DIR + # Fixes "detected dubious ownership" error in the ci + git config --global --add safe.directory '*' + + - name: Publish result to GH Pages + if: ${{ steps.run-benchmarks.outcome == 'success' }} + uses: benchmark-action/github-action-benchmark@v1 + with: + tool: "customSmallerIsBetter" + name: ${{ env.BENCH_FILE_NAME }} + output-file-path: ${{ env.BENCH_DIR }}/${{ env.BENCH_FILE_NAME }}.json + benchmark-data-dir-path: ${{ env.BENCH_DIR }} + github-token: ${{ secrets.GITHUB_TOKEN }} + comment-on-alert: ${{ github.event_name == 'pull_request' }} # will comment on PRs if regression is detected + auto-push: false # TODO: enable when gitlab part is removed ${{ github.ref == 'refs/heads/master' }} + diff --git a/.github/workflows/tests-linux-stable.yml b/.github/workflows/tests-linux-stable.yml index 55addf11de06db43b30b336d83b39f282d03c292..4a13f5318f7deb34a4727a3dc88967df12a67ed7 100644 --- a/.github/workflows/tests-linux-stable.yml +++ b/.github/workflows/tests-linux-stable.yml @@ -6,7 +6,7 @@ on: branches: - master pull_request: - types: [opened, synchronize, reopened, ready_for_review] + types: [opened, synchronize, reopened, ready_for_review, labeled] merge_group: concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} @@ -14,9 +14,11 @@ concurrency: jobs: changes: + # TODO: remove once migration is complete or this workflow is fully stable + if: contains(github.event.label.name, 'GHA-migration') permissions: pull-requests: read - uses: ./.github/workflows/check-changed-files.yml + uses: ./.github/workflows/reusable-check-changed-files.yml set-image: # GitHub Actions allows using 'env' in a container context. @@ -51,7 +53,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: script - run: WASM_BUILD_NO_COLOR=1 time forklift cargo test -p staging-node-cli --release --locked -- --ignored + run: WASM_BUILD_NO_COLOR=1 forklift cargo test -p staging-node-cli --release --locked -- --ignored # https://github.com/paritytech/ci_cd/issues/864 test-linux-stable-runtime-benchmarks: @@ -70,4 +72,55 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: script - run: time forklift cargo nextest run --workspace --features runtime-benchmarks benchmark --locked --cargo-profile testnet + run: forklift cargo nextest run --workspace --features runtime-benchmarks benchmark --locked --cargo-profile testnet + + test-linux-stable: + needs: [set-image, changes] + if: ${{ needs.changes.outputs.rust }} + runs-on: ${{ matrix.runners }} + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + partition: [1/3, 2/3, 3/3] + runners: [arc-runners-polkadot-sdk-beefy, oldlinux] + container: + image: ${{ needs.set-image.outputs.IMAGE }} + # needed for tests that use unshare syscall + options: --security-opt seccomp=unconfined + env: + RUST_TOOLCHAIN: stable + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: script + run: | + # Fixes "detected dubious ownership" error in the ci + git config --global --add safe.directory '*' + forklift cargo nextest run \ + --workspace \ + --locked \ + --release \ + --no-fail-fast \ + --features try-runtime,experimental,riscv,ci-only-tests \ + --partition count:${{ matrix.partition }} + # run runtime-api tests with `enable-staging-api` feature on the 1st node + - name: runtime-api tests + if: ${{ matrix.partition == '1/3' }} + run: forklift cargo nextest run -p sp-api-test --features enable-staging-api + + confirm-required-jobs-passed: + runs-on: ubuntu-latest + name: All tests passed + # If any new job gets added, be sure to add it to this array + needs: + [ + test-linux-stable-int, + test-linux-stable-runtime-benchmarks, + test-linux-stable, + ] + steps: + - run: echo '### Good job! All the tests passed 🚀' >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a413d330615931faab5326da6aee31469ac2903f..1be2dd7921e0c521606556b3e567eab1661257d0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -5,7 +5,7 @@ on: branches: - master pull_request: - types: [opened, synchronize, reopened, ready_for_review] + types: [ opened, synchronize, reopened, ready_for_review ] merge_group: concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} @@ -15,7 +15,7 @@ jobs: changes: permissions: pull-requests: read - uses: ./.github/workflows/check-changed-files.yml + uses: ./.github/workflows/reusable-check-changed-files.yml set-image: # GitHub Actions allows using 'env' in a container context. @@ -31,7 +31,7 @@ jobs: run: cat .github/env >> $GITHUB_OUTPUT quick-benchmarks: - needs: [set-image, changes] + needs: [ set-image, changes ] if: ${{ needs.changes.outputs.rust }} runs-on: arc-runners-polkadot-sdk-beefy timeout-minutes: 60 @@ -50,7 +50,7 @@ jobs: # cf https://github.com/paritytech/polkadot-sdk/issues/1652 test-syscalls: - needs: [set-image, changes] + needs: [ set-image, changes ] if: ${{ needs.changes.outputs.rust }} runs-on: arc-runners-polkadot-sdk-beefy timeout-minutes: 60 @@ -75,7 +75,7 @@ jobs: # fi cargo-check-all-benches: - needs: [set-image, changes] + needs: [ set-image, changes ] if: ${{ needs.changes.outputs.rust }} runs-on: arc-runners-polkadot-sdk-beefy timeout-minutes: 60 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/test.yml b/.gitlab/pipeline/test.yml index d171a8a19426c959f776aa0780f4373c4b23b4e6..319c95ad6112c33bbb27ca765e100e224e945c28 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -110,8 +110,6 @@ test-linux-stable-codecov: codecovcli -v do-upload -f target/coverage/result/report-${CI_NODE_INDEX}.lcov --disable-search -t ${CODECOV_TOKEN} -r paritytech/polkadot-sdk --commit-sha ${CI_COMMIT_SHA} --fail-on-error --git-service github; fi - # - test-linux-stable: stage: test extends: @@ -398,6 +396,11 @@ test-frame-ui: script: - time cargo test --locked -q --profile testnet -p frame-support-test --features=frame-feature-testing,no-metadata-docs,try-runtime,experimental - time cargo test --locked -q --profile testnet -p frame-support-test --features=frame-feature-testing,frame-feature-testing-2,no-metadata-docs,try-runtime,experimental + - time cargo test --locked -q --profile testnet -p xcm-procedural + - time cargo test --locked -q --profile testnet -p frame-election-provider-solution-type + - time cargo test --locked -q --profile testnet -p sp-api-test + # There is multiple version of sp-runtime-interface in the repo. So we point to the manifest. + - time cargo test --locked -q --profile testnet --manifest-path substrate/primitives/runtime-interface/Cargo.toml - cat /cargo_target_dir/debug/.fingerprint/memory_units-759eddf317490d2b/lib-memory_units.json || true # This job runs all benchmarks defined in the `/bin/node/runtime` once to check that there are no errors. 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 ad75224fefdc47bc2f3c21b789464bbae9ca050c..cc8b64457a7920fa4fcf160955587891322243ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", ] @@ -649,7 +649,7 @@ dependencies = [ [[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", @@ -725,7 +725,7 @@ 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 0.12.6", ] @@ -737,7 +737,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", "synstructure 0.13.1", ] @@ -749,7 +749,7 @@ 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", ] @@ -760,15 +760,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "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", @@ -824,6 +824,7 @@ dependencies = [ "sp-runtime", "staging-xcm", "staging-xcm-executor", + "xcm-runtime-apis", ] [[package]] @@ -1016,6 +1017,7 @@ dependencies = [ "polkadot-runtime-common", "primitive-types", "scale-info", + "snowbridge-router-primitives", "sp-api", "sp-block-builder", "sp-consensus-aura", @@ -1025,6 +1027,7 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", + "sp-std 14.0.0", "sp-storage 19.0.0", "sp-transaction-pool", "sp-version", @@ -1094,7 +1097,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", ] @@ -1206,7 +1209,7 @@ checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ "event-listener 5.2.0", "event-listener-strategy", - "pin-project-lite 0.2.12", + "pin-project-lite", ] [[package]] @@ -1260,7 +1263,7 @@ dependencies = [ "log", "memchr", "once_cell", - "pin-project-lite 0.2.12", + "pin-project-lite", "pin-utils", "slab", "wasm-bindgen-futures", @@ -1274,7 +1277,7 @@ checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", - "pin-project-lite 0.2.12", + "pin-project-lite", ] [[package]] @@ -1284,7 +1287,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", ] @@ -1301,7 +1304,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -1315,7 +1318,7 @@ dependencies = [ "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.12", + "pin-project-lite", ] [[package]] @@ -1360,7 +1363,7 @@ checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" dependencies = [ "proc-macro-error", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -1383,9 +1386,9 @@ dependencies = [ [[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", @@ -1399,7 +1402,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", @@ -1408,8 +1411,6 @@ dependencies = [ "ark-serialize 0.4.2", "ark-std 0.4.0", "dleq_vrf", - "fflonk", - "merlin", "rand_chacha", "rand_core", "ring 0.1.0", @@ -1478,11 +1479,11 @@ name = "binary-merkle-tree" version = "13.0.0" dependencies = [ "array-bytes", - "env_logger 0.11.3", "hash-db", "log", "sp-core", "sp-runtime", + "sp-tracing 16.0.0", ] [[package]] @@ -1508,7 +1509,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", @@ -2111,6 +2112,7 @@ dependencies = [ "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", + "frame-metadata-hash-extension", "frame-support", "frame-system", "frame-system-benchmarking", @@ -2173,7 +2175,6 @@ dependencies = [ "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", - "static_assertions", "substrate-wasm-builder", "testnet-parachains-constants", "xcm-runtime-apis", @@ -2234,10 +2235,13 @@ dependencies = [ name = "bridge-hub-westend-integration-tests" version = "1.0.0" dependencies = [ + "asset-hub-westend-runtime", + "bridge-hub-westend-runtime", "cumulus-pallet-xcmp-queue", "emulated-integration-tests-common", "frame-support", "hex-literal", + "log", "pallet-asset-conversion", "pallet-assets", "pallet-balances", @@ -2245,10 +2249,20 @@ dependencies = [ "pallet-message-queue", "pallet-xcm", "parachains-common", + "parity-scale-codec", "rococo-westend-system-emulated-network", + "scale-info", + "snowbridge-core", + "snowbridge-pallet-inbound-queue", + "snowbridge-pallet-inbound-queue-fixtures", + "snowbridge-pallet-outbound-queue", + "snowbridge-pallet-system", + "snowbridge-router-primitives", + "sp-core", "sp-runtime", "staging-xcm", "staging-xcm-executor", + "testnet-parachains-constants", ] [[package]] @@ -2281,6 +2295,7 @@ dependencies = [ "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", + "frame-metadata-hash-extension", "frame-support", "frame-system", "frame-system-benchmarking", @@ -2312,6 +2327,17 @@ dependencies = [ "polkadot-runtime-common", "scale-info", "serde", + "snowbridge-beacon-primitives", + "snowbridge-core", + "snowbridge-outbound-queue-runtime-api", + "snowbridge-pallet-ethereum-client", + "snowbridge-pallet-inbound-queue", + "snowbridge-pallet-outbound-queue", + "snowbridge-pallet-system", + "snowbridge-router-primitives", + "snowbridge-runtime-common", + "snowbridge-runtime-test-common", + "snowbridge-system-runtime-api", "sp-api", "sp-block-builder", "sp-consensus-aura", @@ -2331,7 +2357,6 @@ dependencies = [ "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", - "static_assertions", "substrate-wasm-builder", "testnet-parachains-constants", "westend-runtime-constants", @@ -2381,9 +2406,9 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bs58" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ "tinyvec", ] @@ -2511,9 +2536,9 @@ checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" [[package]] name = "cc" -version = "1.0.83" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7" dependencies = [ "jobserver", "libc", @@ -2755,12 +2780,12 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.3" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" +checksum = "35723e6a11662c2afb578bcf0b88bf6ea8e21282a953428f240574fcc3a2b5b3" dependencies = [ "clap_builder", - "clap_derive 4.5.3", + "clap_derive 4.5.11", ] [[package]] @@ -2774,9 +2799,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "49eb96cbfa7cfa35017b7cd548c75b14c3118c98b423041d70562665e07fb0fa" dependencies = [ "anstream", "anstyle", @@ -2791,7 +2816,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.11", ] [[package]] @@ -2803,19 +2828,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.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" +checksum = "5d029b67f89d30bbb547c89fd5161293c0aec155fc691d7924b64550662db93e" dependencies = [ "heck 0.5.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -2884,6 +2909,7 @@ dependencies = [ "pallet-message-queue", "pallet-treasury", "pallet-utility", + "pallet-whitelist", "pallet-xcm", "parachains-common", "parity-scale-codec", @@ -3002,7 +3028,7 @@ checksum = "d51beaa537d73d2d1ff34ee70bc095f170420ab2ec5d687ecd3ec2b0d092514b" dependencies = [ "nom", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -3047,7 +3073,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", @@ -3258,6 +3284,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" @@ -3324,6 +3380,36 @@ dependencies = [ "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]] name = "coretime-westend-runtime" version = "0.1.0" @@ -3557,7 +3643,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.3", + "clap 4.5.11", "criterion-plot", "futures", "is-terminal", @@ -3691,7 +3777,7 @@ dependencies = [ name = "cumulus-client-cli" version = "0.7.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.11", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -4065,7 +4151,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", ] @@ -4150,15 +4236,29 @@ dependencies = [ ] [[package]] -name = "cumulus-primitives-aura" -version = "0.7.0" +name = "cumulus-pov-validator" +version = "0.1.0" dependencies = [ + "anyhow", + "clap 4.5.11", "parity-scale-codec", - "polkadot-core-primitives", + "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" +dependencies = [ "sp-api", "sp-consensus-aura", - "sp-runtime", ] [[package]] @@ -4186,8 +4286,6 @@ dependencies = [ "scale-info", "sp-core", "sp-inherents", - "sp-runtime", - "sp-state-machine", "sp-trie", ] @@ -4226,8 +4324,6 @@ name = "cumulus-primitives-timestamp" version = "0.7.0" dependencies = [ "cumulus-primitives-core", - "futures", - "parity-scale-codec", "sp-inherents", "sp-timestamp", ] @@ -4242,8 +4338,6 @@ dependencies = [ "pallet-asset-conversion", "parity-scale-codec", "polkadot-runtime-common", - "polkadot-runtime-parachains", - "sp-io", "sp-runtime", "staging-xcm", "staging-xcm-builder", @@ -4463,7 +4557,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.5.3", + "clap 4.5.11", "criterion", "cumulus-client-cli", "cumulus-client-collator", @@ -4592,7 +4686,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", ] @@ -4631,7 +4725,7 @@ dependencies = [ "codespan-reporting", "once_cell", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "scratch", "syn 2.0.61", ] @@ -4649,7 +4743,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", ] @@ -4741,9 +4835,12 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] [[package]] name = "derivative" @@ -4752,7 +4849,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -4763,7 +4860,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", ] @@ -4774,7 +4871,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", ] @@ -4786,7 +4883,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", ] @@ -4882,7 +4979,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", ] @@ -4895,7 +4992,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", @@ -4942,7 +5039,7 @@ dependencies = [ "derive-syn-parse", "once_cell", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "regex", "syn 2.0.61", "termcolor", @@ -4991,7 +5088,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", ] @@ -5137,7 +5234,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", ] @@ -5149,7 +5246,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", ] @@ -5169,18 +5266,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", ] @@ -5191,7 +5288,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" dependencies = [ "log", - "regex", ] [[package]] @@ -5226,7 +5322,6 @@ dependencies = [ "anstream", "anstyle", "env_filter", - "humantime", "log", ] @@ -5352,7 +5447,7 @@ checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91" dependencies = [ "concurrent-queue", "parking", - "pin-project-lite 0.2.12", + "pin-project-lite", ] [[package]] @@ -5362,7 +5457,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ "event-listener 5.2.0", - "pin-project-lite 0.2.12", + "pin-project-lite", ] [[package]] @@ -5385,7 +5480,7 @@ dependencies = [ "fs-err", "prettyplease 0.2.12", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -5457,7 +5552,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", ] @@ -5659,9 +5754,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", ] @@ -5725,7 +5820,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.5.3", + "clap 4.5.11", "comfy-table", "frame-benchmarking", "frame-support", @@ -5789,7 +5884,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", @@ -5817,7 +5912,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.5.3", + "clap 4.5.11", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -5889,14 +5984,14 @@ dependencies = [ name = "frame-omni-bencher" version = "0.1.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.11", "cumulus-primitives-proof-size-hostfunction", - "env_logger 0.11.3", "frame-benchmarking-cli", "log", "sc-cli", "sp-runtime", "sp-statement-store", + "sp-tracing 16.0.0", ] [[package]] @@ -5973,15 +6068,26 @@ dependencies = [ "Inflector", "cfg-expr", "derive-syn-parse", + "docify", "expander", + "frame-support", "frame-support-procedural-tools", + "frame-system", "itertools 0.11.0", "macro_magic", + "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", ] @@ -5992,7 +6098,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", ] @@ -6001,7 +6107,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", ] @@ -6231,7 +6337,7 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite 0.2.12", + "pin-project-lite", "waker-fn", ] @@ -6242,7 +6348,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ "futures-core", - "pin-project-lite 0.2.12", + "pin-project-lite", ] [[package]] @@ -6252,7 +6358,7 @@ 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", ] @@ -6297,7 +6403,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.12", + "pin-project-lite", "pin-utils", "slab", ] @@ -6665,9 +6771,9 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "hkdf" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ "hmac 0.12.1", ] @@ -6755,7 +6861,7 @@ checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", "http 0.2.9", - "pin-project-lite 0.2.12", + "pin-project-lite", ] [[package]] @@ -6778,7 +6884,7 @@ dependencies = [ "futures-util", "http 1.1.0", "http-body 1.0.0", - "pin-project-lite 0.2.12", + "pin-project-lite", ] [[package]] @@ -6815,7 +6921,7 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project-lite 0.2.12", + "pin-project-lite", "socket2 0.5.7", "tokio", "tower-service", @@ -6838,7 +6944,7 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project-lite 0.2.12", + "pin-project-lite", "smallvec", "tokio", "want", @@ -6890,7 +6996,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.0", "hyper 1.3.1", - "pin-project-lite 0.2.12", + "pin-project-lite", "socket2 0.5.7", "tokio", "tower", @@ -6942,6 +7048,16 @@ 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.10.2" @@ -7035,7 +7151,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", ] @@ -7055,7 +7171,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]] @@ -7399,7 +7515,7 @@ dependencies = [ "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", ] @@ -7596,9 +7712,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" @@ -7787,11 +7903,11 @@ dependencies = [ [[package]] name = "libp2p-identity" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "999ec70441b2fb35355076726a6bc466c932e9bdc66f6a11c6c0aa17c7ab9be0" +checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" dependencies = [ - "bs58 0.5.0", + "bs58 0.5.1", "ed25519-dalek", "hkdf", "multihash 0.19.1", @@ -7987,7 +8103,7 @@ dependencies = [ "heck 0.4.1", "proc-macro-warning 0.4.2", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -8059,9 +8175,9 @@ dependencies = [ [[package]] name = "libp2p-websocket" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3facf0691bab65f571bc97c6c65ffa836248ca631d631b7691ac91deb7fceb5f" +checksum = "004ee9c4a4631435169aee6aad2f62e3984dc031c43b6d29731e8e82a016c538" dependencies = [ "either", "futures", @@ -8070,9 +8186,10 @@ dependencies = [ "libp2p-identity", "log", "parking_lot 0.12.3", - "quicksink", + "pin-project-lite", "rw-stream-sink", - "soketto 0.7.1", + "soketto 0.8.0", + "thiserror", "url", "webpki-roots 0.25.2", ] @@ -8313,9 +8430,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", @@ -8400,7 +8517,7 @@ checksum = "cc33f9f0351468d26fbc53d9ce00a096c8522ecb42f19b50f34f2c422f76d21d" dependencies = [ "macro_magic_core", "macro_magic_macros", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -8414,7 +8531,7 @@ dependencies = [ "derive-syn-parse", "macro_magic_core_macros", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -8425,7 +8542,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -8436,7 +8553,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" dependencies = [ "macro_magic_core", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -8488,9 +8605,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memfd" @@ -8629,7 +8746,7 @@ dependencies = [ name = "minimal-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.11", "docify", "futures", "futures-timer", @@ -8800,7 +8917,7 @@ checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" dependencies = [ "cfg-if", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -8812,7 +8929,7 @@ checksum = "af7cbce79ec385a1d4f54baa90a76401eb15d9cab93685f62e7e9f942aa00ae2" dependencies = [ "cfg-if", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -8924,7 +9041,7 @@ 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 0.12.6", ] @@ -8972,7 +9089,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", ] @@ -9122,7 +9239,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", - "clap 4.5.3", + "clap 4.5.11", "derive_more", "fs_extra", "futures", @@ -9180,7 +9297,6 @@ dependencies = [ "sc-mixnet", "sc-rpc", "sc-rpc-api", - "sc-rpc-spec-v2", "sc-sync-state-rpc", "sc-transaction-pool-api", "sp-api", @@ -9201,7 +9317,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.11", "generate-bags", "kitchensink-runtime", ] @@ -9210,7 +9326,7 @@ dependencies = [ name = "node-template-release" version = "3.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.11", "flate2", "fs_extra", "glob", @@ -9352,6 +9468,12 @@ 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" @@ -9359,7 +9481,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", ] @@ -9526,7 +9648,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", ] @@ -9593,7 +9715,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", ] @@ -9753,7 +9875,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -9960,6 +10081,7 @@ version = "28.0.0" dependencies = [ "array-bytes", "binary-merkle-tree", + "frame-benchmarking", "frame-support", "frame-system", "log", @@ -10203,7 +10325,6 @@ dependencies = [ "array-bytes", "assert_matches", "bitflags 1.3.2", - "env_logger 0.11.3", "environmental", "frame-benchmarking", "frame-support", @@ -10298,7 +10419,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", ] @@ -10881,7 +11002,6 @@ name = "pallet-mmr" version = "27.0.0" dependencies = [ "array-bytes", - "env_logger 0.11.3", "frame-benchmarking", "frame-support", "frame-system", @@ -10893,6 +11013,7 @@ dependencies = [ "sp-io", "sp-mmr-primitives", "sp-runtime", + "sp-tracing 16.0.0", ] [[package]] @@ -11532,7 +11653,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", ] @@ -11891,6 +12012,7 @@ dependencies = [ "log", "pallet-balances", "pallet-bridge-messages", + "pallet-xcm-bridge-hub-router", "parity-scale-codec", "scale-info", "sp-core", @@ -11925,7 +12047,7 @@ dependencies = [ name = "parachain-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.11", "color-print", "cumulus-client-cli", "cumulus-client-collator", @@ -12176,7 +12298,7 @@ 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", ] @@ -12288,9 +12410,9 @@ dependencies = [ [[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" @@ -12512,6 +12634,7 @@ dependencies = [ "pallet-balances", "pallet-identity", "pallet-message-queue", + "pallet-xcm", "parachains-common", "parity-scale-codec", "polkadot-runtime-common", @@ -12589,9 +12712,9 @@ dependencies = [ [[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" @@ -12622,7 +12745,7 @@ dependencies = [ "pest", "pest_meta", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -12663,21 +12786,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" @@ -12762,7 +12879,6 @@ version = "7.0.0" dependencies = [ "assert_matches", "bitvec", - "env_logger 0.11.3", "futures", "futures-timer", "itertools 0.11.0", @@ -12782,6 +12898,7 @@ dependencies = [ "schnorrkel 0.11.4", "sp-authority-discovery", "sp-core", + "sp-tracing 16.0.0", "tracing-gum", ] @@ -12792,10 +12909,8 @@ dependencies = [ "always-assert", "assert_matches", "bitvec", - "env_logger 0.11.3", "futures", "futures-timer", - "log", "maplit", "polkadot-node-network-protocol", "polkadot-node-subsystem", @@ -12809,6 +12924,7 @@ dependencies = [ "sp-core", "sp-keyring", "sp-keystore", + "sp-tracing 16.0.0", "tracing-gum", ] @@ -12891,7 +13007,7 @@ name = "polkadot-cli" version = "7.0.0" dependencies = [ "cfg-if", - "clap 4.5.3", + "clap 4.5.11", "frame-benchmarking-cli", "futures", "log", @@ -12921,11 +13037,9 @@ version = "7.0.0" dependencies = [ "assert_matches", "bitvec", - "env_logger 0.11.3", "fatality", "futures", "futures-timer", - "log", "parity-scale-codec", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -12941,6 +13055,7 @@ dependencies = [ "sp-keyring", "sp-keystore", "sp-runtime", + "sp-tracing 16.0.0", "thiserror", "tokio-util", "tracing-gum", @@ -13094,7 +13209,6 @@ dependencies = [ "async-trait", "bitvec", "derive_more", - "env_logger 0.11.3", "futures", "futures-timer", "itertools 0.11.0", @@ -13127,6 +13241,7 @@ dependencies = [ "sp-keyring", "sp-keystore", "sp-runtime", + "sp-tracing 16.0.0", "thiserror", "tracing-gum", ] @@ -13137,7 +13252,6 @@ version = "7.0.0" dependencies = [ "assert_matches", "bitvec", - "env_logger 0.11.3", "futures", "futures-timer", "kvdb", @@ -13157,6 +13271,7 @@ dependencies = [ "sp-consensus", "sp-core", "sp-keyring", + "sp-tracing 16.0.0", "thiserror", "tracing-gum", ] @@ -13224,8 +13339,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", ] @@ -13320,23 +13437,17 @@ name = "polkadot-node-core-prospective-parachains" version = "6.0.0" dependencies = [ "assert_matches", - "bitvec", "fatality", "futures", - "parity-scale-codec", - "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", - "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-primitives", "polkadot-primitives-test-helpers", + "rand", "rstest", - "sc-keystore", - "sp-application-crypto", "sp-core", - "sp-keyring", - "sp-keystore", + "sp-tracing 16.0.0", "thiserror", "tracing-gum", ] @@ -13466,8 +13577,10 @@ dependencies = [ "nix 0.28.0", "parity-scale-codec", "polkadot-node-core-pvf-common", + "polkadot-node-primitives", "polkadot-parachain-primitives", "polkadot-primitives", + "sp-maybe-compressed-blob", "tracing-gum", ] @@ -13482,6 +13595,7 @@ dependencies = [ "nix 0.28.0", "parity-scale-codec", "polkadot-node-core-pvf-common", + "polkadot-node-primitives", "polkadot-primitives", "rayon", "rococo-runtime", @@ -13538,7 +13652,7 @@ name = "polkadot-node-metrics" version = "7.0.0" dependencies = [ "assert_cmd", - "bs58 0.5.0", + "bs58 0.5.1", "futures", "futures-timer", "http-body-util", @@ -13676,7 +13790,6 @@ dependencies = [ "assert_matches", "async-trait", "derive_more", - "env_logger 0.11.3", "fatality", "futures", "futures-channel", @@ -13749,8 +13862,9 @@ dependencies = [ "async-trait", "bridge-hub-rococo-runtime", "bridge-hub-westend-runtime", - "clap 4.5.3", + "clap 4.5.11", "collectives-westend-runtime", + "color-eyre", "color-print", "contracts-rococo-runtime", "coretime-rococo-runtime", @@ -13982,7 +14096,7 @@ dependencies = [ name = "polkadot-runtime-metrics" version = "7.0.0" dependencies = [ - "bs58 0.5.0", + "bs58 0.5.1", "frame-benchmarking", "parity-scale-codec", "polkadot-primitives", @@ -14011,6 +14125,7 @@ dependencies = [ "pallet-balances", "pallet-broker", "pallet-message-queue", + "pallet-mmr", "pallet-session", "pallet-staking", "pallet-timestamp", @@ -14040,6 +14155,7 @@ dependencies = [ "sp-runtime", "sp-session", "sp-staking", + "sp-std 14.0.0", "sp-tracing 16.0.0", "staging-xcm", "staging-xcm-executor", @@ -14054,25 +14170,14 @@ dependencies = [ "asset-test-utils", "assets-common", "binary-merkle-tree", - "bp-asset-hub-rococo", - "bp-asset-hub-westend", - "bp-bridge-hub-cumulus", - "bp-bridge-hub-kusama", - "bp-bridge-hub-polkadot", - "bp-bridge-hub-rococo", - "bp-bridge-hub-westend", "bp-header-chain", - "bp-kusama", "bp-messages", "bp-parachains", "bp-polkadot", - "bp-polkadot-bulletin", "bp-polkadot-core", "bp-relayers", - "bp-rococo", "bp-runtime", "bp-test-utils", - "bp-westend", "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "bridge-hub-common", @@ -14283,7 +14388,6 @@ dependencies = [ "polkadot-service", "polkadot-statement-distribution", "polkadot-statement-table", - "rococo-runtime-constants", "sc-allocator", "sc-authority-discovery", "sc-basic-authorship", @@ -14427,7 +14531,6 @@ dependencies = [ "testnet-parachains-constants", "tracing-gum", "tracing-gum-proc-macro", - "westend-runtime-constants", "xcm-emulator", "xcm-procedural", "xcm-runtime-apis", @@ -14450,6 +14553,7 @@ dependencies = [ "frame-support", "frame-system", "kitchensink-runtime", + "log", "minimal-template-runtime", "pallet-asset-conversion-tx-payment", "pallet-asset-tx-payment", @@ -14476,6 +14580,7 @@ dependencies = [ "pallet-transaction-payment", "pallet-uniques", "pallet-utility", + "pallet-xcm", "parachain-template-runtime", "parity-scale-codec", "polkadot-sdk", @@ -14513,9 +14618,12 @@ dependencies = [ "staging-node-cli", "staging-parachain-info", "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "subkey", "substrate-wasm-builder", "xcm-docs", + "xcm-simulator", ] [[package]] @@ -14557,7 +14665,6 @@ dependencies = [ "assert_matches", "async-trait", "bitvec", - "env_logger 0.11.3", "frame-benchmarking", "frame-benchmarking-cli", "frame-metadata-hash-extension", @@ -14665,6 +14772,7 @@ dependencies = [ "sp-state-machine", "sp-storage 19.0.0", "sp-timestamp", + "sp-tracing 16.0.0", "sp-transaction-pool", "sp-version", "sp-weights", @@ -14731,11 +14839,10 @@ dependencies = [ "async-trait", "bincode", "bitvec", - "clap 4.5.3", + "clap 4.5.11", "clap-num", "color-eyre", "colored", - "env_logger 0.11.3", "futures", "futures-timer", "hex", @@ -14788,6 +14895,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-timestamp", + "sp-tracing 16.0.0", "strum 0.26.2", "substrate-prometheus-endpoint", "tokio", @@ -14829,7 +14937,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "async-trait", - "clap 4.5.3", + "clap 4.5.11", "color-eyre", "futures", "futures-timer", @@ -14971,7 +15079,7 @@ dependencies = [ name = "polkadot-voter-bags" version = "7.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.11", "generate-bags", "sp-io", "westend-runtime", @@ -15025,7 +15133,7 @@ checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c" dependencies = [ "polkavm-common", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -15072,7 +15180,7 @@ dependencies = [ "concurrent-queue", "libc", "log", - "pin-project-lite 0.2.12", + "pin-project-lite", "windows-sys 0.48.0", ] @@ -15084,7 +15192,7 @@ checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14" dependencies = [ "cfg-if", "concurrent-queue", - "pin-project-lite 0.2.12", + "pin-project-lite", "rustix 0.38.21", "tracing", "windows-sys 0.52.0", @@ -15128,6 +15236,12 @@ dependencies = [ "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" @@ -15284,7 +15398,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", ] @@ -15296,7 +15410,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", ] @@ -15313,7 +15427,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -15324,7 +15438,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", ] @@ -15405,7 +15519,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", ] @@ -15513,7 +15627,7 @@ dependencies = [ "anyhow", "itertools 0.10.5", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -15526,7 +15640,7 @@ dependencies = [ "anyhow", "itertools 0.11.0", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -15653,17 +15767,6 @@ dependencies = [ "rand", ] -[[package]] -name = "quicksink" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77de3c815e5a160b1539c6592796801df2043ae35e123b46d73380cfa57af858" -dependencies = [ - "futures-core", - "futures-sink", - "pin-project-lite 0.1.12", -] - [[package]] name = "quinn" version = "0.9.4" @@ -15671,7 +15774,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e8b432585672228923edbbf64b8b12c14e1112f62e88737655b4a083dbcd78e" dependencies = [ "bytes", - "pin-project-lite 0.2.12", + "pin-project-lite", "quinn-proto 0.9.6", "quinn-udp 0.3.2", "rustc-hash", @@ -15690,7 +15793,7 @@ checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" dependencies = [ "bytes", "futures-io", - "pin-project-lite 0.2.12", + "pin-project-lite", "quinn-proto 0.10.6", "quinn-udp 0.4.1", "rustc-hash", @@ -15772,9 +15875,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", ] @@ -15962,21 +16065,21 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acde58d073e9c79da00f2b5b84eed919c8326832648a5b109b3fce1bb1175280" +checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" +checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -16105,13 +16208,12 @@ dependencies = [ name = "relay-utils" version = "0.1.0" dependencies = [ - "ansi_term", "anyhow", "async-std", "async-trait", "backoff", "bp-runtime", - "env_logger 0.11.3", + "console", "futures", "isahc", "jsonpath_lib", @@ -16120,6 +16222,7 @@ dependencies = [ "parking_lot 0.12.3", "serde_json", "sp-runtime", + "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "sysinfo", "thiserror", @@ -16131,7 +16234,7 @@ dependencies = [ name = "remote-ext-tests-bags-list" version = "1.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.11", "frame-system", "log", "pallet-bags-list-remote-tests", @@ -16164,7 +16267,7 @@ dependencies = [ "mime", "once_cell", "percent-encoding", - "pin-project-lite 0.2.12", + "pin-project-lite", "rustls 0.21.7", "rustls-pemfile 1.0.3", "serde", @@ -16204,13 +16307,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", @@ -16466,6 +16570,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", @@ -16524,7 +16629,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", @@ -16979,7 +17084,7 @@ name = "sc-chain-spec" version = "28.0.0" dependencies = [ "array-bytes", - "clap 4.5.3", + "clap 4.5.11", "docify", "log", "memmap2 0.9.3", @@ -17012,7 +17117,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", ] @@ -17022,7 +17127,7 @@ version = "0.36.0" dependencies = [ "array-bytes", "chrono", - "clap 4.5.3", + "clap 4.5.11", "fdlimit", "futures", "futures-timer", @@ -17497,7 +17602,6 @@ dependencies = [ "array-bytes", "assert_matches", "criterion", - "env_logger 0.11.3", "num_cpus", "parity-scale-codec", "parking_lot 0.12.3", @@ -17580,7 +17684,7 @@ dependencies = [ name = "sc-informant" version = "0.33.0" dependencies = [ - "ansi_term", + "console", "futures", "futures-timer", "log", @@ -17872,7 +17976,7 @@ dependencies = [ name = "sc-network-types" version = "0.10.0" dependencies = [ - "bs58 0.5.0", + "bs58 0.5.1", "ed25519-dalek", "libp2p-identity", "litep2p", @@ -17940,7 +18044,6 @@ name = "sc-rpc" version = "29.0.0" dependencies = [ "assert_matches", - "env_logger 0.11.3", "futures", "jsonrpsee", "log", @@ -17971,6 +18074,7 @@ dependencies = [ "sp-runtime", "sp-session", "sp-statement-store", + "sp-tracing 16.0.0", "sp-version", "substrate-test-runtime-client", "tokio", @@ -18186,7 +18290,6 @@ dependencies = [ name = "sc-statement-store" version = "10.0.0" dependencies = [ - "env_logger 0.11.3", "log", "parity-db", "parking_lot 0.12.3", @@ -18197,6 +18300,7 @@ dependencies = [ "sp-core", "sp-runtime", "sp-statement-store", + "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "tempfile", "tokio", @@ -18206,7 +18310,7 @@ dependencies = [ name = "sc-storage-monitor" version = "0.16.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.11", "fs4", "log", "sp-core", @@ -18276,8 +18380,8 @@ dependencies = [ name = "sc-tracing" version = "28.0.0" dependencies = [ - "ansi_term", "chrono", + "console", "criterion", "is-terminal", "lazy_static", @@ -18308,7 +18412,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", ] @@ -18422,7 +18526,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", ] @@ -18460,7 +18564,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", ] @@ -18728,9 +18832,9 @@ checksum = "f97841a747eef040fcd2e7b3b9a220a7205926e60488e673d9e4926d27772ce5" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.206" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "5b3e4cd94123dd520a128bcd11e34d9e9e423e7e3e50425cb1b4b1e3549d0284" dependencies = [ "serde_derive", ] @@ -18755,12 +18859,12 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.206" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "fabfb6138d2383ea8208cf98ccf69cdfb1aff4088460681d84189aa259762f97" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -18771,7 +18875,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", ] @@ -18786,12 +18890,13 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.124" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "66ad62847a56b3dba58cc891acd13884b9c61138d330c0d7b6181713d4fce38d" dependencies = [ "indexmap 2.2.3", "itoa", + "memchr", "ryu", "serde", ] @@ -18819,9 +18924,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", @@ -18861,7 +18966,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", ] @@ -19152,7 +19257,7 @@ dependencies = [ "base64 0.21.2", "bip39", "blake2-rfc", - "bs58 0.5.0", + "bs58 0.5.1", "chacha20", "crossbeam-queue", "derive_more", @@ -19350,7 +19455,6 @@ name = "snowbridge-outbound-queue-merkle-tree" version = "0.3.0" dependencies = [ "array-bytes", - "env_logger 0.11.3", "hex", "hex-literal", "parity-scale-codec", @@ -19358,6 +19462,7 @@ dependencies = [ "sp-core", "sp-crypto-hashing", "sp-runtime", + "sp-tracing 16.0.0", ] [[package]] @@ -19628,8 +19733,9 @@ dependencies = [ name = "solochain-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.11", "frame-benchmarking-cli", + "frame-metadata-hash-extension", "frame-system", "futures", "jsonrpsee", @@ -19672,6 +19778,7 @@ version = "0.0.0" dependencies = [ "frame-benchmarking", "frame-executive", + "frame-metadata-hash-extension", "frame-support", "frame-system", "frame-system-benchmarking", @@ -19735,7 +19842,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", ] @@ -19855,7 +19962,6 @@ name = "sp-blockchain" version = "28.0.0" dependencies = [ "futures", - "log", "parity-scale-codec", "parking_lot 0.12.3", "schnellru", @@ -19866,6 +19972,7 @@ dependencies = [ "sp-runtime", "sp-state-machine", "thiserror", + "tracing", ] [[package]] @@ -19932,6 +20039,7 @@ dependencies = [ "sp-keystore", "sp-mmr-primitives", "sp-runtime", + "sp-weights", "strum 0.26.2", "w3f-bls", ] @@ -19995,7 +20103,7 @@ dependencies = [ "bitflags 1.3.2", "blake2 0.10.6", "bounded-collections", - "bs58 0.5.0", + "bs58 0.5.1", "criterion", "dyn-clonable", "ed25519-zebra", @@ -20118,7 +20226,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", ] @@ -20137,7 +20245,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", ] @@ -20146,7 +20254,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", ] @@ -20302,7 +20410,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.5.3", + "clap 4.5.11", "honggfuzz", "rand", "sp-npos-elections", @@ -20418,7 +20526,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", ] @@ -20430,7 +20538,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", ] @@ -20691,7 +20799,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", ] @@ -20748,9 +20856,9 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spinners" -version = "4.1.0" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08615eea740067d9899969bc2891c68a19c315cb1f66640af9a9ecb91b13bcab" +checksum = "a0ef947f358b9c238923f764c72a4a9d42f2d637c46e059dbd319d6e7cfb4f82" dependencies = [ "lazy_static", "maplit", @@ -20776,7 +20884,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", @@ -20801,7 +20909,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", ] @@ -20815,7 +20923,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" name = "staging-chain-spec-builder" version = "1.6.1" dependencies = [ - "clap 4.5.3", + "clap 4.5.11", "log", "sc-chain-spec", "serde_json", @@ -20828,7 +20936,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "clap 4.5.3", + "clap 4.5.11", "clap_complete", "criterion", "futures", @@ -20842,6 +20950,7 @@ dependencies = [ "parity-scale-codec", "platforms", "polkadot-sdk", + "pretty_assertions", "rand", "regex", "sc-service-test", @@ -20862,7 +20971,7 @@ dependencies = [ name = "staging-node-inspect" version = "0.12.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.11", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -20908,6 +21017,7 @@ dependencies = [ "schemars", "serde", "sp-io", + "sp-runtime", "sp-weights", "xcm-procedural", ] @@ -20921,6 +21031,7 @@ dependencies = [ "frame-system", "impl-trait-for-tuples", "log", + "pallet-asset-conversion", "pallet-assets", "pallet-balances", "pallet-salary", @@ -20934,6 +21045,7 @@ dependencies = [ "primitive-types", "scale-info", "sp-arithmetic", + "sp-core", "sp-io", "sp-runtime", "sp-weights", @@ -20990,7 +21102,7 @@ dependencies = [ "cfg_aliases", "memchr", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -21063,7 +21175,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", ] @@ -21099,7 +21211,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", ] @@ -21112,7 +21224,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", ] @@ -21125,7 +21237,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", ] @@ -21134,7 +21246,7 @@ dependencies = [ name = "subkey" version = "9.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.11", "sc-cli", ] @@ -21430,6 +21542,7 @@ dependencies = [ "console", "filetime", "frame-metadata", + "jobserver", "merkleized-metadata", "parity-scale-codec", "parity-wasm", @@ -21574,7 +21687,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", ] @@ -21585,7 +21698,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", ] @@ -21597,7 +21710,7 @@ checksum = "86b837ef12ab88835251726eb12237655e61ec8dc8a280085d1961cdc3dfd047" dependencies = [ "paste", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -21608,7 +21721,7 @@ 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", ] @@ -21620,7 +21733,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", ] @@ -21739,7 +21852,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", ] @@ -21759,7 +21872,7 @@ dependencies = [ name = "test-parachain-adder-collator" version = "1.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.11", "futures", "futures-timer", "log", @@ -21806,7 +21919,7 @@ dependencies = [ name = "test-parachain-undying-collator" version = "1.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.11", "futures", "futures-timer", "log", @@ -21903,7 +22016,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", ] @@ -21914,7 +22027,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", ] @@ -21989,14 +22102,16 @@ dependencies = [ [[package]] name = "time" -version = "0.3.27" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb39ee79a6d8de55f48f2293a830e040392f1c5f16e336bdd1788cd0aadce07" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", "libc", + "num-conv", "num_threads", + "powerfmt", "serde", "time-core", "time-macros", @@ -22004,16 +22119,17 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.13" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733d258752e9303d392b94b75230d07b0b9c489350c69b851fc6c065fde3e8f9" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] @@ -22063,7 +22179,7 @@ dependencies = [ "mio", "num_cpus", "parking_lot 0.12.3", - "pin-project-lite 0.2.12", + "pin-project-lite", "signal-hook-registry", "socket2 0.5.7", "tokio-macros", @@ -22077,7 +22193,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", ] @@ -22120,7 +22236,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", ] @@ -22163,7 +22279,7 @@ dependencies = [ "futures-core", "futures-io", "futures-sink", - "pin-project-lite 0.2.12", + "pin-project-lite", "tokio", ] @@ -22230,7 +22346,7 @@ dependencies = [ "futures-core", "futures-util", "pin-project", - "pin-project-lite 0.2.12", + "pin-project-lite", "tokio", "tower-layer", "tower-service", @@ -22248,7 +22364,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.0", "http-body-util", - "pin-project-lite 0.2.12", + "pin-project-lite", "tower-layer", "tower-service", ] @@ -22272,7 +22388,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", ] @@ -22284,7 +22400,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", ] @@ -22326,7 +22442,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", ] @@ -22399,6 +22515,7 @@ dependencies = [ "sharded-slab", "smallvec", "thread_local", + "time", "tracing", "tracing-core", "tracing-log 0.2.0", @@ -22716,12 +22833,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", ] @@ -22850,9 +22967,9 @@ checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -22875,11 +22992,12 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "serde", "serde_json", "wasm-bindgen-macro", @@ -22887,15 +23005,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" 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", ] @@ -22914,22 +23032,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" 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.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "syn 2.0.61", "wasm-bindgen-backend", "wasm-bindgen-shared", @@ -22937,9 +23055,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-bindgen-test" @@ -22962,7 +23080,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]] @@ -23445,6 +23563,7 @@ dependencies = [ "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-offences-benchmarking", + "pallet-parameters", "pallet-preimage", "pallet-proxy", "pallet-recovery", @@ -23455,7 +23574,6 @@ dependencies = [ "pallet-session-benchmarking", "pallet-society", "pallet-staking", - "pallet-staking-reward-curve", "pallet-staking-runtime-api", "pallet-state-trie-migration", "pallet-sudo", @@ -23532,6 +23650,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", @@ -24027,7 +24146,7 @@ version = "7.0.0" dependencies = [ "Inflector", "proc-macro2 1.0.82", - "quote 1.0.35", + "quote 1.0.36", "staging-xcm", "syn 2.0.61", "trybuild", @@ -24037,7 +24156,6 @@ dependencies = [ name = "xcm-runtime-apis" version = "0.1.0" dependencies = [ - "env_logger 0.11.3", "frame-executive", "frame-support", "frame-system", @@ -24050,6 +24168,7 @@ dependencies = [ "scale-info", "sp-api", "sp-io", + "sp-tracing 16.0.0", "sp-weights", "staging-xcm", "staging-xcm-builder", @@ -24193,7 +24312,7 @@ 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", ] @@ -24213,7 +24332,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 0999d630401300ebf4475f4be226756d8e10e5a2..74b12f96603ada0cebb369c2cf7915b618b06b68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,9 @@ [workspace.package] authors = ["Parity Technologies "] edition = "2021" -repository = "https://github.com/paritytech/polkadot-sdk.git" +homepage = "https://paritytech.github.io/polkadot-sdk/" license = "GPL-3.0-only" -homepage = "https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/index.html" +repository = "https://github.com/paritytech/polkadot-sdk.git" [workspace] resolver = "2" @@ -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", @@ -537,32 +542,34 @@ default-members = [ [workspace.lints.rust] suspicious_double_ref_op = { level = "allow", priority = 2 } +# `substrate_runtime` is a common `cfg` condition name used in the repo. +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(substrate_runtime)'] } [workspace.lints.clippy] all = { level = "allow", priority = 0 } -correctness = { level = "warn", priority = 1 } +bind_instead_of_map = { level = "allow", priority = 2 } # stylistic +borrowed-box = { level = "allow", priority = 2 } # Reasonable to fix this one complexity = { level = "warn", priority = 1 } +correctness = { level = "warn", priority = 1 } +default_constructed_unit_structs = { level = "allow", priority = 2 } # stylistic +derivable_impls = { level = "allow", priority = 2 } # false positives +eq_op = { level = "allow", priority = 2 } # In tests we test equality. +erasing_op = { level = "allow", priority = 2 } # E.g. 0 * DOLLARS +extra-unused-type-parameters = { level = "allow", priority = 2 } # stylistic +identity-op = { level = "allow", priority = 2 } # One case where we do 0 + if-same-then-else = { level = "allow", priority = 2 } -zero-prefixed-literal = { level = "allow", priority = 2 } # 00_1000_000 -type_complexity = { level = "allow", priority = 2 } # raison d'etre +needless-lifetimes = { level = "allow", priority = 2 } # generated code +needless_option_as_deref = { level = "allow", priority = 2 } # false positives nonminimal-bool = { level = "allow", priority = 2 } # maybe -borrowed-box = { level = "allow", priority = 2 } # Reasonable to fix this one +option-map-unit-fn = { level = "allow", priority = 2 } # stylistic +stable_sort_primitive = { level = "allow", priority = 2 } # prefer stable sort too-many-arguments = { level = "allow", priority = 2 } # (Turning this on would lead to) -needless-lifetimes = { level = "allow", priority = 2 } # generated code +type_complexity = { level = "allow", priority = 2 } # raison d'etre +unit_arg = { level = "allow", priority = 2 } # stylistic unnecessary_cast = { level = "allow", priority = 2 } # Types may change -identity-op = { level = "allow", priority = 2 } # One case where we do 0 + useless_conversion = { level = "allow", priority = 2 } # Types may change -unit_arg = { level = "allow", priority = 2 } # stylistic -option-map-unit-fn = { level = "allow", priority = 2 } # stylistic -bind_instead_of_map = { level = "allow", priority = 2 } # stylistic -erasing_op = { level = "allow", priority = 2 } # E.g. 0 * DOLLARS -eq_op = { level = "allow", priority = 2 } # In tests we test equality. while_immutable_condition = { level = "allow", priority = 2 } # false positives -needless_option_as_deref = { level = "allow", priority = 2 } # false positives -derivable_impls = { level = "allow", priority = 2 } # false positives -stable_sort_primitive = { level = "allow", priority = 2 } # prefer stable sort -extra-unused-type-parameters = { level = "allow", priority = 2 } # stylistic -default_constructed_unit_structs = { level = "allow", priority = 2 } # stylistic +zero-prefixed-literal = { level = "allow", priority = 2 } # 00_1000_000 [workspace.dependencies] Inflector = { version = "0.11.4" } @@ -571,7 +578,6 @@ 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" } -ansi_term = { version = "0.12.1" } anyhow = { version = "1.0.81" } aquamarine = { version = "0.5.0" } arbitrary = { version = "1.3.2" } @@ -589,7 +595,7 @@ ark-ed-on-bls12-381-bandersnatch-ext = { version = "0.4.1", default-features = f 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.10" } +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 } @@ -602,7 +608,7 @@ 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.64" } +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" } @@ -642,7 +648,7 @@ bridge-hub-test-utils = { path = "cumulus/parachains/runtimes/bridge-hubs/test-u 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 } +bs58 = { version = "0.5.1", 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 } @@ -654,7 +660,7 @@ chain-spec-builder = { path = "substrate/bin/utils/chain-spec-builder", default- 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.3" } +clap = { version = "4.5.10" } clap-num = { version = "1.0.2" } clap_complete = { version = "4.0.2" } coarsetime = { version = "0.1.22" } @@ -667,7 +673,9 @@ 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 } @@ -720,8 +728,7 @@ 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.12" } -env_logger = { version = "0.11.3" } +enumn = { version = "0.1.13" } 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" } @@ -797,6 +804,7 @@ 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" } @@ -808,17 +816,17 @@ 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.153" } +libc = { version = "0.2.155" } libfuzzer-sys = { version = "0.4" } libp2p = { version = "0.52.4" } -libp2p-identity = { version = "0.2.3" } +libp2p-identity = { version = "0.2.9" } 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.21", default-features = false } +log = { version = "0.4.22", default-features = false } macro_magic = { version = "0.5.1" } maplit = { version = "1.0.2" } memmap2 = { version = "0.9.3" } @@ -986,7 +994,7 @@ 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.14", default-features = false } +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" } @@ -1069,7 +1077,7 @@ 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.33" } +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" } @@ -1077,7 +1085,7 @@ 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" } +ref-cast = { version = "1.0.23" } regex = { version = "1.10.2" } relay-substrate-client = { path = "bridges/relays/client-substrate" } relay-utils = { path = "bridges/relays/utils" } @@ -1164,10 +1172,10 @@ 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.197", default-features = false } +serde = { version = "1.0.206", 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.124", default-features = false } serde_yaml = { version = "0.9" } serial_test = { version = "2.0.0" } sha1 = { version = "0.10.6" } @@ -1254,7 +1262,7 @@ 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" } +spinners = { version = "4.1.1" } 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 } @@ -1314,7 +1322,7 @@ 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" } +trybuild = { version = "1.0.89" } tt-call = { version = "1.0.8" } tuplex = { version = "0.1", default-features = false } twox-hash = { version = "1.6.3", default-features = false } @@ -1323,7 +1331,7 @@ 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" } +walkdir = { version = "2.5.0" } wasm-bindgen-test = { version = "0.3.19" } wasm-instrument = { version = "0.4", default-features = false } wasm-opt = { version = "0.116" } @@ -1349,22 +1357,22 @@ zstd = { version = "0.12.4", default-features = false } [profile.release] # Polkadot runtime requires unwinding. -panic = "unwind" opt-level = 3 +panic = "unwind" # make sure dev builds with backtrace do not slow us down [profile.dev.package.backtrace] inherits = "release" [profile.production] +codegen-units = 1 inherits = "release" lto = true -codegen-units = 1 [profile.testnet] -inherits = "release" debug = 1 # debug symbols are useful for profilers debug-assertions = true +inherits = "release" overflow-checks = true # The list of dependencies below (which can be both direct and indirect dependencies) are crates diff --git a/README.md b/README.md index 92901d070db0854dd4b1daef8c3ed7a3fd3893f2..34d657194daa67de18088fb04d3ae878421c6d9f 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,7 @@ forks](https://img.shields.io/github/forks/paritytech/polkadot-sdk) -[![StackExchange](https://img.shields.io/badge/StackExchange-Community%20&%20Support-222222?logo=stackexchange)](https://substrate.stackexchange.com/)  ![GitHub contributors](https://img.shields.io/github/contributors/paritytech/polkadot-sdk)  ![GitHub commit activity](https://img.shields.io/github/commit-activity/m/paritytech/polkadot-sdk) - -![GitHub lines of code](https://tokei.rs/b1/github/paritytech/polkadot-sdk)   -![GitHub last commit](https://img.shields.io/github/last-commit/paritytech/polkadot-sdk) +[![StackExchange](https://img.shields.io/badge/StackExchange-Community%20&%20Support-222222?logo=stackexchange)](https://substrate.stackexchange.com/)  ![GitHub contributors](https://img.shields.io/github/contributors/paritytech/polkadot-sdk)  ![GitHub commit activity](https://img.shields.io/github/commit-activity/m/paritytech/polkadot-sdk)  ![GitHub last commit](https://img.shields.io/github/last-commit/paritytech/polkadot-sdk) > The Polkadot SDK repository provides all the components needed to start building on the > [Polkadot](https://polkadot.network) network, a multi-chain blockchain platform that enables @@ -21,6 +18,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 | bash +``` + ## 📚 Documentation * [🦀 rust-docs](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/index.html) diff --git a/bridges/bin/runtime-common/src/integrity.rs b/bridges/bin/runtime-common/src/integrity.rs index f661db8a22057ecf6c8b217336e5a98660344cb2..a0a9367dd1400309d0f0be967665a4543ad982cb 100644 --- a/bridges/bin/runtime-common/src/integrity.rs +++ b/bridges/bin/runtime-common/src/integrity.rs @@ -27,17 +27,25 @@ use frame_support::{storage::generator::StorageValue, traits::Get, weights::Weig 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>); @@ -60,14 +68,15 @@ macro_rules! assert_bridge_messages_pallet_types( 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 $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; - use 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) assert_type_eq_all!(<$r as MessagesConfig<$i>>::ThisChain, $this); assert_type_eq_all!(<$r as MessagesConfig<$i>>::BridgedChain, $bridged); diff --git a/bridges/chains/chain-asset-hub-rococo/Cargo.toml b/bridges/chains/chain-asset-hub-rococo/Cargo.toml index b765fbc57bb0aec2eb4544a01dd84c057ced16ef..363a869048aae4d875d68a8ca46e30756cbc799f 100644 --- a/bridges/chains/chain-asset-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-asset-hub-rococo/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" repository.workspace = true +[package.metadata.polkadot-sdk] +exclude-from-umbrella = true + [lints] workspace = true diff --git a/bridges/chains/chain-asset-hub-westend/Cargo.toml b/bridges/chains/chain-asset-hub-westend/Cargo.toml index ff89864fb2db4667d7929ef540ad4ec46cf2a36c..430d9b6116cfc7fba648b96b1de6ef379f3e38f3 100644 --- a/bridges/chains/chain-asset-hub-westend/Cargo.toml +++ b/bridges/chains/chain-asset-hub-westend/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" repository.workspace = true +[package.metadata.polkadot-sdk] +exclude-from-umbrella = true + [lints] workspace = true diff --git a/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml b/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml index 5609398385f98b9d3731b196a057e939b1c099de..99ba721991ee90b04e708beb37dcca2f0aa5c96c 100644 --- a/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" repository.workspace = true +[package.metadata.polkadot-sdk] +exclude-from-umbrella = true + [lints] workspace = true diff --git a/bridges/chains/chain-bridge-hub-kusama/Cargo.toml b/bridges/chains/chain-bridge-hub-kusama/Cargo.toml index 605643b0a4eb7e5d514edb1d4f1ad9db65a2c8ec..39f7b44daa5543b83108761d7acf5f72d5a8458f 100644 --- a/bridges/chains/chain-bridge-hub-kusama/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-kusama/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" repository.workspace = true +[package.metadata.polkadot-sdk] +exclude-from-umbrella = true + [lints] workspace = true diff --git a/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml b/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml index 97e36a19c748c0e5da990eda75bdbed9aa444e6f..3b0ac96e7cd367cd373cdaedcbeaf299af7debe0 100644 --- a/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" repository.workspace = true +[package.metadata.polkadot-sdk] +exclude-from-umbrella = true + [lints] workspace = true diff --git a/bridges/chains/chain-bridge-hub-rococo/Cargo.toml b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml index 5c918470322353c32556c3e5d381fb2ea713b2ab..66848ba0e2634b3b4e525f27013b04768204c749 100644 --- a/bridges/chains/chain-bridge-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" repository.workspace = true +[package.metadata.polkadot-sdk] +exclude-from-umbrella = true + [lints] workspace = true diff --git a/bridges/chains/chain-bridge-hub-westend/Cargo.toml b/bridges/chains/chain-bridge-hub-westend/Cargo.toml index 0b429ab9a0bd9793a9129ed8483a608f71bfb44c..24a196c1d70d128c49ddb788a699fe6e22e6c359 100644 --- a/bridges/chains/chain-bridge-hub-westend/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-westend/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" repository.workspace = true +[package.metadata.polkadot-sdk] +exclude-from-umbrella = true + [lints] workspace = true diff --git a/bridges/chains/chain-kusama/Cargo.toml b/bridges/chains/chain-kusama/Cargo.toml index ec45c1eddce5d3b7be1f3a8ae9b83ca6332e7c28..aec4041f7d574243c07f3fefa66b8b6d4cb36057 100644 --- a/bridges/chains/chain-kusama/Cargo.toml +++ b/bridges/chains/chain-kusama/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" repository.workspace = true +[package.metadata.polkadot-sdk] +exclude-from-umbrella = true + [lints] workspace = true diff --git a/bridges/chains/chain-polkadot-bulletin/Cargo.toml b/bridges/chains/chain-polkadot-bulletin/Cargo.toml index ea5f4d2e77591bd8840e869f9b3567df5d56fd56..aecf9314273686f03a25b0f4e5988eabb157dfe7 100644 --- a/bridges/chains/chain-polkadot-bulletin/Cargo.toml +++ b/bridges/chains/chain-polkadot-bulletin/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" repository.workspace = true +[package.metadata.polkadot-sdk] +exclude-from-umbrella = true + [lints] workspace = true diff --git a/bridges/chains/chain-rococo/Cargo.toml b/bridges/chains/chain-rococo/Cargo.toml index 49a1a397ee096532cfc0b5d3a42cf14469f8ed46..8a99267691dc218d924fd0786e9fc45a5baa7f3c 100644 --- a/bridges/chains/chain-rococo/Cargo.toml +++ b/bridges/chains/chain-rococo/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" repository.workspace = true +[package.metadata.polkadot-sdk] +exclude-from-umbrella = true + [lints] workspace = true diff --git a/bridges/chains/chain-westend/Cargo.toml b/bridges/chains/chain-westend/Cargo.toml index 5e27bc647bfc5f07d5ab029307ef6dcf67121fb3..cd6abe8abe6d69d5e5b9aa65d3ff7861c42d23cf 100644 --- a/bridges/chains/chain-westend/Cargo.toml +++ b/bridges/chains/chain-westend/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" repository.workspace = true +[package.metadata.polkadot-sdk] +exclude-from-umbrella = true + [lints] workspace = true diff --git a/bridges/modules/messages/src/proofs.rs b/bridges/modules/messages/src/proofs.rs index 18367029d72cd356939f19f769a36b634ad1991e..a3318833fa611a6515469172dcc24f114bbbf4ad 100644 --- a/bridges/modules/messages/src/proofs.rs +++ b/bridges/modules/messages/src/proofs.rs @@ -63,7 +63,7 @@ pub fn verify_messages_proof, I: 'static>( 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); + let messages_in_the_proof = nonces_range.saturating_len(); if messages_in_the_proof != MessageNonce::from(messages_count) { return Err(VerificationError::MessagesCountMismatch) } diff --git a/bridges/modules/messages/src/tests/mock.rs b/bridges/modules/messages/src/tests/mock.rs index ffdd536830b5f7dde6671c75ba1ac108d7d218e4..99da019dc0847d0787c30ada8e614270e83ddfdb 100644 --- a/bridges/modules/messages/src/tests/mock.rs +++ b/bridges/modules/messages/src/tests/mock.rs @@ -225,7 +225,7 @@ impl crate::benchmarking::Config<()> for TestRuntime { use bp_runtime::RangeInclusiveExt; let dispatch_weight = - REGULAR_PAYLOAD.declared_weight * params.message_nonces.checked_len().unwrap_or(0); + REGULAR_PAYLOAD.declared_weight * params.message_nonces.saturating_len(); ( *prepare_messages_proof( params.message_nonces.into_iter().map(|n| message(n, REGULAR_PAYLOAD)).collect(), diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index 092df477265fc0933180feaf355f174ca433df6f..8fbf61a0a5354e808ad4a5c74094c907eb29470d 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -38,6 +38,8 @@ xcm-executor = { workspace = true } 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 df72e7a3c4fcc596cd89cc119c44aeb7c6915eaf..0cca32ba9e5f55a80baa4168f483ea33ba69ce58 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -25,14 +25,24 @@ use bp_messages::{ 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, 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}, + 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; @@ -50,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, } } @@ -137,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 { @@ -160,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())) ]; } diff --git a/bridges/relays/utils/Cargo.toml b/bridges/relays/utils/Cargo.toml index 93e42763967b90c32409dcacbac22486a09a9892..beb03b9381d4f8289f6119fd57c94b04de9faa44 100644 --- a/bridges/relays/utils/Cargo.toml +++ b/bridges/relays/utils/Cargo.toml @@ -11,13 +11,13 @@ publish = false workspace = true [dependencies] -ansi_term = { workspace = true } anyhow = { workspace = true } async-std = { workspace = true } async-trait = { workspace = true } backoff = { workspace = true } +console = { workspace = true } isahc = { workspace = true } -env_logger = { workspace = true } +sp-tracing = { workspace = true, default-features = true } futures = { workspace = true } jsonpath_lib = { workspace = true } log = { workspace = true } diff --git a/bridges/relays/utils/src/initialize.rs b/bridges/relays/utils/src/initialize.rs index 64d710242710b722b3b5be67dc439f814cd7e9df..564ed1f0e5cc831e27df6dbb973583752ad4374f 100644 --- a/bridges/relays/utils/src/initialize.rs +++ b/bridges/relays/utils/src/initialize.rs @@ -17,7 +17,14 @@ //! Relayer initialization functions. use parking_lot::Mutex; -use std::{cell::RefCell, fmt::Display, io::Write}; +use sp_tracing::{ + tracing::Level, + tracing_subscriber::{ + fmt::{time::OffsetTime, SubscriberBuilder}, + EnvFilter, + }, +}; +use std::cell::RefCell; /// Relayer version that is provided as metric. Must be set by a binary /// (get it with `option_env!("CARGO_PKG_VERSION")` from a binary package code). @@ -40,102 +47,25 @@ pub fn initialize_logger(with_timestamp: bool) { ) .expect("static format string is valid"); - let mut builder = env_logger::Builder::new(); - builder.filter_level(log::LevelFilter::Warn); - builder.filter_module("bridge", log::LevelFilter::Info); - builder.parse_default_env(); - if with_timestamp { - builder.format(move |buf, record| { - let timestamp = time::OffsetDateTime::now_local() - .unwrap_or_else(|_| time::OffsetDateTime::now_utc()); - let timestamp = timestamp.format(&format).unwrap_or_else(|_| timestamp.to_string()); + let local_time = OffsetTime::new( + time::UtcOffset::current_local_offset().unwrap_or(time::UtcOffset::UTC), + format, + ); - let log_level = color_level(record.level()); - let log_target = color_target(record.target()); - let timestamp = if cfg!(windows) { - Either::Left(timestamp) - } else { - Either::Right(ansi_term::Colour::Fixed(8).bold().paint(timestamp)) - }; + let env_filter = EnvFilter::from_default_env() + .add_directive(Level::WARN.into()) + .add_directive("bridge=info".parse().expect("static filter string is valid")); - writeln!( - buf, - "{}{} {} {} {}", - loop_name_prefix(), - timestamp, - log_level, - log_target, - record.args(), - ) - }); - } else { - builder.format(move |buf, record| { - let log_level = color_level(record.level()); - let log_target = color_target(record.target()); + let builder = SubscriberBuilder::default().with_env_filter(env_filter); - writeln!(buf, "{}{log_level} {log_target} {}", loop_name_prefix(), record.args(),) - }); + if with_timestamp { + builder.with_timer(local_time).init(); + } else { + builder.without_time().init(); } - - builder.init(); } /// Initialize relay loop. Must only be called once per every loop task. pub(crate) fn initialize_loop(loop_name: String) { LOOP_NAME.with(|g_loop_name| *g_loop_name.borrow_mut() = loop_name); } - -/// Returns loop name prefix to use in logs. The prefix is initialized with the `initialize_loop` -/// call. -fn loop_name_prefix() -> String { - // try_with to avoid panic outside of async-std task context - LOOP_NAME - .try_with(|loop_name| { - // using borrow is ok here, because loop is only initialized once (=> borrow_mut will - // only be called once) - let loop_name = loop_name.borrow(); - if loop_name.is_empty() { - String::new() - } else { - format!("[{loop_name}] ") - } - }) - .unwrap_or_else(|_| String::new()) -} - -enum Either { - Left(A), - Right(B), -} -impl Display for Either { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - Self::Left(a) => write!(fmt, "{a}"), - Self::Right(b) => write!(fmt, "{b}"), - } - } -} - -fn color_target(target: &str) -> impl Display + '_ { - if cfg!(windows) { - Either::Left(target) - } else { - Either::Right(ansi_term::Colour::Fixed(8).paint(target)) - } -} - -fn color_level(level: log::Level) -> impl Display { - if cfg!(windows) { - 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), - }) - } -} diff --git a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml index 00cc700fbe832cea4e77ddabe3a148c42bd30bef..9d4cffc98d789532ef13ed2a59f9f8d28d330ebb 100644 --- a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml +++ b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml @@ -23,10 +23,10 @@ sp-runtime = { workspace = true } [dev-dependencies] 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 } +sp-tracing = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/src/lib.rs b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/src/lib.rs index 8c91ccd04d9a6b001db3cf561b95ff0723d700aa..d5c89b9c0987f22573aed765ce87ca0ec54c5bf1 100644 --- a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/src/lib.rs +++ b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/src/lib.rs @@ -335,7 +335,7 @@ mod tests { #[test] fn should_generate_empty_root() { // given - let _ = env_logger::try_init(); + sp_tracing::init_for_tests(); let data = vec![]; // when @@ -351,7 +351,7 @@ mod tests { #[test] fn should_generate_single_root() { // given - let _ = env_logger::try_init(); + sp_tracing::init_for_tests(); let data = make_leaves(1); // when @@ -367,7 +367,7 @@ mod tests { #[test] fn should_generate_root_pow_2() { // given - let _ = env_logger::try_init(); + sp_tracing::init_for_tests(); let data = make_leaves(2); // when @@ -382,7 +382,7 @@ mod tests { #[test] fn should_generate_root_complex() { - let _ = env_logger::try_init(); + sp_tracing::init_for_tests(); let test = |root, data: Vec| { assert_eq!( array_bytes::bytes2hex("", merkle_root::(data.into_iter()).as_ref()), @@ -401,7 +401,7 @@ mod tests { #[ignore] fn should_generate_and_verify_proof() { // given - let _ = env_logger::try_init(); + sp_tracing::init_for_tests(); let data: Vec = make_leaves(3); // when @@ -458,7 +458,7 @@ mod tests { #[test] #[should_panic] fn should_panic_on_invalid_leaf_index() { - let _ = env_logger::try_init(); + sp_tracing::init_for_tests(); merkle_proof::(make_leaves(1).into_iter(), 5); } } 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/consensus/aura/src/collators/lookahead.rs b/cumulus/client/consensus/aura/src/collators/lookahead.rs index 749b131123949de9a00801558017b6637e48380d..02d60538a7323b86948c4378c7d0d4cd5c634116 100644 --- a/cumulus/client/consensus/aura/src/collators/lookahead.rs +++ b/cumulus/client/consensus/aura/src/collators/lookahead.rs @@ -39,10 +39,13 @@ use cumulus_primitives_aura::AuraUnincludedSegmentApi; use cumulus_primitives_core::{CollectCollationInfo, PersistedValidationData}; use cumulus_relay_chain_interface::RelayChainInterface; -use polkadot_node_primitives::SubmitCollationParams; +use polkadot_node_primitives::{PoV, SubmitCollationParams}; use polkadot_node_subsystem::messages::CollationGenerationMessage; use polkadot_overseer::Handle as OverseerHandle; -use polkadot_primitives::{CollatorPair, Id as ParaId, OccupiedCoreAssumption}; +use polkadot_primitives::{ + BlockNumber as RBlockNumber, CollatorPair, Hash as RHash, HeadData, Id as ParaId, + OccupiedCoreAssumption, +}; use futures::prelude::*; use sc_client_api::{backend::AuxStore, BlockBackend, BlockOf}; @@ -54,10 +57,49 @@ 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 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}; +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 { @@ -97,7 +139,58 @@ pub struct Params { /// Run async-backing-friendly Aura. pub fn run( - mut params: Params, + params: Params, +) -> 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, +{ + 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, @@ -339,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. // 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/pallets/collator-selection/Cargo.toml b/cumulus/pallets/collator-selection/Cargo.toml index b3512dc2ae6c9a646e63d911bdf09b132f5098cd..8d67db3daf8bb5b1284ef1dd6e7bfea7305b452f 100644 --- a/cumulus/pallets/collator-selection/Cargo.toml +++ b/cumulus/pallets/collator-selection/Cargo.toml @@ -2,7 +2,7 @@ authors.workspace = true description = "Simple pallet to select collators for a parachain." edition.workspace = true -homepage = "https://substrate.io" +homepage.workspace = true license = "Apache-2.0" name = "pallet-collator-selection" readme = "README.md" diff --git a/cumulus/pallets/collator-selection/src/mock.rs b/cumulus/pallets/collator-selection/src/mock.rs index 459b1cb5fdf28c118751c3afccc4b882891d1cc3..d13f9e9d8c44d3190cce7a168a26bad784824a0f 100644 --- a/cumulus/pallets/collator-selection/src/mock.rs +++ b/cumulus/pallets/collator-selection/src/mock.rs @@ -187,7 +187,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { candidacy_bond: 10, invulnerables, }; - let session = pallet_session::GenesisConfig:: { keys }; + let session = pallet_session::GenesisConfig:: { keys, ..Default::default() }; pallet_balances::GenesisConfig:: { balances } .assimilate_storage(&mut t) .unwrap(); diff --git a/cumulus/pallets/session-benchmarking/Cargo.toml b/cumulus/pallets/session-benchmarking/Cargo.toml index e182ac45edebd9c22df15d18f9d3548176c538c5..5af94434e0afeacec3866f8f531f6afe1f88ee64 100644 --- a/cumulus/pallets/session-benchmarking/Cargo.toml +++ b/cumulus/pallets/session-benchmarking/Cargo.toml @@ -4,7 +4,7 @@ version = "9.0.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true description = "FRAME sessions pallet benchmarking" readme = "README.md" 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/src/impls.rs b/cumulus/parachains/common/src/impls.rs index 42ea50c75a8d4e207ffa6b6ad7682013218de64d..c1797c0a75132d4cd3b64ac3e90791fab4dc516a 100644 --- a/cumulus/parachains/common/src/impls.rs +++ b/cumulus/parachains/common/src/impls.rs @@ -67,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/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 3a87322664d91edb829b44603122c300602f2978..5b70ed490c633b7d78558e72762fb60a2f7d0635 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 @@ -62,6 +62,7 @@ pub fn genesis() -> Storage { ) }) .collect(), + ..Default::default() }, polkadot_xcm: asset_hub_rococo_runtime::PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION), @@ -69,7 +70,7 @@ pub fn genesis() -> Storage { }, assets: asset_hub_rococo_runtime::AssetsConfig { assets: vec![ - (RESERVABLE_ASSET_ID, AssetHubRococoAssetOwner::get(), true, ED), + (RESERVABLE_ASSET_ID, AssetHubRococoAssetOwner::get(), false, ED), (USDT_ID, AssetHubRococoAssetOwner::get(), true, ED), ], ..Default::default() @@ -80,7 +81,7 @@ pub fn genesis() -> Storage { ( PenpalTeleportableAssetLocation::get(), PenpalSiblingSovereignAccount::get(), - true, + false, ED, ), ], 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 80d2376c6811d7e8f407330dd3c2b02a5260159b..1f98d3ba964d8b808f42f17fdb44a4add24beb90 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 @@ -59,5 +59,5 @@ impl_accounts_helpers_for_parachain!(AssetHubRococo); impl_assert_events_helpers_for_parachain!(AssetHubRococo); impl_assets_helpers_for_system_parachain!(AssetHubRococo, Rococo); impl_assets_helpers_for_parachain!(AssetHubRococo); -impl_foreign_assets_helpers_for_parachain!(AssetHubRococo, xcm::v3::Location); +impl_foreign_assets_helpers_for_parachain!(AssetHubRococo, xcm::v4::Location); impl_xcm_helpers_for_parachain!(AssetHubRococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs index 219d1306906cbc6c20609870bec496c5bd16eaeb..d20e059f9fea48a649934b6ca2a0470327ee5e54 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/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}; @@ -58,13 +58,17 @@ pub fn genesis() -> Storage { ) }) .collect(), + ..Default::default() }, polkadot_xcm: asset_hub_westend_runtime::PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION), ..Default::default() }, assets: asset_hub_westend_runtime::AssetsConfig { - assets: vec![(RESERVABLE_ASSET_ID, AssetHubWestendAssetOwner::get(), true, ED)], + assets: vec![ + (RESERVABLE_ASSET_ID, AssetHubWestendAssetOwner::get(), false, ED), + (USDT_ID, AssetHubWestendAssetOwner::get(), true, ED), + ], ..Default::default() }, foreign_assets: asset_hub_westend_runtime::ForeignAssetsConfig { @@ -73,7 +77,7 @@ pub fn genesis() -> Storage { ( PenpalTeleportableAssetLocation::get(), PenpalSiblingSovereignAccount::get(), - true, + false, ED, ), ], 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 608690218d2f4c439511e508e261fe3e74d37465..6066adec52c30020e2c9b26cf2db303e0948fa9c 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 @@ -59,5 +59,5 @@ impl_accounts_helpers_for_parachain!(AssetHubWestend); impl_assert_events_helpers_for_parachain!(AssetHubWestend); impl_assets_helpers_for_system_parachain!(AssetHubWestend, Westend); impl_assets_helpers_for_parachain!(AssetHubWestend); -impl_foreign_assets_helpers_for_parachain!(AssetHubWestend, xcm::v3::Location); +impl_foreign_assets_helpers_for_parachain!(AssetHubWestend, xcm::v4::Location); impl_xcm_helpers_for_parachain!(AssetHubWestend); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs index 12778215b1320f591bec787198243c825313e858..3786d529ea6502988f92c18955722a7a0f9ebded 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs @@ -52,6 +52,7 @@ pub fn genesis() -> Storage { ) }) .collect(), + ..Default::default() }, polkadot_xcm: bridge_hub_rococo_runtime::PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION), 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 d8b8edaf2409ba1da0aef01874792d6ef21e6a8a..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 @@ -17,6 +17,7 @@ pub mod genesis; pub use bridge_hub_rococo_runtime::{ xcm_config::XcmConfig as BridgeHubRococoXcmConfig, EthereumBeaconClient, EthereumInboundQueue, + ExistentialDeposit as BridgeHubRococoExistentialDeposit, RuntimeOrigin as BridgeHubRococoRuntimeOrigin, }; diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs index 4be68e510f4d254dcf645db682b6cf34ff69e634..f38f385db65068928b0f83de4cdef998813c0dba 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs @@ -23,6 +23,7 @@ use emulated_integration_tests_common::{ use parachains_common::Balance; pub const PARA_ID: u32 = 1002; +pub const ASSETHUB_PARA_ID: u32 = 1000; pub const ED: Balance = testnet_parachains_constants::westend::currency::EXISTENTIAL_DEPOSIT; pub fn genesis() -> Storage { @@ -51,6 +52,7 @@ pub fn genesis() -> Storage { ) }) .collect(), + ..Default::default() }, polkadot_xcm: bridge_hub_westend_runtime::PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION), @@ -64,6 +66,11 @@ pub fn genesis() -> Storage { owner: Some(get_account_id_from_seed::(accounts::BOB)), ..Default::default() }, + ethereum_system: bridge_hub_westend_runtime::EthereumSystemConfig { + para_id: PARA_ID.into(), + asset_hub_para_id: ASSETHUB_PARA_ID.into(), + ..Default::default() + }, ..Default::default() }; 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 f701b3096994a3da7bd59726bedb0802e1b14276..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,7 +15,10 @@ pub mod genesis; -pub use bridge_hub_westend_runtime::xcm_config::XcmConfig as BridgeHubWestendXcmConfig; +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/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/genesis.rs index 6a28b1a9dddb8ca8b118592d85ef11367569d2a0..d4ef184ea392de3bcd936b889aa030e032ad120c 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/genesis.rs @@ -51,6 +51,7 @@ pub fn genesis() -> Storage { ) }) .collect(), + ..Default::default() }, polkadot_xcm: collectives_westend_runtime::PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION), 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..e0f035c368e3966f1d2fc08b7d0bf2597fadda01 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/src/genesis.rs @@ -0,0 +1,67 @@ +// 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(), + ..Default::default() + }, + 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..239ad3760c1120b5bfdf04f93e442bf1a50f2976 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/src/genesis.rs @@ -0,0 +1,67 @@ +// 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(), + ..Default::default() + }, + 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/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/src/genesis.rs index b14009933029bfbc5cd5eeda9263126cd92a23c6..36a701d24c27e9cda44a06d033332e7f03177d88 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/src/genesis.rs @@ -18,7 +18,9 @@ use sp_core::storage::Storage; // Cumulus use cumulus_primitives_core::ParaId; -use emulated_integration_tests_common::{build_genesis_storage, collators, SAFE_XCM_VERSION}; +use emulated_integration_tests_common::{ + accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, +}; use parachains_common::Balance; pub const PARA_ID: u32 = 1004; @@ -27,6 +29,9 @@ pub const ED: Balance = testnet_parachains_constants::rococo::currency::EXISTENT pub fn genesis() -> Storage { let genesis_config = people_rococo_runtime::RuntimeGenesisConfig { system: people_rococo_runtime::SystemConfig::default(), + balances: people_rococo_runtime::BalancesConfig { + balances: accounts::init_balances().iter().cloned().map(|k| (k, ED * 4096)).collect(), + }, parachain_info: people_rococo_runtime::ParachainInfoConfig { parachain_id: ParaId::from(PARA_ID), ..Default::default() @@ -47,6 +52,7 @@ pub fn genesis() -> Storage { ) }) .collect(), + ..Default::default() }, polkadot_xcm: people_rococo_runtime::PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION), diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/src/genesis.rs index d385fbebc821c05205f55bc5ea5f04d57ec9af21..942ec1b31d2b46f3b3ec9c253a1c6ee521119b4d 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/src/genesis.rs @@ -18,7 +18,9 @@ use sp_core::storage::Storage; // Cumulus use cumulus_primitives_core::ParaId; -use emulated_integration_tests_common::{build_genesis_storage, collators, SAFE_XCM_VERSION}; +use emulated_integration_tests_common::{ + accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, +}; use parachains_common::Balance; pub const PARA_ID: u32 = 1004; @@ -27,6 +29,9 @@ pub const ED: Balance = testnet_parachains_constants::westend::currency::EXISTEN pub fn genesis() -> Storage { let genesis_config = people_westend_runtime::RuntimeGenesisConfig { system: people_westend_runtime::SystemConfig::default(), + balances: people_westend_runtime::BalancesConfig { + balances: accounts::init_balances().iter().cloned().map(|k| (k, ED * 4096)).collect(), + }, parachain_info: people_westend_runtime::ParachainInfoConfig { parachain_id: ParaId::from(PARA_ID), ..Default::default() @@ -47,6 +52,7 @@ pub fn genesis() -> Storage { ) }) .collect(), + ..Default::default() }, polkadot_xcm: people_westend_runtime::PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION), diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs index 450439f5ea3080b66c5c572dfdae972c23c52a4b..38c94b34aa2e3bfc7b81f8ee46737ba4e153c659 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs @@ -22,7 +22,7 @@ use emulated_integration_tests_common::{ accounts, build_genesis_storage, collators, get_account_id_from_seed, SAFE_XCM_VERSION, }; use parachains_common::{AccountId, Balance}; -use penpal_runtime::xcm_config::{LocalReservableFromAssetHub, RelayLocation}; +use penpal_runtime::xcm_config::{LocalReservableFromAssetHub, RelayLocation, UsdtFromAssetHub}; // Penpal pub const PARA_ID_A: u32 = 2000; pub const PARA_ID_B: u32 = 2001; @@ -59,6 +59,7 @@ pub fn genesis(para_id: u32) -> Storage { ) }) .collect(), + ..Default::default() }, polkadot_xcm: penpal_runtime::PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION), @@ -80,6 +81,8 @@ pub fn genesis(para_id: u32) -> Storage { (RelayLocation::get(), PenpalAssetOwner::get(), true, ED), // Sufficient AssetHub asset representation (LocalReservableFromAssetHub::get(), PenpalAssetOwner::get(), true, ED), + // USDT from Asset Hub + (UsdtFromAssetHub::get(), PenpalAssetOwner::get(), true, ED), ], ..Default::default() }, diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs index 074a1de5e1852279ad32aafe97e40289cecb6758..9cb25b403600f7b8318b6d1ab41129a66107f0ac 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs @@ -75,6 +75,7 @@ pub fn genesis() -> Storage { ) }) .collect::>(), + ..Default::default() }, babe: rococo_runtime::BabeConfig { authorities: Default::default(), diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs index b9f12932b84e163214f0cfc12d32d7da24b5bc05..172e6e0ac93ec9cf2ec2f95257ffa1af450ad5a1 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs @@ -77,6 +77,7 @@ pub fn genesis() -> Storage { ) }) .collect::>(), + ..Default::default() }, staking: westend_runtime::StakingConfig { validator_count: validators::initial_authorities().len() as u32, diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 7077fbbb0a9aa2d1b572720da448ccae2fe95f03..30e66ced1fb08f640d912a1c08c3354090b67db4 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -63,11 +63,11 @@ pub const PENPAL_ID: u32 = 2000; pub const ASSETS_PALLET_ID: u8 = 50; parameter_types! { - pub PenpalTeleportableAssetLocation: xcm::v3::Location - = xcm::v3::Location::new(1, [ - xcm::v3::Junction::Parachain(PENPAL_ID), - xcm::v3::Junction::PalletInstance(ASSETS_PALLET_ID), - xcm::v3::Junction::GeneralIndex(TELEPORTABLE_ASSET_ID.into()), + pub PenpalTeleportableAssetLocation: xcm::v4::Location + = xcm::v4::Location::new(1, [ + xcm::v4::Junction::Parachain(PENPAL_ID), + xcm::v4::Junction::PalletInstance(ASSETS_PALLET_ID), + xcm::v4::Junction::GeneralIndex(TELEPORTABLE_ASSET_ID.into()), ] ); pub PenpalSiblingSovereignAccount: AccountId = Sibling::from(PENPAL_ID).into_account_truncating(); @@ -132,6 +132,7 @@ pub mod accounts { pub const EVE_STASH: &str = "Eve//stash"; pub const FERDIE_STASH: &str = "Ferdie//stash"; pub const FERDIE_BEEFY: &str = "Ferdie//stash"; + pub const DUMMY_EMPTY: &str = "JohnDoe"; pub fn init_balances() -> Vec { vec![ diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index 6f6bbe41e01bd208ee6d40a9f3b4ba8f98f7975b..578bca84ce5a54df1973803888e9d9d8d1cfe511 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,276 @@ 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 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); + } + }; +} + +#[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/common/src/xcm_helpers.rs b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs index 25e1cffad543c0aad6d955315721b63c6d509ca1..7a289a3f1ac62383e834645a57080ffa04c00710 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs @@ -23,16 +23,15 @@ use xcm::{prelude::*, DoubleEncoded}; pub fn xcm_transact_paid_execution( call: DoubleEncoded<()>, origin_kind: OriginKind, - native_asset: Asset, + fees: Asset, beneficiary: AccountId, ) -> VersionedXcm<()> { let weight_limit = WeightLimit::Unlimited; let require_weight_at_most = Weight::from_parts(1000000000, 200000); - let native_assets: Assets = native_asset.clone().into(); VersionedXcm::from(Xcm(vec![ - WithdrawAsset(native_assets), - BuyExecution { fees: native_asset, weight_limit }, + WithdrawAsset(fees.clone().into()), + BuyExecution { fees, weight_limit }, Transact { require_weight_at_most, origin_kind, call }, RefundSurplus, DepositAsset { @@ -69,3 +68,11 @@ pub fn non_fee_asset(assets: &Assets, fee_idx: usize) -> Option<(Location, u128) }; Some((asset.id.0, asset_amount)) } + +pub fn get_amount_from_versioned_assets(assets: VersionedAssets) -> u128 { + let latest_assets: Assets = assets.try_into().unwrap(); + let Fungible(amount) = latest_assets.inner()[0].fun else { + unreachable!("asset is non-fungible"); + }; + 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 298be7362ec3a4e63bb4139b1050d1b0223c9382..864f3c6edd7e3f91566666c65c509d2494009d4d 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/rococo-system/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/networks/rococo-system/Cargo.toml @@ -18,3 +18,4 @@ 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/westend-system/Cargo.toml b/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml index 37c14aa30352922b6f9f44ab89c6501484c3212d..cec2e3733b2a0fbe83608f75981e5c288c70ea7f 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml @@ -19,3 +19,4 @@ 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 b4579da94cbf6fc6fbb5f5d0e47fdfabdb5134da..f66a5f1d5fe7e0dc0aaee8325a9717e25e9f1068 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 @@ -28,6 +28,7 @@ pallet-utility = { workspace = true } xcm = { workspace = true } pallet-xcm = { workspace = true } xcm-executor = { workspace = true } +xcm-runtime-apis = { workspace = true, default-features = true } polkadot-runtime-common = { workspace = true, default-features = true } rococo-runtime-constants = { workspace = true, default-features = 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 f00945926963cb562c627eba90171f7ad58c70a5..87a090bf1ae68cb79f43b4c06a8871b7ccbdf865 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 @@ -35,12 +35,16 @@ mod imports { // Cumulus pub use asset_test_utils::xcm_helpers; pub use emulated_integration_tests_common::{ - test_parachain_is_trusted_teleporter, + accounts::DUMMY_EMPTY, + get_account_id_from_seed, test_parachain_is_trusted_teleporter, + test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, xcm_emulator::{ assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, Test, TestArgs, TestContext, TestExt, }, - xcm_helpers::{non_fee_asset, xcm_transact_paid_execution}, + xcm_helpers::{ + get_amount_from_versioned_assets, non_fee_asset, xcm_transact_paid_execution, + }, ASSETS_PALLET_ID, RESERVABLE_ASSET_ID, XCM_V3, }; pub use parachains_common::Balance; @@ -52,6 +56,7 @@ mod imports { XcmConfig as AssetHubRococoXcmConfig, }, AssetConversionOrigin as AssetHubRococoAssetConversionOrigin, + ExistentialDeposit as AssetHubRococoExistentialDeposit, }, genesis::{AssetHubRococoAssetOwner, ED as ASSET_HUB_ROCOCO_ED}, AssetHubRococoParaPallet as AssetHubRococoPallet, @@ -87,7 +92,6 @@ mod imports { pub const ASSET_ID: u32 = 3; pub const ASSET_MIN_BALANCE: u128 = 1000; - pub type RelayToSystemParaTest = Test; pub type RelayToParaTest = Test; pub type ParaToRelayTest = Test; pub type SystemParaToRelayTest = Test; 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/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs index 138ce419757b98b03d4e9a6b26259d81ca779d69..88fa379c4072b97e867f3eccb68bb23b0eeedff2 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; @@ -20,3 +21,4 @@ mod set_xcm_versions; mod swap; mod teleport; mod treasury; +mod xcm_fee_estimation; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 8b9fedcd4947cf5aaef5db0233166c6bc7cbcf21..70dde03d75a27ed300f1dbaa18a9af6536df2c13 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -493,9 +493,9 @@ fn para_to_para_through_relay_limited_reserve_transfer_assets( ) } -/// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work +/// Reserve Transfers of native asset from Relay Chain to the Asset Hub shouldn't work #[test] -fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { +fn reserve_transfer_native_asset_from_relay_to_asset_hub_fails() { // Init values for Relay Chain let signed_origin = ::RuntimeOrigin::signed(RococoSender::get().into()); let destination = Rococo::child_location_of(AssetHubRococo::para_id()); @@ -526,10 +526,10 @@ fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { }); } -/// Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work +/// Reserve Transfers of native asset from Asset Hub to Relay Chain shouldn't work #[test] -fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { - // Init values for System Parachain +fn reserve_transfer_native_asset_from_asset_hub_to_relay_fails() { + // Init values for Asset Hub let signed_origin = ::RuntimeOrigin::signed(AssetHubRococoSender::get().into()); let destination = AssetHubRococo::parent_location(); @@ -691,10 +691,10 @@ fn reserve_transfer_native_asset_from_para_to_relay() { // ========================================================================= // ======= Reserve Transfers - Native Asset - AssetHub<>Parachain ========== // ========================================================================= -/// Reserve Transfers of native asset from System Parachain to Parachain should work +/// Reserve Transfers of native asset from Asset Hub to Parachain should work #[test] -fn reserve_transfer_native_asset_from_system_para_to_para() { - // Init values for System Parachain +fn reserve_transfer_native_asset_from_asset_hub_to_para() { + // Init values for Asset Hub let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); let sender = AssetHubRococoSender::get(); let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 10000; @@ -749,9 +749,9 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { assert!(receiver_assets_after < receiver_assets_before + amount_to_send); } -/// Reserve Transfers of native asset from Parachain to System Parachain should work +/// Reserve Transfers of native asset from Parachain to Asset Hub should work #[test] -fn reserve_transfer_native_asset_from_para_to_system_para() { +fn reserve_transfer_native_asset_from_para_to_asset_hub() { // Init values for Parachain let destination = PenpalA::sibling_location_of(AssetHubRococo::para_id()); let sender = PenpalASender::get(); @@ -768,12 +768,12 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { amount_to_send * 2, ); - // Init values for System Parachain + // Init values for Asset Hub let receiver = AssetHubRococoReceiver::get(); let penpal_location_as_seen_by_ahr = AssetHubRococo::sibling_location_of(PenpalA::para_id()); let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location_as_seen_by_ahr); - // fund Parachain's SA on System Parachain with the native tokens held in reserve + // fund Parachain's SA on Asset Hub with the native tokens held in reserve AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), amount_to_send * 2)]); // Init Test @@ -824,11 +824,11 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { // ================================================================================== // ======= Reserve Transfers - Native + Non-system Asset - AssetHub<>Parachain ====== // ================================================================================== -/// Reserve Transfers of a local asset and native asset from System Parachain to Parachain should +/// Reserve Transfers of a local asset and native asset from Asset Hub to Parachain should /// work #[test] -fn reserve_transfer_assets_from_system_para_to_para() { - // Init values for System Parachain +fn reserve_transfer_multiple_assets_from_asset_hub_to_para() { + // Init values for Asset Hub let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(destination.clone()); let sender = AssetHubRococoSender::get(); @@ -939,10 +939,12 @@ fn reserve_transfer_assets_from_system_para_to_para() { ); } -/// Reserve Transfers of a foreign asset and native asset from Parachain to System Para should -/// work +/// Reserve Transfers of a random asset and native asset from Parachain to Asset Hub should work +/// Receiver is empty account to show deposit works as long as transfer includes enough DOT for ED. +/// Once we have https://github.com/paritytech/polkadot-sdk/issues/5298, +/// we should do equivalent test with USDT instead of DOT. #[test] -fn reserve_transfer_assets_from_para_to_system_para() { +fn reserve_transfer_multiple_assets_from_para_to_asset_hub() { // Init values for Parachain let destination = PenpalA::sibling_location_of(AssetHubRococo::para_id()); let sender = PenpalASender::get(); @@ -965,24 +967,23 @@ fn reserve_transfer_assets_from_para_to_system_para() { // Fund Parachain's sender account with some foreign assets PenpalA::mint_foreign_asset( penpal_asset_owner_signer.clone(), - asset_location_on_penpal, + asset_location_on_penpal.clone(), sender.clone(), asset_amount_to_send * 2, ); // Fund Parachain's sender account with some system assets PenpalA::mint_foreign_asset( penpal_asset_owner_signer, - system_asset_location_on_penpal, + system_asset_location_on_penpal.clone(), sender.clone(), fee_amount_to_send * 2, ); - // Init values for System Parachain - let receiver = AssetHubRococoReceiver::get(); + // Beneficiary is a new (empty) account + let receiver = get_account_id_from_seed::(DUMMY_EMPTY); + // Init values for Asset Hub let penpal_location_as_seen_by_ahr = AssetHubRococo::sibling_location_of(PenpalA::para_id()); let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location_as_seen_by_ahr); - let system_para_native_asset_location = RelayLocation::get(); - let system_para_foreign_asset_location = PenpalLocalReservableFromAssetHub::get(); let ah_asset_owner = AssetHubRococoAssetOwner::get(); let ah_asset_owner_signer = ::RuntimeOrigin::signed(ah_asset_owner); @@ -1017,11 +1018,11 @@ fn reserve_transfer_assets_from_para_to_system_para() { // Query initial balances let sender_system_assets_before = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location.clone(), &sender) + >::balance(system_asset_location_on_penpal.clone(), &sender) }); let sender_foreign_assets_before = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; - >::balance(system_para_foreign_asset_location.clone(), &sender) + >::balance(asset_location_on_penpal.clone(), &sender) }); let receiver_balance_before = test.receiver.balance; let receiver_assets_before = AssetHubRococo::execute_with(|| { @@ -1038,11 +1039,11 @@ fn reserve_transfer_assets_from_para_to_system_para() { // Query final balances let sender_system_assets_after = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location.clone(), &sender) + >::balance(system_asset_location_on_penpal, &sender) }); let sender_foreign_assets_after = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; - >::balance(system_para_foreign_asset_location, &sender) + >::balance(asset_location_on_penpal, &sender) }); let receiver_balance_after = test.receiver.balance; let receiver_assets_after = AssetHubRococo::execute_with(|| { diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs index 364fbd0d439f62ed1fce356d1935331ec8e0d90b..29eaa96946436fcafd189adcee9ec0bde6dc3548 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs @@ -18,7 +18,7 @@ use crate::imports::*; /// Relay Chain should be able to execute `Transact` instructions in System Parachain /// when `OriginKind::Superuser`. #[test] -fn send_transact_as_superuser_from_relay_to_system_para_works() { +fn send_transact_as_superuser_from_relay_to_asset_hub_works() { AssetHubRococo::force_create_asset_from_relay_as_root( ASSET_ID, ASSET_MIN_BALANCE, @@ -29,28 +29,25 @@ fn send_transact_as_superuser_from_relay_to_system_para_works() { } /// We tests two things here: -/// - Parachain should be able to send XCM paying its fee with system asset in the System Parachain -/// - Parachain should be able to create a new Foreign Asset in the System Parachain +/// - Parachain should be able to send XCM paying its fee at Asset Hub using system asset +/// - Parachain should be able to create a new Foreign Asset at Asset Hub #[test] -fn send_xcm_from_para_to_system_para_paying_fee_with_system_assets_works() { +fn send_xcm_from_para_to_asset_hub_paying_fee_with_system_asset() { let para_sovereign_account = AssetHubRococo::sovereign_account_id_of( AssetHubRococo::sibling_location_of(PenpalA::para_id()), ); - let asset_location_on_penpal = v3::Location::new( + let asset_location_on_penpal = Location::new( 0, - [ - v3::Junction::PalletInstance(ASSETS_PALLET_ID), - v3::Junction::GeneralIndex(ASSET_ID.into()), - ], + [Junction::PalletInstance(ASSETS_PALLET_ID), Junction::GeneralIndex(ASSET_ID.into())], ); let foreign_asset_at_asset_hub = - v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())]) + Location::new(1, [Junction::Parachain(PenpalA::para_id().into())]) .appended_with(asset_location_on_penpal) .unwrap(); // Encoded `create_asset` call to be executed in AssetHub let call = AssetHubRococo::create_foreign_asset_call( - foreign_asset_at_asset_hub, + foreign_asset_at_asset_hub.clone(), ASSET_MIN_BALANCE, para_sovereign_account.clone(), ); @@ -86,12 +83,7 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_system_assets_works() { AssetHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; - - AssetHubRococo::assert_xcmp_queue_success(Some(Weight::from_parts( - 15_594_564_000, - 562_893, - ))); - + AssetHubRococo::assert_xcmp_queue_success(None); assert_expected_events!( AssetHubRococo, vec![ @@ -115,15 +107,15 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_system_assets_works() { } /// We tests two things here: -/// - Parachain should be able to send XCM paying its fee with system assets in the System Parachain -/// - Parachain should be able to create a new Asset in the System Parachain +/// - Parachain should be able to send XCM paying its fee at Asset Hub using sufficient asset +/// - Parachain should be able to create a new Asset at Asset Hub #[test] -fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { +fn send_xcm_from_para_to_asset_hub_paying_fee_with_sufficient_asset() { let para_sovereign_account = AssetHubRococo::sovereign_account_id_of( AssetHubRococo::sibling_location_of(PenpalA::para_id()), ); - // Force create and mint assets for Parachain's sovereign account + // Force create and mint sufficient assets for Parachain's sovereign account AssetHubRococo::force_create_and_mint_asset( ASSET_ID, ASSET_MIN_BALANCE, @@ -170,12 +162,7 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { AssetHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; - - AssetHubRococo::assert_xcmp_queue_success(Some(Weight::from_parts( - 15_594_564_000, - 562_893, - ))); - + AssetHubRococo::assert_xcmp_queue_success(None); assert_expected_events!( AssetHubRococo, vec![ 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 16e0512da960559d192fb427ad55485fd0922172..ac0c90ba198d0542f55412a7763efc6c2f0ee199 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,13 +17,10 @@ use crate::imports::*; #[test] fn swap_locally_on_chain_using_local_assets() { - let asset_native = Box::new(v3::Location::try_from(RelayLocation::get()).unwrap()); - let asset_one = Box::new(v3::Location::new( + let asset_native = Box::new(Location::try_from(RelayLocation::get()).unwrap()); + let asset_one = Box::new(Location::new( 0, - [ - v3::Junction::PalletInstance(ASSETS_PALLET_ID), - v3::Junction::GeneralIndex(ASSET_ID.into()), - ], + [Junction::PalletInstance(ASSETS_PALLET_ID), Junction::GeneralIndex(ASSET_ID.into())], )); AssetHubRococo::execute_with(|| { @@ -112,11 +109,11 @@ fn swap_locally_on_chain_using_local_assets() { #[test] fn swap_locally_on_chain_using_foreign_assets() { - let asset_native = Box::new(v3::Location::try_from(RelayLocation::get()).unwrap()); + let asset_native = Box::new(Location::try_from(RelayLocation::get()).unwrap()); let asset_location_on_penpal = - v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).unwrap(); + Location::try_from(PenpalLocalTeleportableToAssetHub::get()).unwrap(); let foreign_asset_at_asset_hub_rococo = - v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())]) + Location::new(1, [Junction::Parachain(PenpalA::para_id().into())]) .appended_with(asset_location_on_penpal) .unwrap(); @@ -141,7 +138,7 @@ fn swap_locally_on_chain_using_foreign_assets() { // 1. Mint foreign asset (in reality this should be a teleport or some such) assert_ok!(::ForeignAssets::mint( ::RuntimeOrigin::signed(sov_penpal_on_ahr.clone().into()), - foreign_asset_at_asset_hub_rococo, + foreign_asset_at_asset_hub_rococo.clone(), sov_penpal_on_ahr.clone().into(), ASSET_HUB_ROCOCO_ED * 3_000_000_000_000, )); @@ -157,7 +154,7 @@ fn swap_locally_on_chain_using_foreign_assets() { assert_ok!(::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubRococoSender::get()), asset_native.clone(), - Box::new(foreign_asset_at_asset_hub_rococo), + Box::new(foreign_asset_at_asset_hub_rococo.clone()), )); assert_expected_events!( @@ -171,7 +168,7 @@ fn swap_locally_on_chain_using_foreign_assets() { assert_ok!(::AssetConversion::add_liquidity( ::RuntimeOrigin::signed(sov_penpal_on_ahr.clone()), asset_native.clone(), - Box::new(foreign_asset_at_asset_hub_rococo), + Box::new(foreign_asset_at_asset_hub_rococo.clone()), 1_000_000_000_000, 2_000_000_000_000, 0, @@ -189,7 +186,7 @@ fn swap_locally_on_chain_using_foreign_assets() { ); // 4. Swap! - let path = vec![asset_native.clone(), Box::new(foreign_asset_at_asset_hub_rococo)]; + let path = vec![asset_native.clone(), Box::new(foreign_asset_at_asset_hub_rococo.clone())]; assert_ok!( ::AssetConversion::swap_exact_tokens_for_tokens( @@ -216,7 +213,7 @@ fn swap_locally_on_chain_using_foreign_assets() { assert_ok!(::AssetConversion::remove_liquidity( ::RuntimeOrigin::signed(sov_penpal_on_ahr.clone()), asset_native.clone(), - Box::new(foreign_asset_at_asset_hub_rococo), + Box::new(foreign_asset_at_asset_hub_rococo.clone()), 1414213562273 - ASSET_HUB_ROCOCO_ED * 2, // all but the 2 EDs can't be retrieved. 0, 0, @@ -252,8 +249,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).unwrap()), - Box::new(v3::Location::try_from(asset_one).unwrap()), + Box::new(Location::try_from(asset_native).unwrap()), + Box::new(Location::try_from(asset_one).unwrap()), ), Err(DispatchError::Module(ModuleError{index: _, error: _, message})) => assert_eq!(message, Some("Unknown")) ); @@ -262,12 +259,12 @@ 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(RelayLocation::get()).unwrap(); - let asset_one = xcm::v3::Location { + let asset_native = Location::try_from(RelayLocation::get()).unwrap(); + let asset_one = Location { parents: 0, interior: [ - xcm::v3::Junction::PalletInstance(ASSETS_PALLET_ID), - xcm::v3::Junction::GeneralIndex(ASSET_ID.into()), + Junction::PalletInstance(ASSETS_PALLET_ID), + Junction::GeneralIndex(ASSET_ID.into()), ] .into(), }; @@ -296,8 +293,8 @@ fn pay_xcm_fee_with_some_asset_swapped_for_native() { assert_ok!(::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubRococoSender::get()), - Box::new(asset_native), - Box::new(asset_one), + Box::new(asset_native.clone()), + Box::new(asset_one.clone()), )); assert_expected_events!( diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs index f74378d7631a610a57c61153e62aedfcb588a611..c8da801a14bff5adea1a695313672dfb9c9d8437 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs @@ -15,53 +15,6 @@ use crate::imports::*; -fn relay_origin_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - Rococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(631_531_000, 7_186))); - - assert_expected_events!( - Rococo, - vec![ - // Amount to teleport is withdrawn from Sender - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, - }, - // Amount to teleport is deposited in Relay's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) => { - who: *who == ::XcmPallet::check_account(), - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn relay_dest_assertions(t: SystemParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - - Rococo::assert_ump_queue_processed( - true, - Some(AssetHubRococo::para_id()), - Some(Weight::from_parts(307_225_000, 7_186)), - ); - - assert_expected_events!( - Rococo, - vec![ - // Amount is withdrawn from Relay Chain's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == ::XcmPallet::check_account(), - amount: *amount == t.args.amount, - }, - // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, - }, - ] - ); -} - fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) { Rococo::assert_ump_queue_processed( false, @@ -92,22 +45,6 @@ fn para_origin_assertions(t: SystemParaToRelayTest) { ); } -fn para_dest_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubRococo::assert_dmp_queue_complete(Some(Weight::from_parts(157_718_000, 3593))); - - assert_expected_events!( - AssetHubRococo, - vec![ - // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, - }, - ] - ); -} - fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; let system_para_native_asset_location = RelayLocation::get(); @@ -141,7 +78,6 @@ fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) { ); let (expected_foreign_asset_id, expected_foreign_asset_amount) = non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); - let expected_foreign_asset_id_v3: v3::Location = expected_foreign_asset_id.try_into().unwrap(); AssetHubRococo::assert_xcmp_queue_success(None); @@ -159,7 +95,7 @@ fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) { who: *who == t.receiver.account_id, }, RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { - asset_id: *asset_id == expected_foreign_asset_id_v3, + asset_id: *asset_id == expected_foreign_asset_id, owner: *owner == t.receiver.account_id, amount: *amount == expected_foreign_asset_amount, }, @@ -173,7 +109,6 @@ fn ah_to_penpal_foreign_assets_sender_assertions(t: SystemParaToParaTest) { AssetHubRococo::assert_xcm_pallet_attempted_complete(None); let (expected_foreign_asset_id, expected_foreign_asset_amount) = non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); - let expected_foreign_asset_id_v3: v3::Location = expected_foreign_asset_id.try_into().unwrap(); assert_expected_events!( AssetHubRococo, vec![ @@ -189,7 +124,7 @@ fn ah_to_penpal_foreign_assets_sender_assertions(t: SystemParaToParaTest) { }, // foreign asset is burned locally as part of teleportation RuntimeEvent::ForeignAssets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { - asset_id: *asset_id == expected_foreign_asset_id_v3, + asset_id: *asset_id == expected_foreign_asset_id, owner: *owner == t.sender.account_id, balance: *balance == expected_foreign_asset_amount, }, @@ -232,17 +167,6 @@ fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) { ); } -fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::limited_teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { ::PolkadotXcm::limited_teleport_assets( t.signed_origin, @@ -276,90 +200,41 @@ fn system_para_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResul ) } -/// Limited Teleport of native asset from Relay Chain to the System Parachain should work #[test] -fn limited_teleport_native_assets_from_relay_to_system_para_works() { - // Init values for Relay Chain - let amount_to_send: Balance = ROCOCO_ED * 1000; - let dest = Rococo::child_location_of(AssetHubRococo::para_id()); - let beneficiary_id = AssetHubRococoReceiver::get(); - let test_args = TestContext { - sender: RococoSender::get(), - receiver: AssetHubRococoReceiver::get(), - args: TestArgs::new_relay(dest, beneficiary_id, amount_to_send), - }; - - let mut test = RelayToSystemParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(para_dest_assertions); - test.set_dispatchable::(relay_limited_teleport_assets); - test.assert(); - - let delivery_fees = Rococo::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; +fn teleport_to_other_system_parachains_works() { + let amount = ASSET_HUB_ROCOCO_ED * 100; + let native_asset: Assets = (Parent, amount).into(); - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); + test_parachain_is_trusted_teleporter!( + AssetHubRococo, // Origin + AssetHubRococoXcmConfig, // XCM Configuration + vec![BridgeHubRococo], // Destinations + (native_asset, amount) + ); } -/// Limited Teleport of native asset from System Parachain to Relay Chain -/// should work when there is enough balance in Relay Chain's `CheckAccount` #[test] -fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { - // Dependency - Relay Chain's `CheckAccount` should have enough balance - limited_teleport_native_assets_from_relay_to_system_para_works(); - - // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; - let destination = AssetHubRococo::parent_location(); - let beneficiary_id = RococoReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubRococoSender::get(), - receiver: RococoReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions); - test.set_dispatchable::(system_para_limited_teleport_assets); - test.assert(); +fn teleport_from_and_to_relay() { + let amount = ROCOCO_ED * 100; + let native_asset: Assets = (Here, amount).into(); - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = AssetHubRococo::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); + test_relay_is_trusted_teleporter!( + Rococo, + RococoXcmConfig, + vec![AssetHubRococo], + (native_asset, amount) + ); - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); + test_parachain_is_trusted_teleporter_for_relay!( + AssetHubRococo, + AssetHubRococoXcmConfig, + Rococo, + amount + ); } /// Limited Teleport of native asset from System Parachain to Relay Chain -/// should't work when there is not enough balance in Relay Chain's `CheckAccount` +/// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` #[test] fn limited_teleport_native_assets_from_system_para_to_relay_fails() { // Init values for Relay Chain @@ -399,19 +274,6 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { assert_eq!(receiver_balance_after, receiver_balance_before); } -#[test] -fn teleport_to_other_system_parachains_works() { - let amount = ASSET_HUB_ROCOCO_ED * 100; - let native_asset: Assets = (Parent, amount).into(); - - test_parachain_is_trusted_teleporter!( - AssetHubRococo, // Origin - AssetHubRococoXcmConfig, // XCM Configuration - vec![BridgeHubRococo], // Destinations - (native_asset, amount) - ); -} - /// Bidirectional teleports of local Penpal assets to Asset Hub as foreign assets while paying /// fees using (reserve transferred) native asset. pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt( 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 f8190e11c51c8b202804dcee9cf689d93ef33678..3320392b495d281bf9c127ab299793535362ddcd 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 @@ -14,7 +14,10 @@ // limitations under the License. use crate::imports::*; -use emulated_integration_tests_common::accounts::{ALICE, BOB}; +use emulated_integration_tests_common::{ + accounts::{ALICE, BOB}, + USDT_ID, +}; use frame_support::{ dispatch::RawOrigin, sp_runtime::traits::Dispatchable, @@ -161,7 +164,6 @@ fn spend_roc_on_asset_hub() { #[test] fn create_and_claim_treasury_spend_in_usdt() { - const ASSET_ID: u32 = 1984; const SPEND_AMOUNT: u128 = 10_000_000; // treasury location from a sibling parachain. let treasury_location: Location = Location::new(1, PalletInstance(18)); @@ -175,7 +177,7 @@ fn create_and_claim_treasury_spend_in_usdt() { let asset_kind = VersionedLocatableAsset::V3 { location: asset_hub_location, asset_id: v3::AssetId::Concrete( - (v3::Junction::PalletInstance(50), v3::Junction::GeneralIndex(ASSET_ID.into())).into(), + (v3::Junction::PalletInstance(50), v3::Junction::GeneralIndex(USDT_ID.into())).into(), ), }; // treasury spend beneficiary. @@ -187,9 +189,9 @@ fn create_and_claim_treasury_spend_in_usdt() { type Assets = ::Assets; // USDT created at genesis, mint some assets to the treasury account. - assert_ok!(>::mint_into(ASSET_ID, &treasury_account, SPEND_AMOUNT * 4)); + assert_ok!(>::mint_into(USDT_ID, &treasury_account, SPEND_AMOUNT * 4)); // beneficiary has zero balance. - assert_eq!(>::balance(ASSET_ID, &alice,), 0u128,); + assert_eq!(>::balance(USDT_ID, &alice,), 0u128,); }); Rococo::execute_with(|| { @@ -231,7 +233,7 @@ fn create_and_claim_treasury_spend_in_usdt() { AssetHubRococo, vec![ RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id: id, from, to, amount }) => { - id: id == &ASSET_ID, + id: id == &USDT_ID, from: from == &treasury_account, to: to == &alice, amount: amount == &SPEND_AMOUNT, @@ -241,7 +243,7 @@ fn create_and_claim_treasury_spend_in_usdt() { ] ); // beneficiary received the assets from the treasury. - assert_eq!(>::balance(ASSET_ID, &alice,), SPEND_AMOUNT,); + assert_eq!(>::balance(USDT_ID, &alice,), SPEND_AMOUNT,); }); Rococo::execute_with(|| { diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/xcm_fee_estimation.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/xcm_fee_estimation.rs new file mode 100644 index 0000000000000000000000000000000000000000..aa0e183ecddaf1a07c1f91d04253138b2625df46 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/xcm_fee_estimation.rs @@ -0,0 +1,286 @@ +// 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 for XCM fee estimation in the runtime. + +use crate::imports::*; +use frame_support::{ + dispatch::RawOrigin, + sp_runtime::{traits::Dispatchable, DispatchResult}, +}; +use xcm_runtime_apis::{ + dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, + fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, +}; + +fn sender_assertions(test: ParaToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + PenpalA::assert_xcm_pallet_attempted_complete(None); + + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance } + ) => { + asset_id: *asset_id == Location::new(1, []), + owner: *owner == test.sender.account_id, + balance: *balance == test.args.amount, + }, + ] + ); +} + +fn hop_assertions(test: ParaToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + AssetHubRococo::assert_xcmp_queue_success(None); + + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::Balances( + pallet_balances::Event::Burned { amount, .. } + ) => { + amount: *amount == test.args.amount, + }, + ] + ); +} + +fn receiver_assertions(test: ParaToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + PenpalB::assert_xcmp_queue_success(None); + + assert_expected_events!( + PenpalB, + vec![ + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Issued { asset_id, owner, .. } + ) => { + asset_id: *asset_id == Location::new(1, []), + owner: *owner == test.receiver.account_id, + }, + ] + ); +} + +fn transfer_assets_para_to_para_through_ah_dispatchable( + test: ParaToParaThroughAHTest, +) -> DispatchResult { + let call = transfer_assets_para_to_para_through_ah_call(test.clone()); + match call.dispatch(test.signed_origin) { + Ok(_) => Ok(()), + Err(error_with_post_info) => Err(error_with_post_info.error), + } +} + +fn transfer_assets_para_to_para_through_ah_call( + test: ParaToParaThroughAHTest, +) -> ::RuntimeCall { + type RuntimeCall = ::RuntimeCall; + + let asset_hub_location: Location = PenpalB::sibling_location_of(AssetHubRococo::para_id()); + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(test.args.assets.len() as u32)), + beneficiary: test.args.beneficiary, + }]); + RuntimeCall::PolkadotXcm(pallet_xcm::Call::transfer_assets_using_type_and_then { + dest: bx!(test.args.dest.into()), + assets: bx!(test.args.assets.clone().into()), + assets_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), + remote_fees_id: bx!(VersionedAssetId::V4(AssetId(Location::new(1, [])))), + fees_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.into())), + custom_xcm_on_dest: bx!(VersionedXcm::from(custom_xcm_on_dest)), + weight_limit: test.args.weight_limit, + }) +} + +/// We are able to dry-run and estimate the fees for a multi-hop XCM journey. +/// Scenario: Alice on PenpalA has some DOTs and wants to send them to PenpalB. +/// We want to know the fees using the `DryRunApi` and `XcmPaymentApi`. +#[test] +fn multi_hop_works() { + let destination = PenpalA::sibling_location_of(PenpalB::para_id()); + let sender = PenpalASender::get(); + let amount_to_send = 1_000_000_000_000; + let asset_owner = PenpalAssetOwner::get(); + let assets: Assets = (Parent, amount_to_send).into(); + let relay_native_asset_location = Location::parent(); + let sender_as_seen_by_ah = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let sov_of_sender_on_ah = AssetHubRococo::sovereign_account_id_of(sender_as_seen_by_ah.clone()); + + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner.clone()), + relay_native_asset_location.clone(), + sender.clone(), + amount_to_send * 2, + ); + + // fund the Parachain Origin's SA on AssetHub with the native tokens held in reserve. + AssetHubRococo::fund_accounts(vec![(sov_of_sender_on_ah.clone(), amount_to_send * 2)]); + + // Init values for Parachain Destination + let beneficiary_id = PenpalBReceiver::get(); + + let test_args = TestContext { + sender: PenpalASender::get(), // Bob in PenpalB. + receiver: PenpalBReceiver::get(), // Alice. + args: TestArgs::new_para( + destination, + beneficiary_id.clone(), + amount_to_send, + assets, + None, + 0, + ), + }; + let mut test = ParaToParaThroughAHTest::new(test_args); + + // We get them from the PenpalA closure. + let mut delivery_fees_amount = 0; + let mut remote_message = VersionedXcm::V4(Xcm(Vec::new())); + ::execute_with(|| { + type Runtime = ::Runtime; + type OriginCaller = ::OriginCaller; + + let call = transfer_assets_para_to_para_through_ah_call(test.clone()); + let origin = OriginCaller::system(RawOrigin::Signed(sender.clone())); + let result = Runtime::dry_run_call(origin, call).unwrap(); + // We filter the result to get only the messages we are interested in. + let (destination_to_query, messages_to_query) = &result + .forwarded_xcms + .iter() + .find(|(destination, _)| { + *destination == VersionedLocation::V4(Location::new(1, [Parachain(1000)])) + }) + .unwrap(); + assert_eq!(messages_to_query.len(), 1); + remote_message = messages_to_query[0].clone(); + let delivery_fees = + Runtime::query_delivery_fees(destination_to_query.clone(), remote_message.clone()) + .unwrap(); + delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); + }); + + // These are set in the AssetHub closure. + let mut intermediate_execution_fees = 0; + let mut intermediate_delivery_fees_amount = 0; + let mut intermediate_remote_message = VersionedXcm::V4(Xcm::<()>(Vec::new())); + ::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + + // First we get the execution fees. + let weight = Runtime::query_xcm_weight(remote_message.clone()).unwrap(); + intermediate_execution_fees = Runtime::query_weight_to_asset_fee( + weight, + VersionedAssetId::V4(Location::new(1, []).into()), + ) + .unwrap(); + + // We have to do this to turn `VersionedXcm<()>` into `VersionedXcm`. + let xcm_program = + VersionedXcm::V4(Xcm::::from(remote_message.clone().try_into().unwrap())); + + // Now we get the delivery fees to the final destination. + let result = + Runtime::dry_run_xcm(sender_as_seen_by_ah.clone().into(), xcm_program).unwrap(); + let (destination_to_query, messages_to_query) = &result + .forwarded_xcms + .iter() + .find(|(destination, _)| { + *destination == VersionedLocation::V4(Location::new(1, [Parachain(2001)])) + }) + .unwrap(); + // There's actually two messages here. + // One created when the message we sent from PenpalA arrived and was executed. + // The second one when we dry-run the xcm. + // We could've gotten the message from the queue without having to dry-run, but + // offchain applications would have to dry-run, so we do it here as well. + intermediate_remote_message = messages_to_query[0].clone(); + let delivery_fees = Runtime::query_delivery_fees( + destination_to_query.clone(), + intermediate_remote_message.clone(), + ) + .unwrap(); + intermediate_delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); + }); + + // Get the final execution fees in the destination. + let mut final_execution_fees = 0; + ::execute_with(|| { + type Runtime = ::Runtime; + + let weight = Runtime::query_xcm_weight(intermediate_remote_message.clone()).unwrap(); + final_execution_fees = + Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::V4(Parent.into())) + .unwrap(); + }); + + // Dry-running is done. + PenpalA::reset_ext(); + AssetHubRococo::reset_ext(); + PenpalB::reset_ext(); + + // Fund accounts again. + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner), + relay_native_asset_location.clone(), + sender.clone(), + amount_to_send * 2, + ); + AssetHubRococo::fund_accounts(vec![(sov_of_sender_on_ah, amount_to_send * 2)]); + + // Actually run the extrinsic. + let sender_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &sender) + }); + let receiver_assets_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &beneficiary_id) + }); + + test.set_assertion::(sender_assertions); + test.set_assertion::(hop_assertions); + test.set_assertion::(receiver_assertions); + test.set_dispatchable::(transfer_assets_para_to_para_through_ah_dispatchable); + test.assert(); + + let sender_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &sender) + }); + let receiver_assets_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location, &beneficiary_id) + }); + + // We know the exact fees on every hop. + assert_eq!( + sender_assets_after, + sender_assets_before - amount_to_send - delivery_fees_amount /* This is charged directly + * from the sender's + * account. */ + ); + assert_eq!( + receiver_assets_after, + receiver_assets_before + amount_to_send - + intermediate_execution_fees - + intermediate_delivery_fees_amount - + final_execution_fees + ); +} 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 db8ada3f4ea281a61e9daaf3fa2cc2ba19747090..a887ee6a532a68eed9914d0df80d32c1ead761a7 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 @@ -26,21 +26,22 @@ mod imports { }; // Polkadot - pub use xcm::{ - prelude::{AccountId32 as AccountId32Junction, *}, - v3, - }; + pub use xcm::prelude::{AccountId32 as AccountId32Junction, *}; pub use xcm_executor::traits::TransferType; // Cumulus pub use asset_test_utils::xcm_helpers; pub use emulated_integration_tests_common::{ - test_parachain_is_trusted_teleporter, + accounts::DUMMY_EMPTY, + get_account_id_from_seed, test_parachain_is_trusted_teleporter, + test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, xcm_emulator::{ assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, Test, TestArgs, TestContext, TestExt, }, - xcm_helpers::{non_fee_asset, xcm_transact_paid_execution}, + xcm_helpers::{ + get_amount_from_versioned_assets, non_fee_asset, xcm_transact_paid_execution, + }, ASSETS_PALLET_ID, RESERVABLE_ASSET_ID, XCM_V3, }; pub use parachains_common::{AccountId, Balance}; @@ -52,6 +53,7 @@ mod imports { XcmConfig as AssetHubWestendXcmConfig, }, AssetConversionOrigin as AssetHubWestendAssetConversionOrigin, + ExistentialDeposit as AssetHubWestendExistentialDeposit, }, genesis::{AssetHubWestendAssetOwner, ED as ASSET_HUB_WESTEND_ED}, AssetHubWestendParaPallet as AssetHubWestendPallet, @@ -87,7 +89,6 @@ mod imports { pub const ASSET_ID: u32 = 3; pub const ASSET_MIN_BALANCE: u128 = 1000; - pub type RelayToSystemParaTest = Test; pub type RelayToParaTest = Test; pub type ParaToRelayTest = Test; pub type SystemParaToRelayTest = Test; 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 15f4fe33bddc1b65f079832facc4ce495823ad84..9520659712fc625ff479da489ffdae7acbb7d185 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 @@ -14,15 +14,17 @@ // limitations under the License. use crate::imports::*; -use emulated_integration_tests_common::accounts::{ALICE, BOB}; -use frame_support::traits::fungibles::{Create, Inspect, Mutate}; +use emulated_integration_tests_common::{ + accounts::{ALICE, BOB}, + USDT_ID, +}; +use frame_support::traits::fungibles::{Inspect, Mutate}; use polkadot_runtime_common::impls::VersionedLocatableAsset; use xcm_executor::traits::ConvertLocation; #[test] fn create_and_claim_treasury_spend() { - const ASSET_ID: u32 = 1984; - const SPEND_AMOUNT: u128 = 1_000_000; + const SPEND_AMOUNT: u128 = 1_000_000_000; // treasury location from a sibling parachain. let treasury_location: Location = Location::new(1, [Parachain(CollectivesWestend::para_id().into()), PalletInstance(65)]); @@ -34,7 +36,7 @@ fn create_and_claim_treasury_spend() { // asset kind to be spent from the treasury. let asset_kind = VersionedLocatableAsset::V4 { location: asset_hub_location, - asset_id: AssetId((PalletInstance(50), GeneralIndex(ASSET_ID.into())).into()), + asset_id: AssetId((PalletInstance(50), GeneralIndex(USDT_ID.into())).into()), }; // treasury spend beneficiary. let alice: AccountId = Westend::account_id_of(ALICE); @@ -44,16 +46,10 @@ fn create_and_claim_treasury_spend() { AssetHubWestend::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 - )); - assert_ok!(>::mint_into(ASSET_ID, &treasury_account, SPEND_AMOUNT * 4)); + // USDT created at genesis, mint some assets to the fellowship treasury account. + assert_ok!(>::mint_into(USDT_ID, &treasury_account, SPEND_AMOUNT * 4)); // beneficiary has zero balance. - assert_eq!(>::balance(ASSET_ID, &alice,), 0u128,); + assert_eq!(>::balance(USDT_ID, &alice,), 0u128,); }); CollectivesWestend::execute_with(|| { @@ -96,7 +92,7 @@ fn create_and_claim_treasury_spend() { AssetHubWestend, vec![ RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id: id, from, to, amount }) => { - id: id == &ASSET_ID, + id: id == &USDT_ID, from: from == &treasury_account, to: to == &alice, amount: amount == &SPEND_AMOUNT, @@ -106,7 +102,7 @@ fn create_and_claim_treasury_spend() { ] ); // beneficiary received the assets from the treasury. - assert_eq!(>::balance(ASSET_ID, &alice,), SPEND_AMOUNT,); + assert_eq!(>::balance(USDT_ID, &alice,), SPEND_AMOUNT,); }); CollectivesWestend::execute_with(|| { 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/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs index 65d013a0eec40aa90b42a475f40dca9197f318e9..59f63d3805908d29e553b3d710e2843165edfe78 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -493,9 +493,9 @@ fn para_to_para_through_relay_limited_reserve_transfer_assets( ) } -/// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work +/// Reserve Transfers of native asset from Relay Chain to the Asset Hub shouldn't work #[test] -fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { +fn reserve_transfer_native_asset_from_relay_to_asset_hub_fails() { // Init values for Relay Chain let signed_origin = ::RuntimeOrigin::signed(WestendSender::get().into()); let destination = Westend::child_location_of(AssetHubWestend::para_id()); @@ -526,10 +526,10 @@ fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { }); } -/// Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work +/// Reserve Transfers of native asset from Asset Hub to Relay Chain shouldn't work #[test] -fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { - // Init values for System Parachain +fn reserve_transfer_native_asset_from_asset_hub_to_relay_fails() { + // Init values for Asset Hub let signed_origin = ::RuntimeOrigin::signed(AssetHubWestendSender::get().into()); let destination = AssetHubWestend::parent_location(); @@ -691,10 +691,10 @@ fn reserve_transfer_native_asset_from_para_to_relay() { // ========================================================================= // ======= Reserve Transfers - Native Asset - AssetHub<>Parachain ========== // ========================================================================= -/// Reserve Transfers of native asset from System Parachain to Parachain should work +/// Reserve Transfers of native asset from Asset Hub to Parachain should work #[test] -fn reserve_transfer_native_asset_from_system_para_to_para() { - // Init values for System Parachain +fn reserve_transfer_native_asset_from_asset_hub_to_para() { + // Init values for Asset Hub let destination = AssetHubWestend::sibling_location_of(PenpalA::para_id()); let sender = AssetHubWestendSender::get(); let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 2000; @@ -749,9 +749,9 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { assert!(receiver_assets_after < receiver_assets_before + amount_to_send); } -/// Reserve Transfers of native asset from Parachain to System Parachain should work +/// Reserve Transfers of native asset from Parachain to Asset Hub should work #[test] -fn reserve_transfer_native_asset_from_para_to_system_para() { +fn reserve_transfer_native_asset_from_para_to_asset_hub() { // Init values for Parachain let destination = PenpalA::sibling_location_of(AssetHubWestend::para_id()); let sender = PenpalASender::get(); @@ -768,13 +768,13 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { amount_to_send * 2, ); - // Init values for System Parachain + // Init values for Asset Hub let receiver = AssetHubWestendReceiver::get(); let penpal_location_as_seen_by_ahr = AssetHubWestend::sibling_location_of(PenpalA::para_id()); let sov_penpal_on_ahr = AssetHubWestend::sovereign_account_id_of(penpal_location_as_seen_by_ahr); - // fund Parachain's SA on System Parachain with the native tokens held in reserve + // fund Parachain's SA on Asset Hub with the native tokens held in reserve AssetHubWestend::fund_accounts(vec![(sov_penpal_on_ahr.into(), amount_to_send * 2)]); // Init Test @@ -825,11 +825,11 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { // ========================================================================= // ======= Reserve Transfers - Non-system Asset - AssetHub<>Parachain ====== // ========================================================================= -/// Reserve Transfers of a local asset and native asset from System Parachain to Parachain should +/// Reserve Transfers of a local asset and native asset from Asset Hub to Parachain should /// work #[test] -fn reserve_transfer_assets_from_system_para_to_para() { - // Init values for System Parachain +fn reserve_transfer_multiple_assets_from_asset_hub_to_para() { + // Init values for Asset Hub let destination = AssetHubWestend::sibling_location_of(PenpalA::para_id()); let sov_penpal_on_ahr = AssetHubWestend::sovereign_account_id_of(destination.clone()); let sender = AssetHubWestendSender::get(); @@ -940,10 +940,12 @@ fn reserve_transfer_assets_from_system_para_to_para() { ); } -/// Reserve Transfers of a foreign asset and native asset from Parachain to System Para should -/// work +/// Reserve Transfers of a random asset and native asset from Parachain to Asset Hub should work +/// Receiver is empty account to show deposit works as long as transfer includes enough DOT for ED. +/// Once we have https://github.com/paritytech/polkadot-sdk/issues/5298, +/// we should do equivalent test with USDT instead of DOT. #[test] -fn reserve_transfer_assets_from_para_to_system_para() { +fn reserve_transfer_multiple_assets_from_para_to_asset_hub() { // Init values for Parachain let destination = PenpalA::sibling_location_of(AssetHubWestend::para_id()); let sender = PenpalASender::get(); @@ -966,25 +968,24 @@ fn reserve_transfer_assets_from_para_to_system_para() { // Fund Parachain's sender account with some foreign assets PenpalA::mint_foreign_asset( penpal_asset_owner_signer.clone(), - asset_location_on_penpal, + asset_location_on_penpal.clone(), sender.clone(), asset_amount_to_send * 2, ); // Fund Parachain's sender account with some system assets PenpalA::mint_foreign_asset( penpal_asset_owner_signer, - system_asset_location_on_penpal, + system_asset_location_on_penpal.clone(), sender.clone(), fee_amount_to_send * 2, ); - // Init values for System Parachain - let receiver = AssetHubWestendReceiver::get(); + // Beneficiary is a new (empty) account + let receiver = get_account_id_from_seed::(DUMMY_EMPTY); + // Init values for Asset Hub let penpal_location_as_seen_by_ahr = AssetHubWestend::sibling_location_of(PenpalA::para_id()); let sov_penpal_on_ahr = AssetHubWestend::sovereign_account_id_of(penpal_location_as_seen_by_ahr); - let system_para_native_asset_location = RelayLocation::get(); - let system_para_foreign_asset_location = PenpalLocalReservableFromAssetHub::get(); let ah_asset_owner = AssetHubWestendAssetOwner::get(); let ah_asset_owner_signer = ::RuntimeOrigin::signed(ah_asset_owner); @@ -1019,11 +1020,11 @@ fn reserve_transfer_assets_from_para_to_system_para() { // Query initial balances let sender_system_assets_before = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location.clone(), &sender) + >::balance(system_asset_location_on_penpal.clone(), &sender) }); let sender_foreign_assets_before = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; - >::balance(system_para_foreign_asset_location.clone(), &sender) + >::balance(asset_location_on_penpal.clone(), &sender) }); let receiver_balance_before = test.receiver.balance; let receiver_assets_before = AssetHubWestend::execute_with(|| { @@ -1040,11 +1041,11 @@ fn reserve_transfer_assets_from_para_to_system_para() { // Query final balances let sender_system_assets_after = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location, &sender) + >::balance(system_asset_location_on_penpal, &sender) }); let sender_foreign_assets_after = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; - >::balance(system_para_foreign_asset_location, &sender) + >::balance(asset_location_on_penpal, &sender) }); let receiver_balance_after = test.receiver.balance; let receiver_assets_after = AssetHubWestend::execute_with(|| { diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs index eb0e985cc0ce6f84318f763cb37e707beaeca718..761c7c12255c5890fd99e53a20b81060e2e2b8c2 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs @@ -18,7 +18,7 @@ use crate::imports::*; /// Relay Chain should be able to execute `Transact` instructions in System Parachain /// when `OriginKind::Superuser`. #[test] -fn send_transact_as_superuser_from_relay_to_system_para_works() { +fn send_transact_as_superuser_from_relay_to_asset_hub_works() { AssetHubWestend::force_create_asset_from_relay_as_root( ASSET_ID, ASSET_MIN_BALANCE, @@ -29,28 +29,25 @@ fn send_transact_as_superuser_from_relay_to_system_para_works() { } /// We tests two things here: -/// - Parachain should be able to send XCM paying its fee with system asset in the System Parachain -/// - Parachain should be able to create a new Foreign Asset in the System Parachain +/// - Parachain should be able to send XCM paying its fee at Asset Hub using system asset +/// - Parachain should be able to create a new Foreign Asset at Asset Hub #[test] -fn send_xcm_from_para_to_system_para_paying_fee_with_system_assets_works() { +fn send_xcm_from_para_to_asset_hub_paying_fee_with_system_asset() { let para_sovereign_account = AssetHubWestend::sovereign_account_id_of( AssetHubWestend::sibling_location_of(PenpalA::para_id()), ); - let asset_location_on_penpal = v3::Location::new( + let asset_location_on_penpal = Location::new( 0, - [ - v3::Junction::PalletInstance(ASSETS_PALLET_ID), - v3::Junction::GeneralIndex(ASSET_ID.into()), - ], + [Junction::PalletInstance(ASSETS_PALLET_ID), Junction::GeneralIndex(ASSET_ID.into())], ); let foreign_asset_at_asset_hub = - v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())]) + Location::new(1, [Junction::Parachain(PenpalA::para_id().into())]) .appended_with(asset_location_on_penpal) .unwrap(); // Encoded `create_asset` call to be executed in AssetHub let call = AssetHubWestend::create_foreign_asset_call( - foreign_asset_at_asset_hub, + foreign_asset_at_asset_hub.clone(), ASSET_MIN_BALANCE, para_sovereign_account.clone(), ); @@ -86,12 +83,7 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_system_assets_works() { AssetHubWestend::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; - - AssetHubWestend::assert_xcmp_queue_success(Some(Weight::from_parts( - 15_594_564_000, - 562_893, - ))); - + AssetHubWestend::assert_xcmp_queue_success(None); assert_expected_events!( AssetHubWestend, vec![ @@ -115,15 +107,15 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_system_assets_works() { } /// We tests two things here: -/// - Parachain should be able to send XCM paying its fee with system assets in the System Parachain -/// - Parachain should be able to create a new Asset in the System Parachain +/// - Parachain should be able to send XCM paying its fee at Asset Hub using sufficient asset +/// - Parachain should be able to create a new Asset at Asset Hub #[test] -fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { +fn send_xcm_from_para_to_asset_hub_paying_fee_with_sufficient_asset() { let para_sovereign_account = AssetHubWestend::sovereign_account_id_of( AssetHubWestend::sibling_location_of(PenpalA::para_id()), ); - // Force create and mint assets for Parachain's sovereign account + // Force create and mint sufficient assets for Parachain's sovereign account AssetHubWestend::force_create_and_mint_asset( ASSET_ID, ASSET_MIN_BALANCE, @@ -170,12 +162,7 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { AssetHubWestend::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; - - AssetHubWestend::assert_xcmp_queue_success(Some(Weight::from_parts( - 15_594_564_000, - 562_893, - ))); - + AssetHubWestend::assert_xcmp_queue_success(None); assert_expected_events!( AssetHubWestend, vec![ 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 cf429378cf6d8eb79eb0c53a9da1c882fc86537a..1a2821452155db77eca049f490a7ce6cacd873d0 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 @@ -18,12 +18,12 @@ use crate::imports::*; #[test] fn swap_locally_on_chain_using_local_assets() { let asset_native = - Box::new(v3::Location::try_from(RelayLocation::get()).expect("conversion works")); - let asset_one = Box::new(v3::Location { + Box::new(Location::try_from(RelayLocation::get()).expect("conversion works")); + let asset_one = Box::new(Location { parents: 0, interior: [ - v3::Junction::PalletInstance(ASSETS_PALLET_ID), - v3::Junction::GeneralIndex(ASSET_ID.into()), + Junction::PalletInstance(ASSETS_PALLET_ID), + Junction::GeneralIndex(ASSET_ID.into()), ] .into(), }); @@ -112,11 +112,11 @@ fn swap_locally_on_chain_using_local_assets() { #[test] fn swap_locally_on_chain_using_foreign_assets() { - let asset_native = Box::new(v3::Location::try_from(RelayLocation::get()).unwrap()); + let asset_native = Box::new(Location::try_from(RelayLocation::get()).unwrap()); let asset_location_on_penpal = - v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).expect("conversion_works"); + Location::try_from(PenpalLocalTeleportableToAssetHub::get()).expect("conversion_works"); let foreign_asset_at_asset_hub_westend = - v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())]) + Location::new(1, [Junction::Parachain(PenpalA::para_id().into())]) .appended_with(asset_location_on_penpal) .unwrap(); @@ -141,7 +141,7 @@ fn swap_locally_on_chain_using_foreign_assets() { // 1. Mint foreign asset (in reality this should be a teleport or some such) assert_ok!(::ForeignAssets::mint( ::RuntimeOrigin::signed(sov_penpal_on_ahr.clone().into()), - foreign_asset_at_asset_hub_westend, + foreign_asset_at_asset_hub_westend.clone(), sov_penpal_on_ahr.clone().into(), ASSET_HUB_WESTEND_ED * 3_000_000_000_000, )); @@ -157,7 +157,7 @@ fn swap_locally_on_chain_using_foreign_assets() { assert_ok!(::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubWestendSender::get()), asset_native.clone(), - Box::new(foreign_asset_at_asset_hub_westend), + Box::new(foreign_asset_at_asset_hub_westend.clone()), )); assert_expected_events!( @@ -171,7 +171,7 @@ fn swap_locally_on_chain_using_foreign_assets() { assert_ok!(::AssetConversion::add_liquidity( ::RuntimeOrigin::signed(sov_penpal_on_ahr.clone()), asset_native.clone(), - Box::new(foreign_asset_at_asset_hub_westend), + Box::new(foreign_asset_at_asset_hub_westend.clone()), 1_000_000_000_000_000, 2_000_000_000_000_000, 0, @@ -189,7 +189,7 @@ fn swap_locally_on_chain_using_foreign_assets() { ); // 4. Swap! - let path = vec![asset_native.clone(), Box::new(foreign_asset_at_asset_hub_westend)]; + let path = vec![asset_native.clone(), Box::new(foreign_asset_at_asset_hub_westend.clone())]; assert_ok!( ::AssetConversion::swap_exact_tokens_for_tokens( @@ -252,8 +252,8 @@ fn cannot_create_pool_from_pool_assets() { assert_matches::assert_matches!( ::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubWestendSender::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(Location::try_from(asset_native).expect("conversion works")), + Box::new(Location::try_from(asset_one).expect("conversion works")), ), Err(DispatchError::Module(ModuleError{index: _, error: _, message})) => assert_eq!(message, Some("Unknown")) ); @@ -262,12 +262,12 @@ 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(RelayLocation::get()).expect("conversion works"); - let asset_one = xcm::v3::Location { + let asset_native = Location::try_from(RelayLocation::get()).expect("conversion works"); + let asset_one = Location { parents: 0, interior: [ - xcm::v3::Junction::PalletInstance(ASSETS_PALLET_ID), - xcm::v3::Junction::GeneralIndex(ASSET_ID.into()), + Junction::PalletInstance(ASSETS_PALLET_ID), + Junction::GeneralIndex(ASSET_ID.into()), ] .into(), }; @@ -296,8 +296,8 @@ fn pay_xcm_fee_with_some_asset_swapped_for_native() { assert_ok!(::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - Box::new(asset_native), - Box::new(asset_one), + Box::new(asset_native.clone()), + Box::new(asset_one.clone()), )); assert_expected_events!( diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs index a524b87b2daf3a1352af1ea33b64282c2f4a8137..15d39858acca4b099cd0215a55d017b42a695dda 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs @@ -15,53 +15,6 @@ use crate::imports::*; -fn relay_origin_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - Westend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(631_531_000, 7_186))); - - assert_expected_events!( - Westend, - vec![ - // Amount to teleport is withdrawn from Sender - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, - }, - // Amount to teleport is deposited in Relay's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) => { - who: *who == ::XcmPallet::check_account(), - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn relay_dest_assertions(t: SystemParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - - Westend::assert_ump_queue_processed( - true, - Some(AssetHubWestend::para_id()), - Some(Weight::from_parts(307_225_000, 7_186)), - ); - - assert_expected_events!( - Westend, - vec![ - // Amount is withdrawn from Relay Chain's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == ::XcmPallet::check_account(), - amount: *amount == t.args.amount, - }, - // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, - }, - ] - ); -} - fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) { Westend::assert_ump_queue_processed( false, @@ -92,22 +45,6 @@ fn para_origin_assertions(t: SystemParaToRelayTest) { ); } -fn para_dest_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubWestend::assert_dmp_queue_complete(Some(Weight::from_parts(157_718_000, 3593))); - - assert_expected_events!( - AssetHubWestend, - vec![ - // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, - }, - ] - ); -} - fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; let system_para_native_asset_location = RelayLocation::get(); @@ -141,7 +78,6 @@ fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) { ); let (expected_foreign_asset_id, expected_foreign_asset_amount) = non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); - let expected_foreign_asset_id_v3: v3::Location = expected_foreign_asset_id.try_into().unwrap(); AssetHubWestend::assert_xcmp_queue_success(None); @@ -159,7 +95,7 @@ fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) { who: *who == t.receiver.account_id, }, RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { - asset_id: *asset_id == expected_foreign_asset_id_v3, + asset_id: *asset_id == expected_foreign_asset_id, owner: *owner == t.receiver.account_id, amount: *amount == expected_foreign_asset_amount, }, @@ -173,7 +109,6 @@ fn ah_to_penpal_foreign_assets_sender_assertions(t: SystemParaToParaTest) { AssetHubWestend::assert_xcm_pallet_attempted_complete(None); let (expected_foreign_asset_id, expected_foreign_asset_amount) = non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); - let expected_foreign_asset_id_v3: v3::Location = expected_foreign_asset_id.try_into().unwrap(); assert_expected_events!( AssetHubWestend, vec![ @@ -189,7 +124,7 @@ fn ah_to_penpal_foreign_assets_sender_assertions(t: SystemParaToParaTest) { }, // foreign asset is burned locally as part of teleportation RuntimeEvent::ForeignAssets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { - asset_id: *asset_id == expected_foreign_asset_id_v3, + asset_id: *asset_id == expected_foreign_asset_id, owner: *owner == t.sender.account_id, balance: *balance == expected_foreign_asset_amount, }, @@ -232,17 +167,6 @@ fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) { ); } -fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::limited_teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { ::PolkadotXcm::limited_teleport_assets( t.signed_origin, @@ -276,90 +200,41 @@ fn system_para_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResul ) } -/// Limited Teleport of native asset from Relay Chain to the System Parachain should work #[test] -fn limited_teleport_native_assets_from_relay_to_system_para_works() { - // Init values for Relay Chain - let amount_to_send: Balance = WESTEND_ED * 1000; - let dest = Westend::child_location_of(AssetHubWestend::para_id()); - let beneficiary_id = AssetHubWestendReceiver::get(); - let test_args = TestContext { - sender: WestendSender::get(), - receiver: AssetHubWestendReceiver::get(), - args: TestArgs::new_relay(dest, beneficiary_id, amount_to_send), - }; - - let mut test = RelayToSystemParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(para_dest_assertions); - test.set_dispatchable::(relay_limited_teleport_assets); - test.assert(); - - let delivery_fees = Westend::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; +fn teleport_to_other_system_parachains_works() { + let amount = ASSET_HUB_WESTEND_ED * 100; + let native_asset: Assets = (Parent, amount).into(); - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); + test_parachain_is_trusted_teleporter!( + AssetHubWestend, // Origin + AssetHubWestendXcmConfig, // XCM Configuration + vec![BridgeHubWestend], // Destinations + (native_asset, amount) + ); } -/// Limited Teleport of native asset from System Parachain to Relay Chain -/// should work when there is enough balance in Relay Chain's `CheckAccount` #[test] -fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { - // Dependency - Relay Chain's `CheckAccount` should have enough balance - limited_teleport_native_assets_from_relay_to_system_para_works(); - - // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; - let destination = AssetHubWestend::parent_location(); - let beneficiary_id = WestendReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubWestendSender::get(), - receiver: WestendReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions); - test.set_dispatchable::(system_para_limited_teleport_assets); - test.assert(); +fn teleport_from_and_to_relay() { + let amount = WESTEND_ED * 100; + let native_asset: Assets = (Here, amount).into(); - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = AssetHubWestend::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); + test_relay_is_trusted_teleporter!( + Westend, + WestendXcmConfig, + vec![AssetHubWestend], + (native_asset, amount) + ); - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); + test_parachain_is_trusted_teleporter_for_relay!( + AssetHubWestend, + AssetHubWestendXcmConfig, + Westend, + amount + ); } /// Limited Teleport of native asset from System Parachain to Relay Chain -/// should't work when there is not enough balance in Relay Chain's `CheckAccount` +/// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` #[test] fn limited_teleport_native_assets_from_system_para_to_relay_fails() { // Init values for Relay Chain @@ -399,19 +274,6 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { assert_eq!(receiver_balance_after, receiver_balance_before); } -#[test] -fn teleport_to_other_system_parachains_works() { - let amount = ASSET_HUB_WESTEND_ED * 100; - let native_asset: Assets = (Parent, amount).into(); - - test_parachain_is_trusted_teleporter!( - AssetHubWestend, // Origin - AssetHubWestendXcmConfig, // XCM Configuration - vec![BridgeHubWestend], // Destinations - (native_asset, amount) - ); -} - /// Bidirectional teleports of local Penpal assets to Asset Hub as foreign assets while paying /// fees using (reserve transferred) native asset. pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt( 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 8cbce3e0d223277e240e159e99f76696b7b339be..b70967184387a868b4bd2b49970f8e16d418d62d 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 @@ -14,15 +14,17 @@ // limitations under the License. use crate::imports::*; -use emulated_integration_tests_common::accounts::{ALICE, BOB}; -use frame_support::traits::fungibles::{Create, Inspect, Mutate}; +use emulated_integration_tests_common::{ + accounts::{ALICE, BOB}, + USDT_ID, +}; +use frame_support::traits::fungibles::{Inspect, Mutate}; use polkadot_runtime_common::impls::VersionedLocatableAsset; use xcm_executor::traits::ConvertLocation; #[test] fn create_and_claim_treasury_spend() { - const ASSET_ID: u32 = 1984; - const SPEND_AMOUNT: u128 = 1_000_000; + const SPEND_AMOUNT: u128 = 1_000_000_000; // treasury location from a sibling parachain. let treasury_location: Location = Location::new(1, PalletInstance(37)); // treasury account on a sibling parachain. @@ -33,7 +35,7 @@ fn create_and_claim_treasury_spend() { // asset kind to be spend from the treasury. let asset_kind = VersionedLocatableAsset::V4 { location: asset_hub_location, - asset_id: AssetId([PalletInstance(50), GeneralIndex(ASSET_ID.into())].into()), + asset_id: AssetId([PalletInstance(50), GeneralIndex(USDT_ID.into())].into()), }; // treasury spend beneficiary. let alice: AccountId = Westend::account_id_of(ALICE); @@ -43,16 +45,10 @@ fn create_and_claim_treasury_spend() { AssetHubWestend::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 - )); - assert_ok!(>::mint_into(ASSET_ID, &treasury_account, SPEND_AMOUNT * 4)); + // USDT created at genesis, mint some assets to the treasury account. + assert_ok!(>::mint_into(USDT_ID, &treasury_account, SPEND_AMOUNT * 4)); // beneficiary has zero balance. - assert_eq!(>::balance(ASSET_ID, &alice,), 0u128,); + assert_eq!(>::balance(USDT_ID, &alice,), 0u128,); }); Westend::execute_with(|| { @@ -94,7 +90,7 @@ fn create_and_claim_treasury_spend() { AssetHubWestend, vec![ RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id: id, from, to, amount }) => { - id: id == &ASSET_ID, + id: id == &USDT_ID, from: from == &treasury_account, to: to == &alice, amount: amount == &SPEND_AMOUNT, @@ -104,7 +100,7 @@ fn create_and_claim_treasury_spend() { ] ); // beneficiary received the assets from the treasury. - assert_eq!(>::balance(ASSET_ID, &alice,), SPEND_AMOUNT,); + assert_eq!(>::balance(USDT_ID, &alice,), SPEND_AMOUNT,); }); Westend::execute_with(|| { 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 c01aa7825336348f5077c89a73c61e7b128a6200..037d6604ea4d5e665928b5629dce3a52abb30a8a 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 @@ -17,89 +17,95 @@ use crate::imports::*; -use frame_system::RawOrigin; +use frame_support::{ + dispatch::RawOrigin, + sp_runtime::{traits::Dispatchable, DispatchResult}, +}; use xcm_runtime_apis::{ dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, }; -/// We are able to dry-run and estimate the fees for a teleport between relay and system para. -/// Scenario: Alice on Westend relay chain wants to teleport WND to Asset Hub. -/// We want to know the fees using the `DryRunApi` and `XcmPaymentApi`. -#[test] -fn teleport_relay_system_para_works() { - let destination: Location = Parachain(1000).into(); // Asset Hub. - let beneficiary_id = AssetHubWestendReceiver::get(); - let beneficiary: Location = AccountId32 { id: beneficiary_id.clone().into(), network: None } // Test doesn't allow specifying a network here. - .into(); // Beneficiary in Asset Hub. - let teleport_amount = 1_000_000_000_000; // One WND (12 decimals). - let assets: Assets = vec![(Here, teleport_amount).into()].into(); - - // We get them from the Westend closure. - let mut delivery_fees_amount = 0; - let mut remote_message = VersionedXcm::V4(Xcm(Vec::new())); - ::new_ext().execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - type OriginCaller = ::OriginCaller; - - let call = RuntimeCall::XcmPallet(pallet_xcm::Call::transfer_assets { - dest: Box::new(VersionedLocation::V4(destination.clone())), - beneficiary: Box::new(VersionedLocation::V4(beneficiary)), - assets: Box::new(VersionedAssets::V4(assets)), - fee_asset_item: 0, - weight_limit: Unlimited, - }); - let origin = OriginCaller::system(RawOrigin::Signed(WestendSender::get())); - let result = Runtime::dry_run_call(origin, call).unwrap(); - assert_eq!(result.forwarded_xcms.len(), 1); - let (destination_to_query, messages_to_query) = &result.forwarded_xcms[0]; - assert_eq!(messages_to_query.len(), 1); - remote_message = messages_to_query[0].clone(); - let delivery_fees = - Runtime::query_delivery_fees(destination_to_query.clone(), remote_message.clone()) - .unwrap(); - delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); - }); - - // This is set in the AssetHubWestend closure. - let mut remote_execution_fees = 0; - ::execute_with(|| { - type Runtime = ::Runtime; - - let weight = Runtime::query_xcm_weight(remote_message.clone()).unwrap(); - remote_execution_fees = - Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::V4(Parent.into())) - .unwrap(); - }); - - let test_args = TestContext { - sender: WestendSender::get(), // Alice. - receiver: AssetHubWestendReceiver::get(), // Bob in Asset Hub. - args: TestArgs::new_relay(destination, beneficiary_id, teleport_amount), - }; - let mut test = RelayToSystemParaTest::new(test_args); +fn sender_assertions(test: ParaToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + PenpalA::assert_xcm_pallet_attempted_complete(None); + + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance } + ) => { + asset_id: *asset_id == Location::new(1, []), + owner: *owner == test.sender.account_id, + balance: *balance == test.args.amount, + }, + ] + ); +} - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - assert_eq!(sender_balance_before, 1_000_000_000_000_000_000); - assert_eq!(receiver_balance_before, 4_096_000_000_000); +fn hop_assertions(test: ParaToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + AssetHubWestend::assert_xcmp_queue_success(None); + + assert_expected_events!( + AssetHubWestend, + vec![ + RuntimeEvent::Balances( + pallet_balances::Event::Burned { amount, .. } + ) => { + amount: *amount == test.args.amount, + }, + ] + ); +} - test.set_dispatchable::(transfer_assets); - test.assert(); +fn receiver_assertions(test: ParaToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + PenpalB::assert_xcmp_queue_success(None); + + assert_expected_events!( + PenpalB, + vec![ + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Issued { asset_id, owner, .. } + ) => { + asset_id: *asset_id == Location::new(1, []), + owner: *owner == test.receiver.account_id, + }, + ] + ); +} - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; +fn transfer_assets_para_to_para_through_ah_dispatchable( + test: ParaToParaThroughAHTest, +) -> DispatchResult { + let call = transfer_assets_para_to_para_through_ah_call(test.clone()); + match call.dispatch(test.signed_origin) { + Ok(_) => Ok(()), + Err(error_with_post_info) => Err(error_with_post_info.error), + } +} - // We now know the exact fees. - assert_eq!( - sender_balance_after, - sender_balance_before - delivery_fees_amount - teleport_amount - ); - assert_eq!( - receiver_balance_after, - receiver_balance_before + teleport_amount - remote_execution_fees - ); +fn transfer_assets_para_to_para_through_ah_call( + test: ParaToParaThroughAHTest, +) -> ::RuntimeCall { + type RuntimeCall = ::RuntimeCall; + + let asset_hub_location: Location = PenpalB::sibling_location_of(AssetHubWestend::para_id()); + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(test.args.assets.len() as u32)), + beneficiary: test.args.beneficiary, + }]); + RuntimeCall::PolkadotXcm(pallet_xcm::Call::transfer_assets_using_type_and_then { + dest: bx!(test.args.dest.into()), + assets: bx!(test.args.assets.clone().into()), + assets_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), + remote_fees_id: bx!(VersionedAssetId::V4(AssetId(Location::new(1, [])))), + fees_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.into())), + custom_xcm_on_dest: bx!(VersionedXcm::from(custom_xcm_on_dest)), + weight_limit: test.args.weight_limit, + }) } /// We are able to dry-run and estimate the fees for a multi-hop XCM journey. @@ -109,12 +115,13 @@ fn teleport_relay_system_para_works() { fn multi_hop_works() { let destination = PenpalA::sibling_location_of(PenpalB::para_id()); let sender = PenpalASender::get(); - let amount_to_send = 1_000_000_000_000; // One WND (12 decimals). + let amount_to_send = 1_000_000_000_000; let asset_owner = PenpalAssetOwner::get(); let assets: Assets = (Parent, amount_to_send).into(); - let relay_native_asset_location = RelayLocation::get(); - let sender_as_seen_by_relay = Westend::child_location_of(PenpalA::para_id()); - let sov_of_sender_on_relay = Westend::sovereign_account_id_of(sender_as_seen_by_relay.clone()); + let relay_native_asset_location = Location::parent(); + let sender_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let sov_of_sender_on_ah = + AssetHubWestend::sovereign_account_id_of(sender_as_seen_by_ah.clone()); // fund Parachain's sender account PenpalA::mint_foreign_asset( @@ -124,36 +131,44 @@ fn multi_hop_works() { amount_to_send * 2, ); - // fund the Parachain Origin's SA on Relay Chain with the native tokens held in reserve - Westend::fund_accounts(vec![(sov_of_sender_on_relay.clone().into(), amount_to_send * 2)]); + // fund the Parachain Origin's SA on AssetHub with the native tokens held in reserve. + AssetHubWestend::fund_accounts(vec![(sov_of_sender_on_ah.clone(), amount_to_send * 2)]); // Init values for Parachain Destination let beneficiary_id = PenpalBReceiver::get(); - let beneficiary: Location = AccountId32 { - id: beneficiary_id.clone().into(), - network: None, // Test doesn't allow specifying a network here. - } - .into(); + + let test_args = TestContext { + sender: PenpalASender::get(), // Bob in PenpalB. + receiver: PenpalBReceiver::get(), // Alice. + args: TestArgs::new_para( + destination, + beneficiary_id.clone(), + amount_to_send, + assets, + None, + 0, + ), + }; + let mut test = ParaToParaThroughAHTest::new(test_args); // We get them from the PenpalA closure. let mut delivery_fees_amount = 0; let mut remote_message = VersionedXcm::V4(Xcm(Vec::new())); ::execute_with(|| { type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; type OriginCaller = ::OriginCaller; - let call = RuntimeCall::PolkadotXcm(pallet_xcm::Call::transfer_assets { - dest: Box::new(VersionedLocation::V4(destination.clone())), - beneficiary: Box::new(VersionedLocation::V4(beneficiary)), - assets: Box::new(VersionedAssets::V4(assets.clone())), - fee_asset_item: 0, - weight_limit: Unlimited, - }); - let origin = OriginCaller::system(RawOrigin::Signed(PenpalASender::get())); + let call = transfer_assets_para_to_para_through_ah_call(test.clone()); + let origin = OriginCaller::system(RawOrigin::Signed(sender.clone())); let result = Runtime::dry_run_call(origin, call).unwrap(); - assert_eq!(result.forwarded_xcms.len(), 1); - let (destination_to_query, messages_to_query) = &result.forwarded_xcms[0]; + // We filter the result to get only the messages we are interested in. + let (destination_to_query, messages_to_query) = &result + .forwarded_xcms + .iter() + .find(|(destination, _)| { + *destination == VersionedLocation::V4(Location::new(1, [Parachain(1000)])) + }) + .unwrap(); assert_eq!(messages_to_query.len(), 1); remote_message = messages_to_query[0].clone(); let delivery_fees = @@ -162,18 +177,21 @@ fn multi_hop_works() { delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); }); - // This is set in the Westend closure. + // These are set in the AssetHub closure. let mut intermediate_execution_fees = 0; let mut intermediate_delivery_fees_amount = 0; let mut intermediate_remote_message = VersionedXcm::V4(Xcm::<()>(Vec::new())); - ::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; + ::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; // First we get the execution fees. let weight = Runtime::query_xcm_weight(remote_message.clone()).unwrap(); - intermediate_execution_fees = - Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::V4(Here.into())).unwrap(); + intermediate_execution_fees = Runtime::query_weight_to_asset_fee( + weight, + VersionedAssetId::V4(Location::new(1, []).into()), + ) + .unwrap(); // We have to do this to turn `VersionedXcm<()>` into `VersionedXcm`. let xcm_program = @@ -181,8 +199,14 @@ fn multi_hop_works() { // Now we get the delivery fees to the final destination. let result = - Runtime::dry_run_xcm(sender_as_seen_by_relay.clone().into(), xcm_program).unwrap(); - let (destination_to_query, messages_to_query) = &result.forwarded_xcms[0]; + Runtime::dry_run_xcm(sender_as_seen_by_ah.clone().into(), xcm_program).unwrap(); + let (destination_to_query, messages_to_query) = &result + .forwarded_xcms + .iter() + .find(|(destination, _)| { + *destination == VersionedLocation::V4(Location::new(1, [Parachain(2001)])) + }) + .unwrap(); // There's actually two messages here. // One created when the message we sent from PenpalA arrived and was executed. // The second one when we dry-run the xcm. @@ -200,7 +224,7 @@ fn multi_hop_works() { // Get the final execution fees in the destination. let mut final_execution_fees = 0; ::execute_with(|| { - type Runtime = ::Runtime; + type Runtime = ::Runtime; let weight = Runtime::query_xcm_weight(intermediate_remote_message.clone()).unwrap(); final_execution_fees = @@ -210,7 +234,7 @@ fn multi_hop_works() { // Dry-running is done. PenpalA::reset_ext(); - Westend::reset_ext(); + AssetHubWestend::reset_ext(); PenpalB::reset_ext(); // Fund accounts again. @@ -220,23 +244,9 @@ fn multi_hop_works() { sender.clone(), amount_to_send * 2, ); - Westend::fund_accounts(vec![(sov_of_sender_on_relay.into(), amount_to_send * 2)]); + AssetHubWestend::fund_accounts(vec![(sov_of_sender_on_ah, amount_to_send * 2)]); // Actually run the extrinsic. - let test_args = TestContext { - sender: PenpalASender::get(), // Alice. - receiver: PenpalBReceiver::get(), // Bob in PenpalB. - args: TestArgs::new_para( - destination, - beneficiary_id.clone(), - amount_to_send, - assets, - None, - 0, - ), - }; - let mut test = ParaToParaThroughRelayTest::new(test_args); - let sender_assets_before = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; >::balance(relay_native_asset_location.clone(), &sender) @@ -246,7 +256,10 @@ fn multi_hop_works() { >::balance(relay_native_asset_location.clone(), &beneficiary_id) }); - test.set_dispatchable::(transfer_assets_para_to_para); + test.set_assertion::(sender_assertions); + test.set_assertion::(hop_assertions); + test.set_assertion::(receiver_assertions); + test.set_dispatchable::(transfer_assets_para_to_para_through_ah_dispatchable); test.assert(); let sender_assets_after = PenpalA::execute_with(|| { @@ -273,33 +286,3 @@ fn multi_hop_works() { final_execution_fees ); } - -fn get_amount_from_versioned_assets(assets: VersionedAssets) -> u128 { - let latest_assets: Assets = assets.try_into().unwrap(); - let Fungible(amount) = latest_assets.inner()[0].fun else { - unreachable!("asset is fungible"); - }; - amount -} - -fn transfer_assets(test: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::transfer_assets( - test.signed_origin, - bx!(test.args.dest.into()), - bx!(test.args.beneficiary.into()), - bx!(test.args.assets.into()), - test.args.fee_asset_item, - test.args.weight_limit, - ) -} - -fn transfer_assets_para_to_para(test: ParaToParaThroughRelayTest) -> DispatchResult { - ::PolkadotXcm::transfer_assets( - test.signed_origin, - bx!(test.args.dest.into()), - bx!(test.args.beneficiary.into()), - bx!(test.args.assets.into()), - test.args.fee_asset_item, - test.args.weight_limit, - ) -} 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 04466a611c71318280d135324ba3de418f9348d9..ac08e48ded68dacad27756ff62b55caf6a1a7f32 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 @@ -23,7 +23,8 @@ mod imports { pub use xcm::{ latest::ParentThen, prelude::{AccountId32 as AccountId32Junction, *}, - v3::{self, NetworkId::Westend as WestendId}, + v4, + v4::NetworkId::Westend as WestendId, }; pub use xcm_executor::traits::TransferType; @@ -31,7 +32,8 @@ mod imports { pub use emulated_integration_tests_common::{ accounts::ALICE, impls::Inspect, - test_parachain_is_trusted_teleporter, + test_parachain_is_trusted_teleporter, test_parachain_is_trusted_teleporter_for_relay, + test_relay_is_trusted_teleporter, xcm_emulator::{ assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, TestExt, }, @@ -48,7 +50,7 @@ mod imports { genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, }, bridge_hub_rococo_emulated_chain::{ - genesis::ED as BRIDGE_HUB_ROCOCO_ED, + genesis::ED as BRIDGE_HUB_ROCOCO_ED, BridgeHubRococoExistentialDeposit, BridgeHubRococoParaPallet as BridgeHubRococoPallet, BridgeHubRococoRuntimeOrigin, BridgeHubRococoXcmConfig, EthereumBeaconClient, EthereumInboundQueue, }, @@ -59,15 +61,20 @@ mod imports { }, PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner, }, - rococo_emulated_chain::{genesis::ED as ROCOCO_ED, RococoRelayPallet as RococoPallet}, + rococo_emulated_chain::{ + genesis::ED as ROCOCO_ED, rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig, + RococoRelayPallet as RococoPallet, + }, AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, AssetHubRococoParaSender as AssetHubRococoSender, AssetHubWestendPara as AssetHubWestend, AssetHubWestendParaReceiver as AssetHubWestendReceiver, AssetHubWestendParaSender as AssetHubWestendSender, BridgeHubRococoPara as BridgeHubRococo, + BridgeHubRococoParaReceiver as BridgeHubRococoReceiver, BridgeHubRococoParaSender as BridgeHubRococoSender, BridgeHubWestendPara as BridgeHubWestend, PenpalAPara as PenpalA, PenpalAParaReceiver as PenpalAReceiver, PenpalAParaSender as PenpalASender, - RococoRelay as Rococo, + RococoRelay as Rococo, RococoRelayReceiver as RococoReceiver, + RococoRelaySender as RococoSender, }; pub const ASSET_MIN_BALANCE: u128 = 1000; 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 6053936487b26e97fe8575cd5b666a03cff7ccf6..8a674f89c9ef9cdc6c5c6512d93196f96144f6a8 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 @@ -36,10 +36,10 @@ fn send_assets_over_bridge(send_fn: F) { fn set_up_rocs_for_penpal_rococo_through_ahr_to_ahw( sender: &AccountId, amount: u128, -) -> (Location, v3::Location) { +) -> (Location, v4::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); + let roc_at_asset_hub_westend = bridged_roc_at_ah_westend(); + create_foreign_on_ah_westend(roc_at_asset_hub_westend.clone(), true); let penpal_location = AssetHubRococo::sibling_location_of(PenpalA::para_id()); let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location); @@ -121,11 +121,11 @@ 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(); + let roc_at_asset_hub_rococo = roc_at_ah_rococo(); + let bridged_roc_at_asset_hub_westend = bridged_roc_at_ah_westend(); - 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); + create_foreign_on_ah_westend(bridged_roc_at_asset_hub_westend.clone(), true); + set_up_pool_with_wnd_on_ah_westend(bridged_roc_at_asset_hub_westend.clone()); //////////////////////////////////////////////////////////// // Let's first send over just some ROCs as a simple example @@ -138,12 +138,13 @@ fn send_roc_usdt_and_weth_from_asset_hub_rococo_to_asset_hub_westend() { ::account_data_of(sov_ahw_on_ahr.clone()).free; 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); + foreign_balance_on_ah_westend(bridged_roc_at_asset_hub_westend.clone(), &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 assets: Assets = + (Location::try_from(roc_at_asset_hub_rococo.clone()).unwrap(), amount).into(); let fee_idx = 0; assert_ok!(send_assets_from_asset_hub_rococo(destination, assets, fee_idx)); }); @@ -185,9 +186,9 @@ fn send_roc_usdt_and_weth_from_asset_hub_rococo_to_asset_hub_westend() { ///////////////////////////////////////////////////////////// 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(); + let bridged_usdt_at_asset_hub_westend = bridged_usdt_at_ah_westend(); // 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_weth_at_ah = weth_at_asset_hubs(); // mint USDT in sender's account (USDT already created in genesis) AssetHubRococo::mint_asset( @@ -197,19 +198,23 @@ fn send_roc_usdt_and_weth_from_asset_hub_rococo_to_asset_hub_westend() { 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); + create_foreign_on_ah_rococo( + bridged_weth_at_ah.clone(), + true, + vec![(sender.clone(), amount * 2)], + ); + create_foreign_on_ah_westend(bridged_weth_at_ah.clone(), true); + create_foreign_on_ah_westend(bridged_usdt_at_asset_hub_westend.clone(), true); + set_up_pool_with_wnd_on_ah_westend(bridged_usdt_at_asset_hub_westend.clone()); 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); + foreign_balance_on_ah_westend(bridged_usdt_at_asset_hub_westend.clone(), &receiver); + let receiver_weth_before = foreign_balance_on_ah_westend(bridged_weth_at_ah.clone(), &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(), + (Location::try_from(bridged_weth_at_ah.clone()).unwrap(), amount).into(), ] .into(); // use USDT for fees @@ -258,9 +263,8 @@ fn send_back_wnds_from_asset_hub_rococo_to_asset_hub_westend() { 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); + create_foreign_on_ah_rococo(wnd_at_asset_hub_rococo.clone(), 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( @@ -273,14 +277,14 @@ fn send_back_wnds_from_asset_hub_rococo_to_asset_hub_westend() { ::account_data_of(sov_ahr_on_ahw.clone()).free; assert_eq!(wnds_in_reserve_on_ahw_before, prefund_amount); - let sender_wnds_before = foreign_balance_on_ah_rococo(wnd_at_asset_hub_rococo_v3, &sender); + let sender_wnds_before = foreign_balance_on_ah_rococo(wnd_at_asset_hub_rococo.clone(), &sender); assert_eq!(sender_wnds_before, prefund_amount); 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 assets: Assets = (wnd_at_asset_hub_rococo.clone(), amount_to_send).into(); let fee_idx = 0; assert_ok!(send_assets_from_asset_hub_rococo(destination, assets, fee_idx)); }); @@ -309,7 +313,7 @@ fn send_back_wnds_from_asset_hub_rococo_to_asset_hub_westend() { ); }); - let sender_wnds_after = foreign_balance_on_ah_rococo(wnd_at_asset_hub_rococo_v3, &sender); + let sender_wnds_after = foreign_balance_on_ah_rococo(wnd_at_asset_hub_rococo, &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; @@ -341,7 +345,8 @@ fn send_rocs_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_westend() type ForeignAssets = ::ForeignAssets; >::balance(roc_at_rococo_parachains.clone(), &sender) }); - let receiver_rocs_before = foreign_balance_on_ah_westend(roc_at_asset_hub_westend, &receiver); + let receiver_rocs_before = + foreign_balance_on_ah_westend(roc_at_asset_hub_westend.clone(), &receiver); // Send ROCs over bridge { @@ -372,7 +377,7 @@ fn send_rocs_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_westend() vec![ // 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(), + asset_id: *asset_id == roc_at_rococo_parachains.clone(), owner: owner == &receiver, }, // message processed successfully @@ -403,7 +408,6 @@ fn send_rocs_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_westend() #[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(); @@ -416,7 +420,7 @@ fn send_back_wnds_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_weste 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); + create_foreign_on_ah_rococo(wnd_at_rococo_parachains.clone(), true, prefund_accounts); let asset_owner: AccountId = AssetHubRococo::account_id_of(ALICE); PenpalA::force_create_foreign_asset( wnd_at_rococo_parachains.clone(), 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 58c52e1328c81f60c9a60d3fd9677a1bf8f66e95..6ce8ecef0df3ff66f0a39d26899aa47202e8a121 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,6 +16,7 @@ use crate::imports::*; mod asset_transfers; +mod claim_assets; mod send_xcm; mod snowbridge; mod teleport; @@ -68,7 +69,7 @@ pub(crate) fn weth_at_asset_hubs() -> Location { } pub(crate) fn create_foreign_on_ah_rococo( - id: v3::Location, + id: v4::Location, sufficient: bool, prefund_accounts: Vec<(AccountId, u128)>, ) { @@ -77,18 +78,18 @@ pub(crate) fn create_foreign_on_ah_rococo( AssetHubRococo::force_create_foreign_asset(id, owner, sufficient, min, prefund_accounts); } -pub(crate) fn create_foreign_on_ah_westend(id: v3::Location, sufficient: bool) { +pub(crate) fn create_foreign_on_ah_westend(id: v4::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 { +pub(crate) fn foreign_balance_on_ah_rococo(id: v4::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 { +pub(crate) fn foreign_balance_on_ah_westend(id: v4::Location, who: &AccountId) -> u128 { AssetHubWestend::execute_with(|| { type Assets = ::ForeignAssets; >::balance(id, who) @@ -96,8 +97,8 @@ pub(crate) fn foreign_balance_on_ah_westend(id: v3::Location, who: &AccountId) - } // 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(); +pub(crate) fn set_up_pool_with_wnd_on_ah_westend(foreign_asset: v4::Location) { + let wnd: v4::Location = v4::Parent.into(); AssetHubWestend::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; let owner = AssetHubWestendSender::get(); @@ -105,14 +106,14 @@ pub(crate) fn set_up_pool_with_wnd_on_ah_westend(foreign_asset: v3::Location) { assert_ok!(::ForeignAssets::mint( signed_owner.clone(), - foreign_asset.into(), + foreign_asset.clone().into(), owner.clone().into(), 3_000_000_000_000, )); assert_ok!(::AssetConversion::create_pool( signed_owner.clone(), - Box::new(wnd), - Box::new(foreign_asset), + Box::new(wnd.clone()), + Box::new(foreign_asset.clone()), )); assert_expected_events!( AssetHubWestend, 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 652447fa56010918d8816187207bc86e2ae99ea5..3f2038b4bdd1b510305eb27b7564aa9bbd778c40 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 @@ -29,7 +29,7 @@ fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable let xcm = VersionedXcm::from(Xcm(vec![ UnpaidExecution { weight_limit, check_origin }, ExportMessage { - network: WestendId.into(), + network: WestendId, destination: [Parachain(AssetHubWestend::para_id().into())].into(), xcm: remote_xcm, }, 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 40a1968ec557bd99730fd27e151a4aa9f2f2cfd9..84328fb7c6d201b86edf9aba954d84b7598e3005 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 @@ -560,7 +560,6 @@ fn send_token_from_ethereum_to_asset_hub_with_fee(account_id: [u8; 32], fee: u12 2, [EthereumNetwork::get().into(), AccountKey20 { network: None, key: WETH }], ); - // (Parent, Parent, EthereumNetwork::get(), AccountKey20 { network: None, key: WETH }) // Fund asset hub sovereign on bridge hub let asset_hub_sovereign = BridgeHubRococo::sovereign_account_id_of(Location::new( 1, @@ -669,8 +668,8 @@ fn send_token_from_ethereum_to_non_existent_account_on_asset_hub_with_insufficie #[test] fn send_token_from_ethereum_to_non_existent_account_on_asset_hub_with_sufficient_fee_but_do_not_satisfy_ed( ) { - // On AH the xcm fee is 33_873_024 and the ED is 3_300_000 - send_token_from_ethereum_to_asset_hub_with_fee([1; 32], 36_000_000); + // On AH the xcm fee is 26_789_690 and the ED is 3_300_000 + send_token_from_ethereum_to_asset_hub_with_fee([1; 32], 30_000_000); AssetHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; 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 1fb03748d926c9a422ede319977c5e39c0f24b16..8cdd9613dc52126ea134ed69ced701dbb0e5f744 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 @@ -27,3 +27,23 @@ fn teleport_to_other_system_parachains_works() { (native_asset, amount) ); } + +#[test] +fn teleport_from_and_to_relay() { + let amount = ROCOCO_ED * 100; + let native_asset: Assets = (Here, amount).into(); + + test_relay_is_trusted_teleporter!( + Rococo, + RococoXcmConfig, + vec![BridgeHubRococo], + (native_asset, amount) + ); + + test_parachain_is_trusted_teleporter_for_relay!( + BridgeHubRococo, + BridgeHubRococoXcmConfig, + Rococo, + 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 6b83479eaf89a5677a77816b748948c8ba93fa53..1f2d2c8ece2437fee863a888713ae8d868359b84 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 @@ -12,6 +12,9 @@ workspace = true [dependencies] hex-literal = { workspace = true, default-features = true } +codec = { workspace = true } +log = { workspace = true } +scale-info = { workspace = true } # Substrate frame-support = { workspace = true } @@ -19,6 +22,7 @@ pallet-assets = { workspace = true } pallet-asset-conversion = { workspace = true } pallet-balances = { workspace = true } pallet-message-queue = { workspace = true, default-features = true } +sp-core = { workspace = true } sp-runtime = { workspace = true } # Polkadot @@ -34,3 +38,14 @@ 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 } +testnet-parachains-constants = { workspace = true, features = ["westend"] } +asset-hub-westend-runtime = { workspace = true } +bridge-hub-westend-runtime = { workspace = true } + +# Snowbridge +snowbridge-core = { workspace = true } +snowbridge-router-primitives = { workspace = true } +snowbridge-pallet-system = { workspace = true } +snowbridge-pallet-outbound-queue = { workspace = true } +snowbridge-pallet-inbound-queue = { workspace = true } +snowbridge-pallet-inbound-queue-fixtures = { 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 3b0fcea57a26f3e06080c28e9d6495f1b71e3680..5e0462d14882a9922c8d6232dd7ebe781ca5c88a 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 @@ -23,8 +23,7 @@ mod imports { pub use xcm::{ latest::ParentThen, prelude::{AccountId32 as AccountId32Junction, *}, - v3, - v4::NetworkId::Rococo as RococoId, + v4::{self, NetworkId::Rococo as RococoId}, }; pub use xcm_executor::traits::TransferType; @@ -32,7 +31,8 @@ mod imports { pub use emulated_integration_tests_common::{ accounts::ALICE, impls::Inspect, - test_parachain_is_trusted_teleporter, + test_parachain_is_trusted_teleporter, test_parachain_is_trusted_teleporter_for_relay, + test_relay_is_trusted_teleporter, xcm_emulator::{ assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, TestExt, }, @@ -48,21 +48,26 @@ mod imports { genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, }, bridge_hub_westend_emulated_chain::{ - genesis::ED as BRIDGE_HUB_WESTEND_ED, + 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, }, - westend_emulated_chain::WestendRelayPallet as WestendPallet, + westend_emulated_chain::{ + genesis::ED as WESTEND_ED, westend_runtime::xcm_config::XcmConfig as WestendXcmConfig, + WestendRelayPallet as WestendPallet, + }, AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, AssetHubRococoParaSender as AssetHubRococoSender, AssetHubWestendPara as AssetHubWestend, AssetHubWestendParaReceiver as AssetHubWestendReceiver, AssetHubWestendParaSender as AssetHubWestendSender, BridgeHubRococoPara as BridgeHubRococo, BridgeHubWestendPara as BridgeHubWestend, + BridgeHubWestendParaReceiver as BridgeHubWestendReceiver, BridgeHubWestendParaSender as BridgeHubWestendSender, PenpalBPara as PenpalB, PenpalBParaSender as PenpalBSender, WestendRelay as Westend, + WestendRelayReceiver as WestendReceiver, WestendRelaySender as WestendSender, }; pub const ASSET_MIN_BALANCE: u128 = 1000; 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 0c0b04cd45a91c42592052799ba9580bd6e4219a..fc8b772a9c7e02e9937d78607ceb2b106b16fd24 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 @@ -35,10 +35,10 @@ fn send_assets_over_bridge(send_fn: F) { fn set_up_wnds_for_penpal_westend_through_ahw_to_ahr( sender: &AccountId, amount: u128, -) -> (Location, v3::Location) { +) -> (Location, v4::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); + let wnd_at_asset_hub_rococo = bridged_wnd_at_ah_rococo(); + create_foreign_on_ah_rococo(wnd_at_asset_hub_rococo.clone(), true); let penpal_location = AssetHubWestend::sibling_location_of(PenpalB::para_id()); let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of(penpal_location); @@ -116,10 +116,10 @@ fn send_wnds_from_asset_hub_westend_to_asset_hub_rococo() { 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); + let bridged_wnd_at_asset_hub_rococo = bridged_wnd_at_ah_rococo(); + create_foreign_on_ah_rococo(bridged_wnd_at_asset_hub_rococo.clone(), true); - set_up_pool_with_roc_on_ah_rococo(bridged_wnd_at_asset_hub_rococo, true); + set_up_pool_with_roc_on_ah_rococo(bridged_wnd_at_asset_hub_rococo.clone(), true); let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( Rococo, @@ -129,7 +129,7 @@ fn send_wnds_from_asset_hub_westend_to_asset_hub_rococo() { ::account_data_of(sov_ahr_on_ahw.clone()).free; 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); + foreign_balance_on_ah_rococo(bridged_wnd_at_asset_hub_rococo.clone(), &receiver); // send WNDs, use them for fees send_assets_over_bridge(|| { @@ -187,10 +187,8 @@ fn send_back_rocs_usdt_and_weth_from_asset_hub_westend_to_asset_hub_rococo() { 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); + create_foreign_on_ah_westend(bridged_roc_at_asset_hub_westend.clone(), true, prefund_accounts); //////////////////////////////////////////////////////////// // Let's first send back just some ROCs as a simple example @@ -208,14 +206,14 @@ fn send_back_rocs_usdt_and_weth_from_asset_hub_westend_to_asset_hub_rococo() { assert_eq!(rocs_in_reserve_on_ahr_before, prefund_amount); let sender_rocs_before = - foreign_balance_on_ah_westend(bridged_roc_at_asset_hub_westend_v3, &sender); + foreign_balance_on_ah_westend(bridged_roc_at_asset_hub_westend.clone(), &sender); assert_eq!(sender_rocs_before, prefund_amount); 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 assets: Assets = (bridged_roc_at_asset_hub_westend.clone(), amount_to_send).into(); let fee_idx = 0; assert_ok!(send_assets_from_asset_hub_westend(destination, assets, fee_idx)); }); @@ -245,7 +243,7 @@ fn send_back_rocs_usdt_and_weth_from_asset_hub_westend_to_asset_hub_rococo() { }); let sender_rocs_after = - foreign_balance_on_ah_westend(bridged_roc_at_asset_hub_westend_v3, &sender); + foreign_balance_on_ah_westend(bridged_roc_at_asset_hub_westend, &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; @@ -262,14 +260,14 @@ fn send_back_rocs_usdt_and_weth_from_asset_hub_westend_to_asset_hub_rococo() { ////////////////////////////////////////////////////////////////// // 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(); + let bridged_weth_at_ah = weth_at_asset_hubs(); + let bridged_usdt_at_asset_hub_westend = bridged_usdt_at_ah_westend(); // 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); + set_up_pool_with_roc_on_ah_rococo(usdt_at_ah_rococo(), false); // create wETH on Rococo (IRL it's already created by Snowbridge) - create_foreign_on_ah_rococo(bridged_weth_at_ah, true); + create_foreign_on_ah_rococo(bridged_weth_at_ah.clone(), 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, @@ -283,7 +281,7 @@ fn send_back_rocs_usdt_and_weth_from_asset_hub_westend_to_asset_hub_rococo() { ); AssetHubRococo::mint_foreign_asset( ::RuntimeOrigin::signed(AssetHubRococo::account_id_of(ALICE)), - bridged_weth_at_ah, + bridged_weth_at_ah.clone(), sov_ahw_on_ahr, amount_to_send * 2, ); @@ -291,21 +289,21 @@ fn send_back_rocs_usdt_and_weth_from_asset_hub_westend_to_asset_hub_rococo() { // 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); + create_foreign_on_ah_westend(bridged_weth_at_ah.clone(), true, prefund_accounts.clone()); + create_foreign_on_ah_westend(bridged_usdt_at_asset_hub_westend.clone(), 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 receiver_weth_before = foreign_balance_on_ah_rococo(bridged_weth_at_ah.clone(), &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(), + (Location::try_from(bridged_weth_at_ah.clone()).unwrap(), amount_to_send).into(), ] .into(); // use USDT for fees @@ -367,7 +365,8 @@ fn send_wnds_from_penpal_westend_through_asset_hub_westend_to_asset_hub_rococo() type ForeignAssets = ::ForeignAssets; >::balance(wnd_at_westend_parachains.clone(), &sender) }); - let receiver_wnds_before = foreign_balance_on_ah_rococo(wnd_at_asset_hub_rococo, &receiver); + let receiver_wnds_before = + foreign_balance_on_ah_rococo(wnd_at_asset_hub_rococo.clone(), &receiver); // Send WNDs over bridge { @@ -398,7 +397,7 @@ fn send_wnds_from_penpal_westend_through_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_westend_parachains.clone().try_into().unwrap(), + asset_id: *asset_id == wnd_at_westend_parachains.clone(), owner: owner == &receiver, }, // message processed successfully @@ -429,7 +428,6 @@ fn send_wnds_from_penpal_westend_through_asset_hub_westend_to_asset_hub_rococo() #[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(); @@ -442,7 +440,7 @@ fn send_back_rocs_from_penpal_westend_through_asset_hub_westend_to_asset_hub_roc 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); + create_foreign_on_ah_westend(roc_at_westend_parachains.clone(), true, prefund_accounts); let asset_owner: AccountId = AssetHubWestend::account_id_of(ALICE); PenpalB::force_create_foreign_asset( roc_at_westend_parachains.clone(), @@ -454,7 +452,7 @@ fn send_back_rocs_from_penpal_westend_through_asset_hub_westend_to_asset_hub_roc // 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, + Westend, AssetHubWestend::para_id(), ); AssetHubRococo::fund_accounts(vec![(sov_ahw_on_ahr.clone(), amount * 2)]); 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 92e864229a9cd605fbe0f8ca843deef6d74d30c2..bf894a3baf585da518287b3a30527b403c55aa3a 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,14 +16,11 @@ use crate::imports::*; mod asset_transfers; +mod claim_assets; mod send_xcm; +mod snowbridge; 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())]) } @@ -72,13 +69,13 @@ pub(crate) fn weth_at_asset_hubs() -> Location { ) } -pub(crate) fn create_foreign_on_ah_rococo(id: v3::Location, sufficient: bool) { +pub(crate) fn create_foreign_on_ah_rococo(id: v4::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, + id: v4::Location, sufficient: bool, prefund_accounts: Vec<(AccountId, u128)>, ) { @@ -87,13 +84,13 @@ pub(crate) fn create_foreign_on_ah_westend( 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 { +pub(crate) fn foreign_balance_on_ah_rococo(id: v4::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 { +pub(crate) fn foreign_balance_on_ah_westend(id: v4::Location, who: &AccountId) -> u128 { AssetHubWestend::execute_with(|| { type Assets = ::ForeignAssets; >::balance(id, who) @@ -101,8 +98,8 @@ pub(crate) fn foreign_balance_on_ah_westend(id: v3::Location, who: &AccountId) - } // 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(); +pub(crate) fn set_up_pool_with_roc_on_ah_rococo(asset: v4::Location, is_foreign: bool) { + let roc: v4::Location = v4::Parent.into(); AssetHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; let owner = AssetHubRococoSender::get(); @@ -111,13 +108,13 @@ pub(crate) fn set_up_pool_with_roc_on_ah_rococo(asset: v3::Location, is_foreign: if is_foreign { assert_ok!(::ForeignAssets::mint( signed_owner.clone(), - asset.into(), + asset.clone().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, + let asset_id = match asset.interior.last() { + Some(v4::Junction::GeneralIndex(id)) => *id as u32, _ => unreachable!(), }; assert_ok!(::Assets::mint( @@ -129,8 +126,8 @@ pub(crate) fn set_up_pool_with_roc_on_ah_rococo(asset: v3::Location, is_foreign: } assert_ok!(::AssetConversion::create_pool( signed_owner.clone(), - Box::new(roc), - Box::new(asset), + Box::new(roc.clone()), + Box::new(asset.clone()), )); assert_expected_events!( AssetHubRococo, diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge.rs new file mode 100644 index 0000000000000000000000000000000000000000..b4db9b365f390c820b83ca069912a5fa09e2a069 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge.rs @@ -0,0 +1,307 @@ +// 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::imports::*; +use asset_hub_westend_runtime::xcm_config::bridging::to_ethereum::DefaultBridgeHubEthereumBaseFee; +use bridge_hub_westend_runtime::EthereumInboundQueue; +use codec::{Decode, Encode}; +use frame_support::pallet_prelude::TypeInfo; +use hex_literal::hex; +use snowbridge_core::outbound::OperatingMode; +use snowbridge_router_primitives::inbound::{ + Command, ConvertMessage, Destination, MessageV1, VersionedMessage, +}; +use testnet_parachains_constants::westend::snowbridge::EthereumNetwork; + +const INITIAL_FUND: u128 = 5_000_000_000_000_000_000; +pub const CHAIN_ID: u64 = 11155111; +pub const WETH: [u8; 20] = hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d"); +const ETHEREUM_DESTINATION_ADDRESS: [u8; 20] = hex!("44a57ee2f2FCcb85FDa2B0B18EBD0D8D2333700e"); +const XCM_FEE: u128 = 100_000_000_000; +const WETH_AMOUNT: u128 = 1_000_000_000; + +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +pub enum ControlCall { + #[codec(index = 3)] + CreateAgent, + #[codec(index = 4)] + CreateChannel { mode: OperatingMode }, +} + +#[allow(clippy::large_enum_variant)] +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +pub enum SnowbridgeControl { + #[codec(index = 83)] + Control(ControlCall), +} + +/// Tests the registering of a token as an asset on AssetHub. +#[test] +fn register_weth_token_from_ethereum_to_asset_hub() { + // Fund AssetHub sovereign account so that it can pay execution fees. + BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id().into(), INITIAL_FUND); + + BridgeHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + type Converter = ::MessageConverter; + + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::RegisterToken { token: WETH.into(), fee: XCM_FEE }, + }); + let (xcm, _) = Converter::convert(message).unwrap(); + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubRococo::para_id().into()).unwrap(); + + assert_expected_events!( + BridgeHubWestend, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); + }); + + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + AssetHubWestend, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Created { .. }) => {}, + ] + ); + }); +} + +/// Tests the registering of a token as an asset on AssetHub, and then subsequently sending +/// a token from Ethereum to AssetHub. +#[test] +fn send_token_from_ethereum_to_asset_hub() { + let asset_hub_sovereign = BridgeHubWestend::sovereign_account_id_of(Location::new( + 1, + [Parachain(AssetHubWestend::para_id().into())], + )); + // Fund AssetHub sovereign account so it can pay execution fees for the asset transfer + BridgeHubWestend::fund_accounts(vec![(asset_hub_sovereign.clone(), INITIAL_FUND)]); + + // Fund ethereum sovereign on AssetHub + AssetHubWestend::fund_accounts(vec![(AssetHubWestendReceiver::get(), INITIAL_FUND)]); + + let weth_asset_location: Location = + (Parent, Parent, EthereumNetwork::get(), AccountKey20 { network: None, key: WETH }).into(); + + AssetHubWestend::execute_with(|| { + type RuntimeOrigin = ::RuntimeOrigin; + + assert_ok!(::ForeignAssets::force_create( + RuntimeOrigin::root(), + weth_asset_location.clone().try_into().unwrap(), + asset_hub_sovereign.into(), + false, + 1, + )); + + assert!(::ForeignAssets::asset_exists( + weth_asset_location.clone().try_into().unwrap(), + )); + }); + + BridgeHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + type Converter = ::MessageConverter; + + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::SendToken { + token: WETH.into(), + destination: Destination::AccountId32 { id: AssetHubWestendReceiver::get().into() }, + amount: WETH_AMOUNT, + fee: XCM_FEE, + }, + }); + let (xcm, _) = Converter::convert(message).unwrap(); + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubWestend::para_id().into()).unwrap(); + + // Check that the message was sent + assert_expected_events!( + BridgeHubWestend, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); + }); + + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Check that the token was received and issued as a foreign asset on AssetHub + assert_expected_events!( + AssetHubWestend, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, + ] + ); + }); +} + +/// Tests the full cycle of token transfers: +/// - registering a token on AssetHub +/// - sending a token to AssetHub +/// - returning the token to Ethereum +#[test] +fn send_weth_asset_from_asset_hub_to_ethereum() { + let assethub_location = BridgeHubWestend::sibling_location_of(AssetHubWestend::para_id()); + let assethub_sovereign = BridgeHubWestend::sovereign_account_id_of(assethub_location); + let weth_asset_location: Location = + (Parent, Parent, EthereumNetwork::get(), AccountKey20 { network: None, key: WETH }).into(); + + AssetHubWestend::force_default_xcm_version(Some(XCM_VERSION)); + BridgeHubWestend::force_default_xcm_version(Some(XCM_VERSION)); + AssetHubWestend::force_xcm_version( + Location::new(2, [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })]), + XCM_VERSION, + ); + + BridgeHubWestend::fund_accounts(vec![(assethub_sovereign.clone(), INITIAL_FUND)]); + + AssetHubWestend::execute_with(|| { + type RuntimeOrigin = ::RuntimeOrigin; + + assert_ok!(::ForeignAssets::force_create( + RuntimeOrigin::root(), + weth_asset_location.clone().try_into().unwrap(), + assethub_sovereign.clone().into(), + false, + 1, + )); + + assert!(::ForeignAssets::asset_exists( + weth_asset_location.clone().try_into().unwrap(), + )); + }); + + BridgeHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type Converter = ::MessageConverter; + + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::SendToken { + token: WETH.into(), + destination: Destination::AccountId32 { id: AssetHubWestendReceiver::get().into() }, + amount: WETH_AMOUNT, + fee: XCM_FEE, + }, + }); + let (xcm, _) = Converter::convert(message).unwrap(); + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubWestend::para_id().into()).unwrap(); + + // Check that the send token message was sent using xcm + assert_expected_events!( + BridgeHubWestend, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) =>{},] + ); + }); + + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type RuntimeOrigin = ::RuntimeOrigin; + + // Check that AssetHub has issued the foreign asset + assert_expected_events!( + AssetHubWestend, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, + ] + ); + let assets = vec![Asset { + id: AssetId(Location::new( + 2, + [ + GlobalConsensus(Ethereum { chain_id: CHAIN_ID }), + AccountKey20 { network: None, key: WETH }, + ], + )), + fun: Fungible(WETH_AMOUNT), + }]; + let multi_assets = VersionedAssets::V4(Assets::from(assets)); + + let destination = VersionedLocation::V4(Location::new( + 2, + [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })], + )); + + let beneficiary = VersionedLocation::V4(Location::new( + 0, + [AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS.into() }], + )); + + let free_balance_before = + ::Balances::free_balance( + AssetHubWestendReceiver::get(), + ); + // Send the Weth back to Ethereum + ::PolkadotXcm::limited_reserve_transfer_assets( + RuntimeOrigin::signed(AssetHubWestendReceiver::get()), + Box::new(destination), + Box::new(beneficiary), + Box::new(multi_assets), + 0, + Unlimited, + ) + .unwrap(); + let free_balance_after = ::Balances::free_balance( + AssetHubWestendReceiver::get(), + ); + // Assert at least DefaultBridgeHubEthereumBaseFee charged from the sender + let free_balance_diff = free_balance_before - free_balance_after; + assert!(free_balance_diff > DefaultBridgeHubEthereumBaseFee::get()); + }); + + BridgeHubWestend::execute_with(|| { + use bridge_hub_westend_runtime::xcm_config::TreasuryAccount; + type RuntimeEvent = ::RuntimeEvent; + // Check that the transfer token back to Ethereum message was queue in the Ethereum + // Outbound Queue + assert_expected_events!( + BridgeHubWestend, + vec![ + + RuntimeEvent::EthereumOutboundQueue(snowbridge_pallet_outbound_queue::Event::MessageQueued + {..}) => {}, ] + ); + let events = BridgeHubWestend::events(); + // Check that the local fee was credited to the Snowbridge sovereign account + assert!( + events.iter().any(|event| matches!( + event, + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) + if *who == TreasuryAccount::get().into() && *amount == 5071000000 + )), + "Snowbridge sovereign takes local fee." + ); + // Check that the remote fee was credited to the AssetHub sovereign account + assert!( + events.iter().any(|event| matches!( + event, + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) + if *who == assethub_sovereign && *amount == 2680000000000, + )), + "AssetHub sovereign takes remote fee." + ); + }); +} 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 64378a844f52a7cd14fecd2808fd1b5051d62528..a5add3b82957cf83a3d49dc04e32ace90e9bf099 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 @@ -27,3 +27,23 @@ fn teleport_to_other_system_parachains_works() { (native_asset, amount) ); } + +#[test] +fn teleport_from_and_to_relay() { + let amount = WESTEND_ED * 100; + let native_asset: Assets = (Here, amount).into(); + + test_relay_is_trusted_teleporter!( + Westend, + WestendXcmConfig, + vec![BridgeHubWestend], + (native_asset, amount) + ); + + test_parachain_is_trusted_teleporter_for_relay!( + BridgeHubWestend, + BridgeHubWestendXcmConfig, + Westend, + 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 3012e2b19f5326f9df8e61521a82afeaaaa73fae..c4d281b75a77b32a9772ade66e2dbb0837cc8fcf 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 @@ -23,6 +23,7 @@ pallet-assets = { workspace = true } pallet-treasury = { workspace = true } pallet-message-queue = { workspace = true } pallet-utility = { workspace = true } +pallet-whitelist = { workspace = true } # Polkadot polkadot-runtime-common = { workspace = true, default-features = 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 8af93a62f4a17e7f134b9d2f3d53ef7e267370de..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,24 +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::{ - asset_hub_westend_runtime::xcm_config::LocationToAccountId as AssetHubLocationToAccountId, + 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, + collectives_westend_runtime::{ + fellowship as collectives_fellowship, + xcm_config::XcmConfig as CollectivesWestendXcmConfig, + }, + genesis::ED as COLLECTIVES_WESTEND_ED, CollectivesWestendParaPallet as CollectivesWestendPallet, }, westend_emulated_chain::{ - westend_runtime::{governance as westend_governance, OriginCaller as WestendOriginCaller}, + 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, CollectivesWestendPara as CollectivesWestend, - WestendRelay as Westend, + 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.rs b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship.rs new file mode 100644 index 0000000000000000000000000000000000000000..f97599bda7f08be29d3388cd4a0856db77a30858 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship.rs @@ -0,0 +1,72 @@ +// 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 codec::Encode; +use collectives_fellowship::pallet_fellowship_origins::Origin::Fellows as FellowsOrigin; +use frame_support::{assert_ok, sp_runtime::traits::Dispatchable}; + +#[test] +fn fellows_whitelist_call() { + CollectivesWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type RuntimeCall = ::RuntimeCall; + type RuntimeOrigin = ::RuntimeOrigin; + type Runtime = ::Runtime; + type WestendCall = ::RuntimeCall; + type WestendRuntime = ::Runtime; + + let call_hash = [1u8; 32].into(); + + let whitelist_call = RuntimeCall::PolkadotXcm(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::parent())), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::Xcm, + require_weight_at_most: Weight::from_parts(5_000_000_000, 500_000), + call: WestendCall::Whitelist( + pallet_whitelist::Call::::whitelist_call { call_hash } + ) + .encode() + .into(), + } + ]))), + }); + + let fellows_origin: RuntimeOrigin = FellowsOrigin.into(); + + assert_ok!(whitelist_call.dispatch(fellows_origin)); + + assert_expected_events!( + CollectivesWestend, + vec![ + RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + Westend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + Westend, + vec![ + RuntimeEvent::Whitelist(pallet_whitelist::Event::CallWhitelisted { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, + ] + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship_salary.rs b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship_salary.rs new file mode 100644 index 0000000000000000000000000000000000000000..840d2da4946306498605853366daf46fb145ca78 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship_salary.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 collectives_fellowship::FellowshipSalaryPaymaster; +use frame_support::{ + assert_ok, + traits::{fungibles::Mutate, tokens::Pay}, +}; +use xcm_executor::traits::ConvertLocation; + +const FELLOWSHIP_SALARY_PALLET_ID: u8 = 64; + +#[test] +fn pay_salary() { + let asset_id: u32 = 1984; + let fellowship_salary = ( + Parent, + Parachain(CollectivesWestend::para_id().into()), + PalletInstance(FELLOWSHIP_SALARY_PALLET_ID), + ); + let pay_from = + AssetHubLocationToAccountId::convert_location(&fellowship_salary.into()).unwrap(); + let pay_to = Westend::account_id_of(ALICE); + let pay_amount = 9_000_000_000; + + AssetHubWestend::execute_with(|| { + type AssetHubAssets = ::Assets; + assert_ok!(>::mint_into(asset_id, &pay_from, pay_amount * 2)); + }); + + CollectivesWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_ok!(FellowshipSalaryPaymaster::pay(&pay_to, (), pay_amount)); + assert_expected_events!( + CollectivesWestend, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); + }); + + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + AssetHubWestend, + vec![ + RuntimeEvent::Assets(pallet_assets::Event::Transferred { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {}, + ] + ); + }); +} 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 abd9a982c8ed5e5407776d3bb6d84686009f59f4..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,7 +14,6 @@ // limitations under the License. use crate::*; -use emulated_integration_tests_common::accounts::ALICE; use frame_support::{ assert_ok, dispatch::RawOrigin, instances::Instance1, sp_runtime::traits::Dispatchable, traits::fungible::Inspect, 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..ef4e4885183d092c087329b8ebc414afa105a500 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 @@ -13,4 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +mod fellowship; +mod fellowship_salary; 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/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/lib.rs index 6c23c2f1f292e9f8235b1f862e2ac934877609d8..06b0b6ba600534793b83f24e6e8d9b9d730736bd 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 @@ -15,15 +15,8 @@ #[cfg(test)] mod imports { - pub use codec::Encode; - // Substrate - pub use frame_support::{ - assert_ok, - pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchResult}, - traits::fungibles::Inspect, - }; + pub use frame_support::{assert_ok, sp_runtime::DispatchResult, traits::fungibles::Inspect}; // Polkadot pub use xcm::prelude::*; @@ -37,17 +30,14 @@ mod imports { pub use parachains_common::Balance; pub use rococo_system_emulated_network::{ people_rococo_emulated_chain::{ - genesis::ED as PEOPLE_ROCOCO_ED, - people_rococo_runtime::{people, xcm_config::XcmConfig as PeopleRococoXcmConfig}, + people_rococo_runtime::{ + xcm_config::XcmConfig as PeopleRococoXcmConfig, + ExistentialDeposit as PeopleRococoExistentialDeposit, + }, PeopleRococoParaPallet as PeopleRococoPallet, }, rococo_emulated_chain::{ - genesis::ED as ROCOCO_ED, - rococo_runtime::{ - xcm_config::XcmConfig as RococoXcmConfig, BasicDeposit, ByteDeposit, - MaxAdditionalFields, MaxSubAccounts, RuntimeOrigin as RococoOrigin, - SubAccountDeposit, - }, + genesis::ED as ROCOCO_ED, rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig, RococoRelayPallet as RococoPallet, }, PeopleRococoPara as PeopleRococo, PeopleRococoParaReceiver as PeopleRococoReceiver, @@ -55,7 +45,6 @@ mod imports { RococoRelayReceiver as RococoReceiver, RococoRelaySender as RococoSender, }; - pub type RelayToSystemParaTest = Test; pub type SystemParaToRelayTest = Test; } 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..08749b295dc21def8feb2c2318bcbed2b258ba9e 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,5 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod reap_identity; +mod claim_assets; 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 deleted file mode 100644 index 342a8f053f6076cdb62a7ff2dc6dfccd98c3b7bc..0000000000000000000000000000000000000000 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/reap_identity.rs +++ /dev/null @@ -1,545 +0,0 @@ -// 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. - -//! # OnReapIdentity Tests -//! -//! This file contains the test cases for migrating Identity data away from the Rococo Relay -//! chain and to the PeopleRococo parachain. This migration is part of the broader Minimal Relay -//! effort: -//! https://github.com/polkadot-fellows/RFCs/blob/main/text/0032-minimal-relay.md -//! -//! ## Overview -//! -//! The tests validate the robustness and correctness of the `OnReapIdentityHandler` -//! ensuring that it behaves as expected in various scenarios. Key aspects tested include: -//! -//! - **Deposit Handling**: Confirming that deposits are correctly migrated from the Relay Chain to -//! the People parachain in various scenarios (different `IdentityInfo` fields and different -//! numbers of sub-accounts). -//! -//! ### Test Scenarios -//! -//! The tests are categorized into several scenarios, each resulting in different deposits required -//! on the destination parachain. The tests ensure: -//! -//! - Reserved deposits on the Relay Chain are fully released; -//! - The freed deposit from the Relay Chain is sufficient for the parachain deposit; and -//! - The account will exist on the parachain. - -use crate::imports::*; -use frame_support::BoundedVec; -use pallet_balances::Event as BalancesEvent; -use pallet_identity::{legacy::IdentityInfo, Data, Event as IdentityEvent}; -use people::{ - BasicDeposit as BasicDepositParachain, ByteDeposit as ByteDepositParachain, - IdentityInfo as IdentityInfoParachain, SubAccountDeposit as SubAccountDepositParachain, -}; -use rococo_runtime_constants::currency::*; -use rococo_system_emulated_network::{ - rococo_emulated_chain::RococoRelayPallet, RococoRelay, RococoRelaySender, -}; - -type Balance = u128; -type RococoIdentity = ::Identity; -type RococoBalances = ::Balances; -type RococoIdentityMigrator = ::IdentityMigrator; -type PeopleRococoIdentity = ::Identity; -type PeopleRococoBalances = ::Balances; - -#[derive(Clone, Debug)] -struct Identity { - relay: IdentityInfo, - para: IdentityInfoParachain, - subs: Subs, -} - -impl Identity { - fn new( - full: bool, - additional: Option>, - subs: Subs, - ) -> Self { - let pgp_fingerprint = [ - 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, - 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, - ]; - let make_data = |data: &[u8], full: bool| -> Data { - if full { - Data::Raw(data.to_vec().try_into().unwrap()) - } else { - Data::None - } - }; - let (github, discord) = additional - .as_ref() - .and_then(|vec| vec.first()) - .map(|(g, d)| (g.clone(), d.clone())) - .unwrap_or((Data::None, Data::None)); - Self { - relay: IdentityInfo { - display: make_data(b"xcm-test", full), - legal: make_data(b"The Xcm Test, Esq.", full), - web: make_data(b"https://visitme/", full), - riot: make_data(b"xcm-riot", full), - email: make_data(b"xcm-test@gmail.com", full), - pgp_fingerprint: Some(pgp_fingerprint), - image: make_data(b"xcm-test.png", full), - twitter: make_data(b"@xcm-test", full), - additional: additional.unwrap_or_default(), - }, - para: IdentityInfoParachain { - display: make_data(b"xcm-test", full), - legal: make_data(b"The Xcm Test, Esq.", full), - web: make_data(b"https://visitme/", full), - matrix: make_data(b"xcm-matrix@server", full), - email: make_data(b"xcm-test@gmail.com", full), - pgp_fingerprint: Some(pgp_fingerprint), - image: make_data(b"xcm-test.png", full), - twitter: make_data(b"@xcm-test", full), - github, - discord, - }, - subs, - } - } -} - -#[derive(Clone, Debug)] -enum Subs { - Zero, - Many(u32), -} - -enum IdentityOn<'a> { - Relay(&'a IdentityInfo), - Para(&'a IdentityInfoParachain), -} - -impl IdentityOn<'_> { - fn calculate_deposit(self) -> Balance { - match self { - IdentityOn::Relay(id) => { - let base_deposit = BasicDeposit::get(); - let byte_deposit = - ByteDeposit::get() * TryInto::::try_into(id.encoded_size()).unwrap(); - base_deposit + byte_deposit - }, - IdentityOn::Para(id) => { - let base_deposit = BasicDepositParachain::get(); - let byte_deposit = ByteDepositParachain::get() * - TryInto::::try_into(id.encoded_size()).unwrap(); - base_deposit + byte_deposit - }, - } - } -} - -/// Generate an `AccountId32` from a `u32`. -/// This creates a 32-byte array, initially filled with `255`, and then repeatedly fills it -/// with the 4-byte little-endian representation of the `u32` value, until the array is full. -/// -/// **Example**: -/// -/// `account_from_u32(5)` will return an `AccountId32` with the bytes -/// `[0, 5, 0, 0, 0, 0, 0, 0, 0, 5 ... ]` -fn account_from_u32(id: u32) -> AccountId32 { - let mut buffer = [255u8; 32]; - let id_bytes = id.to_le_bytes(); - let id_size = id_bytes.len(); - for chunk in buffer.chunks_mut(id_size) { - chunk.clone_from_slice(&id_bytes); - } - AccountId32::new(buffer) -} - -// Set up the Relay Chain with an identity. -fn set_id_relay(id: &Identity) -> Balance { - let mut total_deposit: Balance = 0; - - // Set identity and Subs on Relay Chain - RococoRelay::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_ok!(RococoIdentity::set_identity( - RococoOrigin::signed(RococoRelaySender::get()), - Box::new(id.relay.clone()) - )); - - if let Subs::Many(n) = id.subs { - let subs: Vec<_> = (0..n) - .map(|i| (account_from_u32(i), Data::Raw(b"name".to_vec().try_into().unwrap()))) - .collect(); - - assert_ok!(RococoIdentity::set_subs( - RococoOrigin::signed(RococoRelaySender::get()), - subs, - )); - } - - let reserved_balance = RococoBalances::reserved_balance(RococoRelaySender::get()); - let id_deposit = IdentityOn::Relay(&id.relay).calculate_deposit(); - - let total_deposit = match id.subs { - Subs::Zero => { - total_deposit = id_deposit; // No subs - assert_expected_events!( - RococoRelay, - vec![ - RuntimeEvent::Identity(IdentityEvent::IdentitySet { .. }) => {}, - RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => { - who: *who == RococoRelaySender::get(), - amount: *amount == id_deposit, - }, - ] - ); - total_deposit - }, - Subs::Many(n) => { - let sub_account_deposit = n as Balance * SubAccountDeposit::get(); - total_deposit = - sub_account_deposit + IdentityOn::Relay(&id.relay).calculate_deposit(); - assert_expected_events!( - RococoRelay, - vec![ - RuntimeEvent::Identity(IdentityEvent::IdentitySet { .. }) => {}, - RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => { - who: *who == RococoRelaySender::get(), - amount: *amount == id_deposit, - }, - RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => { - who: *who == RococoRelaySender::get(), - amount: *amount == sub_account_deposit, - }, - ] - ); - total_deposit - }, - }; - - assert_eq!(reserved_balance, total_deposit); - }); - total_deposit -} - -// Set up the parachain with an identity and (maybe) sub accounts, but with zero deposits. -fn assert_set_id_parachain(id: &Identity) { - // Set identity and Subs on Parachain with zero deposit - PeopleRococo::execute_with(|| { - let free_bal = PeopleRococoBalances::free_balance(PeopleRococoSender::get()); - let reserved_balance = PeopleRococoBalances::reserved_balance(PeopleRococoSender::get()); - - // total balance at Genesis should be zero - assert_eq!(reserved_balance + free_bal, 0); - - assert_ok!(PeopleRococoIdentity::set_identity_no_deposit( - &PeopleRococoSender::get(), - id.para.clone(), - )); - - match id.subs { - Subs::Zero => {}, - Subs::Many(n) => { - let subs: Vec<_> = (0..n) - .map(|ii| { - (account_from_u32(ii), Data::Raw(b"name".to_vec().try_into().unwrap())) - }) - .collect(); - assert_ok!(PeopleRococoIdentity::set_subs_no_deposit( - &PeopleRococoSender::get(), - subs, - )); - }, - } - - // 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()); - - let (_, sub_accounts) = PeopleRococoIdentity::subs_of(PeopleRococoSender::get()); - - match id.subs { - Subs::Zero => assert_eq!(sub_accounts.len(), 0), - Subs::Many(n) => assert_eq!(sub_accounts.len(), n as usize), - } - }); -} - -// Reap the identity on the Relay Chain and assert that the correct things happen there. -fn assert_reap_id_relay(total_deposit: Balance, id: &Identity) { - RococoRelay::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - let free_bal_before_reap = RococoBalances::free_balance(RococoRelaySender::get()); - let reserved_balance = RococoBalances::reserved_balance(RococoRelaySender::get()); - - assert_eq!(reserved_balance, total_deposit); - - assert_ok!(RococoIdentityMigrator::reap_identity( - RococoOrigin::signed(RococoRelaySender::get()), - RococoRelaySender::get() - )); - - let remote_deposit = match id.subs { - Subs::Zero => calculate_remote_deposit(id.relay.encoded_size() as u32, 0), - Subs::Many(n) => calculate_remote_deposit(id.relay.encoded_size() as u32, n), - }; - - assert_expected_events!( - RococoRelay, - vec![ - // `reap_identity` sums the identity and subs deposits and unreserves them in one - // call. Therefore, we only expect one `Unreserved` event. - RuntimeEvent::Balances(BalancesEvent::Unreserved { who, amount }) => { - who: *who == RococoRelaySender::get(), - amount: *amount == total_deposit, - }, - RuntimeEvent::IdentityMigrator( - polkadot_runtime_common::identity_migrator::Event::IdentityReaped { - who, - }) => { - who: *who == PeopleRococoSender::get(), - }, - ] - ); - // Identity should be gone. - assert!(PeopleRococoIdentity::identity(RococoRelaySender::get()).is_none()); - - // Subs should be gone. - let (_, sub_accounts) = RococoIdentity::subs_of(RococoRelaySender::get()); - assert_eq!(sub_accounts.len(), 0); - - let reserved_balance = RococoBalances::reserved_balance(RococoRelaySender::get()); - assert_eq!(reserved_balance, 0); - - // Free balance should be greater (i.e. the teleport should work even if 100% of an - // account's balance is reserved for Identity). - let free_bal_after_reap = RococoBalances::free_balance(RococoRelaySender::get()); - assert!(free_bal_after_reap > free_bal_before_reap); - - // Implicit: total_deposit > remote_deposit. As in, accounts should always have enough - // reserved for the parachain deposit. - assert_eq!(free_bal_after_reap, free_bal_before_reap + total_deposit - remote_deposit); - }); -} - -// Reaping the identity on the Relay Chain will have sent an XCM program to the parachain. Ensure -// that everything happens as expected. -fn assert_reap_parachain(id: &Identity) { - PeopleRococo::execute_with(|| { - let reserved_balance = PeopleRococoBalances::reserved_balance(PeopleRococoSender::get()); - let id_deposit = IdentityOn::Para(&id.para).calculate_deposit(); - let total_deposit = match id.subs { - Subs::Zero => id_deposit, - Subs::Many(n) => id_deposit + n as Balance * SubAccountDepositParachain::get(), - }; - assert_reap_events(id_deposit, id); - assert_eq!(reserved_balance, total_deposit); - - // Should have at least one ED after in free balance after the reap. - assert!(PeopleRococoBalances::free_balance(PeopleRococoSender::get()) >= PEOPLE_ROCOCO_ED); - }); -} - -// Assert the events that should happen on the parachain upon reaping an identity on the Relay -// Chain. -fn assert_reap_events(id_deposit: Balance, id: &Identity) { - type RuntimeEvent = ::RuntimeEvent; - match id.subs { - Subs::Zero => { - assert_expected_events!( - PeopleRococo, - vec![ - // Deposit and Endowed from teleport - RuntimeEvent::Balances(BalancesEvent::Minted { .. }) => {}, - RuntimeEvent::Balances(BalancesEvent::Endowed { .. }) => {}, - // Amount reserved for identity info - RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => { - who: *who == PeopleRococoSender::get(), - amount: *amount == id_deposit, - }, - // Confirmation from Migrator with individual identity and subs deposits - RuntimeEvent::IdentityMigrator( - polkadot_runtime_common::identity_migrator::Event::DepositUpdated { - who, identity, subs - }) => { - who: *who == PeopleRococoSender::get(), - identity: *identity == id_deposit, - subs: *subs == 0, - }, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { .. }) => {}, - ] - ); - }, - Subs::Many(n) => { - let subs_deposit = n as Balance * SubAccountDepositParachain::get(); - assert_expected_events!( - PeopleRococo, - vec![ - // Deposit and Endowed from teleport - RuntimeEvent::Balances(BalancesEvent::Minted { .. }) => {}, - RuntimeEvent::Balances(BalancesEvent::Endowed { .. }) => {}, - // Amount reserved for identity info - RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => { - who: *who == PeopleRococoSender::get(), - amount: *amount == id_deposit, - }, - // Amount reserved for subs - RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => { - who: *who == PeopleRococoSender::get(), - amount: *amount == subs_deposit, - }, - // Confirmation from Migrator with individual identity and subs deposits - RuntimeEvent::IdentityMigrator( - polkadot_runtime_common::identity_migrator::Event::DepositUpdated { - who, identity, subs - }) => { - who: *who == PeopleRococoSender::get(), - identity: *identity == id_deposit, - subs: *subs == subs_deposit, - }, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { .. }) => {}, - ] - ); - }, - }; -} - -/// Duplicate of the impl of `ToParachainIdentityReaper` in the Rococo runtime. -fn calculate_remote_deposit(bytes: u32, subs: u32) -> Balance { - // Note: These `deposit` functions and `EXISTENTIAL_DEPOSIT` correspond to the Relay Chain's. - // Pulled in: use rococo_runtime_constants::currency::*; - let para_basic_deposit = deposit(1, 17) / 100; - let para_byte_deposit = deposit(0, 1) / 100; - let para_sub_account_deposit = deposit(1, 53) / 100; - let para_existential_deposit = EXISTENTIAL_DEPOSIT / 10; - - // pallet deposits - let id_deposit = - para_basic_deposit.saturating_add(para_byte_deposit.saturating_mul(bytes as Balance)); - let subs_deposit = para_sub_account_deposit.saturating_mul(subs as Balance); - - id_deposit - .saturating_add(subs_deposit) - .saturating_add(para_existential_deposit.saturating_mul(2)) -} - -// Represent some `additional` data that would not be migrated to the parachain. The encoded size, -// and thus the byte deposit, should decrease. -fn nonsensical_additional() -> BoundedVec<(Data, Data), MaxAdditionalFields> { - BoundedVec::try_from(vec![( - Data::Raw(b"fOo".to_vec().try_into().unwrap()), - Data::Raw(b"baR".to_vec().try_into().unwrap()), - )]) - .unwrap() -} - -// Represent some `additional` data that will be migrated to the parachain as first-class fields. -fn meaningful_additional() -> BoundedVec<(Data, Data), MaxAdditionalFields> { - BoundedVec::try_from(vec![ - ( - Data::Raw(b"github".to_vec().try_into().unwrap()), - Data::Raw(b"niels-username".to_vec().try_into().unwrap()), - ), - ( - Data::Raw(b"discord".to_vec().try_into().unwrap()), - Data::Raw(b"bohr-username".to_vec().try_into().unwrap()), - ), - ]) - .unwrap() -} - -// Execute a single test case. -fn assert_relay_para_flow(id: &Identity) { - let total_deposit = set_id_relay(id); - assert_set_id_parachain(id); - assert_reap_id_relay(total_deposit, id); - assert_reap_parachain(id); -} - -// Tests with empty `IdentityInfo`. - -#[test] -fn on_reap_identity_works_for_minimal_identity_with_zero_subs() { - assert_relay_para_flow(&Identity::new(false, None, Subs::Zero)); -} - -#[test] -fn on_reap_identity_works_for_minimal_identity() { - assert_relay_para_flow(&Identity::new(false, None, Subs::Many(1))); -} - -#[test] -fn on_reap_identity_works_for_minimal_identity_with_max_subs() { - assert_relay_para_flow(&Identity::new(false, None, Subs::Many(MaxSubAccounts::get()))); -} - -// Tests with full `IdentityInfo`. - -#[test] -fn on_reap_identity_works_for_full_identity_no_additional_zero_subs() { - assert_relay_para_flow(&Identity::new(true, None, Subs::Zero)); -} - -#[test] -fn on_reap_identity_works_for_full_identity_no_additional() { - assert_relay_para_flow(&Identity::new(true, None, Subs::Many(1))); -} - -#[test] -fn on_reap_identity_works_for_full_identity_no_additional_max_subs() { - assert_relay_para_flow(&Identity::new(true, None, Subs::Many(MaxSubAccounts::get()))); -} - -// Tests with full `IdentityInfo` and `additional` fields that will _not_ be migrated. - -#[test] -fn on_reap_identity_works_for_full_identity_nonsense_additional_zero_subs() { - assert_relay_para_flow(&Identity::new(true, Some(nonsensical_additional()), Subs::Zero)); -} - -#[test] -fn on_reap_identity_works_for_full_identity_nonsense_additional() { - assert_relay_para_flow(&Identity::new(true, Some(nonsensical_additional()), Subs::Many(1))); -} - -#[test] -fn on_reap_identity_works_for_full_identity_nonsense_additional_max_subs() { - assert_relay_para_flow(&Identity::new( - true, - Some(nonsensical_additional()), - Subs::Many(MaxSubAccounts::get()), - )); -} - -// Tests with full `IdentityInfo` and `additional` fields that will be migrated. - -#[test] -fn on_reap_identity_works_for_full_identity_meaningful_additional_zero_subs() { - assert_relay_para_flow(&Identity::new(true, Some(meaningful_additional()), Subs::Zero)); -} - -#[test] -fn on_reap_identity_works_for_full_identity_meaningful_additional() { - assert_relay_para_flow(&Identity::new(true, Some(meaningful_additional()), Subs::Many(1))); -} - -#[test] -fn on_reap_identity_works_for_full_identity_meaningful_additional_max_subs() { - assert_relay_para_flow(&Identity::new( - true, - Some(meaningful_additional()), - Subs::Many(MaxSubAccounts::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 4410d1bd40dcc1276bb5441962f855823861d1cd..44e6b3934f0e7999d15e78d0393aed129ada2455 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,68 +14,38 @@ // limitations under the License. use crate::imports::*; +use emulated_integration_tests_common::{ + test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, +}; -fn relay_origin_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - Rococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(627_959_000, 7_200))); +#[test] +fn teleport_from_and_to_relay() { + let amount = ROCOCO_ED * 100; + let native_asset: Assets = (Here, amount).into(); - assert_expected_events!( + test_relay_is_trusted_teleporter!( Rococo, - vec![ - // Amount to teleport is withdrawn from Sender - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, - }, - // Amount to teleport is deposited in Relay's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) => { - who: *who == ::XcmPallet::check_account(), - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn relay_dest_assertions(t: SystemParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - - Rococo::assert_ump_queue_processed( - true, - Some(PeopleRococo::para_id()), - Some(Weight::from_parts(304_266_000, 7_186)), + RococoXcmConfig, + vec![PeopleRococo], + (native_asset, amount) ); - assert_expected_events!( + test_parachain_is_trusted_teleporter_for_relay!( + PeopleRococo, + PeopleRococoXcmConfig, Rococo, - vec![ - // Amount is withdrawn from Relay Chain's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == ::XcmPallet::check_account(), - amount: *amount == t.args.amount, - }, - // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, - }, - ] + amount ); } fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) { - Rococo::assert_ump_queue_processed( - false, - Some(PeopleRococo::para_id()), - Some(Weight::from_parts(157_718_000, 3_593)), - ); + Rococo::assert_ump_queue_processed(false, Some(PeopleRococo::para_id()), None); } fn para_origin_assertions(t: SystemParaToRelayTest) { type RuntimeEvent = ::RuntimeEvent; - PeopleRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 600_000_000, - 7_000, - ))); + PeopleRococo::assert_xcm_pallet_attempted_complete(None); PeopleRococo::assert_parachain_system_ump_sent(); @@ -91,33 +61,6 @@ fn para_origin_assertions(t: SystemParaToRelayTest) { ); } -fn para_dest_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - PeopleRococo::assert_dmp_queue_complete(Some(Weight::from_parts(162_456_000, 0))); - - assert_expected_events!( - PeopleRococo, - vec![ - // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, - }, - ] - ); -} - -fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::limited_teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { ::PolkadotXcm::limited_teleport_assets( t.signed_origin, @@ -129,92 +72,8 @@ fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResu ) } -/// Limited Teleport of native asset from Relay Chain to the System Parachain should work -#[test] -fn limited_teleport_native_assets_from_relay_to_system_para_works() { - // Init values for Relay Chain - let amount_to_send: Balance = ROCOCO_ED * 1000; - let dest = Rococo::child_location_of(PeopleRococo::para_id()); - let beneficiary_id = PeopleRococoReceiver::get(); - let test_args = TestContext { - sender: RococoSender::get(), - receiver: PeopleRococoReceiver::get(), - args: TestArgs::new_relay(dest, beneficiary_id, amount_to_send), - }; - - let mut test = RelayToSystemParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(para_dest_assertions); - test.set_dispatchable::(relay_limited_teleport_assets); - test.assert(); - - let delivery_fees = Rococo::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - -/// Limited Teleport of native asset from System Parachain to Relay Chain -/// should work when there is enough balance in Relay Chain's `CheckAccount` -#[test] -fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { - // Dependency - Relay Chain's `CheckAccount` should have enough balance - limited_teleport_native_assets_from_relay_to_system_para_works(); - - let amount_to_send: Balance = PEOPLE_ROCOCO_ED * 1000; - let destination = PeopleRococo::parent_location(); - let beneficiary_id = RococoReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - // Fund a sender - PeopleRococo::fund_accounts(vec![(PeopleRococoSender::get(), ROCOCO_ED * 2_000u128)]); - - let test_args = TestContext { - sender: PeopleRococoSender::get(), - receiver: RococoReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions); - test.set_dispatchable::(system_para_limited_teleport_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = PeopleRococo::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - /// Limited Teleport of native asset from System Parachain to Relay Chain -/// should't work when there is not enough balance in Relay Chain's `CheckAccount` +/// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` #[test] fn limited_teleport_native_assets_from_system_para_to_relay_fails() { // Init values for Relay Chain 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 f7e1cce85a2cf7895d178cb3f95a24070c790198..aa6eebc5458f4a1f149b8d5981f18d9e646e7339 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 @@ -15,6 +15,7 @@ frame-support = { workspace = true } pallet-balances = { workspace = true } pallet-message-queue = { workspace = true } pallet-identity = { workspace = true } +pallet-xcm = { workspace = true } sp-runtime = { workspace = true } # Polkadot 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 ce1ed9751a2e68ab1cb087983dbb01e21d34bcc8..418cfea07ddc2b7fec7e372fd7c54e62631f4df8 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 @@ -15,14 +15,8 @@ #[cfg(test)] mod imports { - pub use codec::Encode; // Substrate - pub use frame_support::{ - assert_ok, - pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchResult}, - traits::fungibles::Inspect, - }; + pub use frame_support::{assert_ok, sp_runtime::DispatchResult, traits::fungibles::Inspect}; // Polkadot pub use xcm::prelude::*; @@ -37,17 +31,14 @@ mod imports { pub use westend_system_emulated_network::{ self, people_westend_emulated_chain::{ - genesis::ED as PEOPLE_WESTEND_ED, - people_westend_runtime::{people, xcm_config::XcmConfig as PeopleWestendXcmConfig}, + people_westend_runtime::{ + xcm_config::XcmConfig as PeopleWestendXcmConfig, + ExistentialDeposit as PeopleWestendExistentialDeposit, + }, PeopleWestendParaPallet as PeopleWestendPallet, }, westend_emulated_chain::{ - genesis::ED as WESTEND_ED, - westend_runtime::{ - xcm_config::XcmConfig as WestendXcmConfig, BasicDeposit, ByteDeposit, - MaxAdditionalFields, MaxSubAccounts, RuntimeOrigin as WestendOrigin, - SubAccountDeposit, - }, + genesis::ED as WESTEND_ED, westend_runtime::xcm_config::XcmConfig as WestendXcmConfig, WestendRelayPallet as WestendPallet, }, PeopleWestendPara as PeopleWestend, PeopleWestendParaReceiver as PeopleWestendReceiver, @@ -55,7 +46,6 @@ mod imports { WestendRelayReceiver as WestendReceiver, WestendRelaySender as WestendSender, }; - pub type RelayToSystemParaTest = Test; pub type SystemParaToRelayTest = Test; } 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..08749b295dc21def8feb2c2318bcbed2b258ba9e 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,5 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod reap_identity; +mod claim_assets; 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 deleted file mode 100644 index 28d1be853204ea5e3943de7da8b14a7601006bd6..0000000000000000000000000000000000000000 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/reap_identity.rs +++ /dev/null @@ -1,547 +0,0 @@ -// 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. - -//! # OnReapIdentity Tests -//! -//! This file contains the test cases for migrating Identity data away from the Westend Relay -//! chain and to the PeopleWestend parachain. This migration is part of the broader Minimal Relay -//! effort: -//! https://github.com/polkadot-fellows/RFCs/blob/main/text/0032-minimal-relay.md -//! -//! ## Overview -//! -//! The tests validate the robustness and correctness of the `OnReapIdentityHandler` -//! ensuring that it behaves as expected in various scenarios. Key aspects tested include: -//! -//! - **Deposit Handling**: Confirming that deposits are correctly migrated from the Relay Chain to -//! the People parachain in various scenarios (different `IdentityInfo` fields and different -//! numbers of sub-accounts). -//! -//! ### Test Scenarios -//! -//! The tests are categorized into several scenarios, each resulting in different deposits required -//! on the destination parachain. The tests ensure: -//! -//! - Reserved deposits on the Relay Chain are fully released; -//! - The freed deposit from the Relay Chain is sufficient for the parachain deposit; and -//! - The account will exist on the parachain. - -use crate::imports::*; -use frame_support::BoundedVec; -use pallet_balances::Event as BalancesEvent; -use pallet_identity::{legacy::IdentityInfo, Data, Event as IdentityEvent}; -use people::{ - BasicDeposit as BasicDepositParachain, ByteDeposit as ByteDepositParachain, - IdentityInfo as IdentityInfoParachain, SubAccountDeposit as SubAccountDepositParachain, -}; -use westend_runtime_constants::currency::*; -use westend_system_emulated_network::{ - westend_emulated_chain::WestendRelayPallet, WestendRelay, WestendRelaySender, -}; - -type Balance = u128; -type WestendIdentity = ::Identity; -type WestendBalances = ::Balances; -type WestendIdentityMigrator = ::IdentityMigrator; -type PeopleWestendIdentity = ::Identity; -type PeopleWestendBalances = ::Balances; - -#[derive(Clone, Debug)] -struct Identity { - relay: IdentityInfo, - para: IdentityInfoParachain, - subs: Subs, -} - -impl Identity { - fn new( - full: bool, - additional: Option>, - subs: Subs, - ) -> Self { - let pgp_fingerprint = [ - 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, - 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, - ]; - let make_data = |data: &[u8], full: bool| -> Data { - if full { - Data::Raw(data.to_vec().try_into().unwrap()) - } else { - Data::None - } - }; - let (github, discord) = additional - .as_ref() - .and_then(|vec| vec.first()) - .map(|(g, d)| (g.clone(), d.clone())) - .unwrap_or((Data::None, Data::None)); - Self { - relay: IdentityInfo { - display: make_data(b"xcm-test", full), - legal: make_data(b"The Xcm Test, Esq.", full), - web: make_data(b"https://visitme/", full), - riot: make_data(b"xcm-riot", full), - email: make_data(b"xcm-test@gmail.com", full), - pgp_fingerprint: Some(pgp_fingerprint), - image: make_data(b"xcm-test.png", full), - twitter: make_data(b"@xcm-test", full), - additional: additional.unwrap_or_default(), - }, - para: IdentityInfoParachain { - display: make_data(b"xcm-test", full), - legal: make_data(b"The Xcm Test, Esq.", full), - web: make_data(b"https://visitme/", full), - matrix: make_data(b"xcm-matrix@server", full), - email: make_data(b"xcm-test@gmail.com", full), - pgp_fingerprint: Some(pgp_fingerprint), - image: make_data(b"xcm-test.png", full), - twitter: make_data(b"@xcm-test", full), - github, - discord, - }, - subs, - } - } -} - -#[derive(Clone, Debug)] -enum Subs { - Zero, - Many(u32), -} - -enum IdentityOn<'a> { - Relay(&'a IdentityInfo), - Para(&'a IdentityInfoParachain), -} - -impl IdentityOn<'_> { - fn calculate_deposit(self) -> Balance { - match self { - IdentityOn::Relay(id) => { - let base_deposit = BasicDeposit::get(); - let byte_deposit = - ByteDeposit::get() * TryInto::::try_into(id.encoded_size()).unwrap(); - base_deposit + byte_deposit - }, - IdentityOn::Para(id) => { - let base_deposit = BasicDepositParachain::get(); - let byte_deposit = ByteDepositParachain::get() * - TryInto::::try_into(id.encoded_size()).unwrap(); - base_deposit + byte_deposit - }, - } - } -} - -/// Generate an `AccountId32` from a `u32`. -/// This creates a 32-byte array, initially filled with `255`, and then repeatedly fills it -/// with the 4-byte little-endian representation of the `u32` value, until the array is full. -/// -/// **Example**: -/// -/// `account_from_u32(5)` will return an `AccountId32` with the bytes -/// `[0, 5, 0, 0, 0, 0, 0, 0, 0, 5 ... ]` -fn account_from_u32(id: u32) -> AccountId32 { - let mut buffer = [255u8; 32]; - let id_bytes = id.to_le_bytes(); - let id_size = id_bytes.len(); - for chunk in buffer.chunks_mut(id_size) { - chunk.clone_from_slice(&id_bytes); - } - AccountId32::new(buffer) -} - -// Set up the Relay Chain with an identity. -fn set_id_relay(id: &Identity) -> Balance { - let mut total_deposit: Balance = 0; - - // Set identity and Subs on Relay Chain - WestendRelay::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_ok!(WestendIdentity::set_identity( - WestendOrigin::signed(WestendRelaySender::get()), - Box::new(id.relay.clone()) - )); - - if let Subs::Many(n) = id.subs { - let subs: Vec<_> = (0..n) - .map(|i| (account_from_u32(i), Data::Raw(b"name".to_vec().try_into().unwrap()))) - .collect(); - - assert_ok!(WestendIdentity::set_subs( - WestendOrigin::signed(WestendRelaySender::get()), - subs, - )); - } - - let reserved_balance = WestendBalances::reserved_balance(WestendRelaySender::get()); - let id_deposit = IdentityOn::Relay(&id.relay).calculate_deposit(); - - let total_deposit = match id.subs { - Subs::Zero => { - total_deposit = id_deposit; // No subs - assert_expected_events!( - WestendRelay, - vec![ - RuntimeEvent::Identity(IdentityEvent::IdentitySet { .. }) => {}, - RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => { - who: *who == WestendRelaySender::get(), - amount: *amount == id_deposit, - }, - ] - ); - total_deposit - }, - Subs::Many(n) => { - let sub_account_deposit = n as Balance * SubAccountDeposit::get(); - total_deposit = - sub_account_deposit + IdentityOn::Relay(&id.relay).calculate_deposit(); - assert_expected_events!( - WestendRelay, - vec![ - RuntimeEvent::Identity(IdentityEvent::IdentitySet { .. }) => {}, - RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => { - who: *who == WestendRelaySender::get(), - amount: *amount == id_deposit, - }, - RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => { - who: *who == WestendRelaySender::get(), - amount: *amount == sub_account_deposit, - }, - ] - ); - total_deposit - }, - }; - - assert_eq!(reserved_balance, total_deposit); - }); - total_deposit -} - -// Set up the parachain with an identity and (maybe) sub accounts, but with zero deposits. -fn assert_set_id_parachain(id: &Identity) { - // Set identity and Subs on Parachain with zero deposit - PeopleWestend::execute_with(|| { - let free_bal = PeopleWestendBalances::free_balance(PeopleWestendSender::get()); - let reserved_balance = PeopleWestendBalances::reserved_balance(PeopleWestendSender::get()); - - // total balance at Genesis should be zero - assert_eq!(reserved_balance + free_bal, 0); - - assert_ok!(PeopleWestendIdentity::set_identity_no_deposit( - &PeopleWestendSender::get(), - id.para.clone(), - )); - - match id.subs { - Subs::Zero => {}, - Subs::Many(n) => { - let subs: Vec<_> = (0..n) - .map(|ii| { - (account_from_u32(ii), Data::Raw(b"name".to_vec().try_into().unwrap())) - }) - .collect(); - assert_ok!(PeopleWestendIdentity::set_subs_no_deposit( - &PeopleWestendSender::get(), - subs, - )); - }, - } - - // 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()); - - let (_, sub_accounts) = PeopleWestendIdentity::subs_of(PeopleWestendSender::get()); - - match id.subs { - Subs::Zero => assert_eq!(sub_accounts.len(), 0), - Subs::Many(n) => assert_eq!(sub_accounts.len(), n as usize), - } - }); -} - -// Reap the identity on the Relay Chain and assert that the correct things happen there. -fn assert_reap_id_relay(total_deposit: Balance, id: &Identity) { - WestendRelay::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - let free_bal_before_reap = WestendBalances::free_balance(WestendRelaySender::get()); - let reserved_balance = WestendBalances::reserved_balance(WestendRelaySender::get()); - - assert_eq!(reserved_balance, total_deposit); - - assert_ok!(WestendIdentityMigrator::reap_identity( - WestendOrigin::signed(WestendRelaySender::get()), - WestendRelaySender::get() - )); - - let remote_deposit = match id.subs { - Subs::Zero => calculate_remote_deposit(id.relay.encoded_size() as u32, 0), - Subs::Many(n) => calculate_remote_deposit(id.relay.encoded_size() as u32, n), - }; - - assert_expected_events!( - WestendRelay, - vec![ - // `reap_identity` sums the identity and subs deposits and unreserves them in one - // call. Therefore, we only expect one `Unreserved` event. - RuntimeEvent::Balances(BalancesEvent::Unreserved { who, amount }) => { - who: *who == WestendRelaySender::get(), - amount: *amount == total_deposit, - }, - RuntimeEvent::IdentityMigrator( - polkadot_runtime_common::identity_migrator::Event::IdentityReaped { - who, - }) => { - who: *who == PeopleWestendSender::get(), - }, - ] - ); - // Identity should be gone. - assert!(PeopleWestendIdentity::identity(WestendRelaySender::get()).is_none()); - - // Subs should be gone. - let (_, sub_accounts) = WestendIdentity::subs_of(WestendRelaySender::get()); - assert_eq!(sub_accounts.len(), 0); - - let reserved_balance = WestendBalances::reserved_balance(WestendRelaySender::get()); - assert_eq!(reserved_balance, 0); - - // Free balance should be greater (i.e. the teleport should work even if 100% of an - // account's balance is reserved for Identity). - let free_bal_after_reap = WestendBalances::free_balance(WestendRelaySender::get()); - assert!(free_bal_after_reap > free_bal_before_reap); - - // Implicit: total_deposit > remote_deposit. As in, accounts should always have enough - // reserved for the parachain deposit. - assert_eq!(free_bal_after_reap, free_bal_before_reap + total_deposit - remote_deposit); - }); -} - -// Reaping the identity on the Relay Chain will have sent an XCM program to the parachain. Ensure -// that everything happens as expected. -fn assert_reap_parachain(id: &Identity) { - PeopleWestend::execute_with(|| { - let reserved_balance = PeopleWestendBalances::reserved_balance(PeopleWestendSender::get()); - let id_deposit = IdentityOn::Para(&id.para).calculate_deposit(); - let total_deposit = match id.subs { - Subs::Zero => id_deposit, - Subs::Many(n) => id_deposit + n as Balance * SubAccountDepositParachain::get(), - }; - assert_reap_events(id_deposit, id); - assert_eq!(reserved_balance, total_deposit); - - // Should have at least one ED after in free balance after the reap. - assert!( - PeopleWestendBalances::free_balance(PeopleWestendSender::get()) >= PEOPLE_WESTEND_ED - ); - }); -} - -// Assert the events that should happen on the parachain upon reaping an identity on the Relay -// Chain. -fn assert_reap_events(id_deposit: Balance, id: &Identity) { - type RuntimeEvent = ::RuntimeEvent; - match id.subs { - Subs::Zero => { - assert_expected_events!( - PeopleWestend, - vec![ - // Deposit and Endowed from teleport - RuntimeEvent::Balances(BalancesEvent::Minted { .. }) => {}, - RuntimeEvent::Balances(BalancesEvent::Endowed { .. }) => {}, - // Amount reserved for identity info - RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => { - who: *who == PeopleWestendSender::get(), - amount: *amount == id_deposit, - }, - // Confirmation from Migrator with individual identity and subs deposits - RuntimeEvent::IdentityMigrator( - polkadot_runtime_common::identity_migrator::Event::DepositUpdated { - who, identity, subs - }) => { - who: *who == PeopleWestendSender::get(), - identity: *identity == id_deposit, - subs: *subs == 0, - }, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { .. }) => {}, - ] - ); - }, - Subs::Many(n) => { - let subs_deposit = n as Balance * SubAccountDepositParachain::get(); - assert_expected_events!( - PeopleWestend, - vec![ - // Deposit and Endowed from teleport - RuntimeEvent::Balances(BalancesEvent::Minted { .. }) => {}, - RuntimeEvent::Balances(BalancesEvent::Endowed { .. }) => {}, - // Amount reserved for identity info - RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => { - who: *who == PeopleWestendSender::get(), - amount: *amount == id_deposit, - }, - // Amount reserved for subs - RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => { - who: *who == PeopleWestendSender::get(), - amount: *amount == subs_deposit, - }, - // Confirmation from Migrator with individual identity and subs deposits - RuntimeEvent::IdentityMigrator( - polkadot_runtime_common::identity_migrator::Event::DepositUpdated { - who, identity, subs - }) => { - who: *who == PeopleWestendSender::get(), - identity: *identity == id_deposit, - subs: *subs == subs_deposit, - }, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { .. }) => {}, - ] - ); - }, - }; -} - -/// Duplicate of the impl of `ToParachainIdentityReaper` in the Westend runtime. -fn calculate_remote_deposit(bytes: u32, subs: u32) -> Balance { - // Note: These `deposit` functions and `EXISTENTIAL_DEPOSIT` correspond to the Relay Chain's. - // Pulled in: use westend_runtime_constants::currency::*; - let para_basic_deposit = deposit(1, 17) / 100; - let para_byte_deposit = deposit(0, 1) / 100; - let para_sub_account_deposit = deposit(1, 53) / 100; - let para_existential_deposit = EXISTENTIAL_DEPOSIT / 10; - - // pallet deposits - let id_deposit = - para_basic_deposit.saturating_add(para_byte_deposit.saturating_mul(bytes as Balance)); - let subs_deposit = para_sub_account_deposit.saturating_mul(subs as Balance); - - id_deposit - .saturating_add(subs_deposit) - .saturating_add(para_existential_deposit.saturating_mul(2)) -} - -// Represent some `additional` data that would not be migrated to the parachain. The encoded size, -// and thus the byte deposit, should decrease. -fn nonsensical_additional() -> BoundedVec<(Data, Data), MaxAdditionalFields> { - BoundedVec::try_from(vec![( - Data::Raw(b"fOo".to_vec().try_into().unwrap()), - Data::Raw(b"baR".to_vec().try_into().unwrap()), - )]) - .unwrap() -} - -// Represent some `additional` data that will be migrated to the parachain as first-class fields. -fn meaningful_additional() -> BoundedVec<(Data, Data), MaxAdditionalFields> { - BoundedVec::try_from(vec![ - ( - Data::Raw(b"github".to_vec().try_into().unwrap()), - Data::Raw(b"niels-username".to_vec().try_into().unwrap()), - ), - ( - Data::Raw(b"discord".to_vec().try_into().unwrap()), - Data::Raw(b"bohr-username".to_vec().try_into().unwrap()), - ), - ]) - .unwrap() -} - -// Execute a single test case. -fn assert_relay_para_flow(id: &Identity) { - let total_deposit = set_id_relay(id); - assert_set_id_parachain(id); - assert_reap_id_relay(total_deposit, id); - assert_reap_parachain(id); -} - -// Tests with empty `IdentityInfo`. - -#[test] -fn on_reap_identity_works_for_minimal_identity_with_zero_subs() { - assert_relay_para_flow(&Identity::new(false, None, Subs::Zero)); -} - -#[test] -fn on_reap_identity_works_for_minimal_identity() { - assert_relay_para_flow(&Identity::new(false, None, Subs::Many(1))); -} - -#[test] -fn on_reap_identity_works_for_minimal_identity_with_max_subs() { - assert_relay_para_flow(&Identity::new(false, None, Subs::Many(MaxSubAccounts::get()))); -} - -// Tests with full `IdentityInfo`. - -#[test] -fn on_reap_identity_works_for_full_identity_no_additional_zero_subs() { - assert_relay_para_flow(&Identity::new(true, None, Subs::Zero)); -} - -#[test] -fn on_reap_identity_works_for_full_identity_no_additional() { - assert_relay_para_flow(&Identity::new(true, None, Subs::Many(1))); -} - -#[test] -fn on_reap_identity_works_for_full_identity_no_additional_max_subs() { - assert_relay_para_flow(&Identity::new(true, None, Subs::Many(MaxSubAccounts::get()))); -} - -// Tests with full `IdentityInfo` and `additional` fields that will _not_ be migrated. - -#[test] -fn on_reap_identity_works_for_full_identity_nonsense_additional_zero_subs() { - assert_relay_para_flow(&Identity::new(true, Some(nonsensical_additional()), Subs::Zero)); -} - -#[test] -fn on_reap_identity_works_for_full_identity_nonsense_additional() { - assert_relay_para_flow(&Identity::new(true, Some(nonsensical_additional()), Subs::Many(1))); -} - -#[test] -fn on_reap_identity_works_for_full_identity_nonsense_additional_max_subs() { - assert_relay_para_flow(&Identity::new( - true, - Some(nonsensical_additional()), - Subs::Many(MaxSubAccounts::get()), - )); -} - -// Tests with full `IdentityInfo` and `additional` fields that will be migrated. - -#[test] -fn on_reap_identity_works_for_full_identity_meaningful_additional_zero_subs() { - assert_relay_para_flow(&Identity::new(true, Some(meaningful_additional()), Subs::Zero)); -} - -#[test] -fn on_reap_identity_works_for_full_identity_meaningful_additional() { - assert_relay_para_flow(&Identity::new(true, Some(meaningful_additional()), Subs::Many(1))); -} - -#[test] -fn on_reap_identity_works_for_full_identity_meaningful_additional_max_subs() { - assert_relay_para_flow(&Identity::new( - true, - Some(meaningful_additional()), - Subs::Many(MaxSubAccounts::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 6fd3cdeb61fbc3d3deb5445a7edf57a5008367c6..83888031723ffffef24f86717741ddab1bf2598a 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,68 +14,38 @@ // limitations under the License. use crate::imports::*; +use emulated_integration_tests_common::{ + test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, +}; -fn relay_origin_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - Westend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(627_959_000, 7_200))); +#[test] +fn teleport_from_and_to_relay() { + let amount = WESTEND_ED * 100; + let native_asset: Assets = (Here, amount).into(); - assert_expected_events!( + test_relay_is_trusted_teleporter!( Westend, - vec![ - // Amount to teleport is withdrawn from Sender - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, - }, - // Amount to teleport is deposited in Relay's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) => { - who: *who == ::XcmPallet::check_account(), - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn relay_dest_assertions(t: SystemParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - - Westend::assert_ump_queue_processed( - true, - Some(PeopleWestend::para_id()), - Some(Weight::from_parts(304_266_000, 7_186)), + WestendXcmConfig, + vec![PeopleWestend], + (native_asset, amount) ); - assert_expected_events!( + test_parachain_is_trusted_teleporter_for_relay!( + PeopleWestend, + PeopleWestendXcmConfig, Westend, - vec![ - // Amount is withdrawn from Relay Chain's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == ::XcmPallet::check_account(), - amount: *amount == t.args.amount, - }, - // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, - }, - ] + amount ); } fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) { - Westend::assert_ump_queue_processed( - false, - Some(PeopleWestend::para_id()), - Some(Weight::from_parts(157_718_000, 3_593)), - ); + Westend::assert_ump_queue_processed(false, Some(PeopleWestend::para_id()), None); } fn para_origin_assertions(t: SystemParaToRelayTest) { type RuntimeEvent = ::RuntimeEvent; - PeopleWestend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 351_425_000, - 3_593, - ))); + PeopleWestend::assert_xcm_pallet_attempted_complete(None); PeopleWestend::assert_parachain_system_ump_sent(); @@ -91,33 +61,6 @@ fn para_origin_assertions(t: SystemParaToRelayTest) { ); } -fn para_dest_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - PeopleWestend::assert_dmp_queue_complete(Some(Weight::from_parts(162_456_000, 0))); - - assert_expected_events!( - PeopleWestend, - vec![ - // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, - }, - ] - ); -} - -fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::limited_teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { ::PolkadotXcm::limited_teleport_assets( t.signed_origin, @@ -129,92 +72,8 @@ fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResu ) } -/// Limited Teleport of native asset from Relay Chain to the System Parachain should work -#[test] -fn limited_teleport_native_assets_from_relay_to_system_para_works() { - // Init values for Relay Chain - let amount_to_send: Balance = WESTEND_ED * 1000; - let dest = Westend::child_location_of(PeopleWestend::para_id()); - let beneficiary_id = PeopleWestendReceiver::get(); - let test_args = TestContext { - sender: WestendSender::get(), - receiver: PeopleWestendReceiver::get(), - args: TestArgs::new_relay(dest, beneficiary_id, amount_to_send), - }; - - let mut test = RelayToSystemParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(para_dest_assertions); - test.set_dispatchable::(relay_limited_teleport_assets); - test.assert(); - - let delivery_fees = Westend::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - -/// Limited Teleport of native asset from System Parachain to Relay Chain -/// should work when there is enough balance in Relay Chain's `CheckAccount` -#[test] -fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { - // Dependency - Relay Chain's `CheckAccount` should have enough balance - limited_teleport_native_assets_from_relay_to_system_para_works(); - - let amount_to_send: Balance = PEOPLE_WESTEND_ED * 1000; - let destination = PeopleWestend::parent_location(); - let beneficiary_id = WestendReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - // Fund a sender - PeopleWestend::fund_accounts(vec![(PeopleWestendSender::get(), WESTEND_ED * 2_000u128)]); - - let test_args = TestContext { - sender: PeopleWestendSender::get(), - receiver: WestendReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions); - test.set_dispatchable::(system_para_limited_teleport_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = PeopleWestend::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - /// Limited Teleport of native asset from System Parachain to Relay Chain -/// should't work when there is not enough balance in Relay Chain's `CheckAccount` +/// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` #[test] fn limited_teleport_native_assets_from_system_para_to_relay_fails() { // Init values for Relay Chain 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 f09647854cd0132751889ef2b33bca1c5ec16e74..4c7356707ab61c0e3ef4c6a97f4c83d3728c5f53 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -71,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, @@ -83,10 +83,13 @@ use sp_runtime::{Perbill, RuntimeDebug}; use testnet_parachains_constants::rococo::{consensus::*, currency::*, fee::WeightToFee, time::*}; use xcm_config::{ ForeignAssetsConvertedConcreteId, ForeignCreatorsSovereignAccountOf, GovernanceLocation, - PoolAssetsConvertedConcreteId, TokenLocation, TokenLocationV3, - TrustBackedAssetsConvertedConcreteId, TrustBackedAssetsPalletLocationV3, + PoolAssetsConvertedConcreteId, TokenLocation, TrustBackedAssetsConvertedConcreteId, + TrustBackedAssetsPalletLocation, }; +#[cfg(test)] +mod tests; + #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; @@ -120,7 +123,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 1_014_000, + spec_version: 1_015_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 16, @@ -324,11 +327,11 @@ pub type LocalAndForeignAssets = fungibles::UnionOf< Assets, ForeignAssets, LocalFromLeft< - AssetIdForTrustBackedAssetsConvert, + AssetIdForTrustBackedAssetsConvert, AssetIdForTrustBackedAssets, - xcm::v3::Location, + xcm::v4::Location, >, - xcm::v3::Location, + xcm::v4::Location, AccountId, >; @@ -336,25 +339,25 @@ pub type LocalAndForeignAssets = fungibles::UnionOf< pub type NativeAndAssets = fungible::UnionOf< Balances, LocalAndForeignAssets, - TargetFromLeft, - xcm::v3::Location, + TargetFromLeft, + xcm::v4::Location, AccountId, >; pub type PoolIdToAccountId = pallet_asset_conversion::AccountIdConverter< AssetConversionPalletId, - (xcm::v3::Location, xcm::v3::Location), + (xcm::v4::Location, xcm::v4::Location), >; impl pallet_asset_conversion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; type HigherPrecisionBalance = sp_core::U256; - type AssetKind = xcm::v3::Location; + type AssetKind = xcm::v4::Location; type Assets = NativeAndAssets; type PoolId = (Self::AssetKind, Self::AssetKind); type PoolLocator = pallet_asset_conversion::WithFirstAsset< - TokenLocationV3, + TokenLocation, AccountId, Self::AssetKind, PoolIdToAccountId, @@ -362,7 +365,7 @@ impl pallet_asset_conversion::Config for Runtime { type PoolAssetId = u32; type PoolAssets = PoolAssets; type PoolSetupFee = ConstU128<0>; // Asset class deposit fees are sufficient to prevent spam - type PoolSetupFeeAsset = TokenLocationV3; + type PoolSetupFeeAsset = TokenLocation; type PoolSetupFeeTarget = ResolveAssetTo; type LiquidityWithdrawalFee = LiquidityWithdrawalFee; type LPFee = ConstU32<3>; @@ -372,10 +375,10 @@ impl pallet_asset_conversion::Config for Runtime { type WeightInfo = weights::pallet_asset_conversion::WeightInfo; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = assets_common::benchmarks::AssetPairFactory< - TokenLocationV3, + TokenLocation, parachain_info::Pallet, xcm_config::TrustBackedAssetsPalletIndex, - xcm::v3::Location, + xcm::v4::Location, >; } @@ -409,17 +412,17 @@ pub type ForeignAssetsInstance = pallet_assets::Instance2; impl pallet_assets::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; - type AssetId = xcm::v3::Location; - type AssetIdParameter = xcm::v3::Location; + type AssetId = xcm::v4::Location; + type AssetIdParameter = xcm::v4::Location; type Currency = Balances; type CreateOrigin = ForeignCreators< ( - FromSiblingParachain, xcm::v3::Location>, - FromNetwork, + FromSiblingParachain, xcm::v4::Location>, + FromNetwork, ), ForeignCreatorsSovereignAccountOf, AccountId, - xcm::v3::Location, + xcm::v4::Location, >; type ForceOrigin = AssetsForceOrigin; type AssetDeposit = ForeignAssetsAssetDeposit; @@ -798,11 +801,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::v4::Location; + type OnChargeAssetTransaction = SwapAssetAdapter< + TokenLocation, + NativeAndAssets, + AssetConversion, + ResolveAssetTo, + >; } parameter_types! { @@ -1011,7 +1022,6 @@ pub type SignedExtra = ( pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. -#[allow(deprecated)] pub type Migrations = ( InitStorageVersions, // unreleased @@ -1226,16 +1236,16 @@ impl_runtime_apis! { impl pallet_asset_conversion::AssetConversionApi< Block, Balance, - xcm::v3::Location, + xcm::v4::Location, > for Runtime { - fn quote_price_exact_tokens_for_tokens(asset1: xcm::v3::Location, asset2: xcm::v3::Location, amount: Balance, include_fee: bool) -> Option { + fn quote_price_exact_tokens_for_tokens(asset1: xcm::v4::Location, asset2: xcm::v4::Location, amount: Balance, include_fee: bool) -> Option { AssetConversion::quote_price_exact_tokens_for_tokens(asset1, asset2, amount, include_fee) } - fn quote_price_tokens_for_exact_tokens(asset1: xcm::v3::Location, asset2: xcm::v3::Location, amount: Balance, include_fee: bool) -> Option { + fn quote_price_tokens_for_exact_tokens(asset1: xcm::v4::Location, asset2: xcm::v4::Location, amount: Balance, include_fee: bool) -> Option { AssetConversion::quote_price_tokens_for_exact_tokens(asset1, asset2, amount, include_fee) } - fn get_reserves(asset1: xcm::v3::Location, asset2: xcm::v3::Location) -> Option<(Balance, Balance)> { + fn get_reserves(asset1: xcm::v4::Location, asset2: xcm::v4::Location) -> Option<(Balance, Balance)> { AssetConversion::get_reserves(asset1, asset2).ok() } } @@ -1773,64 +1783,3 @@ cumulus_pallet_parachain_system::register_validate_block! { Runtime = Runtime, BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, } - -#[cfg(test)] -mod tests { - use super::*; - use crate::{CENTS, MILLICENTS}; - use sp_runtime::traits::Zero; - use sp_weights::WeightToFee; - use testnet_parachains_constants::rococo::fee; - - /// We can fit at least 1000 transfers in a block. - #[test] - fn sane_block_weight() { - use pallet_balances::WeightInfo; - let block = RuntimeBlockWeights::get().max_block; - let base = RuntimeBlockWeights::get().get(DispatchClass::Normal).base_extrinsic; - let transfer = - base + weights::pallet_balances::WeightInfo::::transfer_allow_death(); - - let fit = block.checked_div_per_component(&transfer).unwrap_or_default(); - assert!(fit >= 1000, "{} should be at least 1000", fit); - } - - /// The fee for one transfer is at most 1 CENT. - #[test] - fn sane_transfer_fee() { - use pallet_balances::WeightInfo; - let base = RuntimeBlockWeights::get().get(DispatchClass::Normal).base_extrinsic; - let transfer = - base + weights::pallet_balances::WeightInfo::::transfer_allow_death(); - - let fee: Balance = fee::WeightToFee::weight_to_fee(&transfer); - assert!(fee <= CENTS, "{} MILLICENTS should be at most 1000", fee / MILLICENTS); - } - - /// Weight is being charged for both dimensions. - #[test] - fn weight_charged_for_both_components() { - let fee: Balance = fee::WeightToFee::weight_to_fee(&Weight::from_parts(10_000, 0)); - assert!(!fee.is_zero(), "Charges for ref time"); - - let fee: Balance = fee::WeightToFee::weight_to_fee(&Weight::from_parts(0, 10_000)); - assert_eq!(fee, CENTS, "10kb maps to CENT"); - } - - /// Filling up a block by proof size is at most 30 times more expensive than ref time. - /// - /// This is just a sanity check. - #[test] - fn full_block_fee_ratio() { - let block = RuntimeBlockWeights::get().max_block; - let time_fee: Balance = - fee::WeightToFee::weight_to_fee(&Weight::from_parts(block.ref_time(), 0)); - let proof_fee: Balance = - fee::WeightToFee::weight_to_fee(&Weight::from_parts(0, block.proof_size())); - - let proof_o_time = proof_fee.checked_div(time_fee).unwrap_or_default(); - assert!(proof_o_time <= 30, "{} should be at most 30", proof_o_time); - let time_o_proof = time_fee.checked_div(proof_fee).unwrap_or_default(); - assert!(time_o_proof <= 30, "{} should be at most 30", time_o_proof); - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/tests/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/tests/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..12c0bc4e168800a7efd0a72daf75244e92b79255 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/tests/mod.rs @@ -0,0 +1,72 @@ +// 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 for the Rococo runtime. + +use super::*; +use crate::{CENTS, MILLICENTS}; +use sp_runtime::traits::Zero; +use sp_weights::WeightToFee; +use testnet_parachains_constants::rococo::fee; + +/// We can fit at least 1000 transfers in a block. +#[test] +fn sane_block_weight() { + use pallet_balances::WeightInfo; + let block = RuntimeBlockWeights::get().max_block; + let base = RuntimeBlockWeights::get().get(DispatchClass::Normal).base_extrinsic; + let transfer = base + weights::pallet_balances::WeightInfo::::transfer_allow_death(); + + let fit = block.checked_div_per_component(&transfer).unwrap_or_default(); + assert!(fit >= 1000, "{} should be at least 1000", fit); +} + +/// The fee for one transfer is at most 1 CENT. +#[test] +fn sane_transfer_fee() { + use pallet_balances::WeightInfo; + let base = RuntimeBlockWeights::get().get(DispatchClass::Normal).base_extrinsic; + let transfer = base + weights::pallet_balances::WeightInfo::::transfer_allow_death(); + + let fee: Balance = fee::WeightToFee::weight_to_fee(&transfer); + assert!(fee <= CENTS, "{} MILLICENTS should be at most 1000", fee / MILLICENTS); +} + +/// Weight is being charged for both dimensions. +#[test] +fn weight_charged_for_both_components() { + let fee: Balance = fee::WeightToFee::weight_to_fee(&Weight::from_parts(10_000, 0)); + assert!(!fee.is_zero(), "Charges for ref time"); + + let fee: Balance = fee::WeightToFee::weight_to_fee(&Weight::from_parts(0, 10_000)); + assert_eq!(fee, CENTS, "10kb maps to CENT"); +} + +/// Filling up a block by proof size is at most 30 times more expensive than ref time. +/// +/// This is just a sanity check. +#[test] +fn full_block_fee_ratio() { + let block = RuntimeBlockWeights::get().max_block; + let time_fee: Balance = + fee::WeightToFee::weight_to_fee(&Weight::from_parts(block.ref_time(), 0)); + let proof_fee: Balance = + fee::WeightToFee::weight_to_fee(&Weight::from_parts(0, block.proof_size())); + + let proof_o_time = proof_fee.checked_div(time_fee).unwrap_or_default(); + assert!(proof_o_time <= 30, "{} should be at most 30", proof_o_time); + let time_o_proof = time_fee.checked_div(proof_fee).unwrap_or_default(); + assert!(time_o_proof <= 30, "{} should be at most 30", time_o_proof); +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_foreign.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_foreign.rs index 5148edb0ee9e2c5f97c9c0afe830e0f87f2ac92f..c76c1137335a17938e5b409c1642a09ce9824fcd 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_foreign.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_foreign.rs @@ -531,4 +531,14 @@ impl pallet_assets::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } + + fn transfer_all() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 46_573_000 picoseconds. + Weight::from_parts(47_385_000, 3593) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_local.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_local.rs index 4ee235830aed23f9b6c6743a90aa5095bf6f9ed9..cf4f60042bc683fa3a161bbf6d0b9695a718b720 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_local.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_local.rs @@ -528,4 +528,14 @@ impl pallet_assets::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } + + fn transfer_all() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 46_573_000 picoseconds. + Weight::from_parts(47_385_000, 3593) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_pool.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_pool.rs index df7ad2c633867aaf5fea7c737ed926cccb5e2c80..2cd85de0098952d14e15f9e362e6fbe48d2741e7 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_pool.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_pool.rs @@ -528,4 +528,14 @@ impl pallet_assets::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } + + fn transfer_all() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 46_573_000 picoseconds. + Weight::from_parts(47_385_000, 3593) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } 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 03d3785dccbd7f213eee3d8aa51cde7eb5980b48..3d6ae6ddd1d210b5a94d39237d67d4378e9bedec 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 @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-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: @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 21_643_000 picoseconds. - Weight::from_parts(22_410_000, 3593) + // Minimum execution time: 34_180_000 picoseconds. + Weight::from_parts(34_745_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 43_758_000 picoseconds. - Weight::from_parts(44_654_000, 6196) + // Minimum execution time: 42_638_000 picoseconds. + Weight::from_parts(43_454_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -90,20 +90,17 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `8799` - // Minimum execution time: 87_978_000 picoseconds. - Weight::from_parts(88_517_000, 8799) + // Minimum execution time: 102_916_000 picoseconds. + Weight::from_parts(105_699_000, 8799) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } - // Storage: `ParachainInfo::ParachainId` (r:1 w:0) - // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) pub fn reserve_asset_deposited() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `1489` - // Minimum execution time: 6_883_000 picoseconds. - Weight::from_parts(6_979_000, 1489) - .saturating_add(T::DbWeight::get().reads(1)) + // Estimated: `0` + // Minimum execution time: 1_805_000 picoseconds. + Weight::from_parts(1_901_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -125,8 +122,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 198_882_000 picoseconds. - Weight::from_parts(199_930_000, 6196) + // Minimum execution time: 108_018_000 picoseconds. + Weight::from_parts(110_310_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -134,8 +131,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_343_000 picoseconds. - Weight::from_parts(3_487_000, 0) + // Minimum execution time: 3_507_000 picoseconds. + Weight::from_parts(3_724_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -143,13 +140,11 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 19_399_000 picoseconds. - Weight::from_parts(19_659_000, 3593) + // Minimum execution time: 26_269_000 picoseconds. + Weight::from_parts(26_706_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: `System::Account` (r:2 w:2) - // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -160,6 +155,8 @@ impl WeightInfo { // 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: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // 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) @@ -168,8 +165,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `6196` - // Minimum execution time: 59_017_000 picoseconds. - Weight::from_parts(60_543_000, 6196) + // Minimum execution time: 84_759_000 picoseconds. + Weight::from_parts(86_157_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -193,8 +190,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 45_409_000 picoseconds. - Weight::from_parts(47_041_000, 3610) + // Minimum execution time: 50_876_000 picoseconds. + Weight::from_parts(51_512_000, 3610) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } 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 c736d3ee44204156a847bafbb1d4d0b26652a31a..2d1914e059bf7a95f629a821ce885fb02faa02a1 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,17 +55,16 @@ 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; parameter_types! { pub const TokenLocation: Location = Location::parent(); - pub const TokenLocationV3: xcm::v3::Location = xcm::v3::Location::parent(); pub const RelayNetwork: NetworkId = NetworkId::Rococo; pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = @@ -74,8 +73,6 @@ parameter_types! { pub TrustBackedAssetsPalletLocation: Location = PalletInstance(TrustBackedAssetsPalletIndex::get()).into(); pub TrustBackedAssetsPalletIndex: u8 = ::index() as u8; - pub TrustBackedAssetsPalletLocationV3: xcm::v3::Location = - xcm::v3::Junction::PalletInstance(::index() as u8).into(); pub ForeignAssetsPalletLocation: Location = PalletInstance(::index() as u8).into(); pub PoolAssetsPalletLocation: Location = @@ -177,7 +174,7 @@ pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConverte StartsWithExplicitGlobalConsensus, ), Balance, - xcm::v3::Location, + xcm::v4::Location, >; /// Means for transacting foreign assets from different global consensus. @@ -361,7 +358,7 @@ impl xcm_executor::Config for XcmConfig { ResolveTo, >, cumulus_primitives_utility::SwapFirstAssetTrader< - TokenLocationV3, + TokenLocation, crate::AssetConversion, WeightToFee, crate::NativeAndAssets, @@ -369,7 +366,7 @@ impl xcm_executor::Config for XcmConfig { TrustBackedAssetsAsLocation< TrustBackedAssetsPalletLocation, Balance, - xcm::v3::Location, + xcm::v4::Location, >, ForeignAssetsConvertedConcreteId, ), @@ -413,7 +410,7 @@ impl xcm_executor::Config for XcmConfig { type AssetExchanger = (); type FeeManager = XcmFeeManagerFromComponents< WaivedLocations, - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = @@ -502,9 +499,9 @@ pub type ForeignCreatorsSovereignAccountOf = ( /// Simple conversion of `u32` into an `AssetId` for use in benchmarking. pub struct XcmBenchmarkHelper; #[cfg(feature = "runtime-benchmarks")] -impl pallet_assets::BenchmarkHelper for XcmBenchmarkHelper { - fn create_asset_id_parameter(id: u32) -> xcm::v3::Location { - xcm::v3::Location::new(1, [xcm::v3::Junction::Parachain(id)]) +impl pallet_assets::BenchmarkHelper for XcmBenchmarkHelper { + fn create_asset_id_parameter(id: u32) -> xcm::v4::Location { + xcm::v4::Location::new(1, [xcm::v4::Junction::Parachain(id)]) } } 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 ee1461b7f9c85664e25dca1d02b4f248812d4219..83f4f9ec3dc5da6cde0edfec2ace179eb87c7fc1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -85,7 +85,7 @@ fn slot_durations() -> SlotDurations { fn setup_pool_for_paying_fees_with_foreign_assets( (foreign_asset_owner, foreign_asset_id_location, foreign_asset_id_minimum_balance): ( AccountId, - xcm::v3::Location, + Location, Balance, ), ) { @@ -93,7 +93,7 @@ fn setup_pool_for_paying_fees_with_foreign_assets( // setup a pool to pay fees with `foreign_asset_id_location` tokens let pool_owner: AccountId = [14u8; 32].into(); - let native_asset = xcm::v3::Location::parent(); + let native_asset = Location::parent(); let pool_liquidity: Balance = existential_deposit.max(foreign_asset_id_minimum_balance).mul(100_000); @@ -105,15 +105,15 @@ fn setup_pool_for_paying_fees_with_foreign_assets( assert_ok!(ForeignAssets::mint( RuntimeOrigin::signed(foreign_asset_owner), - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), pool_owner.clone().into(), (foreign_asset_id_minimum_balance + pool_liquidity).mul(2).into(), )); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(pool_owner.clone()), - Box::new(native_asset.into()), - Box::new(foreign_asset_id_location.into()) + Box::new(native_asset.clone().into()), + Box::new(foreign_asset_id_location.clone().into()) )); assert_ok!(AssetConversion::add_liquidity( @@ -217,24 +217,14 @@ fn test_buy_and_refund_weight_with_swap_local_asset_xcm_trader() { assert_ok!(AssetConversion::create_pool( RuntimeHelper::origin_of(bob.clone()), - Box::new( - xcm::v3::Location::try_from(native_location.clone()).expect("conversion works") - ), - Box::new( - xcm::v3::Location::try_from(asset_1_location.clone()) - .expect("conversion works") - ) + Box::new(Location::try_from(native_location.clone()).expect("conversion works")), + Box::new(Location::try_from(asset_1_location.clone()).expect("conversion works")) )); assert_ok!(AssetConversion::add_liquidity( RuntimeHelper::origin_of(bob.clone()), - Box::new( - xcm::v3::Location::try_from(native_location.clone()).expect("conversion works") - ), - Box::new( - xcm::v3::Location::try_from(asset_1_location.clone()) - .expect("conversion works") - ), + Box::new(Location::try_from(native_location.clone()).expect("conversion works")), + Box::new(Location::try_from(asset_1_location.clone()).expect("conversion works")), pool_liquidity, pool_liquidity, 1, @@ -270,8 +260,8 @@ fn test_buy_and_refund_weight_with_swap_local_asset_xcm_trader() { let refund_weight = Weight::from_parts(1_000_000_000, 0); let refund = WeightToFee::weight_to_fee(&refund_weight); let (reserve1, reserve2) = AssetConversion::get_reserves( - xcm::v3::Location::try_from(native_location).expect("conversion works"), - xcm::v3::Location::try_from(asset_1_location.clone()).expect("conversion works"), + Location::try_from(native_location).expect("conversion works"), + Location::try_from(asset_1_location.clone()).expect("conversion works"), ) .unwrap(); let asset_refund = @@ -309,14 +299,10 @@ fn test_buy_and_refund_weight_with_swap_foreign_asset_xcm_trader() { let bob: AccountId = SOME_ASSET_ADMIN.into(); let staking_pot = CollatorSelection::account_id(); let native_location = - xcm::v3::Location::try_from(TokenLocation::get()).expect("conversion works"); - let foreign_location = xcm::v3::Location { + Location::try_from(TokenLocation::get()).expect("conversion works"); + let foreign_location = Location { parents: 1, - interior: ( - xcm::v3::Junction::Parachain(1234), - xcm::v3::Junction::GeneralIndex(12345), - ) - .into(), + interior: (Junction::Parachain(1234), Junction::GeneralIndex(12345)).into(), }; // bob's initial balance for native and `asset1` assets. let initial_balance = 200 * UNITS; @@ -325,26 +311,26 @@ fn test_buy_and_refund_weight_with_swap_foreign_asset_xcm_trader() { // init asset, balances and pool. assert_ok!(>::create( - foreign_location, + foreign_location.clone(), bob.clone(), true, 10 )); - assert_ok!(ForeignAssets::mint_into(foreign_location, &bob, initial_balance)); + assert_ok!(ForeignAssets::mint_into(foreign_location.clone(), &bob, initial_balance)); assert_ok!(Balances::mint_into(&bob, initial_balance)); assert_ok!(Balances::mint_into(&staking_pot, initial_balance)); assert_ok!(AssetConversion::create_pool( RuntimeHelper::origin_of(bob.clone()), - Box::new(native_location), - Box::new(foreign_location) + Box::new(native_location.clone()), + Box::new(foreign_location.clone()) )); assert_ok!(AssetConversion::add_liquidity( RuntimeHelper::origin_of(bob.clone()), - Box::new(native_location), - Box::new(foreign_location), + Box::new(native_location.clone()), + Box::new(foreign_location.clone()), pool_liquidity, pool_liquidity, 1, @@ -353,11 +339,9 @@ fn test_buy_and_refund_weight_with_swap_foreign_asset_xcm_trader() { )); // keep initial total issuance to assert later. - let asset_total_issuance = ForeignAssets::total_issuance(foreign_location); + let asset_total_issuance = ForeignAssets::total_issuance(foreign_location.clone()); let native_total_issuance = Balances::total_issuance(); - let foreign_location_latest: Location = foreign_location.try_into().unwrap(); - // prepare input to buy weight. let weight = Weight::from_parts(4_000_000_000, 0); let fee = WeightToFee::weight_to_fee(&weight); @@ -365,7 +349,7 @@ fn test_buy_and_refund_weight_with_swap_foreign_asset_xcm_trader() { AssetConversion::get_amount_in(&fee, &pool_liquidity, &pool_liquidity).unwrap(); let extra_amount = 100; let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None }; - let payment: Asset = (foreign_location_latest.clone(), asset_fee + extra_amount).into(); + let payment: Asset = (foreign_location.clone(), asset_fee + extra_amount).into(); // init trader and buy weight. let mut trader = ::Trader::new(); @@ -373,13 +357,11 @@ fn test_buy_and_refund_weight_with_swap_foreign_asset_xcm_trader() { trader.buy_weight(weight, payment.into(), &ctx).expect("Expected Ok"); // assert. - let unused_amount = unused_asset - .fungible - .get(&foreign_location_latest.clone().into()) - .map_or(0, |a| *a); + let unused_amount = + unused_asset.fungible.get(&foreign_location.clone().into()).map_or(0, |a| *a); assert_eq!(unused_amount, extra_amount); assert_eq!( - ForeignAssets::total_issuance(foreign_location), + ForeignAssets::total_issuance(foreign_location.clone()), asset_total_issuance + asset_fee ); @@ -387,13 +369,13 @@ fn test_buy_and_refund_weight_with_swap_foreign_asset_xcm_trader() { let refund_weight = Weight::from_parts(1_000_000_000, 0); let refund = WeightToFee::weight_to_fee(&refund_weight); let (reserve1, reserve2) = - AssetConversion::get_reserves(native_location, foreign_location).unwrap(); + AssetConversion::get_reserves(native_location, foreign_location.clone()).unwrap(); let asset_refund = AssetConversion::get_amount_out(&refund, &reserve1, &reserve2).unwrap(); // refund. let actual_refund = trader.refund_weight(refund_weight, &ctx).unwrap(); - assert_eq!(actual_refund, (foreign_location_latest, asset_refund).into()); + assert_eq!(actual_refund, (foreign_location.clone(), asset_refund).into()); // assert. assert_eq!(Balances::balance(&staking_pot), initial_balance); @@ -500,17 +482,13 @@ fn test_foreign_asset_xcm_take_first_trader() { .execute_with(|| { // We need root origin to create a sufficient asset let minimum_asset_balance = 3333333_u128; - let foreign_location = xcm::v3::Location { + let foreign_location = Location { parents: 1, - interior: ( - xcm::v3::Junction::Parachain(1234), - xcm::v3::Junction::GeneralIndex(12345), - ) - .into(), + interior: (Junction::Parachain(1234), Junction::GeneralIndex(12345)).into(), }; assert_ok!(ForeignAssets::force_create( RuntimeHelper::root_origin(), - foreign_location.into(), + foreign_location.clone().into(), AccountId::from(ALICE).into(), true, minimum_asset_balance @@ -519,13 +497,11 @@ fn test_foreign_asset_xcm_take_first_trader() { // We first mint enough asset for the account to exist for assets assert_ok!(ForeignAssets::mint( RuntimeHelper::origin_of(AccountId::from(ALICE)), - foreign_location.into(), + foreign_location.clone().into(), AccountId::from(ALICE).into(), minimum_asset_balance )); - let asset_location_v4: Location = foreign_location.try_into().unwrap(); - // Set Alice as block author, who will receive fees RuntimeHelper::run_to_block(2, AccountId::from(ALICE)); @@ -535,7 +511,7 @@ fn test_foreign_asset_xcm_take_first_trader() { // Lets calculate amount needed let asset_amount_needed = ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger::charge_weight_in_fungibles( - foreign_location, + foreign_location.clone(), bought ) .expect("failed to compute"); @@ -543,7 +519,7 @@ fn test_foreign_asset_xcm_take_first_trader() { // Lets pay with: asset_amount_needed + asset_amount_extra let asset_amount_extra = 100_u128; let asset: Asset = - (asset_location_v4.clone(), asset_amount_needed + asset_amount_extra).into(); + (foreign_location.clone(), asset_amount_needed + asset_amount_extra).into(); let mut trader = ::Trader::new(); let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None }; @@ -551,16 +527,15 @@ fn test_foreign_asset_xcm_take_first_trader() { // Lets buy_weight and make sure buy_weight does not return an error let unused_assets = trader.buy_weight(bought, asset.into(), &ctx).expect("Expected Ok"); // Check whether a correct amount of unused assets is returned - assert_ok!( - unused_assets.ensure_contains(&(asset_location_v4, asset_amount_extra).into()) - ); + assert_ok!(unused_assets + .ensure_contains(&(foreign_location.clone(), asset_amount_extra).into())); // Drop trader drop(trader); // Make sure author(Alice) has received the amount assert_eq!( - ForeignAssets::balance(foreign_location, AccountId::from(ALICE)), + ForeignAssets::balance(foreign_location.clone(), AccountId::from(ALICE)), minimum_asset_balance + asset_amount_needed ); @@ -841,15 +816,13 @@ fn test_assets_balances_api_works() { .build() .execute_with(|| { let local_asset_id = 1; - let foreign_asset_id_location = xcm::v3::Location::new( - 1, - [xcm::v3::Junction::Parachain(1234), xcm::v3::Junction::GeneralIndex(12345)], - ); + let foreign_asset_id_location = + Location::new(1, [Junction::Parachain(1234), Junction::GeneralIndex(12345)]); // check before assert_eq!(Assets::balance(local_asset_id, AccountId::from(ALICE)), 0); assert_eq!( - ForeignAssets::balance(foreign_asset_id_location, AccountId::from(ALICE)), + ForeignAssets::balance(foreign_asset_id_location.clone(), AccountId::from(ALICE)), 0 ); assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 0); @@ -886,7 +859,7 @@ fn test_assets_balances_api_works() { let foreign_asset_minimum_asset_balance = 3333333_u128; assert_ok!(ForeignAssets::force_create( RuntimeHelper::root_origin(), - foreign_asset_id_location, + foreign_asset_id_location.clone(), AccountId::from(SOME_ASSET_ADMIN).into(), false, foreign_asset_minimum_asset_balance @@ -895,7 +868,7 @@ fn test_assets_balances_api_works() { // We first mint enough asset for the account to exist for assets assert_ok!(ForeignAssets::mint( RuntimeHelper::origin_of(AccountId::from(SOME_ASSET_ADMIN)), - foreign_asset_id_location, + foreign_asset_id_location.clone(), AccountId::from(ALICE).into(), 6 * foreign_asset_minimum_asset_balance )); @@ -906,7 +879,7 @@ fn test_assets_balances_api_works() { minimum_asset_balance ); assert_eq!( - ForeignAssets::balance(foreign_asset_id_location, AccountId::from(ALICE)), + ForeignAssets::balance(foreign_asset_id_location.clone(), AccountId::from(ALICE)), 6 * minimum_asset_balance ); assert_eq!(Balances::free_balance(AccountId::from(ALICE)), some_currency); @@ -932,10 +905,8 @@ fn test_assets_balances_api_works() { .into()))); // check foreign asset assert!(result.inner().iter().any(|asset| asset.eq(&( - WithLatestLocationConverter::::convert_back( - &foreign_asset_id_location - ) - .unwrap(), + WithLatestLocationConverter::::convert_back(&foreign_asset_id_location) + .unwrap(), 6 * foreign_asset_minimum_asset_balance ) .into()))); @@ -1025,14 +996,11 @@ asset_test_utils::include_asset_transactor_transfer_with_pallet_assets_instance_ Runtime, XcmConfig, ForeignAssetsInstance, - xcm::v3::Location, + Location, JustTry, collator_session_keys(), ExistentialDeposit::get(), - xcm::v3::Location::new( - 1, - [xcm::v3::Junction::Parachain(1313), xcm::v3::Junction::GeneralIndex(12345)] - ), + Location::new(1, [Junction::Parachain(1313), Junction::GeneralIndex(12345)]), Box::new(|| { assert!(Assets::asset_ids().collect::>().is_empty()); }), @@ -1047,8 +1015,8 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p WeightToFee, ForeignCreatorsSovereignAccountOf, ForeignAssetsInstance, - xcm::v3::Location, - WithLatestLocationConverter, + Location, + WithLatestLocationConverter, collator_session_keys(), ExistentialDeposit::get(), AssetDeposit::get(), @@ -1138,16 +1106,17 @@ mod asset_hub_rococo_tests { let block_author_account = AccountId::from(BLOCK_AUTHOR_ACCOUNT); let staking_pot = StakingPot::get(); - let foreign_asset_id_location = xcm::v3::Location::new( - 2, - [xcm::v3::Junction::GlobalConsensus(xcm::v3::NetworkId::Westend)], - ); + let foreign_asset_id_location = + Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]); let foreign_asset_id_minimum_balance = 1_000_000_000; // sovereign account as foreign asset owner (can be whoever for this scenario) let foreign_asset_owner = LocationToAccountId::convert_location(&Location::parent()).unwrap(); - let foreign_asset_create_params = - (foreign_asset_owner, foreign_asset_id_location, foreign_asset_id_minimum_balance); + let foreign_asset_create_params = ( + foreign_asset_owner, + foreign_asset_id_location.clone(), + foreign_asset_id_minimum_balance, + ); asset_test_utils::test_cases_over_bridge::receive_reserve_asset_deposited_from_different_consensus_works::< Runtime, @@ -1181,7 +1150,7 @@ mod asset_hub_rococo_tests { // check now foreign asset for staking pot assert_eq!( ForeignAssets::balance( - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), &staking_pot ), 0 @@ -1195,7 +1164,7 @@ mod asset_hub_rococo_tests { // staking pot receives no foreign assets assert_eq!( ForeignAssets::balance( - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), &staking_pot ), 0 @@ -1211,16 +1180,17 @@ mod asset_hub_rococo_tests { let block_author_account = AccountId::from(BLOCK_AUTHOR_ACCOUNT); let staking_pot = StakingPot::get(); - let foreign_asset_id_location = xcm::v3::Location::new( - 2, - [xcm::v3::Junction::GlobalConsensus(xcm::v3::NetworkId::Westend)], - ); + let foreign_asset_id_location = + Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]); let foreign_asset_id_minimum_balance = 1_000_000_000; // sovereign account as foreign asset owner (can be whoever for this scenario) let foreign_asset_owner = LocationToAccountId::convert_location(&Location::parent()).unwrap(); - let foreign_asset_create_params = - (foreign_asset_owner, foreign_asset_id_location, foreign_asset_id_minimum_balance); + let foreign_asset_create_params = ( + foreign_asset_owner, + foreign_asset_id_location.clone(), + foreign_asset_id_minimum_balance, + ); asset_test_utils::test_cases_over_bridge::receive_reserve_asset_deposited_from_different_consensus_works::< Runtime, @@ -1245,7 +1215,7 @@ mod asset_hub_rococo_tests { // check block author before assert_eq!( ForeignAssets::balance( - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), &block_author_account ), 0 @@ -1255,7 +1225,7 @@ mod asset_hub_rococo_tests { // `TakeFirstAssetTrader` puts fees to the block author assert!( ForeignAssets::balance( - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), &block_author_account ) > 0 ); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 6b1bf769ace3511cc91cb1b557d4a7d5a754fd92..2f244a07e8f13a4ac467fb7394e3afaab6ce5b8b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -53,6 +53,7 @@ sp-inherents = { 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 } @@ -93,6 +94,7 @@ 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 = { workspace = true, default-features = true } @@ -134,6 +136,7 @@ runtime-benchmarks = [ "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", + "snowbridge-router-primitives/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", @@ -230,6 +233,7 @@ std = [ "polkadot-runtime-common/std", "primitive-types/std", "scale-info/std", + "snowbridge-router-primitives/std", "sp-api/std", "sp-block-builder/std", "sp-consensus-aura/std", @@ -239,6 +243,7 @@ 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/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 178b886fc3e84b741eb6721fec1b4e493626795b..ebbc000d1413883037ccab3048a36c0f8a2b8ec3 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -55,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::{ @@ -74,18 +74,22 @@ use sp_runtime::{ #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use testnet_parachains_constants::westend::{consensus::*, currency::*, fee::WeightToFee, time::*}; +use testnet_parachains_constants::westend::{ + consensus::*, currency::*, fee::WeightToFee, snowbridge::EthereumNetwork, time::*, +}; use xcm_config::{ ForeignAssetsConvertedConcreteId, ForeignCreatorsSovereignAccountOf, PoolAssetsConvertedConcreteId, TrustBackedAssetsConvertedConcreteId, - TrustBackedAssetsPalletLocationV3, WestendLocation, WestendLocationV3, - XcmOriginToTransactDispatchOrigin, + TrustBackedAssetsPalletLocation, WestendLocation, XcmOriginToTransactDispatchOrigin, }; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; -use assets_common::{foreign_creators::ForeignCreators, matching::FromSiblingParachain}; +use assets_common::{ + foreign_creators::ForeignCreators, + matching::{FromNetwork, FromSiblingParachain}, +}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use xcm::{ latest::prelude::AssetId, @@ -119,7 +123,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westmint"), impl_name: create_runtime_str!("westmint"), authoring_version: 1, - spec_version: 1_014_000, + spec_version: 1_015_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 16, @@ -321,11 +325,11 @@ pub type LocalAndForeignAssets = fungibles::UnionOf< Assets, ForeignAssets, LocalFromLeft< - AssetIdForTrustBackedAssetsConvert, + AssetIdForTrustBackedAssetsConvert, AssetIdForTrustBackedAssets, - xcm::v3::Location, + xcm::v4::Location, >, - xcm::v3::Location, + xcm::v4::Location, AccountId, >; @@ -333,25 +337,25 @@ pub type LocalAndForeignAssets = fungibles::UnionOf< pub type NativeAndAssets = fungible::UnionOf< Balances, LocalAndForeignAssets, - TargetFromLeft, - xcm::v3::Location, + TargetFromLeft, + xcm::v4::Location, AccountId, >; pub type PoolIdToAccountId = pallet_asset_conversion::AccountIdConverter< AssetConversionPalletId, - (xcm::v3::Location, xcm::v3::Location), + (xcm::v4::Location, xcm::v4::Location), >; impl pallet_asset_conversion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; type HigherPrecisionBalance = sp_core::U256; - type AssetKind = xcm::v3::Location; + type AssetKind = xcm::v4::Location; type Assets = NativeAndAssets; type PoolId = (Self::AssetKind, Self::AssetKind); type PoolLocator = pallet_asset_conversion::WithFirstAsset< - WestendLocationV3, + WestendLocation, AccountId, Self::AssetKind, PoolIdToAccountId, @@ -359,7 +363,7 @@ impl pallet_asset_conversion::Config for Runtime { type PoolAssetId = u32; type PoolAssets = PoolAssets; type PoolSetupFee = ConstU128<0>; // Asset class deposit fees are sufficient to prevent spam - type PoolSetupFeeAsset = WestendLocationV3; + type PoolSetupFeeAsset = WestendLocation; type PoolSetupFeeTarget = ResolveAssetTo; type LiquidityWithdrawalFee = LiquidityWithdrawalFee; type LPFee = ConstU32<3>; @@ -369,10 +373,10 @@ impl pallet_asset_conversion::Config for Runtime { type WeightInfo = weights::pallet_asset_conversion::WeightInfo; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = assets_common::benchmarks::AssetPairFactory< - WestendLocationV3, + WestendLocation, parachain_info::Pallet, xcm_config::TrustBackedAssetsPalletIndex, - xcm::v3::Location, + xcm::v4::Location, >; } @@ -406,14 +410,17 @@ pub type ForeignAssetsInstance = pallet_assets::Instance2; impl pallet_assets::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; - type AssetId = xcm::v3::Location; - type AssetIdParameter = xcm::v3::Location; + type AssetId = xcm::v4::Location; + type AssetIdParameter = xcm::v4::Location; type Currency = Balances; type CreateOrigin = ForeignCreators< - FromSiblingParachain, xcm::v3::Location>, + ( + FromSiblingParachain, xcm::v4::Location>, + FromNetwork, + ), ForeignCreatorsSovereignAccountOf, AccountId, - xcm::v3::Location, + xcm::v4::Location, >; type ForceOrigin = AssetsForceOrigin; type AssetDeposit = ForeignAssetsAssetDeposit; @@ -787,11 +794,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::v4::Location; + type OnChargeAssetTransaction = SwapAssetAdapter< + WestendLocation, + NativeAndAssets, + AssetConversion, + ResolveAssetTo, + >; } parameter_types! { @@ -1315,18 +1330,18 @@ impl_runtime_apis! { impl pallet_asset_conversion::AssetConversionApi< Block, Balance, - xcm::v3::Location, + xcm::v4::Location, > for Runtime { - fn quote_price_exact_tokens_for_tokens(asset1: xcm::v3::Location, asset2: xcm::v3::Location, amount: Balance, include_fee: bool) -> Option { + fn quote_price_exact_tokens_for_tokens(asset1: xcm::v4::Location, asset2: xcm::v4::Location, amount: Balance, include_fee: bool) -> Option { AssetConversion::quote_price_exact_tokens_for_tokens(asset1, asset2, amount, include_fee) } - fn quote_price_tokens_for_exact_tokens(asset1: xcm::v3::Location, asset2: xcm::v3::Location, amount: Balance, include_fee: bool) -> Option { + fn quote_price_tokens_for_exact_tokens(asset1: xcm::v4::Location, asset2: xcm::v4::Location, amount: Balance, include_fee: bool) -> Option { AssetConversion::quote_price_tokens_for_exact_tokens(asset1, asset2, amount, include_fee) } - fn get_reserves(asset1: xcm::v3::Location, asset2: xcm::v3::Location) -> Option<(Balance, Balance)> { + fn get_reserves(asset1: xcm::v4::Location, asset2: xcm::v4::Location) -> Option<(Balance, Balance)> { AssetConversion::get_reserves(asset1, asset2).ok() } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_foreign.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_foreign.rs index 52ba2fd6c40fcfea552b181bcb05cfecab75f6b4..2692de9aeb50daf5085cba094406b63d6a95c829 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_foreign.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_foreign.rs @@ -537,4 +537,14 @@ impl pallet_assets::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } + + fn transfer_all() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 46_573_000 picoseconds. + Weight::from_parts(47_385_000, 3593) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_local.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_local.rs index e78366b91cbe8100c2a46c47a8708c3f1aed918d..d2e12549a45c705882a5233d1e4a0825ada8b1eb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_local.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_local.rs @@ -535,4 +535,14 @@ impl pallet_assets::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } + + fn transfer_all() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 46_573_000 picoseconds. + Weight::from_parts(47_385_000, 3593) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_pool.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_pool.rs index 65cae81069c40f7369d31d8411bf882521b71e11..8368f6e583ccf147a7fb9cf0eb9b9ba04b98da3b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_pool.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_pool.rs @@ -529,4 +529,14 @@ impl pallet_assets::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } + + fn transfer_all() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 46_573_000 picoseconds. + Weight::from_parts(47_385_000, 3593) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } 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 fe8d186139256fbaac3989e0c56fb3acc494d63e..f7891aedc496d188bcf4bab06c68b8d3d3373b52 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 @@ -1,24 +1,25 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// 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. +// 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 . //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-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: @@ -53,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 20_295_000 picoseconds. - Weight::from_parts(21_142_000, 3593) + // Minimum execution time: 32_612_000 picoseconds. + Weight::from_parts(33_359_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -64,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 42_356_000 picoseconds. - Weight::from_parts(43_552_000, 6196) + // Minimum execution time: 41_144_000 picoseconds. + Weight::from_parts(41_788_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -89,20 +90,17 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `8799` - // Minimum execution time: 85_553_000 picoseconds. - Weight::from_parts(87_177_000, 8799) + // Minimum execution time: 101_340_000 picoseconds. + Weight::from_parts(103_686_000, 8799) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } - // Storage: `ParachainInfo::ParachainId` (r:1 w:0) - // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) pub fn reserve_asset_deposited() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `1489` - // Minimum execution time: 6_166_000 picoseconds. - Weight::from_parts(6_352_000, 1489) - .saturating_add(T::DbWeight::get().reads(1)) + // Estimated: `0` + // Minimum execution time: 1_682_000 picoseconds. + Weight::from_parts(1_734_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -124,8 +122,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 184_462_000 picoseconds. - Weight::from_parts(189_593_000, 6196) + // Minimum execution time: 107_335_000 picoseconds. + Weight::from_parts(109_665_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -133,8 +131,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_018_000 picoseconds. - Weight::from_parts(3_098_000, 0) + // Minimum execution time: 3_345_000 picoseconds. + Weight::from_parts(3_548_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -142,13 +140,11 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 18_583_000 picoseconds. - Weight::from_parts(19_057_000, 3593) + // Minimum execution time: 25_560_000 picoseconds. + Weight::from_parts(26_779_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: `System::Account` (r:2 w:2) - // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -159,6 +155,8 @@ impl WeightInfo { // 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: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // 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) @@ -167,8 +165,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `6196` - // Minimum execution time: 56_666_000 picoseconds. - Weight::from_parts(58_152_000, 6196) + // Minimum execution time: 84_453_000 picoseconds. + Weight::from_parts(86_755_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -192,8 +190,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 44_197_000 picoseconds. - Weight::from_parts(45_573_000, 3610) + // Minimum execution time: 50_463_000 picoseconds. + Weight::from_parts(51_587_000, 3610) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } 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 2deeb73eb127b8d9dd262e961703c66915a6c6f6..d61381d3f50b7c5379c71716f60addd6333adb8e 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 @@ -42,6 +42,7 @@ use parachains_common::{ }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; +use snowbridge_router_primitives::inbound::GlobalConsensusEthereumConvertsFor; use sp_runtime::traits::{AccountIdConversion, ConvertInto}; use xcm::latest::prelude::*; use xcm_builder::{ @@ -51,17 +52,16 @@ use xcm_builder::{ EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint, NetworkExportTableItem, NoChecking, NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset, - RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith, - StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, - XcmFeeToAccount, + RelayChainAsNative, SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignPaidRemoteExporter, + SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; parameter_types! { pub const WestendLocation: Location = Location::parent(); - pub const WestendLocationV3: xcm::v3::Location = xcm::v3::Location::parent(); pub const RelayNetwork: Option = Some(NetworkId::Westend); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = @@ -70,8 +70,6 @@ parameter_types! { pub TrustBackedAssetsPalletLocation: Location = PalletInstance(TrustBackedAssetsPalletIndex::get()).into(); pub TrustBackedAssetsPalletIndex: u8 = ::index() as u8; - pub TrustBackedAssetsPalletLocationV3: xcm::v3::Location = - xcm::v3::Junction::PalletInstance(::index() as u8).into(); pub ForeignAssetsPalletLocation: Location = PalletInstance(::index() as u8).into(); pub PoolAssetsPalletLocation: Location = @@ -100,6 +98,9 @@ pub type LocationToAccountId = ( // Different global consensus parachain sovereign account. // (Used for over-bridge transfers and reserve processing) GlobalConsensusParachainConvertsFor, + // Ethereum contract sovereign account. + // (Used to get convert ethereum contract locations to sovereign account) + GlobalConsensusEthereumConvertsFor, ); /// Means for transacting the native currency on this chain. @@ -170,7 +171,7 @@ pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConverte StartsWithExplicitGlobalConsensus, ), Balance, - xcm::v3::Location, + xcm::v4::Location, >; /// Means for transacting foreign assets from different global consensus. @@ -359,7 +360,10 @@ impl xcm_executor::Config for XcmConfig { // as reserve locations (we trust the Bridge Hub to relay the message that a reserve is being // 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 IsReserve = ( + bridging::to_rococo::RococoOrEthereumAssetFromAssetHubRococo, + bridging::to_ethereum::IsTrustedBridgedReserveLocationForForeignAsset, + ); type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; @@ -377,7 +381,7 @@ impl xcm_executor::Config for XcmConfig { ResolveTo, >, cumulus_primitives_utility::SwapFirstAssetTrader< - WestendLocationV3, + WestendLocation, crate::AssetConversion, WeightToFee, crate::NativeAndAssets, @@ -385,7 +389,7 @@ impl xcm_executor::Config for XcmConfig { TrustBackedAssetsAsLocation< TrustBackedAssetsPalletLocation, Balance, - xcm::v3::Location, + xcm::v4::Location, >, ForeignAssetsConvertedConcreteId, ), @@ -429,10 +433,11 @@ impl xcm_executor::Config for XcmConfig { type AssetExchanger = (); type FeeManager = XcmFeeManagerFromComponents< WaivedLocations, - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (); - type UniversalAliases = (bridging::to_rococo::UniversalAliases,); + type UniversalAliases = + (bridging::to_rococo::UniversalAliases, bridging::to_ethereum::UniversalAliases); type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; type Aliasers = Nothing; @@ -464,6 +469,13 @@ pub type XcmRouter = WithUniqueTopic<( // Router which wraps and sends xcm to BridgeHub to be delivered to the Rococo // GlobalConsensus ToRococoXcmRouter, + // Router which wraps and sends xcm to BridgeHub to be delivered to the Ethereum + // GlobalConsensus + SovereignPaidRemoteExporter< + bridging::to_ethereum::EthereumNetworkExportTable, + XcmpQueue, + UniversalLocation, + >, )>; impl pallet_xcm::Config for Runtime { @@ -505,14 +517,15 @@ pub type ForeignCreatorsSovereignAccountOf = ( SiblingParachainConvertsVia, AccountId32Aliases, ParentIsPreset, + GlobalConsensusEthereumConvertsFor, ); /// Simple conversion of `u32` into an `AssetId` for use in benchmarking. pub struct XcmBenchmarkHelper; #[cfg(feature = "runtime-benchmarks")] -impl pallet_assets::BenchmarkHelper for XcmBenchmarkHelper { - fn create_asset_id_parameter(id: u32) -> xcm::v3::Location { - xcm::v3::Location::new(1, [xcm::v3::Junction::Parachain(id)]) +impl pallet_assets::BenchmarkHelper for XcmBenchmarkHelper { + fn create_asset_id_parameter(id: u32) -> xcm::v4::Location { + xcm::v4::Location::new(1, [xcm::v4::Junction::Parachain(id)]) } } @@ -628,6 +641,67 @@ pub mod bridging { } } + pub mod to_ethereum { + use super::*; + use assets_common::matching::FromNetwork; + use sp_std::collections::btree_set::BTreeSet; + use testnet_parachains_constants::westend::snowbridge::{ + EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX, + }; + + parameter_types! { + /// User fee for ERC20 token transfer back to Ethereum. + /// (initially was calculated by test `OutboundQueue::calculate_fees` - ETH/WND 1/400 and fee_per_gas 20 GWEI = 2200698000000 + *25%) + /// Needs to be more than fee calculated from DefaultFeeConfig FeeConfigRecord in snowbridge:parachain/pallets/outbound-queue/src/lib.rs + /// Polkadot uses 10 decimals, Kusama,Rococo,Westend 12 decimals. + pub const DefaultBridgeHubEthereumBaseFee: Balance = 2_750_872_500_000; + pub storage BridgeHubEthereumBaseFee: Balance = DefaultBridgeHubEthereumBaseFee::get(); + pub SiblingBridgeHubWithEthereumInboundQueueInstance: Location = Location::new( + 1, + [ + Parachain(SiblingBridgeHubParaId::get()), + PalletInstance(INBOUND_QUEUE_PALLET_INDEX) + ] + ); + + /// 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![ + NetworkExportTableItem::new( + EthereumNetwork::get(), + Some(sp_std::vec![Junctions::Here]), + SiblingBridgeHub::get(), + Some(( + XcmBridgeHubRouterFeeAssetId::get(), + BridgeHubEthereumBaseFee::get(), + ).into()) + ), + ]; + + /// Universal aliases + pub UniversalAliases: BTreeSet<(Location, Junction)> = BTreeSet::from_iter( + sp_std::vec![ + (SiblingBridgeHubWithEthereumInboundQueueInstance::get(), GlobalConsensus(EthereumNetwork::get())), + ] + ); + + pub EthereumBridgeTable: sp_std::vec::Vec = sp_std::vec::Vec::new().into_iter() + .chain(BridgeTable::get()) + .collect(); + } + + pub type EthereumNetworkExportTable = xcm_builder::NetworkExportTable; + + pub type IsTrustedBridgedReserveLocationForForeignAsset = + IsForeignConcreteAsset>; + + impl Contains<(Location, Junction)> for UniversalAliases { + fn contains(alias: &(Location, Junction)) -> bool { + UniversalAliases::get().contains(alias) + } + } + } + /// Benchmarks helper for bridging configuration. #[cfg(feature = "runtime-benchmarks")] pub struct BridgingBenchmarksHelper; 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 48e6c11d268c7c2e915c3ce4c0213ede2c883911..1c334d6f84f82fa8c045b05792fa452bc14be680 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -86,7 +86,7 @@ fn slot_durations() -> SlotDurations { fn setup_pool_for_paying_fees_with_foreign_assets( (foreign_asset_owner, foreign_asset_id_location, foreign_asset_id_minimum_balance): ( AccountId, - xcm::v3::Location, + xcm::v4::Location, Balance, ), ) { @@ -94,7 +94,7 @@ fn setup_pool_for_paying_fees_with_foreign_assets( // setup a pool to pay fees with `foreign_asset_id_location` tokens let pool_owner: AccountId = [14u8; 32].into(); - let native_asset = xcm::v3::Location::parent(); + let native_asset = xcm::v4::Location::parent(); let pool_liquidity: Balance = existential_deposit.max(foreign_asset_id_minimum_balance).mul(100_000); @@ -106,15 +106,15 @@ fn setup_pool_for_paying_fees_with_foreign_assets( assert_ok!(ForeignAssets::mint( RuntimeOrigin::signed(foreign_asset_owner), - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), pool_owner.clone().into(), (foreign_asset_id_minimum_balance + pool_liquidity).mul(2).into(), )); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(pool_owner.clone()), - Box::new(native_asset.into()), - Box::new(foreign_asset_id_location.into()) + Box::new(native_asset.clone().into()), + Box::new(foreign_asset_id_location.clone().into()) )); assert_ok!(AssetConversion::add_liquidity( @@ -219,10 +219,10 @@ fn test_buy_and_refund_weight_with_swap_local_asset_xcm_trader() { assert_ok!(AssetConversion::create_pool( RuntimeHelper::origin_of(bob.clone()), Box::new( - xcm::v3::Location::try_from(native_location.clone()).expect("conversion works") + xcm::v4::Location::try_from(native_location.clone()).expect("conversion works") ), Box::new( - xcm::v3::Location::try_from(asset_1_location.clone()) + xcm::v4::Location::try_from(asset_1_location.clone()) .expect("conversion works") ) )); @@ -230,10 +230,10 @@ fn test_buy_and_refund_weight_with_swap_local_asset_xcm_trader() { assert_ok!(AssetConversion::add_liquidity( RuntimeHelper::origin_of(bob.clone()), Box::new( - xcm::v3::Location::try_from(native_location.clone()).expect("conversion works") + xcm::v4::Location::try_from(native_location.clone()).expect("conversion works") ), Box::new( - xcm::v3::Location::try_from(asset_1_location.clone()) + xcm::v4::Location::try_from(asset_1_location.clone()) .expect("conversion works") ), pool_liquidity, @@ -271,8 +271,8 @@ fn test_buy_and_refund_weight_with_swap_local_asset_xcm_trader() { let refund_weight = Weight::from_parts(1_000_000_000, 0); let refund = WeightToFee::weight_to_fee(&refund_weight); let (reserve1, reserve2) = AssetConversion::get_reserves( - xcm::v3::Location::try_from(native_location).expect("conversion works"), - xcm::v3::Location::try_from(asset_1_location.clone()).expect("conversion works"), + xcm::v4::Location::try_from(native_location).expect("conversion works"), + xcm::v4::Location::try_from(asset_1_location.clone()).expect("conversion works"), ) .unwrap(); let asset_refund = @@ -310,12 +310,12 @@ fn test_buy_and_refund_weight_with_swap_foreign_asset_xcm_trader() { let bob: AccountId = SOME_ASSET_ADMIN.into(); let staking_pot = CollatorSelection::account_id(); let native_location = - xcm::v3::Location::try_from(WestendLocation::get()).expect("conversion works"); - let foreign_location = xcm::v3::Location { + xcm::v4::Location::try_from(WestendLocation::get()).expect("conversion works"); + let foreign_location = xcm::v4::Location { parents: 1, interior: ( - xcm::v3::Junction::Parachain(1234), - xcm::v3::Junction::GeneralIndex(12345), + xcm::v4::Junction::Parachain(1234), + xcm::v4::Junction::GeneralIndex(12345), ) .into(), }; @@ -326,26 +326,26 @@ fn test_buy_and_refund_weight_with_swap_foreign_asset_xcm_trader() { // init asset, balances and pool. assert_ok!(>::create( - foreign_location, + foreign_location.clone(), bob.clone(), true, 10 )); - assert_ok!(ForeignAssets::mint_into(foreign_location, &bob, initial_balance)); + assert_ok!(ForeignAssets::mint_into(foreign_location.clone(), &bob, initial_balance)); assert_ok!(Balances::mint_into(&bob, initial_balance)); assert_ok!(Balances::mint_into(&staking_pot, initial_balance)); assert_ok!(AssetConversion::create_pool( RuntimeHelper::origin_of(bob.clone()), - Box::new(native_location), - Box::new(foreign_location) + Box::new(native_location.clone()), + Box::new(foreign_location.clone()) )); assert_ok!(AssetConversion::add_liquidity( RuntimeHelper::origin_of(bob.clone()), - Box::new(native_location), - Box::new(foreign_location), + Box::new(native_location.clone()), + Box::new(foreign_location.clone()), pool_liquidity, pool_liquidity, 1, @@ -354,11 +354,9 @@ fn test_buy_and_refund_weight_with_swap_foreign_asset_xcm_trader() { )); // keep initial total issuance to assert later. - let asset_total_issuance = ForeignAssets::total_issuance(foreign_location); + let asset_total_issuance = ForeignAssets::total_issuance(foreign_location.clone()); let native_total_issuance = Balances::total_issuance(); - let foreign_location_latest: Location = foreign_location.try_into().unwrap(); - // prepare input to buy weight. let weight = Weight::from_parts(4_000_000_000, 0); let fee = WeightToFee::weight_to_fee(&weight); @@ -366,7 +364,7 @@ fn test_buy_and_refund_weight_with_swap_foreign_asset_xcm_trader() { AssetConversion::get_amount_in(&fee, &pool_liquidity, &pool_liquidity).unwrap(); let extra_amount = 100; let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None }; - let payment: Asset = (foreign_location_latest.clone(), asset_fee + extra_amount).into(); + let payment: Asset = (foreign_location.clone(), asset_fee + extra_amount).into(); // init trader and buy weight. let mut trader = ::Trader::new(); @@ -374,13 +372,11 @@ fn test_buy_and_refund_weight_with_swap_foreign_asset_xcm_trader() { trader.buy_weight(weight, payment.into(), &ctx).expect("Expected Ok"); // assert. - let unused_amount = unused_asset - .fungible - .get(&foreign_location_latest.clone().into()) - .map_or(0, |a| *a); + let unused_amount = + unused_asset.fungible.get(&foreign_location.clone().into()).map_or(0, |a| *a); assert_eq!(unused_amount, extra_amount); assert_eq!( - ForeignAssets::total_issuance(foreign_location), + ForeignAssets::total_issuance(foreign_location.clone()), asset_total_issuance + asset_fee ); @@ -388,13 +384,13 @@ fn test_buy_and_refund_weight_with_swap_foreign_asset_xcm_trader() { let refund_weight = Weight::from_parts(1_000_000_000, 0); let refund = WeightToFee::weight_to_fee(&refund_weight); let (reserve1, reserve2) = - AssetConversion::get_reserves(native_location, foreign_location).unwrap(); + AssetConversion::get_reserves(native_location, foreign_location.clone()).unwrap(); let asset_refund = AssetConversion::get_amount_out(&refund, &reserve1, &reserve2).unwrap(); // refund. let actual_refund = trader.refund_weight(refund_weight, &ctx).unwrap(); - assert_eq!(actual_refund, (foreign_location_latest, asset_refund).into()); + assert_eq!(actual_refund, (foreign_location.clone(), asset_refund).into()); // assert. assert_eq!(Balances::balance(&staking_pot), initial_balance); @@ -501,17 +497,17 @@ fn test_foreign_asset_xcm_take_first_trader() { .execute_with(|| { // We need root origin to create a sufficient asset let minimum_asset_balance = 3333333_u128; - let foreign_location = xcm::v3::Location { + let foreign_location = xcm::v4::Location { parents: 1, interior: ( - xcm::v3::Junction::Parachain(1234), - xcm::v3::Junction::GeneralIndex(12345), + xcm::v4::Junction::Parachain(1234), + xcm::v4::Junction::GeneralIndex(12345), ) .into(), }; assert_ok!(ForeignAssets::force_create( RuntimeHelper::root_origin(), - foreign_location.into(), + foreign_location.clone().into(), AccountId::from(ALICE).into(), true, minimum_asset_balance @@ -520,12 +516,12 @@ fn test_foreign_asset_xcm_take_first_trader() { // We first mint enough asset for the account to exist for assets assert_ok!(ForeignAssets::mint( RuntimeHelper::origin_of(AccountId::from(ALICE)), - foreign_location.into(), + foreign_location.clone().into(), AccountId::from(ALICE).into(), minimum_asset_balance )); - let asset_location_v4: Location = foreign_location.try_into().unwrap(); + let asset_location_v4: Location = foreign_location.clone().try_into().unwrap(); // Set Alice as block author, who will receive fees RuntimeHelper::run_to_block(2, AccountId::from(ALICE)); @@ -534,7 +530,7 @@ fn test_foreign_asset_xcm_take_first_trader() { let bought = Weight::from_parts(4_000_000_000u64, 0); // Lets calculate amount needed - let asset_amount_needed = ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger::charge_weight_in_fungibles(foreign_location, bought) + let asset_amount_needed = ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger::charge_weight_in_fungibles(foreign_location.clone(), bought) .expect("failed to compute"); // Lets pay with: asset_amount_needed + asset_amount_extra @@ -557,7 +553,7 @@ fn test_foreign_asset_xcm_take_first_trader() { // Make sure author(Alice) has received the amount assert_eq!( - ForeignAssets::balance(foreign_location, AccountId::from(ALICE)), + ForeignAssets::balance(foreign_location.clone(), AccountId::from(ALICE)), minimum_asset_balance + asset_amount_needed ); @@ -837,11 +833,11 @@ fn test_assets_balances_api_works() { .build() .execute_with(|| { let local_asset_id = 1; - let foreign_asset_id_location = xcm::v3::Location { + let foreign_asset_id_location = xcm::v4::Location { parents: 1, interior: [ - xcm::v3::Junction::Parachain(1234), - xcm::v3::Junction::GeneralIndex(12345), + xcm::v4::Junction::Parachain(1234), + xcm::v4::Junction::GeneralIndex(12345), ] .into(), }; @@ -849,7 +845,7 @@ fn test_assets_balances_api_works() { // check before assert_eq!(Assets::balance(local_asset_id, AccountId::from(ALICE)), 0); assert_eq!( - ForeignAssets::balance(foreign_asset_id_location, AccountId::from(ALICE)), + ForeignAssets::balance(foreign_asset_id_location.clone(), AccountId::from(ALICE)), 0 ); assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 0); @@ -886,7 +882,7 @@ fn test_assets_balances_api_works() { let foreign_asset_minimum_asset_balance = 3333333_u128; assert_ok!(ForeignAssets::force_create( RuntimeHelper::root_origin(), - foreign_asset_id_location, + foreign_asset_id_location.clone(), AccountId::from(SOME_ASSET_ADMIN).into(), false, foreign_asset_minimum_asset_balance @@ -895,7 +891,7 @@ fn test_assets_balances_api_works() { // We first mint enough asset for the account to exist for assets assert_ok!(ForeignAssets::mint( RuntimeHelper::origin_of(AccountId::from(SOME_ASSET_ADMIN)), - foreign_asset_id_location, + foreign_asset_id_location.clone(), AccountId::from(ALICE).into(), 6 * foreign_asset_minimum_asset_balance )); @@ -906,7 +902,7 @@ fn test_assets_balances_api_works() { minimum_asset_balance ); assert_eq!( - ForeignAssets::balance(foreign_asset_id_location, AccountId::from(ALICE)), + ForeignAssets::balance(foreign_asset_id_location.clone(), AccountId::from(ALICE)), 6 * minimum_asset_balance ); assert_eq!(Balances::free_balance(AccountId::from(ALICE)), some_currency); @@ -932,7 +928,7 @@ fn test_assets_balances_api_works() { .into()))); // check foreign asset assert!(result.inner().iter().any(|asset| asset.eq(&( - WithLatestLocationConverter::::convert_back( + WithLatestLocationConverter::::convert_back( &foreign_asset_id_location ) .unwrap(), @@ -1025,13 +1021,13 @@ asset_test_utils::include_asset_transactor_transfer_with_pallet_assets_instance_ Runtime, XcmConfig, ForeignAssetsInstance, - xcm::v3::Location, + xcm::v4::Location, JustTry, collator_session_keys(), ExistentialDeposit::get(), - xcm::v3::Location { + xcm::v4::Location { parents: 1, - interior: [xcm::v3::Junction::Parachain(1313), xcm::v3::Junction::GeneralIndex(12345)] + interior: [xcm::v4::Junction::Parachain(1313), xcm::v4::Junction::GeneralIndex(12345)] .into() }, Box::new(|| { @@ -1048,8 +1044,8 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p WeightToFee, ForeignCreatorsSovereignAccountOf, ForeignAssetsInstance, - xcm::v3::Location, - WithLatestLocationConverter, + xcm::v4::Location, + WithLatestLocationConverter, collator_session_keys(), ExistentialDeposit::get(), AssetDeposit::get(), @@ -1127,12 +1123,12 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_pool_s let staking_pot = StakingPot::get(); let foreign_asset_id_location = - xcm::v3::Location::new(2, [xcm::v3::Junction::GlobalConsensus(xcm::v3::NetworkId::Rococo)]); + xcm::v4::Location::new(2, [xcm::v4::Junction::GlobalConsensus(xcm::v4::NetworkId::Rococo)]); let foreign_asset_id_minimum_balance = 1_000_000_000; // sovereign account as foreign asset owner (can be whoever for this scenario) let foreign_asset_owner = LocationToAccountId::convert_location(&Location::parent()).unwrap(); let foreign_asset_create_params = - (foreign_asset_owner, foreign_asset_id_location, foreign_asset_id_minimum_balance); + (foreign_asset_owner, foreign_asset_id_location.clone(), foreign_asset_id_minimum_balance); asset_test_utils::test_cases_over_bridge::receive_reserve_asset_deposited_from_different_consensus_works::< Runtime, @@ -1166,7 +1162,7 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_pool_s // check now foreign asset for staking pot assert_eq!( ForeignAssets::balance( - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), &staking_pot ), 0 @@ -1180,7 +1176,7 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_pool_s // staking pot receives no foreign assets assert_eq!( ForeignAssets::balance( - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), &staking_pot ), 0 @@ -1196,12 +1192,12 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_suffic let staking_pot = StakingPot::get(); let foreign_asset_id_location = - xcm::v3::Location::new(2, [xcm::v3::Junction::GlobalConsensus(xcm::v3::NetworkId::Rococo)]); + xcm::v4::Location::new(2, [xcm::v4::Junction::GlobalConsensus(xcm::v4::NetworkId::Rococo)]); let foreign_asset_id_minimum_balance = 1_000_000_000; // sovereign account as foreign asset owner (can be whoever for this scenario) let foreign_asset_owner = LocationToAccountId::convert_location(&Location::parent()).unwrap(); let foreign_asset_create_params = - (foreign_asset_owner, foreign_asset_id_location, foreign_asset_id_minimum_balance); + (foreign_asset_owner, foreign_asset_id_location.clone(), foreign_asset_id_minimum_balance); asset_test_utils::test_cases_over_bridge::receive_reserve_asset_deposited_from_different_consensus_works::< Runtime, @@ -1226,7 +1222,7 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_suffic // check block author before assert_eq!( ForeignAssets::balance( - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), &block_author_account ), 0 @@ -1236,7 +1232,7 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_suffic // `TakeFirstAssetTrader` puts fees to the block author assert!( ForeignAssets::balance( - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), &block_author_account ) > 0 ); diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs index 884b71369e79ad9713ea3cc8e243820862c9c20d..67b585ecfe86ff71f59888524353c12af1bc44c8 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -367,9 +367,9 @@ pub fn teleports_for_foreign_assets_works< ::Balance: From + Into, SovereignAccountOf: ConvertLocation>, >::AssetId: - From + Into, + From + Into, >::AssetIdParameter: - From + Into, + From + Into, >::Balance: From + Into, ::AccountId: @@ -381,11 +381,11 @@ pub fn teleports_for_foreign_assets_works< { // foreign parachain with the same consensus currency as asset let foreign_para_id = 2222; - let foreign_asset_id_location = xcm::v3::Location { + let foreign_asset_id_location = xcm::v4::Location { parents: 1, interior: [ - xcm::v3::Junction::Parachain(foreign_para_id), - xcm::v3::Junction::GeneralIndex(1234567), + xcm::v4::Junction::Parachain(foreign_para_id), + xcm::v4::Junction::GeneralIndex(1234567), ] .into(), }; @@ -438,14 +438,14 @@ pub fn teleports_for_foreign_assets_works< ); assert_eq!( >::balance( - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), &target_account ), 0.into() ); assert_eq!( >::balance( - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), &CheckingAccount::get() ), 0.into() @@ -454,14 +454,14 @@ pub fn teleports_for_foreign_assets_works< assert_total::< pallet_assets::Pallet, AccountIdOf, - >(foreign_asset_id_location, 0, 0); + >(foreign_asset_id_location.clone(), 0, 0); // create foreign asset (0 total issuance) let asset_minimum_asset_balance = 3333333_u128; assert_ok!( >::force_create( RuntimeHelper::::root_origin(), - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), asset_owner.into(), false, asset_minimum_asset_balance.into() @@ -470,12 +470,9 @@ pub fn teleports_for_foreign_assets_works< assert_total::< pallet_assets::Pallet, AccountIdOf, - >(foreign_asset_id_location, 0, 0); + >(foreign_asset_id_location.clone(), 0, 0); assert!(teleported_foreign_asset_amount > asset_minimum_asset_balance); - let foreign_asset_id_location_latest: Location = - foreign_asset_id_location.try_into().unwrap(); - // 1. process received teleported assets from sibling parachain (foreign_para_id) let xcm = Xcm(vec![ // BuyExecution with relaychain native token @@ -489,12 +486,12 @@ pub fn teleports_for_foreign_assets_works< }, // Process teleported asset ReceiveTeleportedAsset(Assets::from(vec![Asset { - id: AssetId(foreign_asset_id_location_latest.clone()), + id: AssetId(foreign_asset_id_location.clone()), fun: Fungible(teleported_foreign_asset_amount), }])), DepositAsset { assets: Wild(AllOf { - id: AssetId(foreign_asset_id_location_latest.clone()), + id: AssetId(foreign_asset_id_location.clone()), fun: WildFungibility::Fungible, }), beneficiary: Location { @@ -526,7 +523,7 @@ pub fn teleports_for_foreign_assets_works< ); assert_eq!( >::balance( - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), &target_account ), teleported_foreign_asset_amount.into() @@ -538,7 +535,7 @@ pub fn teleports_for_foreign_assets_works< ); assert_eq!( >::balance( - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), &CheckingAccount::get() ), 0.into() @@ -548,7 +545,7 @@ pub fn teleports_for_foreign_assets_works< pallet_assets::Pallet, AccountIdOf, >( - foreign_asset_id_location, + foreign_asset_id_location.clone(), teleported_foreign_asset_amount, teleported_foreign_asset_amount, ); @@ -566,7 +563,7 @@ pub fn teleports_for_foreign_assets_works< let target_account_balance_before_teleport = >::balance( - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), &target_account, ); let asset_to_teleport_away = asset_minimum_asset_balance * 3; @@ -580,7 +577,7 @@ pub fn teleports_for_foreign_assets_works< // Make sure the target account has enough native asset to pay for delivery fees let delivery_fees = xcm_helpers::teleport_assets_delivery_fees::( - (foreign_asset_id_location_latest.clone(), asset_to_teleport_away).into(), + (foreign_asset_id_location.clone(), asset_to_teleport_away).into(), 0, Unlimited, dest_beneficiary.clone(), @@ -596,7 +593,7 @@ pub fn teleports_for_foreign_assets_works< RuntimeHelper::::origin_of(target_account.clone()), dest, dest_beneficiary, - (foreign_asset_id_location_latest.clone(), asset_to_teleport_away), + (foreign_asset_id_location.clone(), asset_to_teleport_away), Some((runtime_para_id, foreign_para_id)), included_head, &alice, @@ -606,14 +603,14 @@ pub fn teleports_for_foreign_assets_works< // check balances assert_eq!( >::balance( - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), &target_account ), (target_account_balance_before_teleport - asset_to_teleport_away.into()) ); assert_eq!( >::balance( - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), &CheckingAccount::get() ), 0.into() @@ -623,7 +620,7 @@ pub fn teleports_for_foreign_assets_works< pallet_assets::Pallet, AccountIdOf, >( - foreign_asset_id_location, + foreign_asset_id_location.clone(), teleported_foreign_asset_amount - asset_to_teleport_away, teleported_foreign_asset_amount - asset_to_teleport_away, ); @@ -1559,9 +1556,6 @@ pub fn reserve_transfer_native_asset_to_non_teleport_para_works< ) .unwrap(); - let v4_xcm: Xcm<()> = xcm_sent.clone().try_into().unwrap(); - dbg!(&v4_xcm); - let delivery_fees = get_fungible_delivery_fees::< ::XcmSender, >(dest.clone(), Xcm::try_from(xcm_sent.clone()).unwrap()); diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs index 0b2364dbb8bd858a95f6a109c800032cb286412b..e0b3f70c75468b69d3a660fb6777f536f4f7df37 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -331,7 +331,7 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< block_author_account: AccountIdOf, (foreign_asset_owner, foreign_asset_id_location, foreign_asset_id_minimum_balance): ( AccountIdOf, - xcm::v3::Location, + xcm::v4::Location, u128, ), foreign_asset_id_amount_to_transfer: u128, @@ -357,9 +357,9 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< BalanceOf: From + Into, XcmConfig: xcm_executor::Config, >::AssetId: - From + Into, + From + Into, >::AssetIdParameter: - From + Into, + From + Into, >::Balance: From + Into + From, ::AccountId: Into<<::RuntimeOrigin as OriginTrait>::AccountId> @@ -390,7 +390,7 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< assert_ok!( >::force_create( RuntimeHelper::::root_origin(), - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), foreign_asset_owner.into(), true, // is_sufficient=true foreign_asset_id_minimum_balance.into() @@ -409,7 +409,7 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< // ForeignAssets balances before assert_eq!( >::balance( - foreign_asset_id_location.into(), + foreign_asset_id_location.clone().into(), &target_account ), 0.into() @@ -418,11 +418,8 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< // additional check before additional_checks_before(); - let foreign_asset_id_location_latest: Location = - foreign_asset_id_location.try_into().unwrap(); - let expected_assets = Assets::from(vec![Asset { - id: AssetId(foreign_asset_id_location_latest.clone()), + id: AssetId(foreign_asset_id_location.clone()), fun: Fungible(foreign_asset_id_amount_to_transfer), }]); let expected_beneficiary = Location::new( @@ -439,7 +436,7 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< ClearOrigin, BuyExecution { fees: Asset { - id: AssetId(foreign_asset_id_location_latest.clone()), + id: AssetId(foreign_asset_id_location.clone()), fun: Fungible(foreign_asset_id_amount_to_transfer), }, weight_limit: Unlimited, 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 98737298468210671a6140fb119f504bd8f7f9e4..f3e03aa743005f9fa79c8a071dba9bde222007e3 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -26,6 +26,7 @@ serde = { optional = true, features = ["derive"], workspace = true, default-feat # Substrate 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 } @@ -121,7 +122,6 @@ snowbridge-runtime-common = { workspace = true } bridge-hub-common = { workspace = true } [dev-dependencies] -static_assertions = { workspace = true, default-features = true } bridge-hub-test-utils = { workspace = true, default-features = true } bridge-runtime-common = { features = [ "integrity-test", @@ -160,6 +160,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", 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 d97e6a1d88e1b698c2a047adb11ede43827f18f1..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 @@ -28,7 +28,6 @@ use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, target_chain::FromBridgedChainMessagesProof, LaneId, }; -use bp_runtime::Chain; use bridge_runtime_common::{ extensions::refund_relayer_extension::{ ActualFeeRefund, RefundBridgedMessages, RefundSignedExtensionAdapter, @@ -48,8 +47,6 @@ use xcm::{ use xcm_builder::BridgeBlobDispatcher; parameter_types! { - /// 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) 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 fe854e20c244545a770edcdb6c6c57a49c93b124..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 @@ -26,7 +26,6 @@ use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, target_chain::FromBridgedChainMessagesProof, LaneId, }; -use bp_runtime::Chain; use bridge_runtime_common::{ extensions::refund_relayer_extension::{ ActualFeeRefund, RefundBridgedMessages, RefundSignedExtensionAdapter, @@ -47,7 +46,6 @@ use xcm::{ use xcm_builder::BridgeBlobDispatcher; parameter_types! { - pub const BridgeHubWestendChainId: bp_runtime::ChainId = bp_bridge_hub_westend::BridgeHubWestend::ID; pub BridgeRococoToWestendMessagesPalletInstance: InteriorLocation = [PalletInstance(::index() as u8)].into(); pub WestendGlobalConsensusNetwork: NetworkId = NetworkId::Westend; pub WestendGlobalConsensusNetworkLocation: Location = Location::new( 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 512c1199f43920f0832d0edf91a4205f37d7c493..c65880771e0863540bf6ff5687d5a8b18c8b3c4c 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 @@ -145,6 +145,7 @@ pub type SignedExtra = ( bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages, ), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, + frame_metadata_hash_extension::CheckMetadataHash, ); /// Unchecked extrinsic type as expected by this runtime. @@ -218,7 +219,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_014_000, + spec_version: 1_016_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 5, @@ -1416,7 +1417,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( @@ -1595,41 +1597,42 @@ mod tests { use bp_polkadot_core::SuffixedCommonSignedExtensionExt; sp_io::TestExternalities::default().execute_with(|| { - frame_system::BlockHash::::insert(BlockNumber::zero(), Hash::default()); - let payload: SignedExtra = ( - frame_system::CheckNonZeroSender::new(), - frame_system::CheckSpecVersion::new(), - frame_system::CheckTxVersion::new(), - frame_system::CheckGenesis::new(), - frame_system::CheckEra::from(Era::Immortal), - frame_system::CheckNonce::from(10), - frame_system::CheckWeight::new(), - pallet_transaction_payment::ChargeTransactionPayment::from(10), - BridgeRejectObsoleteHeadersAndMessages, - ( - bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), - bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages::default(), - ), - cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), - ); - - // for BridgeHubRococo - { - let bhr_indirect_payload = bp_bridge_hub_rococo::SignedExtension::from_params( - VERSION.spec_version, - VERSION.transaction_version, - bp_runtime::TransactionEra::Immortal, - System::block_hash(BlockNumber::zero()), - 10, - 10, - (((), ()), ((), ())), - ); - assert_eq!(payload.encode(), bhr_indirect_payload.encode()); - assert_eq!( - payload.additional_signed().unwrap().encode(), - bhr_indirect_payload.additional_signed().unwrap().encode() - ) - } - }); + frame_system::BlockHash::::insert(BlockNumber::zero(), Hash::default()); + let payload: SignedExtra = ( + frame_system::CheckNonZeroSender::new(), + frame_system::CheckSpecVersion::new(), + frame_system::CheckTxVersion::new(), + frame_system::CheckGenesis::new(), + frame_system::CheckEra::from(Era::Immortal), + frame_system::CheckNonce::from(10), + frame_system::CheckWeight::new(), + pallet_transaction_payment::ChargeTransactionPayment::from(10), + BridgeRejectObsoleteHeadersAndMessages, + ( + bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), + bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages::default(), + ), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), + frame_metadata_hash_extension::CheckMetadataHash::new(false), + ); + + // for BridgeHubRococo + { + let bhr_indirect_payload = bp_bridge_hub_rococo::SignedExtension::from_params( + VERSION.spec_version, + VERSION.transaction_version, + bp_runtime::TransactionEra::Immortal, + System::block_hash(BlockNumber::zero()), + 10, + 10, + (((), ()), ((), ())), + ); + assert_eq!(payload.encode().split_last().unwrap().1, bhr_indirect_payload.encode()); + assert_eq!( + payload.additional_signed().unwrap().encode().split_last().unwrap().1, + bhr_indirect_payload.additional_signed().unwrap().encode() + ) + } + }); } } 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 057dc4313510f79aa1daa1216141538ceb357012..f2cee0e3e80751f3f9dde9cbb812623fb3ae2bf8 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 @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-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-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-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,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 19_610_000 picoseconds. - Weight::from_parts(19_980_000, 3593) + // Minimum execution time: 30_988_000 picoseconds. + Weight::from_parts(31_496_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `153` // Estimated: `6196` - // Minimum execution time: 44_411_000 picoseconds. - Weight::from_parts(45_110_000, 6196) + // Minimum execution time: 42_805_000 picoseconds. + Weight::from_parts(44_207_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -90,8 +90,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `223` // Estimated: `8799` - // Minimum execution time: 89_739_000 picoseconds. - Weight::from_parts(91_256_000, 8799) + // Minimum execution time: 103_376_000 picoseconds. + Weight::from_parts(104_770_000, 8799) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -124,8 +124,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 60_045_000 picoseconds. - Weight::from_parts(60_710_000, 6196) + // Minimum execution time: 71_234_000 picoseconds. + Weight::from_parts(72_990_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -133,8 +133,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_257_000 picoseconds. - Weight::from_parts(3_392_000, 0) + // Minimum execution time: 2_636_000 picoseconds. + Weight::from_parts(2_777_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -142,13 +142,11 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `52` // Estimated: `3593` - // Minimum execution time: 19_423_000 picoseconds. - Weight::from_parts(19_823_000, 3593) + // Minimum execution time: 23_839_000 picoseconds. + Weight::from_parts(24_568_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: `System::Account` (r:2 w:2) - // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -159,6 +157,8 @@ impl WeightInfo { // 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: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // 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) @@ -167,8 +167,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `122` // Estimated: `6196` - // Minimum execution time: 60_484_000 picoseconds. - Weight::from_parts(61_634_000, 6196) + // Minimum execution time: 78_345_000 picoseconds. + Weight::from_parts(80_558_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -192,8 +192,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3593` - // Minimum execution time: 44_863_000 picoseconds. - Weight::from_parts(45_549_000, 3593) + // Minimum execution time: 46_614_000 picoseconds. + Weight::from_parts(47_354_000, 3593) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } 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 5ec545ee0590f180f661e4bc81f3f3c2ffcd8dcf..92368b29212119dc151cd02a2311e01a5b82ac16 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,6 @@ 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, @@ -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(), ); }, } @@ -393,7 +397,9 @@ impl, FeeHandler: HandleFee> FeeManager fn is_waived(origin: Option<&Location>, fee_reason: FeeReason) -> bool { let Some(loc) = origin else { return false }; if let Export { network, destination: Here } = fee_reason { - return !(network == EthereumNetwork::get()) + if network == EthereumNetwork::get() { + return false + } } WaivedLocations::contains(loc) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs index 5960ab7b55054f228d1e946e5d6e5ff7dd9706ac..c7b5850f9ffe56620e26e0751a6cb04c07311bb3 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs @@ -188,6 +188,7 @@ fn construct_extrinsic( OnBridgeHubRococoRefundRococoBulletinMessages::default(), ), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), + frame_metadata_hash_extension::CheckMetadataHash::::new(false), ); let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); 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 1d3d9e55f7eeb99bb46c23aba0bf9940515c69d4..e91837af0b21336d2a2ac5684d73318e3260a1d5 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 @@ -65,6 +65,7 @@ fn construct_extrinsic( bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages::default(), ), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), + frame_metadata_hash_extension::CheckMetadataHash::new(false), ); let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); @@ -147,7 +148,7 @@ mod bridge_hub_westend_tests { }; use bridge_hub_test_utils::test_cases::from_parachain; use bridge_to_westend_config::{ - BridgeHubWestendChainId, BridgeHubWestendLocation, WestendGlobalConsensusNetwork, + BridgeHubWestendLocation, WestendGlobalConsensusNetwork, WithBridgeHubWestendMessagesInstance, XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, }; @@ -313,11 +314,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 + }, ) } @@ -350,8 +354,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, ) } @@ -363,11 +366,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, ) } @@ -380,11 +381,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, ) } @@ -401,8 +400,8 @@ mod bridge_hub_westend_tests { WeightToFee, >() }, - Perbill::from_percent(33), - Some(-33), + Perbill::from_percent(25), + Some(-25), &format!( "Estimate fee for `ExportMessage` for runtime: {:?}", ::Version::get() @@ -420,8 +419,8 @@ mod bridge_hub_westend_tests { RuntimeTestsAdapter, >(collator_session_keys(), construct_and_estimate_extrinsic_fee) }, - Perbill::from_percent(33), - Some(-33), + Perbill::from_percent(25), + Some(-25), &format!( "Estimate fee for `single message delivery` for runtime: {:?}", ::Version::get() @@ -439,8 +438,8 @@ mod bridge_hub_westend_tests { RuntimeTestsAdapter, >(collator_session_keys(), construct_and_estimate_extrinsic_fee) }, - Perbill::from_percent(33), - Some(-33), + Perbill::from_percent(25), + Some(-25), &format!( "Estimate fee for `single message confirmation` for runtime: {:?}", ::Version::get() @@ -454,9 +453,8 @@ 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, WithRococoBulletinMessagesInstance, - XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, + RococoBulletinGlobalConsensusNetwork, RococoBulletinGlobalConsensusNetworkLocation, + WithRococoBulletinMessagesInstance, XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, }; // Para id of sibling chain used in tests. @@ -519,10 +517,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 + }, ) } @@ -555,8 +556,7 @@ mod bridge_hub_bulletin_tests { _ => None, } }), - XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, - || (), + || XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, ) } @@ -567,11 +567,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, ) } @@ -583,11 +581,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, ) } 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 e2671d3d606d1e993a38de2eeacf8a9675bb3b82..a9381501359e99d12056879506f52af2308c53c0 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -22,6 +22,7 @@ serde = { optional = true, features = ["derive"], workspace = true, default-feat # Substrate 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 } @@ -100,11 +101,24 @@ pallet-xcm-bridge-hub = { workspace = true } bridge-runtime-common = { workspace = true } bridge-hub-common = { workspace = true } +# Ethereum Bridge (Snowbridge) +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 } + + [dev-dependencies] -static_assertions = { workspace = true, default-features = true } 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 } +snowbridge-runtime-test-common = { workspace = true, default-features = true } [features] default = ["std"] @@ -135,6 +149,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", @@ -165,6 +180,16 @@ std = [ "polkadot-runtime-common/std", "scale-info/std", "serde", + "snowbridge-beacon-primitives/std", + "snowbridge-core/std", + "snowbridge-outbound-queue-runtime-api/std", + "snowbridge-pallet-ethereum-client/std", + "snowbridge-pallet-inbound-queue/std", + "snowbridge-pallet-outbound-queue/std", + "snowbridge-pallet-system/std", + "snowbridge-router-primitives/std", + "snowbridge-runtime-common/std", + "snowbridge-system-runtime-api/std", "sp-api/std", "sp-block-builder/std", "sp-consensus-aura/std", @@ -216,6 +241,14 @@ runtime-benchmarks = [ "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", + "snowbridge-core/runtime-benchmarks", + "snowbridge-pallet-ethereum-client/runtime-benchmarks", + "snowbridge-pallet-inbound-queue/runtime-benchmarks", + "snowbridge-pallet-outbound-queue/runtime-benchmarks", + "snowbridge-pallet-system/runtime-benchmarks", + "snowbridge-router-primitives/runtime-benchmarks", + "snowbridge-runtime-common/runtime-benchmarks", + "snowbridge-runtime-test-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", @@ -249,6 +282,10 @@ try-runtime = [ "pallet-xcm/try-runtime", "parachain-info/try-runtime", "polkadot-runtime-common/try-runtime", + "snowbridge-pallet-ethereum-client/try-runtime", + "snowbridge-pallet-inbound-queue/try-runtime", + "snowbridge-pallet-outbound-queue/try-runtime", + "snowbridge-pallet-system/try-runtime", "sp-runtime/try-runtime", ] @@ -256,3 +293,5 @@ try-runtime = [ # 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 = ["sp-api/disable-logging"] + +fast-runtime = [] diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs new file mode 100644 index 0000000000000000000000000000000000000000..7922d3ed02b1fe73293fd7bf4344fb5609c3aeda --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs @@ -0,0 +1,219 @@ +// 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 . + +#[cfg(not(feature = "runtime-benchmarks"))] +use crate::XcmRouter; +use crate::{ + xcm_config, + xcm_config::{TreasuryAccount, UniversalLocation}, + Balances, EthereumInboundQueue, EthereumOutboundQueue, EthereumSystem, MessageQueue, Runtime, + RuntimeEvent, TransactionByteFee, +}; +use parachains_common::{AccountId, Balance}; +use snowbridge_beacon_primitives::{Fork, ForkVersions}; +use snowbridge_core::{gwei, meth, AllowSiblingsOnly, PricingParameters, Rewards}; +use snowbridge_router_primitives::{inbound::MessageToXcm, outbound::EthereumBlobExporter}; +use sp_core::H160; +use testnet_parachains_constants::westend::{ + currency::*, + fee::WeightToFee, + snowbridge::{EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX}, +}; + +#[cfg(feature = "runtime-benchmarks")] +use benchmark_helpers::DoNothingRouter; +use frame_support::{parameter_types, weights::ConstantMultiplier}; +use pallet_xcm::EnsureXcm; +use sp_runtime::{ + traits::{ConstU32, ConstU8, Keccak256}, + FixedU128, +}; + +/// Exports message to the Ethereum Gateway contract. +pub type SnowbridgeExporter = EthereumBlobExporter< + UniversalLocation, + EthereumNetwork, + snowbridge_pallet_outbound_queue::Pallet, + snowbridge_core::AgentIdOf, +>; + +// Ethereum Bridge +parameter_types! { + pub storage EthereumGatewayAddress: H160 = H160(hex_literal::hex!("EDa338E4dC46038493b885327842fD3E301CaB39")); +} + +parameter_types! { + pub const CreateAssetCall: [u8;2] = [53, 0]; + pub const CreateAssetDeposit: u128 = (UNITS / 10) + EXISTENTIAL_DEPOSIT; + pub Parameters: PricingParameters = PricingParameters { + exchange_rate: FixedU128::from_rational(1, 400), + fee_per_gas: gwei(20), + rewards: Rewards { local: 1 * UNITS, remote: meth(1) }, + multiplier: FixedU128::from_rational(1, 1), + }; +} + +impl snowbridge_pallet_inbound_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Verifier = snowbridge_pallet_ethereum_client::Pallet; + type Token = Balances; + #[cfg(not(feature = "runtime-benchmarks"))] + type XcmSender = XcmRouter; + #[cfg(feature = "runtime-benchmarks")] + type XcmSender = DoNothingRouter; + type ChannelLookup = EthereumSystem; + type GatewayAddress = EthereumGatewayAddress; + #[cfg(feature = "runtime-benchmarks")] + type Helper = Runtime; + type MessageConverter = MessageToXcm< + CreateAssetCall, + CreateAssetDeposit, + ConstU8, + AccountId, + Balance, + >; + type WeightToFee = WeightToFee; + type LengthToFee = ConstantMultiplier; + type MaxMessageSize = ConstU32<2048>; + type WeightInfo = crate::weights::snowbridge_pallet_inbound_queue::WeightInfo; + type PricingParameters = EthereumSystem; + type AssetTransactor = ::AssetTransactor; +} + +impl snowbridge_pallet_outbound_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Hashing = Keccak256; + type MessageQueue = MessageQueue; + type Decimals = ConstU8<12>; + type MaxMessagePayloadSize = ConstU32<2048>; + type MaxMessagesPerBlock = ConstU32<32>; + type GasMeter = snowbridge_core::outbound::ConstantGasMeter; + type Balance = Balance; + type WeightToFee = WeightToFee; + type WeightInfo = crate::weights::snowbridge_pallet_outbound_queue::WeightInfo; + type PricingParameters = EthereumSystem; + type Channels = EthereumSystem; +} + +#[cfg(any(feature = "std", feature = "fast-runtime", feature = "runtime-benchmarks", test))] +parameter_types! { + pub const ChainForkVersions: ForkVersions = ForkVersions { + genesis: Fork { + version: [0, 0, 0, 0], // 0x00000000 + epoch: 0, + }, + altair: Fork { + version: [1, 0, 0, 0], // 0x01000000 + epoch: 0, + }, + bellatrix: Fork { + version: [2, 0, 0, 0], // 0x02000000 + epoch: 0, + }, + capella: Fork { + version: [3, 0, 0, 0], // 0x03000000 + epoch: 0, + }, + deneb: Fork { + version: [4, 0, 0, 0], // 0x04000000 + epoch: 0, + } + }; +} + +#[cfg(not(any(feature = "std", feature = "fast-runtime", feature = "runtime-benchmarks", test)))] +parameter_types! { + pub const ChainForkVersions: ForkVersions = ForkVersions { + genesis: Fork { + version: [144, 0, 0, 111], // 0x90000069 + epoch: 0, + }, + altair: Fork { + version: [144, 0, 0, 112], // 0x90000070 + epoch: 50, + }, + bellatrix: Fork { + version: [144, 0, 0, 113], // 0x90000071 + epoch: 100, + }, + capella: Fork { + version: [144, 0, 0, 114], // 0x90000072 + epoch: 56832, + }, + deneb: Fork { + version: [144, 0, 0, 115], // 0x90000073 + epoch: 132608, + }, + }; +} + +impl snowbridge_pallet_ethereum_client::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ForkVersions = ChainForkVersions; + type WeightInfo = crate::weights::snowbridge_pallet_ethereum_client::WeightInfo; +} + +impl snowbridge_pallet_system::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OutboundQueue = EthereumOutboundQueue; + type SiblingOrigin = EnsureXcm; + type AgentIdOf = snowbridge_core::AgentIdOf; + type TreasuryAccount = TreasuryAccount; + type Token = Balances; + type WeightInfo = crate::weights::snowbridge_pallet_system::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type Helper = (); + type DefaultPricingParameters = Parameters; + type InboundDeliveryCost = EthereumInboundQueue; +} + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmark_helpers { + use crate::{EthereumBeaconClient, Runtime, RuntimeOrigin}; + use codec::Encode; + use snowbridge_beacon_primitives::BeaconHeader; + use snowbridge_pallet_inbound_queue::BenchmarkHelper; + use sp_core::H256; + use xcm::latest::{Assets, Location, SendError, SendResult, SendXcm, Xcm, XcmHash}; + + impl BenchmarkHelper for Runtime { + fn initialize_storage(beacon_header: BeaconHeader, block_roots_root: H256) { + EthereumBeaconClient::store_finalized_header(beacon_header, block_roots_root).unwrap(); + } + } + + pub struct DoNothingRouter; + impl SendXcm for DoNothingRouter { + type Ticket = Xcm<()>; + + fn validate( + _dest: &mut Option, + xcm: &mut Option>, + ) -> SendResult { + Ok((xcm.clone().unwrap(), Assets::new())) + } + fn deliver(xcm: Xcm<()>) -> Result { + let hash = xcm.using_encoded(sp_io::hashing::blake2_256); + Ok(hash) + } + } + + impl snowbridge_pallet_system::BenchmarkHelper for () { + fn make_xcm_origin(location: Location) -> RuntimeOrigin { + RuntimeOrigin::from(pallet_xcm::Origin::Xcm(location)) + } + } +} 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 42d5ef3eebdb3030d49507fb8cc6d976cb041672..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 @@ -25,7 +25,6 @@ use bp_messages::{ target_chain::FromBridgedChainMessagesProof, LaneId, }; use bp_parachains::SingleParaStoredHeaderDataBuilder; -use bp_runtime::Chain; use bridge_runtime_common::{ extensions::refund_relayer_extension::{ ActualFeeRefund, RefundBridgedMessages, RefundSignedExtensionAdapter, @@ -54,7 +53,6 @@ parameter_types! { pub const RococoBridgeParachainPalletName: &'static str = "Paras"; pub const MaxRococoParaHeadDataSize: u32 = bp_rococo::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE; - pub const BridgeHubRococoChainId: bp_runtime::ChainId = bp_bridge_hub_rococo::BridgeHubRococo::ID; pub BridgeWestendToRococoMessagesPalletInstance: InteriorLocation = [PalletInstance(::index() as u8)].into(); pub RococoGlobalConsensusNetwork: NetworkId = NetworkId::Rococo; pub RococoGlobalConsensusNetworkLocation: Location = Location::new( 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 5d4c35d6610a0fb7a9b15e886750135c36533f5a..1c26742fd67f827e6134f5f5a08f35f6c00938e2 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 @@ -28,6 +28,7 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub mod bridge_common_config; +pub mod bridge_to_ethereum_config; pub mod bridge_to_rococo_config; mod weights; pub mod xcm_config; @@ -96,7 +97,12 @@ use parachains_common::{ impls::DealWithFees, AccountId, Balance, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, NORMAL_DISPATCH_RATIO, }; +use snowbridge_core::{ + outbound::{Command, Fee}, + AgentId, PricingParameters, +}; use testnet_parachains_constants::westend::{consensus::*, currency::*, fee::WeightToFee, time::*}; +use xcm::VersionedLocation; /// The address format for describing accounts. pub type Address = MultiAddress; @@ -123,6 +129,7 @@ pub type SignedExtra = ( BridgeRejectObsoleteHeadersAndMessages, (bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages,), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, + frame_metadata_hash_extension::CheckMetadataHash, ); /// Unchecked extrinsic type as expected by this runtime. @@ -191,7 +198,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_014_000, + spec_version: 1_016_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 5, @@ -351,10 +358,13 @@ impl pallet_message_queue::Config for Runtime { type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor; #[cfg(not(feature = "runtime-benchmarks"))] - type MessageProcessor = xcm_builder::ProcessXcmMessage< - AggregateMessageOrigin, - xcm_executor::XcmExecutor, - RuntimeCall, + type MessageProcessor = bridge_hub_common::BridgeHubMessageRouter< + xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >, + EthereumOutboundQueue, >; type Size = u32; // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: @@ -516,6 +526,11 @@ construct_runtime!( BridgeRococoMessages: pallet_bridge_messages:: = 44, XcmOverBridgeHubRococo: pallet_xcm_bridge_hub:: = 45, + EthereumInboundQueue: snowbridge_pallet_inbound_queue = 80, + EthereumOutboundQueue: snowbridge_pallet_outbound_queue = 81, + EthereumBeaconClient: snowbridge_pallet_ethereum_client = 82, + EthereumSystem: snowbridge_pallet_system = 83, + // Message Queue. Importantly, is registered last so that messages are processed after // the `on_initialize` hooks of bridging pallets. MessageQueue: pallet_message_queue = 250, @@ -568,6 +583,11 @@ mod benches { [pallet_bridge_grandpa, RococoFinality] [pallet_bridge_parachains, WithinRococo] [pallet_bridge_messages, WestendToRococo] + // Ethereum Bridge + [snowbridge_pallet_inbound_queue, EthereumInboundQueue] + [snowbridge_pallet_outbound_queue, EthereumOutboundQueue] + [snowbridge_pallet_system, EthereumSystem] + [snowbridge_pallet_ethereum_client, EthereumBeaconClient] ); } @@ -830,6 +850,22 @@ impl_runtime_apis! { } } + impl snowbridge_outbound_queue_runtime_api::OutboundQueueApi for Runtime { + fn prove_message(leaf_index: u64) -> Option { + snowbridge_pallet_outbound_queue::api::prove_message::(leaf_index) + } + + fn calculate_fee(command: Command, parameters: Option>) -> Fee { + snowbridge_pallet_outbound_queue::api::calculate_fee::(command, parameters) + } + } + + impl snowbridge_system_runtime_api::ControlApi for Runtime { + fn agent_id(location: VersionedLocation) -> Option { + snowbridge_pallet_system::api::agent_id::(location) + } + } + #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { @@ -1100,7 +1136,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( @@ -1244,39 +1281,40 @@ mod tests { use bp_polkadot_core::SuffixedCommonSignedExtensionExt; sp_io::TestExternalities::default().execute_with(|| { - frame_system::BlockHash::::insert(BlockNumber::zero(), Hash::default()); - let payload: SignedExtra = ( - frame_system::CheckNonZeroSender::new(), - frame_system::CheckSpecVersion::new(), - frame_system::CheckTxVersion::new(), - frame_system::CheckGenesis::new(), - frame_system::CheckEra::from(Era::Immortal), - frame_system::CheckNonce::from(10), - frame_system::CheckWeight::new(), - pallet_transaction_payment::ChargeTransactionPayment::from(10), - BridgeRejectObsoleteHeadersAndMessages, - ( - bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages::default(), - ), - cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new() - ); - - { - let bh_indirect_payload = bp_bridge_hub_westend::SignedExtension::from_params( - VERSION.spec_version, - VERSION.transaction_version, - bp_runtime::TransactionEra::Immortal, - System::block_hash(BlockNumber::zero()), - 10, - 10, - (((), ()), ((), ())), - ); - assert_eq!(payload.encode(), bh_indirect_payload.encode()); - assert_eq!( - payload.additional_signed().unwrap().encode(), - bh_indirect_payload.additional_signed().unwrap().encode() - ) - } - }); + frame_system::BlockHash::::insert(BlockNumber::zero(), Hash::default()); + let payload: SignedExtra = ( + frame_system::CheckNonZeroSender::new(), + frame_system::CheckSpecVersion::new(), + frame_system::CheckTxVersion::new(), + frame_system::CheckGenesis::new(), + frame_system::CheckEra::from(Era::Immortal), + frame_system::CheckNonce::from(10), + frame_system::CheckWeight::new(), + pallet_transaction_payment::ChargeTransactionPayment::from(10), + BridgeRejectObsoleteHeadersAndMessages, + ( + bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages::default(), + ), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), + frame_metadata_hash_extension::CheckMetadataHash::new(false), + ); + + { + let bh_indirect_payload = bp_bridge_hub_westend::SignedExtension::from_params( + VERSION.spec_version, + VERSION.transaction_version, + bp_runtime::TransactionEra::Immortal, + System::block_hash(BlockNumber::zero()), + 10, + 10, + (((), ()), ((), ())), + ); + assert_eq!(payload.encode().split_last().unwrap().1, bh_indirect_payload.encode()); + assert_eq!( + payload.additional_signed().unwrap().encode().split_last().unwrap().1, + bh_indirect_payload.additional_signed().unwrap().encode() + ) + } + }); } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs index 245daaf8ed91b69db2a604c51e394c2d768b1c26..9b7f7188782faedc0af4186511fd3ab5e1b02685 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs @@ -43,6 +43,11 @@ pub mod paritydb_weights; pub mod rocksdb_weights; pub mod xcm; +pub mod snowbridge_pallet_ethereum_client; +pub mod snowbridge_pallet_inbound_queue; +pub mod snowbridge_pallet_outbound_queue; +pub mod snowbridge_pallet_system; + pub use block_weights::constants::BlockExecutionWeight; pub use extrinsic_weights::constants::ExtrinsicBaseWeight; pub use rocksdb_weights::constants::RocksDbWeight; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/snowbridge_pallet_ethereum_client.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/snowbridge_pallet_ethereum_client.rs new file mode 100644 index 0000000000000000000000000000000000000000..23e2a9cffb0b4f0f02a1df6fa0b13f5340de4d14 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/snowbridge_pallet_ethereum_client.rs @@ -0,0 +1,120 @@ +// 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. + +//! Autogenerated weights for `snowbridge_pallet_ethereum_client` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-06-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `Claras-MacBook-Pro-2.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/release/polkadot-parachain +// benchmark +// pallet +// --chain=bridge-hub-rococo-dev +// --pallet=snowbridge_pallet_ethereum_client +// --extrinsic +// * +// --wasm-execution=compiled +// --steps +// 50 +// --repeat +// 20 +// --output +// cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_ethereum_client.rs + +#![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 `snowbridge_pallet_ethereum_client`. +pub struct WeightInfo(PhantomData); +impl snowbridge_pallet_ethereum_client::WeightInfo for WeightInfo { + /// Storage: `EthereumBeaconClient::FinalizedBeaconStateIndex` (r:1 w:1) + /// Proof: `EthereumBeaconClient::FinalizedBeaconStateIndex` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `EthereumBeaconClient::FinalizedBeaconStateMapping` (r:1 w:1) + /// Proof: `EthereumBeaconClient::FinalizedBeaconStateMapping` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Storage: `EthereumBeaconClient::NextSyncCommittee` (r:0 w:1) + /// Proof: `EthereumBeaconClient::NextSyncCommittee` (`max_values`: Some(1), `max_size`: Some(92372), added: 92867, mode: `MaxEncodedLen`) + /// Storage: `EthereumBeaconClient::InitialCheckpointRoot` (r:0 w:1) + /// Proof: `EthereumBeaconClient::InitialCheckpointRoot` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `EthereumBeaconClient::ValidatorsRoot` (r:0 w:1) + /// Proof: `EthereumBeaconClient::ValidatorsRoot` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `EthereumBeaconClient::LatestFinalizedBlockRoot` (r:0 w:1) + /// Proof: `EthereumBeaconClient::LatestFinalizedBlockRoot` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `EthereumBeaconClient::CurrentSyncCommittee` (r:0 w:1) + /// Proof: `EthereumBeaconClient::CurrentSyncCommittee` (`max_values`: Some(1), `max_size`: Some(92372), added: 92867, mode: `MaxEncodedLen`) + /// Storage: `EthereumBeaconClient::FinalizedBeaconState` (r:0 w:1) + /// Proof: `EthereumBeaconClient::FinalizedBeaconState` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + fn force_checkpoint() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `3501` + // Minimum execution time: 67_553_000_000 picoseconds. + Weight::from_parts(68_677_000_000, 0) + .saturating_add(Weight::from_parts(0, 3501)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(8)) + } + /// Storage: `EthereumBeaconClient::OperatingMode` (r:1 w:0) + /// Proof: `EthereumBeaconClient::OperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `EthereumBeaconClient::LatestFinalizedBlockRoot` (r:1 w:0) + /// Proof: `EthereumBeaconClient::LatestFinalizedBlockRoot` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `EthereumBeaconClient::FinalizedBeaconState` (r:1 w:0) + /// Proof: `EthereumBeaconClient::FinalizedBeaconState` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `EthereumBeaconClient::NextSyncCommittee` (r:1 w:0) + /// Proof: `EthereumBeaconClient::NextSyncCommittee` (`max_values`: Some(1), `max_size`: Some(92372), added: 92867, mode: `MaxEncodedLen`) + /// Storage: `EthereumBeaconClient::CurrentSyncCommittee` (r:1 w:0) + /// Proof: `EthereumBeaconClient::CurrentSyncCommittee` (`max_values`: Some(1), `max_size`: Some(92372), added: 92867, mode: `MaxEncodedLen`) + /// Storage: `EthereumBeaconClient::ValidatorsRoot` (r:1 w:0) + /// Proof: `EthereumBeaconClient::ValidatorsRoot` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + fn submit() -> Weight { + // Proof Size summary in bytes: + // Measured: `92749` + // Estimated: `93857` + // Minimum execution time: 16_988_000_000 picoseconds. + Weight::from_parts(17_125_000_000, 0) + .saturating_add(Weight::from_parts(0, 93857)) + .saturating_add(T::DbWeight::get().reads(6)) + } + /// Storage: `EthereumBeaconClient::OperatingMode` (r:1 w:0) + /// Proof: `EthereumBeaconClient::OperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `EthereumBeaconClient::LatestFinalizedBlockRoot` (r:1 w:0) + /// Proof: `EthereumBeaconClient::LatestFinalizedBlockRoot` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `EthereumBeaconClient::FinalizedBeaconState` (r:1 w:0) + /// Proof: `EthereumBeaconClient::FinalizedBeaconState` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `EthereumBeaconClient::NextSyncCommittee` (r:1 w:1) + /// Proof: `EthereumBeaconClient::NextSyncCommittee` (`max_values`: Some(1), `max_size`: Some(92372), added: 92867, mode: `MaxEncodedLen`) + /// Storage: `EthereumBeaconClient::CurrentSyncCommittee` (r:1 w:0) + /// Proof: `EthereumBeaconClient::CurrentSyncCommittee` (`max_values`: Some(1), `max_size`: Some(92372), added: 92867, mode: `MaxEncodedLen`) + /// Storage: `EthereumBeaconClient::ValidatorsRoot` (r:1 w:0) + /// Proof: `EthereumBeaconClient::ValidatorsRoot` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + fn submit_with_sync_committee() -> Weight { + // Proof Size summary in bytes: + // Measured: `92749` + // Estimated: `93857` + // Minimum execution time: 84_553_000_000 picoseconds. + Weight::from_parts(87_459_000_000, 0) + .saturating_add(Weight::from_parts(0, 93857)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/snowbridge_pallet_inbound_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/snowbridge_pallet_inbound_queue.rs new file mode 100644 index 0000000000000000000000000000000000000000..153c1d363be10888601dfa66bdcdf5e88af57001 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/snowbridge_pallet_inbound_queue.rs @@ -0,0 +1,69 @@ +// 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. + +//! Autogenerated weights for `snowbridge_pallet_inbound_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `macbook pro 14 m2`, CPU: `m2-arm64` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/polkadot-parachain +// benchmark +// pallet +// --chain=bridge-hub-rococo-dev +// --pallet=snowbridge_inbound_queue +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --steps +// 50 +// --repeat +// 20 +// --output +// ./parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_inbound_queue.rs + +#![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 `snowbridge_pallet_inbound_queue`. +pub struct WeightInfo(PhantomData); +impl snowbridge_pallet_inbound_queue::WeightInfo for WeightInfo { + /// Storage: EthereumInboundQueue PalletOperatingMode (r:1 w:0) + /// Proof: EthereumInboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: EthereumBeaconClient ExecutionHeaders (r:1 w:0) + /// Proof: EthereumBeaconClient ExecutionHeaders (max_values: None, max_size: Some(136), added: 2611, mode: MaxEncodedLen) + /// Storage: EthereumInboundQueue Nonce (r:1 w:1) + /// Proof: EthereumInboundQueue Nonce (max_values: None, max_size: Some(20), added: 2495, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn submit() -> Weight { + // Proof Size summary in bytes: + // Measured: `800` + // Estimated: `7200` + // Minimum execution time: 200_000_000 picoseconds. + Weight::from_parts(200_000_000, 0) + .saturating_add(Weight::from_parts(0, 7200)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(6)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/snowbridge_pallet_outbound_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/snowbridge_pallet_outbound_queue.rs new file mode 100644 index 0000000000000000000000000000000000000000..8adcef076e00add856e387b1a875116f5e8f0208 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/snowbridge_pallet_outbound_queue.rs @@ -0,0 +1,87 @@ +// 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. + +//! Autogenerated weights for `snowbridge_outbound_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-20, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `192.168.1.13`, CPU: `` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 + +// Executed Command: +// ../target/release/polkadot-parachain +// benchmark +// pallet +// --chain=bridge-hub-rococo-dev +// --pallet=snowbridge_outbound_queue +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --output +// ../parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_outbound_queue.rs + +#![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 `snowbridge_outbound_queue`. +pub struct WeightInfo(PhantomData); +impl snowbridge_pallet_outbound_queue::WeightInfo for WeightInfo { + /// Storage: EthereumOutboundQueue MessageLeaves (r:1 w:1) + /// Proof Skipped: EthereumOutboundQueue MessageLeaves (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: EthereumOutboundQueue PendingHighPriorityMessageCount (r:1 w:1) + /// Proof: EthereumOutboundQueue PendingHighPriorityMessageCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: EthereumOutboundQueue Nonce (r:1 w:1) + /// Proof: EthereumOutboundQueue Nonce (max_values: None, max_size: Some(20), added: 2495, mode: MaxEncodedLen) + /// Storage: EthereumOutboundQueue Messages (r:1 w:1) + /// Proof Skipped: EthereumOutboundQueue Messages (max_values: Some(1), max_size: None, mode: Measured) + fn do_process_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `3485` + // Minimum execution time: 39_000_000 picoseconds. + Weight::from_parts(39_000_000, 3485) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: EthereumOutboundQueue MessageLeaves (r:1 w:0) + /// Proof Skipped: EthereumOutboundQueue MessageLeaves (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Digest (r:1 w:1) + /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) + fn commit() -> Weight { + // Proof Size summary in bytes: + // Measured: `1094` + // Estimated: `2579` + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(28_000_000, 2579) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + + fn commit_single() -> Weight { + // Proof Size summary in bytes: + // Measured: `1094` + // Estimated: `2579` + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(9_000_000, 1586) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/snowbridge_pallet_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/snowbridge_pallet_system.rs new file mode 100644 index 0000000000000000000000000000000000000000..c6c188e323af84d11ba396cb9ab4e97983bac33c --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/snowbridge_pallet_system.rs @@ -0,0 +1,256 @@ +// 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. + +//! Autogenerated weights for `snowbridge_system` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-09, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `crake.local`, CPU: `` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/polkadot-parachain +// benchmark +// pallet +// --chain +// bridge-hub-rococo-dev +// --pallet=snowbridge_pallet_system +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --output +// parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_system.rs + +#![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 `snowbridge_system`. +pub struct WeightInfo(PhantomData); +impl snowbridge_pallet_system::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: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) + /// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:0 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn upgrade() -> Weight { + // Proof Size summary in bytes: + // Measured: `80` + // Estimated: `3517` + // Minimum execution time: 47_000_000 picoseconds. + Weight::from_parts(47_000_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: EthereumSystem Agents (r:1 w:1) + /// Proof: EthereumSystem Agents (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ParachainInfo ParachainId (r:1 w:0) + /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) + /// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:0 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn create_agent() -> Weight { + // Proof Size summary in bytes: + // Measured: `187` + // Estimated: `6196` + // Minimum execution time: 87_000_000 picoseconds. + Weight::from_parts(87_000_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: EthereumSystem Agents (r:1 w:0) + /// Proof: EthereumSystem Agents (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: EthereumSystem Channels (r:1 w:1) + /// Proof: EthereumSystem Channels (max_values: None, max_size: Some(12), added: 2487, mode: MaxEncodedLen) + /// Storage: ParachainInfo ParachainId (r:1 w:0) + /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) + /// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn create_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `602` + // Estimated: `69050` + // Minimum execution time: 84_000_000 picoseconds. + Weight::from_parts(84_000_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: EthereumSystem Channels (r:1 w:0) + /// Proof: EthereumSystem Channels (max_values: None, max_size: Some(12), added: 2487, mode: MaxEncodedLen) + /// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) + /// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:0 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn update_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `256` + // Estimated: `6044` + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(41_000_000, 0) + .saturating_add(Weight::from_parts(0, 6044)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: EthereumSystem Channels (r:1 w:0) + /// Proof: EthereumSystem Channels (max_values: None, max_size: Some(12), added: 2487, mode: MaxEncodedLen) + /// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) + /// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:0 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn force_update_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `256` + // Estimated: `6044` + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(41_000_000, 0) + .saturating_add(Weight::from_parts(0, 6044)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: ParachainInfo ParachainId (r:1 w:0) + /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) + /// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:0 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn set_operating_mode() -> Weight { + // Proof Size summary in bytes: + // Measured: `80` + // Estimated: `3517` + // Minimum execution time: 30_000_000 picoseconds. + Weight::from_parts(30_000_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: EthereumSystem Agents (r:1 w:0) + /// Proof: EthereumSystem Agents (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) + /// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:0 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn transfer_native_from_agent() -> Weight { + // Proof Size summary in bytes: + // Measured: `252` + // Estimated: `6044` + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(43_000_000, 0) + .saturating_add(Weight::from_parts(0, 6044)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: EthereumSystem Agents (r:1 w:0) + /// Proof: EthereumSystem Agents (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) + /// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:0 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn force_transfer_native_from_agent() -> Weight { + // Proof Size summary in bytes: + // Measured: `252` + // Estimated: `6044` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(42_000_000, 0) + .saturating_add(Weight::from_parts(0, 6044)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + + /// Storage: ParachainInfo ParachainId (r:1 w:0) + /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) + /// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:0 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn set_token_transfer_fees() -> Weight { + // Proof Size summary in bytes: + // Measured: `80` + // Estimated: `3517` + // Minimum execution time: 31_000_000 picoseconds. + Weight::from_parts(42_000_000, 3517) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + + /// Storage: ParachainInfo ParachainId (r:1 w:0) + /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) + /// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:0 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn set_pricing_parameters() -> Weight { + // Proof Size summary in bytes: + // Measured: `80` + // Estimated: `3517` + // Minimum execution time: 31_000_000 picoseconds. + Weight::from_parts(42_000_000, 3517) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } +} 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 4310b24564758c4a3d95d27f047dd8988a43395c..5bd1d1680aa1ef596940b16f3e5df911647b15f1 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 @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-696hpswk-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: // target/production/polkadot-parachain @@ -33,10 +33,10 @@ // --heap-pages=4096 // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_xcm_benchmarks::fungible -// --chain=bridge-hub-rococo-dev +// --chain=bridge-hub-westend-dev // --header=./cumulus/file_header.txt // --template=./cumulus/templates/xcm-bench-template.hbs -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/ +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 19_037_000 picoseconds. - Weight::from_parts(19_602_000, 3593) + // Minimum execution time: 30_218_000 picoseconds. + Weight::from_parts(30_783_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,15 +65,13 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `153` // Estimated: `6196` - // Minimum execution time: 43_115_000 picoseconds. - Weight::from_parts(43_897_000, 6196) + // Minimum execution time: 42_631_000 picoseconds. + Weight::from_parts(43_127_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } // Storage: `System::Account` (r:3 w:3) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - // Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) - // Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -90,11 +88,11 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn transfer_reserve_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `294` + // Measured: `260` // Estimated: `8799` - // Minimum execution time: 90_267_000 picoseconds. - Weight::from_parts(91_460_000, 8799) - .saturating_add(T::DbWeight::get().reads(11)) + // Minimum execution time: 100_978_000 picoseconds. + Weight::from_parts(102_819_000, 8799) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } // Storage: `Benchmark::Override` (r:0 w:0) @@ -106,8 +104,6 @@ impl WeightInfo { // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. Weight::from_parts(18_446_744_073_709_551_000, 0) } - // Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) - // Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -126,19 +122,19 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn initiate_reserve_withdraw() -> Weight { // Proof Size summary in bytes: - // Measured: `242` + // Measured: `208` // Estimated: `6196` - // Minimum execution time: 60_477_000 picoseconds. - Weight::from_parts(61_314_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 71_533_000 picoseconds. + Weight::from_parts(72_922_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } pub fn receive_teleported_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_996_000 picoseconds. - Weight::from_parts(3_107_000, 0) + // Minimum execution time: 2_863_000 picoseconds. + Weight::from_parts(2_997_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -146,15 +142,11 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `52` // Estimated: `3593` - // Minimum execution time: 18_907_000 picoseconds. - Weight::from_parts(19_475_000, 3593) + // Minimum execution time: 23_763_000 picoseconds. + Weight::from_parts(24_438_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: `System::Account` (r:2 w:2) - // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - // Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) - // Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -165,21 +157,21 @@ impl WeightInfo { // 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: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // 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`) pub fn deposit_reserve_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `193` + // Measured: `159` // Estimated: `6196` - // Minimum execution time: 59_143_000 picoseconds. - Weight::from_parts(60_316_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 78_182_000 picoseconds. + Weight::from_parts(79_575_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } - // Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) - // Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -198,11 +190,11 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn initiate_teleport() -> Weight { // Proof Size summary in bytes: - // Measured: `141` - // Estimated: `3606` - // Minimum execution time: 44_459_000 picoseconds. - Weight::from_parts(45_365_000, 3606) - .saturating_add(T::DbWeight::get().reads(9)) + // Measured: `107` + // Estimated: `3593` + // Minimum execution time: 46_767_000 picoseconds. + Weight::from_parts(47_823_000, 3593) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } } 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..81705ee2dc94c9095fba3d04dc17ff1c64285185 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 @@ -35,19 +35,24 @@ use parachains_common::{ }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; +use snowbridge_runtime_common::XcmExportFeeToSibling; use sp_runtime::traits::AccountIdConversion; +use sp_std::marker::PhantomData; +use testnet_parachains_constants::westend::snowbridge::EthereumNetwork; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, 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, + FungibleAdapter, HandleFee, IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, + SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, +}; +use xcm_executor::{ + traits::{FeeManager, FeeReason, FeeReason::Export}, + XcmExecutor, }; -use xcm_executor::XcmExecutor; parameter_types! { pub const WestendLocation: Location = Location::parent(); @@ -193,11 +198,24 @@ impl xcm_executor::Config for XcmConfig { type SubscriptionService = PolkadotXcm; type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type FeeManager = XcmFeeManagerFromComponents< + type FeeManager = XcmFeeManagerFromComponentsBridgeHub< WaivedLocations, - XcmFeeToAccount, + ( + XcmExportFeeToSibling< + bp_westend::Balance, + AccountId, + WestendLocation, + EthereumNetwork, + Self::AssetTransactor, + crate::EthereumOutboundQueue, + >, + SendXcmFeeToAccount, + ), >; - type MessageExporter = (crate::bridge_to_rococo_config::ToBridgeHubRococoHaulBlobExporter,); + type MessageExporter = ( + crate::bridge_to_rococo_config::ToBridgeHubRococoHaulBlobExporter, + crate::bridge_to_ethereum_config::SnowbridgeExporter, + ); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; @@ -261,3 +279,24 @@ impl cumulus_pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmExecutor = XcmExecutor; } + +pub struct XcmFeeManagerFromComponentsBridgeHub( + PhantomData<(WaivedLocations, HandleFee)>, +); +impl, FeeHandler: HandleFee> FeeManager + for XcmFeeManagerFromComponentsBridgeHub +{ + fn is_waived(origin: Option<&Location>, fee_reason: FeeReason) -> bool { + let Some(loc) = origin else { return false }; + if let Export { network, destination: Here } = fee_reason { + if network == EthereumNetwork::get() { + return false + } + } + WaivedLocations::contains(loc) + } + + fn handle_fee(fee: Assets, context: Option<&XcmContext>, reason: FeeReason) { + FeeHandler::handle_fee(fee, context, reason); + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/snowbridge.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/snowbridge.rs new file mode 100644 index 0000000000000000000000000000000000000000..46a0fa7a664bb186d5e6f4f781a5e97f0ebc923f --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/snowbridge.rs @@ -0,0 +1,202 @@ +// 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 . + +#![cfg(test)] + +use bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID; +use bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID; +use bp_polkadot_core::Signature; +use bridge_hub_westend_runtime::{ + bridge_to_rococo_config, xcm_config::XcmConfig, AllPalletsWithoutSystem, + BridgeRejectObsoleteHeadersAndMessages, Executive, MessageQueueServiceWeight, Runtime, + RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, UncheckedExtrinsic, +}; +use codec::{Decode, Encode}; +use cumulus_primitives_core::XcmError::{FailedToTransactAsset, NotHoldingFees}; +use frame_support::parameter_types; +use parachains_common::{AccountId, AuraId, Balance}; +use snowbridge_pallet_ethereum_client::WeightInfo; +use sp_core::H160; +use sp_keyring::AccountKeyring::Alice; +use sp_runtime::{ + generic::{Era, SignedPayload}, + AccountId32, +}; + +parameter_types! { + pub const DefaultBridgeHubEthereumBaseFee: Balance = 2_750_872_500_000; +} + +fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys { + bridge_hub_test_utils::CollatorSessionKeys::new( + AccountId::from(Alice), + AccountId::from(Alice), + SessionKeys { aura: AuraId::from(Alice.public()) }, + ) +} + +#[test] +pub fn transfer_token_to_ethereum_works() { + snowbridge_runtime_test_common::send_transfer_token_message_success::( + 11155111, + collator_session_keys(), + BRIDGE_HUB_WESTEND_PARACHAIN_ID, + ASSET_HUB_WESTEND_PARACHAIN_ID, + H160::random(), + H160::random(), + DefaultBridgeHubEthereumBaseFee::get(), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::EthereumOutboundQueue(event)) => Some(event), + _ => None, + } + }), + ) +} + +#[test] +pub fn unpaid_transfer_token_to_ethereum_fails_with_barrier() { + snowbridge_runtime_test_common::send_unpaid_transfer_token_message::( + 11155111, + collator_session_keys(), + BRIDGE_HUB_WESTEND_PARACHAIN_ID, + ASSET_HUB_WESTEND_PARACHAIN_ID, + H160::random(), + H160::random(), + ) +} + +#[test] +pub fn transfer_token_to_ethereum_fee_not_enough() { + snowbridge_runtime_test_common::send_transfer_token_message_failure::( + 11155111, + collator_session_keys(), + BRIDGE_HUB_WESTEND_PARACHAIN_ID, + ASSET_HUB_WESTEND_PARACHAIN_ID, + DefaultBridgeHubEthereumBaseFee::get() + 10_000_000_000, + H160::random(), + H160::random(), + // fee not enough + 10_000_000_000, + NotHoldingFees, + ) +} + +#[test] +pub fn transfer_token_to_ethereum_insufficient_fund() { + snowbridge_runtime_test_common::send_transfer_token_message_failure::( + 11155111, + collator_session_keys(), + BRIDGE_HUB_WESTEND_PARACHAIN_ID, + ASSET_HUB_WESTEND_PARACHAIN_ID, + 1_000_000_000, + H160::random(), + H160::random(), + DefaultBridgeHubEthereumBaseFee::get(), + FailedToTransactAsset("Funds are unavailable"), + ) +} + +#[test] +fn max_message_queue_service_weight_is_more_than_beacon_extrinsic_weights() { + let max_message_queue_weight = MessageQueueServiceWeight::get(); + let force_checkpoint = + ::WeightInfo::force_checkpoint(); + let submit_checkpoint = + ::WeightInfo::submit(); + max_message_queue_weight.all_gt(force_checkpoint); + max_message_queue_weight.all_gt(submit_checkpoint); +} + +#[test] +fn ethereum_client_consensus_extrinsics_work() { + snowbridge_runtime_test_common::ethereum_extrinsic( + collator_session_keys(), + BRIDGE_HUB_WESTEND_PARACHAIN_ID, + construct_and_apply_extrinsic, + ); +} + +#[test] +fn ethereum_to_polkadot_message_extrinsics_work() { + snowbridge_runtime_test_common::ethereum_to_polkadot_message_extrinsics_work( + collator_session_keys(), + BRIDGE_HUB_WESTEND_PARACHAIN_ID, + construct_and_apply_extrinsic, + ); +} + +/// Tests that the digest items are as expected when a Ethereum Outbound message is received. +/// If the MessageQueue pallet is configured before (i.e. the MessageQueue pallet is listed before +/// the EthereumOutboundQueue in the construct_runtime macro) the EthereumOutboundQueue, this test +/// will fail. +#[test] +pub fn ethereum_outbound_queue_processes_messages_before_message_queue_works() { + snowbridge_runtime_test_common::ethereum_outbound_queue_processes_messages_before_message_queue_works::< + Runtime, + XcmConfig, + AllPalletsWithoutSystem, + >( + 11155111, + collator_session_keys(), + BRIDGE_HUB_WESTEND_PARACHAIN_ID, + ASSET_HUB_WESTEND_PARACHAIN_ID, + H160::random(), + H160::random(), + DefaultBridgeHubEthereumBaseFee::get(), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::EthereumOutboundQueue(event)) => Some(event), + _ => None, + } + }), + ) +} + +fn construct_extrinsic( + sender: sp_keyring::AccountKeyring, + call: RuntimeCall, +) -> UncheckedExtrinsic { + let account_id = AccountId32::from(sender.public()); + let extra: SignedExtra = ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::::from(Era::immortal()), + frame_system::CheckNonce::::from( + frame_system::Pallet::::account(&account_id).nonce, + ), + frame_system::CheckWeight::::new(), + pallet_transaction_payment::ChargeTransactionPayment::::from(0), + BridgeRejectObsoleteHeadersAndMessages::default(), + (bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages::default(),), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), + frame_metadata_hash_extension::CheckMetadataHash::::new(false), + ); + let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); + let signature = payload.using_encoded(|e| sender.sign(e)); + UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), extra) +} + +fn construct_and_apply_extrinsic( + origin: sp_keyring::AccountKeyring, + call: RuntimeCall, +) -> sp_runtime::DispatchOutcome { + let xt = construct_extrinsic(origin, call); + let r = Executive::apply_extrinsic(xt); + r.unwrap() +} 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 763271fd7af0e69ae8de2aa4fe507083f5d09d9e..a66c0f84240c80cef33d21f35ee505db3c4fe292 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,9 +27,8 @@ use bridge_hub_westend_runtime::{ SignedExtra, TransactionPayment, UncheckedExtrinsic, }; use bridge_to_rococo_config::{ - BridgeGrandpaRococoInstance, BridgeHubRococoChainId, BridgeHubRococoLocation, - BridgeParachainRococoInstance, WithBridgeHubRococoMessagesInstance, - XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, + BridgeGrandpaRococoInstance, BridgeHubRococoLocation, BridgeParachainRococoInstance, + WithBridgeHubRococoMessagesInstance, XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, }; use codec::{Decode, Encode}; use frame_support::{dispatch::GetDispatchInfo, parameter_types, traits::ConstU8}; @@ -78,6 +77,7 @@ fn construct_extrinsic( BridgeRejectObsoleteHeadersAndMessages::default(), (bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages::default(),), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), + frame_metadata_hash_extension::CheckMetadataHash::new(false), ); let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); @@ -212,11 +212,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 + }, ) } @@ -248,8 +251,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, ) } @@ -260,11 +262,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, ) } @@ -300,8 +300,8 @@ pub fn can_calculate_fee_for_standalone_message_delivery_transaction() { RuntimeTestsAdapter, >(collator_session_keys(), construct_and_estimate_extrinsic_fee) }, - Perbill::from_percent(33), - Some(-33), + Perbill::from_percent(25), + Some(-25), &format!( "Estimate fee for `single message delivery` for runtime: {:?}", ::Version::get() @@ -319,8 +319,8 @@ pub fn can_calculate_fee_for_standalone_message_confirmation_transaction() { RuntimeTestsAdapter, >(collator_session_keys(), construct_and_estimate_extrinsic_fee) }, - Perbill::from_percent(33), - Some(-33), + Perbill::from_percent(25), + Some(-25), &format!( "Estimate fee for `single message confirmation` for runtime: {:?}", ::Version::get() 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 d6dfa93731a7d3fe17203330e86486093ca5d7ed..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 @@ -94,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, @@ -125,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::( @@ -141,7 +140,6 @@ pub fn relayed_incoming_message_works( test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< BridgedChainOf, ThisChainOf, - (), >( lane_id, xcm.into(), @@ -197,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, @@ -235,8 +231,9 @@ pub fn free_relay_extrinsic_works( 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; @@ -266,7 +263,6 @@ pub fn free_relay_extrinsic_works( test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< BridgedChainOf, ThisChainOf, - (), >( lane_id, xcm.into(), @@ -328,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, @@ -361,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::( @@ -377,7 +372,6 @@ pub fn complex_relay_extrinsic_works( test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< BridgedChainOf, ThisChainOf, - (), >( lane_id, xcm.into(), @@ -452,7 +446,6 @@ where test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< BridgedChainOf, ThisChainOf, - (), >( LaneId::default(), vec![Instruction::<()>::ClearOrigin; 1_024].into(), @@ -557,7 +550,6 @@ where test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< BridgedChainOf, ThisChainOf, - (), >( LaneId::default(), vec![Instruction::<()>::ClearOrigin; 1_024].into(), 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 728b4e76b1055dd215d68a91ecb01704850d38a4..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 @@ -104,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, @@ -138,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::( @@ -162,7 +161,6 @@ pub fn relayed_incoming_message_works( >::BridgedChain, BridgedChainOf, ThisChainOf, - (), >( lane_id, xcm.into(), @@ -234,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, @@ -275,8 +271,9 @@ pub fn free_relay_extrinsic_works( 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; @@ -315,7 +312,6 @@ pub fn free_relay_extrinsic_works( >::BridgedChain, BridgedChainOf, ThisChainOf, - (), >( lane_id, xcm.into(), @@ -399,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, @@ -435,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::( @@ -459,7 +454,6 @@ pub fn complex_relay_extrinsic_works( >::BridgedChain, BridgedChainOf, ThisChainOf, - (), >( lane_id, xcm.into(), @@ -557,7 +551,6 @@ where >::BridgedChain, BridgedChainOf, ThisChainOf, - (), >( LaneId::default(), vec![Instruction::<()>::ClearOrigin; 1_024].into(), @@ -628,7 +621,6 @@ where >::BridgedChain, BridgedChainOf, ThisChainOf, - (), >( LaneId::default(), 1, @@ -691,7 +683,6 @@ where >::BridgedChain, BridgedChainOf, ThisChainOf, - (), >( LaneId::default(), vec![Instruction::<()>::ClearOrigin; 1_024].into(), @@ -747,7 +738,6 @@ where >::BridgedChain, 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 78b8a170f0d4b0bb6ed0aa71a5cac0dceeca96fe..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,6 +22,7 @@ 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::{ @@ -267,6 +268,7 @@ pub fn relayed_incoming_message_works( InteriorLocation, MessageNonce, Xcm<()>, + bp_runtime::ChainId, ) -> CallsAndVerifiers, ) where Runtime: BasicParachainRuntime + cumulus_pallet_xcmp_queue::Config + BridgeMessagesConfig, @@ -278,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); @@ -339,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 c61a31e5454ba75429929a0c7b879f6baaa72e15..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 @@ -152,13 +152,9 @@ where } /// Prepare storage proofs of messages, stored at the (bridged) source GRANDPA chain. -pub fn make_complex_relayer_delivery_proofs< - BridgedChain, - ThisChainWithMessages, - InnerXcmRuntimeCall, ->( +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, 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 897fe0d0b0f17729e8bbcd8c941d08ec868ac087..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 @@ -195,10 +195,9 @@ pub fn make_complex_relayer_delivery_proofs< BridgedRelayChain, BridgedParachain, ThisChainWithMessages, - InnerXcmRuntimeCall, >( lane_id: LaneId, - xcm_message: Xcm, + xcm_message: Xcm<()>, message_nonce: MessageNonce, message_destination: Junctions, para_header_number: u32, @@ -267,7 +266,6 @@ pub fn make_complex_relayer_confirmation_proofs< BridgedRelayChain, BridgedParachain, ThisChainWithMessages, - InnerXcmRuntimeCall, >( lane_id: LaneId, para_header_number: u32, 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/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index d843d6f6f776e0c4eadec44c72925a19402423df..21206d26dd573cc1473f3ba569433e9b7e61e7af 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -125,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_014_000, + spec_version: 1_015_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, 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..08b1d192b0be18c73b5cad3cc26ead88bdbacb64 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs @@ -40,14 +40,15 @@ 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; parameter_types! { + pub const RootLocation: Location = Location::here(); pub const WndLocation: Location = Location::parent(); pub const RelayNetwork: Option = Some(NetworkId::Westend); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); @@ -139,6 +140,13 @@ impl Contains for ParentOrParentsPlurality { } } +pub struct LocalPlurality; +impl Contains for LocalPlurality { + fn contains(loc: &Location) -> bool { + matches!(loc.unpack(), (0, [Plurality { .. }])) + } +} + pub type Barrier = TrailingSetTopicAsId< DenyThenTry< DenyReserveTransferToRelayChain, @@ -173,6 +181,8 @@ pub type Barrier = TrailingSetTopicAsId< pub type WaivedLocations = ( RelayOrOtherSystemParachains, Equals, + Equals, + LocalPlurality, ); /// Cases where a remote origin is accepted as trusted Teleporter for a given asset: @@ -209,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/constants/src/westend.rs b/cumulus/parachains/runtimes/constants/src/westend.rs index 607d91e8808d7d9c0aacaa8d1f4056ba5ff06821..fec66cec2eb6a8df284a50b95c6b71c6a0d81c17 100644 --- a/cumulus/parachains/runtimes/constants/src/westend.rs +++ b/cumulus/parachains/runtimes/constants/src/westend.rs @@ -168,3 +168,19 @@ pub mod time { pub const HOURS: BlockNumber = MINUTES * 60; pub const DAYS: BlockNumber = HOURS * 24; } + +pub mod snowbridge { + use frame_support::parameter_types; + use xcm::opaque::lts::NetworkId; + + /// The pallet index of the Ethereum inbound queue pallet in the bridge hub runtime. + pub const INBOUND_QUEUE_PALLET_INDEX: u8 = 80; + + parameter_types! { + /// Network and location for the Ethereum chain. On Westend, the Ethereum chain bridged + /// to is the Sepolia Ethereum testnet, with chain ID 11155111. + /// + /// + pub EthereumNetwork: NetworkId = NetworkId::Ethereum { chain_id: 11155111 }; + } +} diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 47ce6f3628ecdd6a426ccbed9f503258d3c6171a..bf173fb618afc91601b11f2a31a93a8a928be15b 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -144,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_014_000, + spec_version: 1_015_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 7, 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/src/coretime.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs index fa0c2644421e7ebc3f34a562e6aa2ea0b255df12..76ee06a87e8d82dea17914e4f03647da2a5f307a 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::*; +use crate::{xcm_config::LocationToAccountId, *}; use codec::{Decode, Encode}; use cumulus_pallet_parachain_system::RelaychainDataProvider; use cumulus_primitives_core::relay_chain; @@ -27,12 +27,14 @@ use frame_support::{ }, }; use frame_system::Pallet as System; -use pallet_broker::{CoreAssignment, CoreIndex, CoretimeInterface, PartsOf57600, RCBlockNumberOf}; +use pallet_broker::{ + CoreAssignment, CoreIndex, CoretimeInterface, PartsOf57600, RCBlockNumberOf, TaskId, +}; use parachains_common::{AccountId, Balance}; use rococo_runtime_constants::system_parachain::coretime; -use sp_runtime::traits::AccountIdConversion; +use sp_runtime::traits::{AccountIdConversion, MaybeConvert}; use xcm::latest::prelude::*; -use xcm_executor::traits::TransactAsset; +use xcm_executor::traits::{ConvertLocation, TransactAsset}; pub struct BurnCoretimeRevenue; impl OnUnbalanced> for BurnCoretimeRevenue { @@ -263,6 +265,15 @@ impl CoretimeInterface for CoretimeAllocator { } } +pub struct SovereignAccountOf; +impl MaybeConvert for SovereignAccountOf { + fn maybe_convert(id: TaskId) -> Option { + // Currently all tasks are parachains. + let location = Location::new(1, [Parachain(id)]); + LocationToAccountId::convert_location(&location) + } +} + impl pallet_broker::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; @@ -275,5 +286,7 @@ impl pallet_broker::Config for Runtime { type WeightInfo = weights::pallet_broker::WeightInfo; type PalletId = BrokerPalletId; type AdminOrigin = EnsureRoot; + type SovereignAccountOf = SovereignAccountOf; + type MaxAutoRenewals = ConstU32<100>; type PriceAdapter = pallet_broker::CenterTargetPrice; } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index 9fd0093840d3fb7008a8fd0f67cb55b858d8600a..25324bf1776420bed76df472739f55cce4295ccc 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -146,7 +146,7 @@ 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_014_000, + spec_version: 1_015_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, @@ -832,7 +832,7 @@ impl_runtime_apis! { let begin = 0; let end = 42; - let region_id = pallet_broker::Pallet::::issue(core, begin, end, None, None); + let region_id = pallet_broker::Pallet::::issue(core, begin, pallet_broker::CoreMask::complete(), end, None, None); Some(( Asset { fun: NonFungible(Index(region_id.into())), 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 83e80e2e91e737827fce0b90fad0ec3d70ce3c33..35708f22de20555656feec8ba2ce822dace81303 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 @@ -549,6 +549,44 @@ impl pallet_broker::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `Broker::SaleInfo` (r:1 w:1) + /// 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: `Broker::Configuration` (r:1 w:0) + /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Storage: `Broker::Status` (r:1 w:0) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Authorship::Author` (r:1 w:0) + /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `System::Digest` (r:1 w:0) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Broker::AutoRenewals` (r:1 w:1) + /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Storage: `Broker::Workplan` (r:0 w:1) + /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) + fn enable_auto_renew() -> Weight { + // Proof Size summary in bytes: + // Measured: `914` + // Estimated: `4698` + // Minimum execution time: 51_938_000 picoseconds. + Weight::from_parts(55_025_000, 4698) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: `Broker::AutoRenewals` (r:1 w:1) + /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + fn disable_auto_renew() -> Weight { + // Proof Size summary in bytes: + // Measured: `480` + // Estimated: `1516` + // Minimum execution time: 9_628_000 picoseconds. + Weight::from_parts(10_400_000, 1516) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } /// 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) 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 73a71980530707930681ebc82a5cd563372eb24e..c8dbdadf7b15dfcd2ea86326fcff2495a2087a3a 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 @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-05-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-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 WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 26_642_000 picoseconds. - Weight::from_parts(27_583_000, 3593) + // Minimum execution time: 29_812_000 picoseconds. + Weight::from_parts(30_526_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 35_124_000 picoseconds. - Weight::from_parts(36_510_000, 6196) + // Minimum execution time: 39_430_000 picoseconds. + Weight::from_parts(39_968_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -88,8 +88,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `207` // Estimated: `6196` - // Minimum execution time: 55_950_000 picoseconds. - Weight::from_parts(57_207_000, 6196) + // Minimum execution time: 65_555_000 picoseconds. + Weight::from_parts(67_161_000, 6196) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -118,8 +118,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 23_747_000 picoseconds. - Weight::from_parts(24_424_000, 3571) + // Minimum execution time: 30_491_000 picoseconds. + Weight::from_parts(31_991_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -127,8 +127,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_853_000 picoseconds. - Weight::from_parts(1_998_000, 0) + // Minimum execution time: 2_568_000 picoseconds. + Weight::from_parts(2_703_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -136,8 +136,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 19_164_000 picoseconds. - Weight::from_parts(19_643_000, 3593) + // Minimum execution time: 22_159_000 picoseconds. + Weight::from_parts(22_517_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -159,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3593` - // Minimum execution time: 48_708_000 picoseconds. - Weight::from_parts(49_610_000, 3593) + // Minimum execution time: 57_126_000 picoseconds. + Weight::from_parts(58_830_000, 3593) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -180,8 +180,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 20_586_000 picoseconds. - Weight::from_parts(21_147_000, 3571) + // Minimum execution time: 26_589_000 picoseconds. + Weight::from_parts(27_285_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } 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/src/coretime.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs index 4f06e3e3669c8d69fcb990e55eb7c9e83432e96f..865ff68d4c659fd8c324595eadf790be655f9655 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::*; +use crate::{xcm_config::LocationToAccountId, *}; use codec::{Decode, Encode}; use cumulus_pallet_parachain_system::RelaychainDataProvider; use cumulus_primitives_core::relay_chain; @@ -28,13 +28,13 @@ use frame_support::{ }; use frame_system::Pallet as System; use pallet_broker::{ - CoreAssignment, CoreIndex, CoretimeInterface, PartsOf57600, RCBlockNumberOf, Timeslice, + CoreAssignment, CoreIndex, CoretimeInterface, PartsOf57600, RCBlockNumberOf, TaskId, Timeslice, }; use parachains_common::{AccountId, Balance}; -use sp_runtime::traits::AccountIdConversion; +use sp_runtime::traits::{AccountIdConversion, MaybeConvert}; use westend_runtime_constants::system_parachain::coretime; use xcm::latest::prelude::*; -use xcm_executor::traits::TransactAsset; +use xcm_executor::traits::{ConvertLocation, TransactAsset}; pub struct BurnCoretimeRevenue; impl OnUnbalanced> for BurnCoretimeRevenue { @@ -277,6 +277,15 @@ impl CoretimeInterface for CoretimeAllocator { } } +pub struct SovereignAccountOf; +impl MaybeConvert for SovereignAccountOf { + fn maybe_convert(id: TaskId) -> Option { + // Currently all tasks are parachains. + let location = Location::new(1, [Parachain(id)]); + LocationToAccountId::convert_location(&location) + } +} + impl pallet_broker::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; @@ -290,5 +299,7 @@ impl pallet_broker::Config for Runtime { type WeightInfo = weights::pallet_broker::WeightInfo; type PalletId = BrokerPalletId; type AdminOrigin = EnsureRoot; + type SovereignAccountOf = SovereignAccountOf; + type MaxAutoRenewals = ConstU32<20>; type PriceAdapter = pallet_broker::CenterTargetPrice; } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index 7907f252cf8e47a1d1694c7721f72a81e660dc74..a3051e4bf2713a4082f19df12082a4fb532b85bb 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -145,7 +145,7 @@ 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_014_000, + spec_version: 1_015_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, @@ -823,7 +823,7 @@ impl_runtime_apis! { let begin = 0; let end = 42; - let region_id = pallet_broker::Pallet::::issue(core, begin, end, None, None); + let region_id = pallet_broker::Pallet::::issue(core, begin, pallet_broker::CoreMask::complete(), end, None, None); Some(( Asset { fun: NonFungible(Index(region_id.into())), 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 d130b306f7a52b75958db353aea24e9e113c82d5..74b1c4e470297e212825a94da1886784e869ccd9 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 @@ -549,6 +549,44 @@ impl pallet_broker::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `Broker::SaleInfo` (r:1 w:1) + /// 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: `Broker::Configuration` (r:1 w:0) + /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Storage: `Broker::Status` (r:1 w:0) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Authorship::Author` (r:1 w:0) + /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `System::Digest` (r:1 w:0) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Broker::AutoRenewals` (r:1 w:1) + /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Storage: `Broker::Workplan` (r:0 w:1) + /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) + fn enable_auto_renew() -> Weight { + // Proof Size summary in bytes: + // Measured: `914` + // Estimated: `4698` + // Minimum execution time: 51_938_000 picoseconds. + Weight::from_parts(55_025_000, 4698) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: `Broker::AutoRenewals` (r:1 w:1) + /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + fn disable_auto_renew() -> Weight { + // Proof Size summary in bytes: + // Measured: `480` + // Estimated: `1516` + // Minimum execution time: 9_628_000 picoseconds. + Weight::from_parts(10_400_000, 1516) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } /// 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 { 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 ddfc599fa579dd7ae4b83d0a94b0e7092fbdc9c1..935636651eb9dcb5ce0580978d9f1340313ef289 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 @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-05-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-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 WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 26_842_000 picoseconds. - Weight::from_parts(27_606_000, 3593) + // Minimum execution time: 29_866_000 picoseconds. + Weight::from_parts(30_363_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 35_076_000 picoseconds. - Weight::from_parts(36_109_000, 6196) + // Minimum execution time: 39_434_000 picoseconds. + Weight::from_parts(40_274_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -88,8 +88,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `207` // Estimated: `6196` - // Minimum execution time: 56_951_000 picoseconds. - Weight::from_parts(58_286_000, 6196) + // Minimum execution time: 66_303_000 picoseconds. + Weight::from_parts(68_294_000, 6196) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -118,8 +118,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 23_796_000 picoseconds. - Weight::from_parts(24_692_000, 3571) + // Minimum execution time: 30_523_000 picoseconds. + Weight::from_parts(31_289_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -127,8 +127,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_990_000 picoseconds. - Weight::from_parts(2_142_000, 0) + // Minimum execution time: 2_517_000 picoseconds. + Weight::from_parts(2_634_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -136,8 +136,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 19_572_000 picoseconds. - Weight::from_parts(20_017_000, 3593) + // Minimum execution time: 22_151_000 picoseconds. + Weight::from_parts(22_907_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -159,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3593` - // Minimum execution time: 49_336_000 picoseconds. - Weight::from_parts(50_507_000, 3593) + // Minimum execution time: 57_763_000 picoseconds. + Weight::from_parts(58_941_000, 3593) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -180,8 +180,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 21_230_000 picoseconds. - Weight::from_parts(21_870_000, 3571) + // Minimum execution time: 26_322_000 picoseconds. + Weight::from_parts(27_197_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } 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/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs index 1b505ad3acbf7aa22a84ce9923a621d826358122..942e11e0b2574e0d7016f452f6808e8ddf633479 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs @@ -102,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_014_000, + spec_version: 1_015_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index 4f007c3fc39db185df12cee525509d9a1433a9d9..77bfb99669c6c2f58d5e6d3398b2d805b4a2ac17 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -134,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_014_000, + spec_version: 1_015_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, 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 11c1bad9aa17866d882f4410d76065a18ab4ef28..58007173ae1d505ad5f831e8f4962d2c4e491615 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 @@ -5,7 +5,7 @@ // 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 +// 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, @@ -60,10 +60,8 @@ impl XcmWeightInfo for PeopleRococoXcmWeight { fn withdraw_asset(assets: &Assets) -> Weight { assets.weigh_assets(XcmFungibleWeight::::withdraw_asset()) } - // Currently there is no trusted reserve - fn reserve_asset_deposited(_assets: &Assets) -> Weight { - // TODO: hardcoded - fix https://github.com/paritytech/cumulus/issues/1974 - Weight::from_parts(1_000_000_000_u64, 0) + fn reserve_asset_deposited(assets: &Assets) -> Weight { + assets.weigh_assets(XcmFungibleWeight::::reserve_asset_deposited()) } fn receive_teleported_asset(assets: &Assets) -> Weight { assets.weigh_assets(XcmFungibleWeight::::receive_teleported_asset()) @@ -114,12 +112,8 @@ impl XcmWeightInfo for PeopleRococoXcmWeight { fn report_error(_query_response_info: &QueryResponseInfo) -> Weight { XcmGeneric::::report_error() } - fn deposit_asset(assets: &AssetFilter, _dest: &Location) -> Weight { - // Hardcoded till the XCM pallet is fixed - let hardcoded_weight = Weight::from_parts(1_000_000_000_u64, 0); - let weight = assets.weigh_assets(XcmFungibleWeight::::deposit_asset()); - hardcoded_weight.min(weight) + assets.weigh_assets(XcmFungibleWeight::::deposit_asset()) } fn deposit_reserve_asset(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::deposit_reserve_asset()) @@ -132,7 +126,7 @@ impl XcmWeightInfo for PeopleRococoXcmWeight { _reserve: &Location, _xcm: &Xcm<()>, ) -> Weight { - assets.weigh_assets(XcmGeneric::::initiate_reserve_withdraw()) + assets.weigh_assets(XcmFungibleWeight::::initiate_reserve_withdraw()) } fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::initiate_teleport()) 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 2364798596d50f396a3a732c1e9dc1ad6c48a5bf..4dd44e66dd5e3cf0e545fac692cf27257cb075f4 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 @@ -1,41 +1,42 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// 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. +// 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 . //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("people-kusama-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("people-rococo-dev"), DB CACHE: 1024 // Executed Command: -// ./artifacts/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --template=./templates/xcm-bench-template.hbs -// --chain=people-kusama-dev -// --execution=wasm -// --wasm-execution=compiled -// --pallet=pallet_xcm_benchmarks::fungible -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./cumulus/parachains/runtimes/people/people-kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm_benchmarks::fungible +// --chain=people-rococo-dev +// --header=./cumulus/file_header.txt +// --template=./cumulus/templates/xcm-bench-template.hbs +// --output=./cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,110 +48,140 @@ use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::fungible`. pub struct WeightInfo(PhantomData); impl WeightInfo { - // Storage: System Account (r:1 w:1) - // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) pub fn withdraw_asset() -> Weight { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 23_309_000 picoseconds. - Weight::from_parts(23_777_000, 3593) + // Minimum execution time: 30_428_000 picoseconds. + Weight::from_parts(31_184_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: System Account (r:2 w:2) - // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) pub fn transfer_asset() -> Weight { // Proof Size summary in bytes: // Measured: `153` // Estimated: `6196` - // Minimum execution time: 48_808_000 picoseconds. - Weight::from_parts(49_427_000, 6196) + // Minimum execution time: 41_912_000 picoseconds. + Weight::from_parts(43_346_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: System Account (r:2 w:2) - // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - // Storage: ParachainInfo ParachainId (r:1 w:0) - // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem HostConfiguration (r:1 w:0) - // Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, 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`) pub fn transfer_reserve_asset() -> Weight { // Proof Size summary in bytes: // Measured: `223` // Estimated: `6196` - // Minimum execution time: 71_204_000 picoseconds. - Weight::from_parts(72_121_000, 6196) + // Minimum execution time: 67_706_000 picoseconds. + Weight::from_parts(69_671_000, 6196) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } + // Storage: `Benchmark::Override` (r:0 w:0) + // Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + pub fn reserve_asset_deposited() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + } + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, 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`) + pub fn initiate_reserve_withdraw() -> Weight { + // Proof Size summary in bytes: + // Measured: `70` + // Estimated: `3535` + // Minimum execution time: 29_790_000 picoseconds. + Weight::from_parts(30_655_000, 3535) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) + } pub fn receive_teleported_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_559_000 picoseconds. - Weight::from_parts(3_616_000, 0) + // Minimum execution time: 2_438_000 picoseconds. + Weight::from_parts(2_597_000, 0) } - // Storage: System Account (r:1 w:1) - // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) pub fn deposit_asset() -> Weight { // Proof Size summary in bytes: // Measured: `52` // Estimated: `3593` - // Minimum execution time: 25_042_000 picoseconds. - Weight::from_parts(25_630_000, 3593) + // Minimum execution time: 24_040_000 picoseconds. + Weight::from_parts(24_538_000, 3593) .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: ParachainInfo ParachainId (r:1 w:0) - // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem HostConfiguration (r:1 w:0) - // Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), 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: `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: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // 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`) pub fn deposit_reserve_asset() -> Weight { // Proof Size summary in bytes: // Measured: `122` // Estimated: `3593` - // Minimum execution time: 49_030_000 picoseconds. - Weight::from_parts(49_828_000, 3593) + // Minimum execution time: 58_275_000 picoseconds. + Weight::from_parts(59_899_000, 3593) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: ParachainInfo ParachainId (r:1 w:0) - // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem HostConfiguration (r:1 w:0) - // Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), 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: `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`) pub fn initiate_teleport() -> Weight { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 27_142_000 picoseconds. - Weight::from_parts(27_416_000, 3535) + // Minimum execution time: 25_638_000 picoseconds. + Weight::from_parts(26_514_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } 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 a50c8860c48f84197843a9fd4d44ddb39d742095..729a3211704198bf5c59e1e2ac47e03f88fb0340 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 @@ -1,41 +1,42 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// 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. +// 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 . //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-08-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("people-kusama-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("people-rococo-dev"), DB CACHE: 1024 // Executed Command: -// ./artifacts/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --template=./templates/xcm-bench-template.hbs -// --chain=people-kusama-dev -// --execution=wasm -// --wasm-execution=compiled -// --pallet=pallet_xcm_benchmarks::generic -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./cumulus/parachains/runtimes/people/people-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm_benchmarks::generic +// --chain=people-rococo-dev +// --header=./cumulus/file_header.txt +// --template=./cumulus/templates/xcm-bench-template.hbs +// --output=./cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,24 +48,24 @@ use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::generic`. pub struct WeightInfo(PhantomData); impl WeightInfo { - // Storage: ParachainInfo ParachainId (r:1 w:0) - // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem HostConfiguration (r:1 w:0) - // Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), 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: `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`) pub fn report_holding() -> Weight { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 30_210_000 picoseconds. - Weight::from_parts(30_864_000, 3535) + // Minimum execution time: 29_430_000 picoseconds. + Weight::from_parts(30_111_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -72,97 +73,97 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_808_000 picoseconds. - Weight::from_parts(2_848_000, 0) + // Minimum execution time: 607_000 picoseconds. + Weight::from_parts(672_000, 0) } - // Storage: PolkadotXcm Queries (r:1 w:0) - // Proof Skipped: PolkadotXcm Queries (max_values: None, max_size: None, mode: Measured) + // Storage: `PolkadotXcm::Queries` (r:1 w:0) + // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) pub fn query_response() -> Weight { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 10_353_000 picoseconds. - Weight::from_parts(10_569_000, 3497) + // Minimum execution time: 7_445_000 picoseconds. + Weight::from_parts(7_623_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: 12_074_000 picoseconds. - Weight::from_parts(12_280_000, 0) + // Minimum execution time: 6_749_000 picoseconds. + Weight::from_parts(7_073_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_080_000 picoseconds. - Weight::from_parts(3_161_000, 0) + // Minimum execution time: 1_275_000 picoseconds. + Weight::from_parts(1_409_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_649_000 picoseconds. - Weight::from_parts(2_732_000, 0) + // Minimum execution time: 670_000 picoseconds. + Weight::from_parts(709_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_652_000 picoseconds. - Weight::from_parts(2_749_000, 0) + // Minimum execution time: 635_000 picoseconds. + Weight::from_parts(723_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_642_000 picoseconds. - Weight::from_parts(2_704_000, 0) + // Minimum execution time: 650_000 picoseconds. + Weight::from_parts(699_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_438_000 picoseconds. - Weight::from_parts(3_508_000, 0) + // Minimum execution time: 678_000 picoseconds. + Weight::from_parts(728_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_626_000 picoseconds. - Weight::from_parts(2_701_000, 0) + // Minimum execution time: 657_000 picoseconds. + Weight::from_parts(703_000, 0) } - // Storage: ParachainInfo ParachainId (r:1 w:0) - // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem HostConfiguration (r:1 w:0) - // Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), 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: `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`) pub fn report_error() -> Weight { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 24_737_000 picoseconds. - Weight::from_parts(25_106_000, 3535) + // Minimum execution time: 25_795_000 picoseconds. + Weight::from_parts(26_415_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: PolkadotXcm AssetTraps (r:1 w:1) - // Proof Skipped: PolkadotXcm AssetTraps (max_values: None, max_size: None, mode: Measured) + // Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) + // Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) pub fn claim_asset() -> Weight { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 14_712_000 picoseconds. - Weight::from_parts(14_976_000, 3555) + // Minimum execution time: 10_792_000 picoseconds. + Weight::from_parts(11_061_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -170,114 +171,93 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_689_000 picoseconds. - Weight::from_parts(2_739_000, 0) + // Minimum execution time: 624_000 picoseconds. + Weight::from_parts(682_000, 0) } - // Storage: PolkadotXcm VersionNotifyTargets (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem HostConfiguration (r:1 w:0) - // Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) + // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) + // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + // 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`) pub fn subscribe_version() -> Weight { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 26_478_000 picoseconds. - Weight::from_parts(26_695_000, 3503) + // Minimum execution time: 23_906_000 picoseconds. + Weight::from_parts(24_740_000, 3503) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: PolkadotXcm VersionNotifyTargets (r:0 w:1) - // Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) + // Storage: `PolkadotXcm::VersionNotifyTargets` (r:0 w:1) + // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) pub fn unsubscribe_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_811_000 picoseconds. - Weight::from_parts(5_062_000, 0) + // Minimum execution time: 2_621_000 picoseconds. + Weight::from_parts(2_788_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: ParachainInfo ParachainId (r:1 w:0) - // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem HostConfiguration (r:1 w:0) - // Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) - pub fn initiate_reserve_withdraw() -> Weight { - // Proof Size summary in bytes: - // Measured: `70` - // Estimated: `3535` - // Minimum execution time: 26_945_000 picoseconds. - Weight::from_parts(28_093_000, 3535) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_144_000 picoseconds. - Weight::from_parts(4_217_000, 0) + // Minimum execution time: 954_000 picoseconds. + Weight::from_parts(1_046_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_726_000 picoseconds. - Weight::from_parts(2_802_000, 0) + // Minimum execution time: 742_000 picoseconds. + Weight::from_parts(790_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_719_000 picoseconds. - Weight::from_parts(2_790_000, 0) + // Minimum execution time: 664_000 picoseconds. + Weight::from_parts(722_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_660_000 picoseconds. - Weight::from_parts(2_742_000, 0) + // Minimum execution time: 619_000 picoseconds. + Weight::from_parts(672_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_874_000 picoseconds. - Weight::from_parts(2_940_000, 0) + // Minimum execution time: 798_000 picoseconds. + Weight::from_parts(851_000, 0) } - // Storage: ParachainInfo ParachainId (r:1 w:0) - // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem HostConfiguration (r:1 w:0) - // Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), 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: `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`) pub fn query_pallet() -> Weight { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 27_235_000 picoseconds. - Weight::from_parts(27_811_000, 3535) + // Minimum execution time: 29_580_000 picoseconds. + Weight::from_parts(31_100_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -285,27 +265,27 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_807_000 picoseconds. - Weight::from_parts(4_918_000, 0) + // Minimum execution time: 3_150_000 picoseconds. + Weight::from_parts(3_326_000, 0) } - // Storage: ParachainInfo ParachainId (r:1 w:0) - // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem HostConfiguration (r:1 w:0) - // Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), 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: `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`) pub fn report_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 24_698_000 picoseconds. - Weight::from_parts(25_077_000, 3535) + // Minimum execution time: 26_152_000 picoseconds. + Weight::from_parts(26_635_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -313,35 +293,35 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_613_000 picoseconds. - Weight::from_parts(2_703_000, 0) + // Minimum execution time: 693_000 picoseconds. + Weight::from_parts(724_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_602_000 picoseconds. - Weight::from_parts(2_661_000, 0) + // Minimum execution time: 632_000 picoseconds. + Weight::from_parts(678_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_557_000 picoseconds. - Weight::from_parts(2_655_000, 0) + // Minimum execution time: 646_000 picoseconds. + Weight::from_parts(694_000, 0) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_724_000 picoseconds. - Weight::from_parts(2_760_000, 0) + // Minimum execution time: 622_000 picoseconds. + Weight::from_parts(656_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_764_000 picoseconds. - Weight::from_parts(2_872_000, 0) + // Minimum execution time: 639_000 picoseconds. + Weight::from_parts(679_000, 0) } } 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/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index 1378324ce7b022e306c39ce4d8b1669ef057eb96..3343d2be749d6570915afc60fe40b8a1bd5eaf77 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -134,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_014_000, + spec_version: 1_015_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, 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 b1fc7ad8ed832ec6aa9a65c5e4ad3334ff3225d1..b44e8d4b61b8fe57ea4191b891da6dcbaa962813 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 @@ -5,7 +5,7 @@ // 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 +// 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, @@ -60,10 +60,8 @@ impl XcmWeightInfo for PeopleWestendXcmWeight { fn withdraw_asset(assets: &Assets) -> Weight { assets.weigh_assets(XcmFungibleWeight::::withdraw_asset()) } - // Currently there is no trusted reserve - fn reserve_asset_deposited(_assets: &Assets) -> Weight { - // TODO: hardcoded - fix https://github.com/paritytech/cumulus/issues/1974 - Weight::from_parts(1_000_000_000_u64, 0) + fn reserve_asset_deposited(assets: &Assets) -> Weight { + assets.weigh_assets(XcmFungibleWeight::::reserve_asset_deposited()) } fn receive_teleported_asset(assets: &Assets) -> Weight { assets.weigh_assets(XcmFungibleWeight::::receive_teleported_asset()) @@ -114,12 +112,8 @@ impl XcmWeightInfo for PeopleWestendXcmWeight { fn report_error(_query_response_info: &QueryResponseInfo) -> Weight { XcmGeneric::::report_error() } - fn deposit_asset(assets: &AssetFilter, _dest: &Location) -> Weight { - // Hardcoded till the XCM pallet is fixed - let hardcoded_weight = Weight::from_parts(1_000_000_000_u64, 0); - let weight = assets.weigh_assets(XcmFungibleWeight::::deposit_asset()); - hardcoded_weight.min(weight) + assets.weigh_assets(XcmFungibleWeight::::deposit_asset()) } fn deposit_reserve_asset(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::deposit_reserve_asset()) @@ -132,13 +126,10 @@ impl XcmWeightInfo for PeopleWestendXcmWeight { _reserve: &Location, _xcm: &Xcm<()>, ) -> Weight { - assets.weigh_assets(XcmGeneric::::initiate_reserve_withdraw()) + assets.weigh_assets(XcmFungibleWeight::::initiate_reserve_withdraw()) } fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight { - // Hardcoded till the XCM pallet is fixed - let hardcoded_weight = Weight::from_parts(200_000_000_u64, 0); - let weight = assets.weigh_assets(XcmFungibleWeight::::initiate_teleport()); - hardcoded_weight.min(weight) + assets.weigh_assets(XcmFungibleWeight::::initiate_teleport()) } fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight { XcmGeneric::::report_holding() 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 92d08a24618075d21614ae53ed17e3618fc2f8ea..8f6bfde986bb36c4fd3c90bdfb767727133f8c35 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 @@ -1,41 +1,42 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// 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. +// 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 . //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("people-polkadot-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("people-westend-dev"), DB CACHE: 1024 // Executed Command: -// ./artifacts/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --template=./templates/xcm-bench-template.hbs -// --chain=people-polkadot-dev -// --execution=wasm -// --wasm-execution=compiled -// --pallet=pallet_xcm_benchmarks::fungible -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./cumulus/parachains/runtimes/people/people-polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm_benchmarks::fungible +// --chain=people-westend-dev +// --header=./cumulus/file_header.txt +// --template=./cumulus/templates/xcm-bench-template.hbs +// --output=./cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,110 +48,140 @@ use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::fungible`. pub struct WeightInfo(PhantomData); impl WeightInfo { - // Storage: System Account (r:1 w:1) - // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) pub fn withdraw_asset() -> Weight { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 23_363_000 picoseconds. - Weight::from_parts(23_663_000, 3593) + // Minimum execution time: 30_040_000 picoseconds. + Weight::from_parts(30_758_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: System Account (r:2 w:2) - // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) pub fn transfer_asset() -> Weight { // Proof Size summary in bytes: // Measured: `153` // Estimated: `6196` - // Minimum execution time: 49_093_000 picoseconds. - Weight::from_parts(49_719_000, 6196) + // Minimum execution time: 42_135_000 picoseconds. + Weight::from_parts(42_970_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: System Account (r:2 w:2) - // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - // Storage: ParachainInfo ParachainId (r:1 w:0) - // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem HostConfiguration (r:1 w:0) - // Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, 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`) pub fn transfer_reserve_asset() -> Weight { // Proof Size summary in bytes: // Measured: `223` // Estimated: `6196` - // Minimum execution time: 74_134_000 picoseconds. - Weight::from_parts(74_719_000, 6196) + // Minimum execution time: 67_385_000 picoseconds. + Weight::from_parts(69_776_000, 6196) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } + // Storage: `Benchmark::Override` (r:0 w:0) + // Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + pub fn reserve_asset_deposited() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + } + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, 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`) + pub fn initiate_reserve_withdraw() -> Weight { + // Proof Size summary in bytes: + // Measured: `70` + // Estimated: `3535` + // Minimum execution time: 29_804_000 picoseconds. + Weight::from_parts(30_662_000, 3535) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) + } pub fn receive_teleported_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_726_000 picoseconds. - Weight::from_parts(3_881_000, 0) + // Minimum execution time: 2_358_000 picoseconds. + Weight::from_parts(2_497_000, 0) } - // Storage: System Account (r:1 w:1) - // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) pub fn deposit_asset() -> Weight { // Proof Size summary in bytes: // Measured: `52` // Estimated: `3593` - // Minimum execution time: 25_903_000 picoseconds. - Weight::from_parts(26_150_000, 3593) + // Minimum execution time: 23_732_000 picoseconds. + Weight::from_parts(24_098_000, 3593) .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: ParachainInfo ParachainId (r:1 w:0) - // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem HostConfiguration (r:1 w:0) - // Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), 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: `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: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // 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`) pub fn deposit_reserve_asset() -> Weight { // Proof Size summary in bytes: // Measured: `122` // Estimated: `3593` - // Minimum execution time: 51_084_000 picoseconds. - Weight::from_parts(51_859_000, 3593) + // Minimum execution time: 58_449_000 picoseconds. + Weight::from_parts(60_235_000, 3593) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: ParachainInfo ParachainId (r:1 w:0) - // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem HostConfiguration (r:1 w:0) - // Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), 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: `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`) pub fn initiate_teleport() -> Weight { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 28_038_000 picoseconds. - Weight::from_parts(28_438_000, 3535) + // Minimum execution time: 25_708_000 picoseconds. + Weight::from_parts(26_495_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } 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 861f038199596ef9813275e58914f252d8842a87..1377d31f2db7df67b58a699253af03498f7f6741 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 @@ -1,41 +1,42 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// 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. +// 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 . //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-08-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("people-polkadot-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("people-westend-dev"), DB CACHE: 1024 // Executed Command: -// ./artifacts/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --template=./templates/xcm-bench-template.hbs -// --chain=people-polkadot-dev -// --execution=wasm -// --wasm-execution=compiled -// --pallet=pallet_xcm_benchmarks::generic -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./cumulus/parachains/runtimes/people/people-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm_benchmarks::generic +// --chain=people-westend-dev +// --header=./cumulus/file_header.txt +// --template=./cumulus/templates/xcm-bench-template.hbs +// --output=./cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,24 +48,24 @@ use core::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::generic`. pub struct WeightInfo(PhantomData); impl WeightInfo { - // Storage: ParachainInfo ParachainId (r:1 w:0) - // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem HostConfiguration (r:1 w:0) - // Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), 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: `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`) pub fn report_holding() -> Weight { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 30_819_000 picoseconds. - Weight::from_parts(31_157_000, 3535) + // Minimum execution time: 29_537_000 picoseconds. + Weight::from_parts(30_513_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -72,97 +73,97 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_869_000 picoseconds. - Weight::from_parts(2_920_000, 0) + // Minimum execution time: 683_000 picoseconds. + Weight::from_parts(738_000, 0) } - // Storage: PolkadotXcm Queries (r:1 w:0) - // Proof Skipped: PolkadotXcm Queries (max_values: None, max_size: None, mode: Measured) + // Storage: `PolkadotXcm::Queries` (r:1 w:0) + // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) pub fn query_response() -> Weight { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 10_268_000 picoseconds. - Weight::from_parts(10_496_000, 3497) + // Minimum execution time: 7_498_000 picoseconds. + Weight::from_parts(7_904_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: 11_990_000 picoseconds. - Weight::from_parts(12_206_000, 0) + // Minimum execution time: 7_029_000 picoseconds. + Weight::from_parts(7_325_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_170_000 picoseconds. - Weight::from_parts(3_308_000, 0) + // Minimum execution time: 1_343_000 picoseconds. + Weight::from_parts(1_410_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_650_000 picoseconds. - Weight::from_parts(2_783_000, 0) + // Minimum execution time: 696_000 picoseconds. + Weight::from_parts(734_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_681_000 picoseconds. - Weight::from_parts(2_829_000, 0) + // Minimum execution time: 690_000 picoseconds. + Weight::from_parts(740_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_622_000 picoseconds. - Weight::from_parts(2_688_000, 0) + // Minimum execution time: 667_000 picoseconds. + Weight::from_parts(697_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_385_000 picoseconds. - Weight::from_parts(3_538_000, 0) + // Minimum execution time: 692_000 picoseconds. + Weight::from_parts(743_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_630_000 picoseconds. - Weight::from_parts(2_720_000, 0) + // Minimum execution time: 670_000 picoseconds. + Weight::from_parts(712_000, 0) } - // Storage: ParachainInfo ParachainId (r:1 w:0) - // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem HostConfiguration (r:1 w:0) - // Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), 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: `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`) pub fn report_error() -> Weight { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 24_446_000 picoseconds. - Weight::from_parts(24_854_000, 3535) + // Minimum execution time: 26_405_000 picoseconds. + Weight::from_parts(26_877_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: PolkadotXcm AssetTraps (r:1 w:1) - // Proof Skipped: PolkadotXcm AssetTraps (max_values: None, max_size: None, mode: Measured) + // Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) + // Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) pub fn claim_asset() -> Weight { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 14_713_000 picoseconds. - Weight::from_parts(15_010_000, 3555) + // Minimum execution time: 10_953_000 picoseconds. + Weight::from_parts(11_345_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -170,114 +171,93 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_702_000 picoseconds. - Weight::from_parts(2_744_000, 0) + // Minimum execution time: 644_000 picoseconds. + Weight::from_parts(693_000, 0) } - // Storage: PolkadotXcm VersionNotifyTargets (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem HostConfiguration (r:1 w:0) - // Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) + // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) + // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + // 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`) pub fn subscribe_version() -> Weight { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 25_955_000 picoseconds. - Weight::from_parts(26_632_000, 3503) + // Minimum execution time: 24_157_000 picoseconds. + Weight::from_parts(24_980_000, 3503) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: PolkadotXcm VersionNotifyTargets (r:0 w:1) - // Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) + // Storage: `PolkadotXcm::VersionNotifyTargets` (r:0 w:1) + // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) pub fn unsubscribe_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_965_000 picoseconds. - Weight::from_parts(5_168_000, 0) + // Minimum execution time: 2_767_000 picoseconds. + Weight::from_parts(2_844_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: ParachainInfo ParachainId (r:1 w:0) - // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem HostConfiguration (r:1 w:0) - // Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) - pub fn initiate_reserve_withdraw() -> Weight { - // Proof Size summary in bytes: - // Measured: `70` - // Estimated: `3535` - // Minimum execution time: 27_707_000 picoseconds. - Weight::from_parts(28_081_000, 3535) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_215_000 picoseconds. - Weight::from_parts(4_362_000, 0) + // Minimum execution time: 1_079_000 picoseconds. + Weight::from_parts(1_141_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_843_000 picoseconds. - Weight::from_parts(2_957_000, 0) + // Minimum execution time: 776_000 picoseconds. + Weight::from_parts(829_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_751_000 picoseconds. - Weight::from_parts(2_809_000, 0) + // Minimum execution time: 696_000 picoseconds. + Weight::from_parts(740_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_674_000 picoseconds. - Weight::from_parts(2_737_000, 0) + // Minimum execution time: 655_000 picoseconds. + Weight::from_parts(684_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_891_000 picoseconds. - Weight::from_parts(2_952_000, 0) + // Minimum execution time: 825_000 picoseconds. + Weight::from_parts(853_000, 0) } - // Storage: ParachainInfo ParachainId (r:1 w:0) - // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem HostConfiguration (r:1 w:0) - // Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), 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: `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`) pub fn query_pallet() -> Weight { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 28_600_000 picoseconds. - Weight::from_parts(29_001_000, 3535) + // Minimum execution time: 30_222_000 picoseconds. + Weight::from_parts(31_110_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -285,27 +265,27 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_748_000 picoseconds. - Weight::from_parts(4_813_000, 0) + // Minimum execution time: 3_108_000 picoseconds. + Weight::from_parts(3_325_000, 0) } - // Storage: ParachainInfo ParachainId (r:1 w:0) - // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem HostConfiguration (r:1 w:0) - // Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), 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: `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`) pub fn report_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 25_483_000 picoseconds. - Weight::from_parts(25_737_000, 3535) + // Minimum execution time: 26_548_000 picoseconds. + Weight::from_parts(26_911_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -313,35 +293,35 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_755_000 picoseconds. - Weight::from_parts(2_817_000, 0) + // Minimum execution time: 684_000 picoseconds. + Weight::from_parts(726_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_700_000 picoseconds. - Weight::from_parts(2_773_000, 0) + // Minimum execution time: 649_000 picoseconds. + Weight::from_parts(700_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_670_000 picoseconds. - Weight::from_parts(2_711_000, 0) + // Minimum execution time: 650_000 picoseconds. + Weight::from_parts(686_000, 0) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_710_000 picoseconds. - Weight::from_parts(2_762_000, 0) + // Minimum execution time: 652_000 picoseconds. + Weight::from_parts(703_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_839_000 picoseconds. - Weight::from_parts(2_931_000, 0) + // Minimum execution time: 673_000 picoseconds. + Weight::from_parts(742_000, 0) } } 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/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index 3fc3822a63eb9a2c98bc273814854ee2d56035bf..940aa1b734dfc856b5a72cf83cc14b5f8980bc5e 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -242,7 +242,7 @@ impl ExtBuilder { .assimilate_storage(&mut t) .unwrap(); - pallet_session::GenesisConfig:: { keys: self.keys } + pallet_session::GenesisConfig:: { keys: self.keys, ..Default::default() } .assimilate_storage(&mut t) .unwrap(); diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index 1a2737f3aa224c1dbf016173a259aafb0224341a..e16629302be6a90c25f365a72edb9dd36baebd75 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -4,7 +4,7 @@ version = "0.14.0" authors = ["Anonymous"] description = "A parachain for communication back and forth with XCM of assets and uniques." license = "Unlicense" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true edition.workspace = true diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 08a2da260c57e67b17eecf55f3845049e371b996..d0c421bccaf89c8a54e348c3ff04950be444a233 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}; @@ -282,6 +282,10 @@ parameter_types! { 1, [Parachain(ASSET_HUB_ID), PalletInstance(ASSETS_PALLET_ID), GeneralIndex(RESERVABLE_ASSET_ID.into())] ); + pub UsdtFromAssetHub: Location = Location::new( + 1, + [Parachain(ASSET_HUB_ID), PalletInstance(ASSETS_PALLET_ID), GeneralIndex(1984)] + ); /// The Penpal runtime is utilized for testing with various environment setups. /// This storage item provides the opportunity to customize testing scenarios @@ -351,7 +355,7 @@ impl xcm_executor::Config for XcmConfig { type AssetExchanger = (); type FeeManager = XcmFeeManagerFromComponents< (), - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = Nothing; diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index b20d2a28fa7f3be2b6517dab5fc422c68d1ec787..5d6548447463a3f960890689890537c2381975dc 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -18,6 +18,7 @@ path = "src/main.rs" async-trait = { workspace = true } clap = { features = ["derive"], workspace = true } codec = { workspace = true, default-features = true } +color-eyre = { workspace = true } color-print = { workspace = true } futures = { workspace = true } hex-literal = { workspace = true, default-features = true } @@ -174,6 +175,7 @@ try-runtime = [ ] fast-runtime = [ "bridge-hub-rococo-runtime/fast-runtime", + "bridge-hub-westend-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/asset_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs index 45920cdb6146b01765fb568506ef861c220b5792..af5bccdc416f4b49714222de3ebde7fe545feef8 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs @@ -389,6 +389,7 @@ fn asset_hub_rococo_genesis( ) }) .collect(), + ..Default::default() }, "polkadotXcm": asset_hub_rococo_runtime::PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION), diff --git a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs index 15e8a1bf11a055e6c5b4950ad07d78cad72f81a8..3b7376d045b8bdd31cfe632bbfcd8c000fc1fdec 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs @@ -357,6 +357,10 @@ pub mod westend { }, "bridgeRococoMessages": { "owner": bridges_pallet_owner.clone(), + }, + "ethereumSystem": { + "paraId": id, + "assetHubParaId": 1000 } }) } 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 d06354dda22057fda87bb21e47340e38835abb64..a5fe33dffc9672682e0585194981e42141803de6 100644 --- a/cumulus/polkadot-parachain/src/cli.rs +++ b/cumulus/polkadot-parachain/src/cli.rs @@ -90,6 +90,13 @@ 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 relay_chain_args: Vec, @@ -97,7 +104,10 @@ pub struct Cli { impl Cli { pub(crate) fn node_extra_args(&self) -> NodeExtraArgs { - NodeExtraArgs { use_slot_based_consensus: self.experimental_use_slot_based } + NodeExtraArgs { + use_slot_based_consensus: self.experimental_use_slot_based, + export_pov: self.export_pov_to_path.clone(), + } } } diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index fcf6c06f42227d5f8b9bb4d0c50686f699854511..3df90c889e8e8f2b73979c26895f8207e7613563 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -17,8 +17,7 @@ #[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::{ @@ -296,6 +295,7 @@ fn extract_parachain_id(id: &str) -> (&str, &str, Option) { let para_prefixes = [ // Penpal "penpal-rococo-", + "penpal-westend-", "penpal-kusama-", "penpal-polkadot-", // Glutton Kusama @@ -388,7 +388,7 @@ impl SubstrateCli for RelayChainCli { fn new_node_spec( config: &sc_service::Configuration, - extra_args: NodeExtraArgs, + extra_args: &NodeExtraArgs, ) -> std::result::Result, sc_cli::Error> { Ok(match config.chain_spec.runtime()? { Runtime::AssetHubPolkadot => @@ -421,35 +421,35 @@ pub fn run() -> Result<()> { Some(Subcommand::CheckBlock(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { - let node = new_node_spec(&config, cli.node_extra_args())?; + let node = new_node_spec(&config, &cli.node_extra_args())?; node.prepare_check_block_cmd(config, cmd) }) }, Some(Subcommand::ExportBlocks(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { - let node = new_node_spec(&config, cli.node_extra_args())?; + let node = new_node_spec(&config, &cli.node_extra_args())?; node.prepare_export_blocks_cmd(config, cmd) }) }, Some(Subcommand::ExportState(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { - let node = new_node_spec(&config, cli.node_extra_args())?; + let node = new_node_spec(&config, &cli.node_extra_args())?; node.prepare_export_state_cmd(config, cmd) }) }, Some(Subcommand::ImportBlocks(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { - let node = new_node_spec(&config, cli.node_extra_args())?; + 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())?; + let node = new_node_spec(&config, &cli.node_extra_args())?; node.prepare_revert_cmd(config, cmd) }) }, @@ -471,7 +471,7 @@ pub fn run() -> Result<()> { Some(Subcommand::ExportGenesisHead(cmd)) => { let runner = cli.create_runner(cmd)?; runner.sync_run(|config| { - let node = new_node_spec(&config, cli.node_extra_args())?; + let node = new_node_spec(&config, &cli.node_extra_args())?; node.run_export_genesis_head_cmd(config, cmd) }) }, @@ -494,12 +494,12 @@ pub fn run() -> Result<()> { )) }), BenchmarkCmd::Block(cmd) => runner.sync_run(|config| { - let node = new_node_spec(&config, cli.node_extra_args())?; + let node = new_node_spec(&config, &cli.node_extra_args())?; node.run_benchmark_block_cmd(config, cmd) }), #[cfg(feature = "runtime-benchmarks")] BenchmarkCmd::Storage(cmd) => runner.sync_run(|config| { - let node = new_node_spec(&config, cli.node_extra_args())?; + let node = new_node_spec(&config, &cli.node_extra_args())?; node.run_benchmark_storage_cmd(config, cmd) }), BenchmarkCmd::Machine(cmd) => @@ -607,9 +607,9 @@ async fn start_node( extra_args: NodeExtraArgs, hwbench: Option, ) -> Result { - let node_spec = new_node_spec(&config, extra_args)?; + let node_spec = new_node_spec(&config, &extra_args)?; node_spec - .start_node(config, polkadot_config, collator_options, id, hwbench) + .start_node(config, polkadot_config, collator_options, id, hwbench, extra_args) .await .map_err(Into::into) } diff --git a/cumulus/polkadot-parachain/src/common/mod.rs b/cumulus/polkadot-parachain/src/common/mod.rs index 9f5febafe30427fbd549b79e81c83d2392a795d5..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: @@ -69,4 +70,7 @@ where /// 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/main.rs b/cumulus/polkadot-parachain/src/main.rs index cbb76fa214cbedf761975888e63f7ef67910d5fa..84e41fc347d9fadb1431b20baa0e2cf95eea6b90 100644 --- a/cumulus/polkadot-parachain/src/main.rs +++ b/cumulus/polkadot-parachain/src/main.rs @@ -50,6 +50,7 @@ mod fake_runtime_api; mod rpc; mod service; -fn main() -> sc_cli::Result<()> { - command::run() +fn main() -> color_eyre::eyre::Result<()> { + color_eyre::install()?; + Ok(command::run()?) } diff --git a/cumulus/polkadot-parachain/src/service.rs b/cumulus/polkadot-parachain/src/service.rs index 6a6cf15635e018833fdc24daa82ca1d55e52214d..3b9ae6bd4457a6213a5f275d3e3f7c042b4dcbe9 100644 --- a/cumulus/polkadot-parachain/src/service.rs +++ b/cumulus/polkadot-parachain/src/service.rs @@ -125,6 +125,7 @@ where overseer_handle: OverseerHandle, announce_block: Arc>) + Send + Sync>, backend: Arc, + node_extra_args: NodeExtraArgs, ) -> Result<(), sc_service::Error>; } @@ -226,6 +227,7 @@ pub(crate) trait NodeSpec { collator_options: CollatorOptions, para_id: ParaId, hwbench: Option, + node_extra_args: NodeExtraArgs, ) -> Pin>>> where Net: NetworkBackend, @@ -255,7 +257,10 @@ pub(crate) trait NodeSpec { 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 net_config = FullNetworkConfiguration::<_, _, Net>::new( + ¶chain_config.network, + prometheus_registry.clone(), + ); let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = build_network(BuildNetworkParams { @@ -361,6 +366,7 @@ pub(crate) trait NodeSpec { overseer_handle, announce_block, backend.clone(), + node_extra_args, )?; } @@ -524,7 +530,7 @@ where const SYBIL_RESISTANCE: CollatorSybilResistance = CollatorSybilResistance::Resistant; } -pub fn new_aura_node_spec(extra_args: NodeExtraArgs) -> Box +pub fn new_aura_node_spec(extra_args: &NodeExtraArgs) -> Box where RuntimeApi: ConstructNodeRuntimeApi>, RuntimeApi::RuntimeApi: AuraRuntimeApi @@ -567,6 +573,7 @@ impl StartConsensus for StartRelayChainConsensus { 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(), @@ -691,6 +698,7 @@ where _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(), @@ -786,6 +794,7 @@ where 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(), @@ -802,33 +811,37 @@ where 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: { - let client = client.clone(); - move |block_hash| { - client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) - } + 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(2000), + reinitialize: false, }, - 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::::Pair, _, _, _, _, _, _, _, _>(params).await; - }; + 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(()) @@ -910,6 +923,7 @@ pub(crate) trait DynNodeSpec { collator_options: CollatorOptions, para_id: ParaId, hwbench: Option, + node_extra_args: NodeExtraArgs, ) -> Pin>>>; } @@ -1000,6 +1014,7 @@ where collator_options: CollatorOptions, para_id: ParaId, hwbench: Option, + node_extra_args: NodeExtraArgs, ) -> Pin>>> { match parachain_config.network.network_backend { sc_network::config::NetworkBackendType::Libp2p => @@ -1009,6 +1024,7 @@ where collator_options, para_id, hwbench, + node_extra_args, ), sc_network::config::NetworkBackendType::Litep2p => ::start_node::( @@ -1017,6 +1033,7 @@ where collator_options, para_id, hwbench, + node_extra_args, ), } } diff --git a/cumulus/primitives/aura/Cargo.toml b/cumulus/primitives/aura/Cargo.toml index 062b9ce736e7f7b9d36f23908bf94437a06f22cb..185b2d40833f0614a0856b79015eb90f0c57c30a 100644 --- a/cumulus/primitives/aura/Cargo.toml +++ b/cumulus/primitives/aura/Cargo.toml @@ -10,24 +10,14 @@ description = "Core primitives for Aura in Cumulus" workspace = true [dependencies] -codec = { features = ["derive"], workspace = true } # Substrate sp-api = { workspace = true } sp-consensus-aura = { workspace = true } -sp-runtime = { workspace = true } - -# Polkadot -polkadot-core-primitives = { workspace = true } -polkadot-primitives = { workspace = true } [features] default = ["std"] std = [ - "codec/std", - "polkadot-core-primitives/std", - "polkadot-primitives/std", "sp-api/std", "sp-consensus-aura/std", - "sp-runtime/std", ] diff --git a/cumulus/primitives/parachain-inherent/Cargo.toml b/cumulus/primitives/parachain-inherent/Cargo.toml index 172af4b9ec63e0843fdf59cdf90f21c842d60b41..a4271d3fd9cc34ac9a32787c3cce16d4cffc38ab 100644 --- a/cumulus/primitives/parachain-inherent/Cargo.toml +++ b/cumulus/primitives/parachain-inherent/Cargo.toml @@ -17,8 +17,6 @@ scale-info = { features = ["derive"], workspace = true } # Substrate 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 @@ -33,7 +31,5 @@ std = [ "scale-info/std", "sp-core/std", "sp-inherents/std", - "sp-runtime?/std", - "sp-state-machine?/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 f48dd927ee962a23a0d831ec071469bb34e517e3..a557e881e26b5f012363dc4b893566b45b8ae58c 100644 --- a/cumulus/primitives/storage-weight-reclaim/src/lib.rs +++ b/cumulus/primitives/storage-weight-reclaim/src/lib.rs @@ -165,15 +165,17 @@ where ); return Ok(()) }; - let benchmarked_weight = info.weight.proof_size(); - let consumed_weight = post_dispatch_proof_size.saturating_sub(pre_dispatch_proof_size); - // Unspent weight according to the `actual_weight` from `PostDispatchInfo` // This unspent weight will be refunded by the `CheckWeight` extension, so we need to // account for that. let unspent = post_info.calc_unspent(info).proof_size(); - let storage_size_diff = - benchmarked_weight.saturating_sub(unspent).abs_diff(consumed_weight as u64); + let benchmarked_weight = info.weight.proof_size().saturating_sub(unspent); + let consumed_weight = post_dispatch_proof_size.saturating_sub(pre_dispatch_proof_size); + + let storage_size_diff = benchmarked_weight.abs_diff(consumed_weight as u64); + + let extrinsic_len = frame_system::AllExtrinsicsLen::::get().unwrap_or(0); + let node_side_pov_size = post_dispatch_proof_size.saturating_add(extrinsic_len.into()); // This value will be reclaimed by [`frame_system::CheckWeight`], so we need to calculate // that in. @@ -191,6 +193,19 @@ where ); current.reduce(Weight::from_parts(0, storage_size_diff), info.class) } + + // If we encounter a situation where the node-side proof size is already higher than + // what we have in the runtime bookkeeping, we add the difference to the `BlockWeight`. + // This prevents that the proof size grows faster than the runtime proof size. + let block_weight_proof_size = current.total().proof_size(); + let missing_from_node = node_side_pov_size.saturating_sub(block_weight_proof_size); + if missing_from_node > 0 { + log::warn!( + target: LOG_TARGET, + "Node-side PoV size higher than runtime proof size weight. node-side: {node_side_pov_size} extrinsic_len: {extrinsic_len} runtime: {block_weight_proof_size}, missing: {missing_from_node}. Setting to node-side proof size." + ); + current.accrue(Weight::from_parts(0, missing_from_node), info.class); + } }); Ok(()) } @@ -294,6 +309,121 @@ mod tests { }) } + #[test] + fn underestimating_refund() { + // We fixed a bug where `pre dispatch info weight > consumed weight > post info weight` + // resulted in error. + + // The real cost will be 100 bytes of storage size + let mut test_ext = setup_test_externalities(&[0, 100]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + + // Benchmarked storage weight: 500 + let info = DispatchInfo { weight: Weight::from_parts(0, 101), ..Default::default() }; + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(0, 99)), + pays_fee: Default::default(), + }; + + assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); + + let pre = StorageWeightReclaim::(PhantomData) + .pre_dispatch(&ALICE, CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(0)); + + assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); + // We expect an accrue of 1 + assert_ok!(StorageWeightReclaim::::post_dispatch( + Some(pre), + &info, + &post_info, + LEN, + &Ok(()) + )); + + assert_eq!(get_storage_weight().total().proof_size(), 1250); + }) + } + + #[test] + fn sets_to_node_storage_proof_if_higher() { + // The storage proof reported by the proof recorder is higher than what is stored on + // the runtime side. + { + let mut test_ext = setup_test_externalities(&[1000, 1005]); + + test_ext.execute_with(|| { + // Stored in BlockWeight is 5 + set_current_storage_weight(5); + + // Benchmarked storage weight: 10 + let info = DispatchInfo { weight: Weight::from_parts(0, 10), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); + + let pre = StorageWeightReclaim::(PhantomData) + .pre_dispatch(&ALICE, CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(1000)); + + assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); + assert_ok!(StorageWeightReclaim::::post_dispatch( + Some(pre), + &info, + &post_info, + LEN, + &Ok(()) + )); + + // We expect that the storage weight was set to the node-side proof size (1005) + + // extrinsics length (150) + assert_eq!(get_storage_weight().total().proof_size(), 1155); + }) + } + + // In this second scenario the proof size on the node side is only lower + // after reclaim happened. + { + let mut test_ext = setup_test_externalities(&[175, 180]); + test_ext.execute_with(|| { + set_current_storage_weight(85); + + // Benchmarked storage weight: 100 + let info = + DispatchInfo { weight: Weight::from_parts(0, 100), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + // After this pre_dispatch, the BlockWeight proof size will be + // 85 (initial) + 100 (benched) + 150 (tx length) = 335 + assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); + + let pre = StorageWeightReclaim::(PhantomData) + .pre_dispatch(&ALICE, CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(175)); + + assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); + + // First we will reclaim 95, which leaves us with 240 BlockWeight. This is lower + // than 180 (proof size hf) + 150 (length), so we expect it to be set to 330. + assert_ok!(StorageWeightReclaim::::post_dispatch( + Some(pre), + &info, + &post_info, + LEN, + &Ok(()) + )); + + // We expect that the storage weight was set to the node-side proof weight + assert_eq!(get_storage_weight().total().proof_size(), 330); + }) + } + } + #[test] fn does_nothing_without_extension() { let mut test_ext = new_test_ext(); @@ -507,7 +637,7 @@ mod tests { #[test] fn test_nothing_relcaimed() { - let mut test_ext = setup_test_externalities(&[100, 200]); + let mut test_ext = setup_test_externalities(&[0, 100]); test_ext.execute_with(|| { set_current_storage_weight(0); @@ -530,7 +660,7 @@ mod tests { .pre_dispatch(&ALICE, CALL, &info, LEN) .unwrap(); // Should return `setup_test_externalities` proof recorder value: 100. - assert_eq!(pre, Some(100)); + assert_eq!(pre, Some(0)); // The `CheckWeight` extension will refund `actual_weight` from `PostDispatchInfo` // we always need to call `post_dispatch` to verify that they interoperate correctly. diff --git a/cumulus/primitives/timestamp/Cargo.toml b/cumulus/primitives/timestamp/Cargo.toml index a50011bc3f0e911f2c682fcc02dc8a7693101ffc..cb328e2f2cc6f1b79293179a238449754dfbab98 100644 --- a/cumulus/primitives/timestamp/Cargo.toml +++ b/cumulus/primitives/timestamp/Cargo.toml @@ -10,9 +10,6 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { features = ["derive"], workspace = true } -futures = { workspace = true } - # Substrate sp-inherents = { workspace = true } sp-timestamp = { workspace = true } @@ -23,7 +20,6 @@ cumulus-primitives-core = { workspace = true } [features] default = ["std"] std = [ - "codec/std", "cumulus-primitives-core/std", "sp-inherents/std", "sp-timestamp/std", diff --git a/cumulus/primitives/utility/Cargo.toml b/cumulus/primitives/utility/Cargo.toml index 82d18c8c0aac60b98fad565857fff5561a1ac21e..2ca8b82001d5ad0146d2b686a9a93f4ee5996385 100644 --- a/cumulus/primitives/utility/Cargo.toml +++ b/cumulus/primitives/utility/Cargo.toml @@ -15,13 +15,11 @@ log = { workspace = true } # Substrate frame-support = { workspace = true } -sp-io = { workspace = true } sp-runtime = { workspace = true } pallet-asset-conversion = { workspace = true } # Polkadot polkadot-runtime-common = { workspace = true } -polkadot-runtime-parachains = { workspace = true } xcm = { workspace = true } xcm-executor = { workspace = true } xcm-builder = { workspace = true } @@ -38,8 +36,6 @@ std = [ "log/std", "pallet-asset-conversion/std", "polkadot-runtime-common/std", - "polkadot-runtime-parachains/std", - "sp-io/std", "sp-runtime/std", "xcm-builder/std", "xcm-executor/std", @@ -51,7 +47,6 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", - "polkadot-runtime-parachains/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", diff --git a/cumulus/primitives/utility/src/lib.rs b/cumulus/primitives/utility/src/lib.rs index 9d5bf4e231eb0d4893360d107d92079b775db1df..3ebcb44fa439480762f4a667b3aac2ad35ef5b60 100644 --- a/cumulus/primitives/utility/src/lib.rs +++ b/cumulus/primitives/utility/src/lib.rs @@ -407,10 +407,22 @@ impl< let first_asset: Asset = payment.fungible.pop_first().ok_or(XcmError::AssetNotFound)?.into(); let (fungibles_asset, balance) = FungiblesAssetMatcher::matches_fungibles(&first_asset) - .map_err(|_| XcmError::AssetNotFound)?; + .map_err(|error| { + log::trace!( + target: "xcm::weight", + "SwapFirstAssetTrader::buy_weight asset {:?} didn't match. Error: {:?}", + first_asset, + error, + ); + XcmError::AssetNotFound + })?; let swap_asset = fungibles_asset.clone().into(); if Target::get().eq(&swap_asset) { + log::trace!( + target: "xcm::weight", + "SwapFirstAssetTrader::buy_weight Asset was same as Target, swap not needed.", + ); // current trader is not applicable. return Err(XcmError::FeesNotMet) } @@ -424,7 +436,12 @@ impl< credit_in, fee, ) - .map_err(|(credit_in, _)| { + .map_err(|(credit_in, error)| { + log::trace!( + target: "xcm::weight", + "SwapFirstAssetTrader::buy_weight swap couldn't be done. Error was: {:?}", + error, + ); drop(credit_in); XcmError::FeesNotMet })?; diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index 51cdebbaf54e036172625682648afd5fd9893d84..503c2f24fd54941e1ac65b2fdabd0790ac375ca2 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -353,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 { @@ -372,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(); @@ -891,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/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile b/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile index 60698de1d6addf53385ba6e3f30b36e9a1d7f784..55b9156e6a0ae811c8ef1d2bf8761452ae8c561a 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.6 +ARG SUBSTRATE_RELAY_IMAGE=docker.io/paritytech/substrate-relay:v1.6.8 # metadata ARG VCS_REF diff --git a/docs/contributor/CONTRIBUTING.md b/docs/contributor/CONTRIBUTING.md index 7d54b2681b41329c15ab4e3c25f37943ecf0d6a7..2e2d7a7fb4f7ce21839ce84e6021a8a4a316c855 100644 --- a/docs/contributor/CONTRIBUTING.md +++ b/docs/contributor/CONTRIBUTING.md @@ -42,13 +42,13 @@ The set of labels and their description can be found [here](https://paritytech.g 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 +4. With respect to auditing, please see [AUDIT.md](../AUDIT.md). In general, merging to master can happen independently 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. +they require some special setup aside from adding it to the list of migrations in the runtime. ## Reviewing pull requests @@ -82,6 +82,45 @@ Non "silent" PRs must come with documentation in the form of a `.prdoc` file. See more about `prdoc` [here](./prdoc.md) +## Crate Configuration `Cargo.toml` + +The Polkadot SDK uses many conventions when configuring a crate. Watch out for these things when you +are creating a new crate. + +### Is the Crate chain-specific? + +Chain-specific crates, for example +[`bp-bridge-hub-rococo`](https://github.com/paritytech/polkadot-sdk/blob/4014b9bf2bf8f74862f63e7114e5c78009529be5/bridges/chains/chain-bridge-hub-rococo/Cargo.toml#L10-L11) +, should not be released as part of the Polkadot-SDK umbrella crate. We have a custom metadata +attribute that is picked up by the [generate-umbrella.py](../../scripts/generate-umbrella.py) +script, that should be applied to all chain-specific crates like such: + +```toml +[package] +# Other stuff... + +[package.metadata.polkadot-sdk] +exclude-from-umbrella = true + +# Other stuff... +``` + +### Is the Crate a Test, Example or Fuzzer? + +Test or example crates, like +[`pallet-example-task`](https://github.com/paritytech/polkadot-sdk/blob/9b4acf27b869d7cbb07b03f0857763b8c8cc7566/substrate/frame/examples/tasks/Cargo.toml#L9) +, should not be released to crates.io. To ensure this, you must add `publish = false` to your +crate's `package` section: + +```toml +[package] +# Other stuff... + +publish = false + +# Other stuff... +``` + ## Helping out We use [labels](https://github.com/paritytech/polkadot-sdk/labels) to manage PRs and issues and communicate state of a diff --git a/docs/contributor/DOCUMENTATION_GUIDELINES.md b/docs/contributor/DOCUMENTATION_GUIDELINES.md index 96811a2772d775f92ce4524416c295a689df1790..5ac99fff1cdbfa2b2425947f5af242c8dd03966f 100644 --- a/docs/contributor/DOCUMENTATION_GUIDELINES.md +++ b/docs/contributor/DOCUMENTATION_GUIDELINES.md @@ -1,7 +1,7 @@ # Substrate Documentation Guidelines This document is focused on documenting parts of Substrate that relate to its external API. The list of such crates can -be found in [CODEOWNERS](./CODEOWNERS). Search for the crates auto-assigned to the `docs-audit` team. +be found in [CODEOWNERS](/.github/CODEOWNERS). Search for the crates auto-assigned to the `docs-audit` team. These crates are used by external developers and need thorough documentation. They are the most concerned with FRAME development. @@ -33,7 +33,7 @@ First, consider the case for all such crates, except for those that are pallets. The first question is, what should you document? Use this filter: -1. In the crates assigned to `docs-audit` in [CODEOWNERS](./CODEOWNERS), +1. In the crates assigned to `docs-audit` in [CODEOWNERS](/.github/CODEOWNERS), 2. All `pub` items need to be documented. If not `pub`, it doesn't appear in the rust-docs, and is not public facing. - Within `pub` items, sometimes they are only `pub` to be used by another internal crate, and you can foresee that @@ -88,20 +88,19 @@ sections](https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/ru we will most likely not need to think about panic and safety in any runtime related code. Our code is never `unsafe`, and will (almost) never panic. -Use `# Examples as much as possible. These are great ways to further demonstrate what your APIs are doing, and add free -test coverage. As an additional benefit, any code in rust-docs is treated as an "integration tests", not unit tests, +Use `# Examples` as much as possible. These are great ways to further demonstrate what your APIs are doing, and add free +test coverage. As an additional benefit, any code in rust-docs is treated as an "integration test", which tests your crate in a different way than unit tests. So, it is both a win for "more documentation" and a win for "more test coverage". You can also consider having an `# Error` section optionally. Of course, this only applies if there is a `Result` being returned, and if the `Error` variants are overly complicated. -Strive to include correct links to other items in your written docs as much as possible. In other words, avoid -\`some_func\` and instead use \[\`some_fund\`\]. Read more about how to correctly use links in your rust-docs +Strive to include correct links to other items in your written docs as much as possible. +Read more about how to correctly use links in your rust-docs [here](https://doc.rust-lang.org/rustdoc/write-documentation/linking-to-items-by-name.html#valid-links) and -[here](https://rust-lang.github.io/rfcs/1946-intra-rustdoc-links.html#additions-to-the-documentation-syntax). Strive to -include correct links to other items in your written docs as much as possible. In other words, avoid `` `some_func` `` -and instead use ``[`some_func`]``. +[here](https://rust-lang.github.io/rfcs/1946-intra-rustdoc-links.html#additions-to-the-documentation-syntax). +In other words, avoid `` `some_func` `` and instead use ``[`some_func`]``. > While you are linking, you might become conscious of the fact that you are in need of linking to (too many) foreign items in order to explain your API. This is leaning more towards API-Design rather than documentation, but it is a @@ -137,7 +136,7 @@ the `macro@my_macro_name` syntax in your link. Read more about how to correctly The above five guidelines must always be reasonably respected in the documentation. -The following are a set of notes that may not necessarily hold in all circumstances: +The following is a set of notes that may not necessarily hold in all circumstances: --- @@ -145,7 +144,7 @@ The following are a set of notes that may not necessarily hold in all circumstan You should make sure that your code is properly-named and well-organized so that your code functions as a form of documentation. However, within the complexity of our projects in Polkadot/Substrate that is not enough. Particularly, -things like examples, errors and panics cannot be documented only through properly- named and well-organized code. +things like examples, errors and panics cannot be documented only through properly-named and well-organized code. > Our north star is self-documenting code that also happens to be well-documented and littered with examples. @@ -206,7 +205,7 @@ properly do this. ## Pallet Crates -The guidelines so far have been general in nature, and are applicable to crates that are pallets and crates that're not +The guidelines so far have been general in nature, and are applicable to crates that are pallets and crates that are not pallets. The following is relevant to how to document parts of a crate that is a pallet. See @@ -272,7 +271,7 @@ For the top-level pallet docs, consider the following template: //! up> ``` -This template's details (heading 3s and beyond) are left flexible, and at the discretion of the developer to make the +This template's details (Heading 3s and beyond) are left flexible, and at the discretion of the developer to make the best final choice about. For example, you might want to include `### Terminology` or not. Moreover, you might find it more useful to include it in `## Overview`. diff --git a/docs/contributor/PULL_REQUEST_TEMPLATE.md b/docs/contributor/PULL_REQUEST_TEMPLATE.md index 083b30b4a3567904a62c83dd07a21677b7c0e048..9612ab6d8d3edbbb47db1994018ac077be5d913c 100644 --- a/docs/contributor/PULL_REQUEST_TEMPLATE.md +++ b/docs/contributor/PULL_REQUEST_TEMPLATE.md @@ -20,7 +20,7 @@ reviewed by reviewers, if the PR does NOT have the `R0-Silent` label. In case of ## Review Notes -*In depth notes about the **implenentation** details of your PR. This should be the main guide for reviewers to +*In depth notes about the **implementation** 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)*. diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index d3e48de5d181911f0686738c6d556e552176fd7a..2f85171bb93d2c1e65b51a02e82559b2c5f96a55 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -40,6 +40,7 @@ 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 } +log = { workspace = true, default-features = true } # Substrate Client sc-network = { workspace = true, default-features = true } @@ -107,7 +108,11 @@ sp-version = { workspace = true, default-features = true } # XCM xcm = { workspace = true, default-features = true } +xcm-builder = { workspace = true } xcm-docs = { workspace = true } +xcm-executor = { workspace = true } +xcm-simulator = { workspace = true } +pallet-xcm = { workspace = true } # runtime guides chain-spec-guide-runtime = { workspace = true } diff --git a/docs/sdk/src/guides/async_backing_guide.rs b/docs/sdk/src/guides/async_backing_guide.rs index f2f4dcabfd29b872de2981cd0a9c5003118c29c0..25ef3a12cbf033d37ebaca2bb6464dd67c92735e 100644 --- a/docs/sdk/src/guides/async_backing_guide.rs +++ b/docs/sdk/src/guides/async_backing_guide.rs @@ -27,8 +27,8 @@ //! "scheduling_lookahead": 2 //! ``` //! -//!
`scheduling_lookahead` must be set to 2, otherwise parachain block times -//! will degrade to worse than with sync backing!
+//!
scheduling_lookahead must be set to 2, otherwise parachain +//! block times will degrade to worse than with sync backing!
//! //! ## Phase 1 - Update Parachain Runtime //! @@ -174,7 +174,7 @@ //! - 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 +//! - Increase `authoring_duration` from 500 milliseconds to 2000 //! ```ignore //! let params = AuraParams { //! .. @@ -185,7 +185,7 @@ //! client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) //! }, //! .. -//! authoring_duration: Duration::from_millis(1500), +//! authoring_duration: Duration::from_millis(2000), //! .. //! }; //! ``` diff --git a/docs/sdk/src/guides/enable_elastic_scaling_mvp.rs b/docs/sdk/src/guides/enable_elastic_scaling_mvp.rs index bc4f36c271fe3c063f85c9debb32fd78f7e33efa..939043b53529c101ea9dc438605865534b7659d8 100644 --- a/docs/sdk/src/guides/enable_elastic_scaling_mvp.rs +++ b/docs/sdk/src/guides/enable_elastic_scaling_mvp.rs @@ -1,7 +1,7 @@ //! # 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. +//! terminology, as defined in the Polkadot Wiki. //! Furthermore, the parachain should have already been upgraded according to the guide.
//! //! ## Quick introduction to elastic scaling @@ -70,9 +70,10 @@ //! - 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.
+//!
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. //! diff --git a/docs/sdk/src/guides/enable_metadata_hash.rs b/docs/sdk/src/guides/enable_metadata_hash.rs index b9cbae8533538d685f39d1cde979758dcc59955b..930afd4d8ff71c6c565700cf76759c1ce06b35f0 100644 --- a/docs/sdk/src/guides/enable_metadata_hash.rs +++ b/docs/sdk/src/guides/enable_metadata_hash.rs @@ -16,15 +16,15 @@ //! the metadata for one or more networks. The next problem is that the offline wallet/user can not //! trust the metadata to be correct. It is very important for the metadata to be correct or //! otherwise an attacker could change them in a way that the offline wallet decodes a transaction -//! in a different way than what it will be decoded to on chain. So, the user may signs an incorrect -//! transaction leading to unexpecting behavior. +//! in a different way than what it will be decoded to on chain. So, the user may sign an incorrect +//! transaction leading to unexpected behavior. //! //! The metadata hash verification circumvents the issues of the huge metadata and the need to trust //! some metadata blob to be correct. To generate a hash for the metadata, the metadata is chunked, //! these chunks are put into a merkle tree and then the root of this merkle tree is the "metadata //! hash". For a more technical explanation on how it works, see //! [RFC78](https://polkadot-fellows.github.io/RFCs/approved/0078-merkleized-metadata.html). At compile -//! time the metadata hash is generated and "backed" into the runtime. This makes it extremely cheap +//! time the metadata hash is generated and "baked" into the runtime. This makes it extremely cheap //! for the runtime to verify on chain that the metadata hash is correct. By having the runtime //! verify the hash on chain, the user also doesn't need to trust the offchain metadata. If the //! metadata hash doesn't match the on chain metadata hash the transaction will be rejected. The diff --git a/docs/sdk/src/guides/enable_pov_reclaim.rs b/docs/sdk/src/guides/enable_pov_reclaim.rs index 3c0c5fba2158691b51abdcceed5db5130e58c9b4..13b27d18956b49fdb66b79fa44208321ad43c6f0 100644 --- a/docs/sdk/src/guides/enable_pov_reclaim.rs +++ b/docs/sdk/src/guides/enable_pov_reclaim.rs @@ -1,3 +1,5 @@ +//! # Enable storage weight reclaiming +//! //! This guide will teach you how to enable storage weight reclaiming for a parachain. The //! explanations in this guide assume a project structure similar to the one detailed in //! the [substrate documentation](crate::polkadot_sdk::substrate#anatomy-of-a-binary-crate). Full diff --git a/docs/sdk/src/guides/mod.rs b/docs/sdk/src/guides/mod.rs index 9384f4c82ab3e37e5d15e0cb853c7d01731b4b41..a7fd146ccdf3a7be21e0a17382ee3abdaa4d961a 100644 --- a/docs/sdk/src/guides/mod.rs +++ b/docs/sdk/src/guides/mod.rs @@ -15,21 +15,21 @@ /// Write your first simple pallet, learning the most most basic features of FRAME along the way. pub mod your_first_pallet; -/// Writing your first real [runtime](`crate::reference_docs::wasm_meta_protocol`), and successfully +/// Write your first real [runtime](`crate::reference_docs::wasm_meta_protocol`), /// compiling it to [WASM](crate::polkadot_sdk::substrate#wasm-build). pub mod your_first_runtime; -/// Running the given runtime with a node. No specific consensus mechanism is used at this stage. +// /// Running the given runtime with a node. No specific consensus mechanism is used at this stage. // TODO // pub mod your_first_node; -/// How to enhance a given runtime and node to be cumulus-enabled, run it as a parachain and connect -/// it to a relay-chain. +// /// How to enhance a given runtime and node to be cumulus-enabled, run it as a parachain +// /// and connect it to a relay-chain. // TODO // pub mod cumulus_enabled_parachain; -/// How to make a given runtime XCM-enabled, capable of sending messages (`Transact`) between itself -/// and the relay chain to which it is connected. +// /// How to make a given runtime XCM-enabled, capable of sending messages (`Transact`) between +// /// itself and the relay chain to which it is connected. // TODO // pub mod xcm_enabled_parachain; diff --git a/docs/sdk/src/guides/your_first_pallet/mod.rs b/docs/sdk/src/guides/your_first_pallet/mod.rs index da4624f5ac2b85dcf884798fefca42da229760e0..3c74469e1768d0b7749353ba337e9f4bdd533589 100644 --- a/docs/sdk/src/guides/your_first_pallet/mod.rs +++ b/docs/sdk/src/guides/your_first_pallet/mod.rs @@ -1,6 +1,6 @@ //! # Currency Pallet //! -//! By the end of this guide, you will write a small FRAME pallet (see +//! By the end of this guide, you will have written a small FRAME pallet (see //! [`crate::polkadot_sdk::frame_runtime`]) that is capable of handling a simple crypto-currency. //! This pallet will: //! @@ -18,7 +18,7 @@ //! //! To get started, use one of the templates mentioned in [`crate::polkadot_sdk::templates`]. We //! recommend using the `polkadot-sdk-minimal-template`. You might need to change small parts of -//! this guide, namely the crate/package names, based on which tutorial you use. +//! this guide, namely the crate/package names, based on which template you use. //! //! > Be aware that you can read the entire source code backing this tutorial by clicking on the //! > [`source`](./mod.rs.html) button at the top right of the page. @@ -45,8 +45,8 @@ //! Consider the following as a "shell pallet". We continue building the rest of this pallet based //! on this template. //! -//! [`pallet::config`] and [`pallet::pallet`] are both mandatory parts of any pallet. Refer to the -//! documentation of each to get an overview of what they do. +//! [`pallet::config`] and [`pallet::pallet`](frame_support::pallet) are both mandatory parts of any +//! pallet. Refer to the documentation of each to get an overview of what they do. #![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", shell_pallet)] //! //! All of the code that follows in this guide should live inside of the `mod pallet`. @@ -73,7 +73,7 @@ //! as normal `fn`s attached to `struct Pallet`. #![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", impl_pallet)] //! -//! The logic of the functions is self-explanatory. Instead, we will focus on the FRAME-related +//! The logic of these functions is self-explanatory. Instead, we will focus on the FRAME-related //! details: //! //! - Where do `T::AccountId` and `T::RuntimeOrigin` come from? These are both defined in @@ -83,7 +83,7 @@ //! document ([`crate::reference_docs::frame_origin`]). For now, you should only know the //! signature of the function: it takes a generic `T::RuntimeOrigin` and returns a //! `Result`. So by the end of this function call, we know that this dispatchable -//! was signed by `who`. +//! was signed by `sender`. #![doc = docify::embed!("../../substrate/frame/system/src/lib.rs", ensure_signed)] //! //! - Where does `mutate`, `get` and `insert` and other storage APIs come from? All of them are @@ -96,7 +96,7 @@ //! Which is more or less a normal Rust `Result`, with a custom [`frame::prelude::DispatchError`] as //! the `Err` variant. We won't cover this error in detail here, but importantly you should know //! that there is an `impl From<&'static string> for DispatchError` provided (see -//! [here](`frame::prelude::DispatchError#impl-From<%26'static+str>-for-DispatchError`)). Therefore, +//! [here](`frame::prelude::DispatchError#impl-From<%26str>-for-DispatchError`)). Therefore, //! we can use basic string literals as our error type and `.into()` them into `DispatchError`. //! //! - Why are all `get` and `mutate` functions returning an `Option`? This is the default behavior @@ -117,7 +117,7 @@ //! ergonomic. #![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", transfer_better_checked)] //! -//! This is more or less all the logic that there is this basic currency pallet! +//! This is more or less all the logic that there is in this basic currency pallet! //! //! ### Your First (Test) Runtime //! diff --git a/docs/sdk/src/lib.rs b/docs/sdk/src/lib.rs index e211476d2514419a3d0889ef426817342155c178..6dc87858530cf61d1a61426423ed6ae55c7fe786 100644 --- a/docs/sdk/src/lib.rs +++ b/docs/sdk/src/lib.rs @@ -13,8 +13,8 @@ //! We suggest the following reading sequence: //! //! - Start by learning about the the [`polkadot_sdk`], its structure and context. -//! - Then, head over the [`guides`]. This modules contains in-depth guides about the most important -//! user-journeys of the Polkadot SDK. +//! - Then, head over to the [`guides`]. This modules contains in-depth guides about the most +//! important user-journeys of the Polkadot SDK. //! - Whilst reading the guides, you might find back-links to [`reference_docs`]. //! - Finally, is the parent website of this crate that contains the //! list of further tools related to the Polkadot SDK. @@ -25,7 +25,7 @@ #![doc = simple_mermaid::mermaid!("../../mermaid/IA.mmd")] #![warn(rustdoc::broken_intra_doc_links)] #![warn(rustdoc::private_intra_doc_links)] -#![doc(html_favicon_url = "https://polkadot.network/favicon-32x32.png")] +#![doc(html_favicon_url = "https://polkadot.com/favicon.ico")] #![doc( html_logo_url = "https://europe1.discourse-cdn.com/standard21/uploads/polkadot2/original/1X/eb57081e2bb7c39e5fcb1a98b443e423fa4448ae.svg" )] @@ -36,7 +36,7 @@ pub mod meta_contributing; /// In-depth guides about the most common components of the Polkadot SDK. They are slightly more -/// high level and broad than reference docs. +/// high level and broad than [`reference_docs`]. pub mod guides; /// An introduction to the Polkadot SDK. Read this module to learn about the structure of the SDK, /// the tools that are provided as a part of it, and to gain a high level understanding of each. diff --git a/docs/sdk/src/meta_contributing.rs b/docs/sdk/src/meta_contributing.rs index a029595254c84dfa58639279b4fcd486f25c3f0e..e1297151b2312f9828bdddecb4fbbb76995132cb 100644 --- a/docs/sdk/src/meta_contributing.rs +++ b/docs/sdk/src/meta_contributing.rs @@ -14,7 +14,7 @@ //! documentation up-to-date, as the overhead is reduced by making sure everything is in one //! repository, and everything being in `.rs` files. //! -//! > This is not say that a more visually appealing version of this crate (for example as an +//! > This is not to say that a more visually appealing version of this crate (for example as an //! > `md-book`) cannot exist, but it would be outside the scope of this crate. //! //! Moreover, we acknowledge that a major pain point has been not only outdated *concepts*, but also diff --git a/docs/sdk/src/polkadot_sdk/frame_runtime.rs b/docs/sdk/src/polkadot_sdk/frame_runtime.rs index 39255c8f51ad6e589c22c7a29f08211b50053203..8acf19f7641379c3fdfda62ce34c5799179d0b4a 100644 --- a/docs/sdk/src/polkadot_sdk/frame_runtime.rs +++ b/docs/sdk/src/polkadot_sdk/frame_runtime.rs @@ -54,7 +54,7 @@ //! //! ### Example //! -//! The following examples showcases a minimal pallet. +//! The following example showcases a minimal pallet. #![doc = docify::embed!("src/polkadot_sdk/frame_runtime.rs", pallet)] //! //! @@ -85,7 +85,7 @@ //! [`crate::reference_docs::wasm_meta_protocol`]). Notable examples are: //! //! * 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). +//! * writing a runtime in AssemblyScript, as explored in [this project](https://github.com/LimeChain/subsembly). /// 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 @@ -119,11 +119,11 @@ pub mod pallet { #[pallet::pallet] pub struct Pallet(PhantomData); - /// The events tha this pallet can emit. + /// The events that this pallet can emit. #[pallet::event] pub enum Event {} - /// A storage item that this pallet contains. This will be part of the state root trie/root + /// A storage item that this pallet contains. This will be part of the state root trie /// of the blockchain. #[pallet::storage] pub type Value = StorageValue; diff --git a/docs/sdk/src/polkadot_sdk/mod.rs b/docs/sdk/src/polkadot_sdk/mod.rs index 124d391421b9049dd5865fae0ac9e739e3f46cce..32cad72fba7e2e3b3bc9b74994309076eae43114 100644 --- a/docs/sdk/src/polkadot_sdk/mod.rs +++ b/docs/sdk/src/polkadot_sdk/mod.rs @@ -12,7 +12,7 @@ //! //! [![RFCs](https://img.shields.io/badge/fellowship-RFCs-e6007a?logo=polkadot)](https://github.com/polkadot-fellows/rfcs) //! [![Runtime](https://img.shields.io/badge/fellowship-runtimes-e6007a?logo=polkadot)](https://github.com/polkadot-fellows/runtimes) -//! [![Manifesto](https://img.shields.io/badge/fellowship-manifesto-e6007a?logo=polkadot)](https://github.com/polkadot-fellows/manifesto) +//! [![Manifesto](https://img.shields.io/badge/fellowship-manifesto-e6007a?logo=polkadot)](https://github.com/polkadot-fellows/manifesto/blob/main/manifesto.pdf) //! //! ## Getting Started //! @@ -34,7 +34,7 @@ //! Repo](https://img.shields.io/badge/github-substrate-2324CC85)](https://github.com/paritytech/polkadot-sdk/blob/master/substrate) //! //! [`substrate`] is the base blockchain framework used to power the Polkadot SDK. It is a full -//! toolkit to create sovereign blockchains, including but not limited to those who connect to +//! toolkit to create sovereign blockchains, including but not limited to those which connect to //! Polkadot as parachains. //! //! #### FRAME @@ -82,7 +82,7 @@ //! //! A Substrate-based chain is a blockchain composed of a runtime and a node. As noted above, the //! runtime is the application logic of the blockchain, and the node is everything else. -//! See [`crate::reference_docs::wasm_meta_protocol`] for an in-depth explanation of this. The +//! See [`reference_docs::wasm_meta_protocol`] for an in-depth explanation of this. The //! former is built with [`frame`], and the latter is built with rest of Substrate. //! //! > You can think of a Substrate-based chain as a white-labeled blockchain. @@ -103,8 +103,8 @@ //! //! ## Trophy Section: Notable Downstream Projects //! -//! A list of projects and tools in the blockchain ecosystem that one way or another parts of the -//! Polkadot SDK: +//! A list of projects and tools in the blockchain ecosystem that one way or another use parts of +//! the Polkadot SDK: //! //! * [Polygon's spin-off, Avail](https://github.com/availproject/avail) //! * [Cardano Partner Chains](https://iohk.io/en/blog/posts/2023/11/03/partner-chains-are-coming-to-cardano/) @@ -116,7 +116,7 @@ //! [`polkadot`]: crate::polkadot_sdk::polkadot //! [`xcm`]: crate::polkadot_sdk::xcm -/// Lean about Cumulus, the framework that transforms [`substrate`]-based chains into +/// Learn about Cumulus, the framework that transforms [`substrate`]-based chains into /// [`polkadot`]-enabled parachains. pub mod cumulus; /// Learn about FRAME, the framework used to build Substrate runtimes. diff --git a/docs/sdk/src/polkadot_sdk/polkadot.rs b/docs/sdk/src/polkadot_sdk/polkadot.rs index e2dcca4dc7dfcd2726d24b9f7725a67bad50246b..69532f323b9db73ceb4bf1254d34f6f22844a1d0 100644 --- a/docs/sdk/src/polkadot_sdk/polkadot.rs +++ b/docs/sdk/src/polkadot_sdk/polkadot.rs @@ -8,18 +8,18 @@ //! - [Polkadot Parachains](https://parachains.info/) //! - [Polkadot (multi-chain) Explorer: Subscan](https://subscan.io/) //! - Polkadot Fellowship -//! - [Manifesto](https://github.com/polkadot-fellows/manifesto) +//! - [Manifesto](https://github.com/polkadot-fellows/manifesto/blob/main/manifesto.pdf) //! - [Runtimes](https://github.com/polkadot-fellows/runtimes) //! - [RFCs](https://github.com/polkadot-fellows/rfcs) //! - [Dashboard](https://polkadot-fellows.github.io/dashboard/) -//! - [Polkadot Specs](spec.polkadot.network) +//! - [Polkadot Specs](http://spec.polkadot.network) //! - [The Polkadot Parachain Host Implementers' Guide](https://paritytech.github.io/polkadot-sdk/book/) //! - [Whitepaper](https://www.polkadot.network/whitepaper/) //! - [JAM Graypaper](https://graypaper.com) //! //! ## Alternative Node Implementations 🌈 //! -//! - [Smoldot](https://crates.io/crates/smoldot-light). Polkadot light node/client. +//! - [Smoldot](https://docs.rs/crate/smoldot-light/latest). Polkadot light node/client. //! - [KAGOME](https://github.com/qdrvm/kagome). C++ implementation of the Polkadot host. //! - [Gossamer](https://github.com/ChainSafe/gossamer). Golang implementation of the Polkadot host. //! @@ -45,7 +45,7 @@ //! > their execution and governance sovereignty. These chains are called "Parachains". //! //! * Shared Security: The idea of shared economic security sits at the core of Polkadot. Polkadot -//! enables different parachains* to pool their economic security from Polkadot (i.e. "*Relay +//! enables different parachains to pool their economic security from Polkadot (i.e. "*Relay //! Chain*"). //! * (heterogenous) Sharded Execution: Yet, each parachain is free to have its own execution logic //! (runtime), which also encompasses governance and sovereignty. Moreover, Polkadot ensures the @@ -80,7 +80,7 @@ //! Within the scope of Polkadot 1.x, two main scheduling ways have been considered: //! //! * Long term Parachains, obtained through locking a sum of DOT in an auction system. -//! * on-demand Parachains, purchased through paying DOT to the relay-chain whenever needed. +//! * On-demand Parachains, purchased through paying DOT to the relay-chain whenever needed. //! //! ### The Future //! diff --git a/docs/sdk/src/polkadot_sdk/substrate.rs b/docs/sdk/src/polkadot_sdk/substrate.rs index 69d74d86db1b585692d9df8ae9db08ae454ca9f9..56b89f8c9c2a3f106ad293c8fc605bd7304739ea 100644 --- a/docs/sdk/src/polkadot_sdk/substrate.rs +++ b/docs/sdk/src/polkadot_sdk/substrate.rs @@ -11,9 +11,9 @@ //! 1. Society and technology evolves. //! 2. Humans are fallible. //! -//! This, makes the task of designing a correct, safe and long-lasting blockchain system hard. +//! This makes the task of designing a correct, safe and long-lasting blockchain system hard. //! -//! Nonetheless, in strive towards achieve this goal, Substrate embraces the following: +//! Nonetheless, in strive towards achieving this goal, Substrate embraces the following: //! //! 1. Use of **Rust** as a modern and safe programming language, which limits human error through //! various means, most notably memory and type safety. @@ -27,7 +27,7 @@ //! blob. //! //! In essence, the meta-protocol of all Substrate based chains is the "Runtime as WASM blob" -//! accord. This enables the Runtime to become inherently upgradeable, crucially without forks. The +//! accord. This enables the Runtime to become inherently upgradeable, crucially without [forks](https://en.wikipedia.org/wiki/Fork_(blockchain)). The //! upgrade is merely a matter of the WASM blob being changed in the state, which is, in principle, //! same as updating an account's balance. Learn more about this in detail in //! [`crate::reference_docs::wasm_meta_protocol`]. @@ -63,9 +63,9 @@ //! categories: //! //! * `sc-*` (short for *Substrate-client*) crates, located under `./client` folder. These are all -//! the crates that lead to the node software. Notable examples [`sc_network`], various consensus -//! crates, RPC ([`sc_rpc_api`]) and database ([`sc_client_db`]), all of which are expected to -//! reside in the node side. +//! the crates that lead to the node software. Notable examples are [`sc_network`], various +//! consensus crates, RPC ([`sc_rpc_api`]) and database ([`sc_client_db`]), all of which are +//! expected to reside in the node side. //! * `sp-*` (short for *substrate-primitives*) crates, located under `./primitives` folder. These //! are crates that facilitate both the node and the runtime, but are not opinionated about what //! framework is using for building the runtime. Notable examples are [`sp_api`] and [`sp_io`], @@ -86,7 +86,9 @@ //! //! Substrate-based runtimes use [`substrate_wasm_builder`] in their `build.rs` to automatically //! build their WASM files as a part of normal build command (e.g. `cargo build`). Once built, the -//! wasm file is placed in `./target/{debug|release}/wbuild/{runtime_name}.wasm`. +//! wasm file is placed in `./target/{debug|release}/wbuild/{runtime_name}/{runtime_name}.wasm`. +//! +//! In order to ensure that the WASM build is **deterministic**, the [Substrate Runtime Toolbox (srtool)](https://github.com/paritytech/srtool) can be used. //! //! ### Binaries //! diff --git a/docs/sdk/src/polkadot_sdk/xcm.rs b/docs/sdk/src/polkadot_sdk/xcm.rs index 58f54068642444e2010d3623d6a49d00f050ebf8..20841b0b55b93986e509a8751ff2e16e32df56eb 100644 --- a/docs/sdk/src/polkadot_sdk/xcm.rs +++ b/docs/sdk/src/polkadot_sdk/xcm.rs @@ -5,7 +5,7 @@ //! //! ## Overview //! -//! XCM is a standard, whose specification lives in the [xcm format repo](https://github.com/paritytech/xcm-format). +//! XCM is a standard, specification of which lives in the [xcm format repo](https://github.com/paritytech/xcm-format). //! It's agnostic both in programming language and blockchain platform, which means it could be used //! in Rust in Polkadot, or in Go or C++ in any other platform like Cosmos or Ethereum. //! @@ -34,13 +34,12 @@ //! but will be moved to its own repo in the future. //! //! Its main components are: -//! - `src`: the definition of the basic types and instructions -//! - [`xcm-executor`](https://paritytech.github.io/polkadot-sdk/master/staging_xcm_executor/struct.XcmExecutor.html): -//! an implementation of the virtual machine to execute instructions -//! - `pallet-xcm`: A FRAME pallet for interacting with the executor -//! - `xcm-builder`: a collection of types to configure the executor -//! - `xcm-simulator`: a playground for trying out different XCM programs and executor -//! configurations +//! - [`xcm`](::xcm): The definition of the basic types and instructions. +//! - [`xcm_executor`]: An implementation of the virtual machine to execute instructions. +//! - [`pallet_xcm`]: A FRAME pallet for interacting with the executor. +//! - [`xcm_builder`]: A collection of types to configure the executor. +//! - [`xcm_simulator`]: A playground for trying out different XCM programs and executor +//! configurations. //! //! ## Example //! 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/cli.rs b/docs/sdk/src/reference_docs/cli.rs index 5779e0f8d04954e9fe1d245e0af4761fb0246805..b9cdbd60e9592418241426c4f82aa9a3223559a4 100644 --- a/docs/sdk/src/reference_docs/cli.rs +++ b/docs/sdk/src/reference_docs/cli.rs @@ -45,7 +45,7 @@ //! - `--chain=customSpec.json`: Uses the custom chain specification as input. //! - `--disable-default-bootnode`: Disables the default bootnodes in the node template. //! - `--raw`: Converts the chain specification into a raw format with encoded storage keys. -//! - `> customSpecRaw.json`: Outputs to customSpecRaw.json. +//! - `> customSpecRaw.json`: Outputs to `customSpecRaw.json`. //! //! #### Starting the First Node in a Private Network //! ```bash diff --git a/docs/sdk/src/reference_docs/custom_runtime_api_rpc.rs b/docs/sdk/src/reference_docs/custom_runtime_api_rpc.rs index 83a70606cb8dd51acf13f7774a0ccf40355ea41a..083ed9f77e10214535dffa290acd256d8f75e633 100644 --- a/docs/sdk/src/reference_docs/custom_runtime_api_rpc.rs +++ b/docs/sdk/src/reference_docs/custom_runtime_api_rpc.rs @@ -1,7 +1,7 @@ //! # Custom RPC do's and don'ts //! -//! **TLDR:** don't create new custom RPCs. Instead, rely on custom Runtime APIs, combined with -//! `state_call` +//! **TLDR:** Don't create new custom RPCs. Instead, rely on custom Runtime APIs, combined with +//! `state_call`. //! //! ## Background //! @@ -20,9 +20,9 @@ //! - To upgrade or add a new RPC logic, the RPC node has to be upgraded. This can cause significant //! trouble when the RPC infrastructure is decentralized as we will need to coordinate multiple //! parties to upgrade the RPC nodes. -//! - A lot of boilerplate code are required to add custom RPC. -//! - It prevents the dApp to use a light client or alternative client. -//! - It makes ecosystem tooling integration much more complicated. For example, the dApp will not +//! - A lot of boilerplate code is required to add custom RPC. +//! - It prevents dApps from using a light client or an alternative client. +//! - It makes ecosystem tooling integration much more complicated. For example, dApps will not //! be able to use [Chopsticks](https://github.com/AcalaNetwork/chopsticks) for testing as //! Chopsticks will not have the custom RPC implementation. //! - Poorly implemented custom RPC can be a DoS vector. @@ -50,7 +50,7 @@ //! //! ## Create a new Runtime API //! -//! For example, let's take a look a the process through which the account nonce can be queried +//! For example, let's take a look at the process through which the account nonce can be queried //! through an RPC. First, a new runtime-api needs to be declared: #![doc = docify::embed!("../../substrate/frame/system/rpc/runtime-api/src/lib.rs", AccountNonceApi)] //! diff --git a/docs/sdk/src/reference_docs/defensive_programming.rs b/docs/sdk/src/reference_docs/defensive_programming.rs index 9828e1b50918f3e832523c686797091db034a985..82d624b01d97fccbd45f690e43ab3b0bdd1d4a89 100644 --- a/docs/sdk/src/reference_docs/defensive_programming.rs +++ b/docs/sdk/src/reference_docs/defensive_programming.rs @@ -16,7 +16,7 @@ //! [Defensive programming](https://en.wikipedia.org/wiki/Defensive_programming) is a design paradigm that enables a program to continue //! running despite unexpected behavior, input, or events that may arise in runtime. //! Usually, unforeseen circumstances may cause the program to stop or, in the Rust context, -//! panic!. Defensive practices allow for these circumstances to be accounted for ahead of time +//! `panic!`. Defensive practices allow for these circumstances to be accounted for ahead of time //! and for them to be handled gracefully, which is in line with the intended fault-tolerant and //! deterministic nature of blockchains. //! @@ -71,7 +71,7 @@ //! ### Defensive Traits //! //! The [`Defensive`](frame::traits::Defensive) trait provides a number of functions, all of which -//! provide an alternative to 'vanilla' Rust functions, e.g.,: +//! provide an alternative to 'vanilla' Rust functions, e.g.: //! //! - [`defensive_unwrap_or()`](frame::traits::Defensive::defensive_unwrap_or) instead of //! `unwrap_or()` @@ -127,7 +127,7 @@ //! - [Fixed point types](sp_arithmetic::fixed_point) and their associated usage can be found here. //! - [PerThing](sp_arithmetic::per_things) and its associated types can be found here. //! -//! Using floating point number types (i.e., f32. f64) in the runtime should be avoided, as a single non-deterministic result could cause chaos for blockchain consensus along with the issues above. For more on the specifics of the peculiarities of floating point calculations, [watch this video by the Computerphile](https://www.youtube.com/watch?v=PZRI1IfStY0). +//! Using floating point number types (i.e. f32, f64) in the runtime should be avoided, as a single non-deterministic result could cause chaos for blockchain consensus along with the issues above. For more on the specifics of the peculiarities of floating point calculations, [watch this video by the Computerphile](https://www.youtube.com/watch?v=PZRI1IfStY0). //! //! The following methods demonstrate different ways to handle numbers natively in Rust safely, //! without fear of panic or unexpected behavior from wrapping. diff --git a/docs/sdk/src/reference_docs/development_environment_advice.rs b/docs/sdk/src/reference_docs/development_environment_advice.rs index 9ba95dfa032945ac684f13b1c3961d4f8d0f649e..a5f38bb280deff9cc3b1ffb0d2a5d08dced39d55 100644 --- a/docs/sdk/src/reference_docs/development_environment_advice.rs +++ b/docs/sdk/src/reference_docs/development_environment_advice.rs @@ -15,8 +15,9 @@ //! ```json //! { //! // Use a separate target dir for Rust Analyzer. Helpful if you want to use Rust -//! // Analyzer and cargo on the command line at the same time. -//! "rust-analyzer.rust.analyzerTargetDir": "target/vscode-rust-analyzer", +//! // Analyzer and cargo on the command line at the same time, +//! // at the expense of duplicating build artifacts. +//! "rust-analyzer.cargo.targetDir": "target/vscode-rust-analyzer", //! // Improve stability //! "rust-analyzer.server.extraEnv": { //! "CHALK_OVERFLOW_DEPTH": "100000000", @@ -145,7 +146,7 @@ //! } //! ``` //! -//! //! and the same in Lua for `neovim/nvim-lspconfig`: +//! and the same in Lua for `neovim/nvim-lspconfig`: //! //! ```lua //! ["rust-analyzer"] = { diff --git a/docs/sdk/src/reference_docs/frame_benchmarking_weight.rs b/docs/sdk/src/reference_docs/frame_benchmarking_weight.rs index db77547a4bf0fe0a6d24f8ffc80cdda206d576b4..cf9e58791492330d827630e76ebbb51df37ecafd 100644 --- a/docs/sdk/src/reference_docs/frame_benchmarking_weight.rs +++ b/docs/sdk/src/reference_docs/frame_benchmarking_weight.rs @@ -14,10 +14,10 @@ //! - improve documentation of `#[weight = ..]` and `#[pallet::weight(..)]`. All syntax variation //! should be covered. //! -//! on FRAME benchmarking machinery: +//! On FRAME benchmarking machinery: //! -//! - component analysis, why everything must be linear. -//! - how to write benchmarks, how you must think of worst case. -//! - how to run benchmarks. +//! - Component analysis, why everything must be linear. +//! - How to write benchmarks, how you must think of worst case. +//! - How to run benchmarks. //! //! - diff --git a/docs/sdk/src/reference_docs/frame_logging.rs b/docs/sdk/src/reference_docs/frame_logging.rs index 301fa7ef83f827c3115a6a30bb8d1ad35b5bfd83..1b03c6a2e35b53cb6775ad0648b6591eea525190 100644 --- a/docs/sdk/src/reference_docs/frame_logging.rs +++ b/docs/sdk/src/reference_docs/frame_logging.rs @@ -34,9 +34,9 @@ //! //! ## Using `log` //! -//! First, ensure you are familiar with the `log` crate. In short, each log statement has: +//! First, ensure you are familiar with the [`log`] crate. In short, each log statement has: //! -//! 1. `log-level`, signifying how important it is +//! 1. `log-level`, signifying how important it is. //! 2. `log-target`, signifying to which component it belongs. //! //! Add log statements to your pallet as such: diff --git a/docs/sdk/src/reference_docs/frame_offchain_workers.rs b/docs/sdk/src/reference_docs/frame_offchain_workers.rs index 1ec9212e2306613b72ec4c6f433a68c92f5bb0d5..b0aaf1789d4cc3855a0718f459beff7778951e97 100644 --- a/docs/sdk/src/reference_docs/frame_offchain_workers.rs +++ b/docs/sdk/src/reference_docs/frame_offchain_workers.rs @@ -88,7 +88,7 @@ //! //! They can both read from the state, and have no means of updating the state, other than the route //! of submitting an extrinsic to the chain. Therefore, it is worth thinking twice before embedding -//! a logic as a part of Substrate's offchain worker API. Does it have to be there? can it not be a +//! a logic as a part of Substrate's offchain worker API. Does it have to be there? Can it not be a //! simple, actual offchain application that lives outside of the chain's WASM blob? //! //! Some of the reasons why you might want to do the opposite, and actually embed an offchain worker diff --git a/docs/sdk/src/reference_docs/frame_pallet_coupling.rs b/docs/sdk/src/reference_docs/frame_pallet_coupling.rs index be464bbbf8359c77fa549ab80bcb0008244488f9..a22137f979dc1455d488dce71e75662e0071cc08 100644 --- a/docs/sdk/src/reference_docs/frame_pallet_coupling.rs +++ b/docs/sdk/src/reference_docs/frame_pallet_coupling.rs @@ -30,8 +30,8 @@ //! //! There are generally two ways to achieve this: //! -//! 1. Tight coupling pallets -//! 2. Loose coupling pallets +//! 1. Tight coupling pallets. +//! 2. Loose coupling pallets. //! //! To explain the difference between the two, consider two pallets, `A` and `B`. In both cases, `A` //! wants to use some functionality exposed by `B`. @@ -74,8 +74,8 @@ //! pallet makes its own `trait Config` be bounded by another pallet's `trait Config`, it is //! expressing two things: //! -//! 1. that it can only exist in a runtime if the other pallet is also present. -//! 2. that it can use the other pallet's functionality. +//! 1. That it can only exist in a runtime if the other pallet is also present. +//! 2. That it can use the other pallet's functionality. //! //! `pallet-foo`'s `Config` would then look like: #![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", tight_config)] @@ -110,7 +110,7 @@ //! Crucially, when using loose coupling, we gain the flexibility of providing different //! implementations of `AuthorProvider`, such that different users of a `pallet-foo` can use //! different ones, without any code change being needed. For example, in the code snippets of this -//! module, you can fund [`OtherAuthorProvider`] which is an alternative implementation of +//! module, you can find [`OtherAuthorProvider`], which is an alternative implementation of //! [`AuthorProvider`]. #![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", other_author_provider)] //! @@ -135,8 +135,8 @@ //! general, it is easier to argue about multiple pallet if they only communicate together via a //! known trait, rather than having access to all of each others public items, such as storage and //! dispatchables. -//! * If a group of pallets are meant to work together, and but are not foreseen to be generalized, -//! or used by others, consider tightly coupling pallets, *if it simplifies the development*. +//! * If a group of pallets is meant to work together, but is not foreseen to be generalized, or +//! used by others, consider tightly coupling pallets, *if it simplifies the development*. //! * If a pallet needs a functionality provided by another pallet, but multiple implementations can //! be foreseen, consider loosely coupling pallets. //! diff --git a/docs/sdk/src/reference_docs/frame_runtime_types.rs b/docs/sdk/src/reference_docs/frame_runtime_types.rs index 1eed9857a1d5951245b4c4f6bef08f35d0c3f03a..e99106ade878137ed308aa05c3bb43236727a3a4 100644 --- a/docs/sdk/src/reference_docs/frame_runtime_types.rs +++ b/docs/sdk/src/reference_docs/frame_runtime_types.rs @@ -36,7 +36,7 @@ #![doc = docify::embed!("./src/reference_docs/frame_runtime_types.rs", pallet_bar)] //! //! Let's explore how each of these affect the [`RuntimeCall`], [`RuntimeOrigin`] and -//! [`RuntimeGenesisConfig`] generated in [`runtime`] by respectively. +//! [`RuntimeGenesisConfig`] generated in [`runtime`] respectively. //! //! As observed, [`RuntimeCall`] has 3 variants, one for each pallet and one for `frame_system`. If //! you explore further, you will soon realize that each variant is merely a pointer to the `Call` diff --git a/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs b/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs index f9a69b892a3152854cdf7b5f97d003e500f64f07..065cbee25709b7f95451c41605d2967ed48d9bc7 100644 --- a/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs +++ b/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs @@ -2,8 +2,8 @@ //! //! At their core, blockchain logic consists of //! -//! 1. on-chain state and -//! 2. a state transition function +//! 1. on-chain state, +//! 2. a state transition function. //! //! In Substrate-based blockchains, state transition functions are referred to as //! [runtimes](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/blockchain_state_machines/index.html). @@ -43,9 +43,9 @@ //! for example when the encoding of a storage item is changed. However, they can also execute //! arbitrary logic such as: //! -//! - Calling arbitrary pallet methods -//! - Mutating arbitrary on-chain state -//! - Cleaning up some old storage items that are no longer needed +//! - Calling arbitrary pallet methods. +//! - Mutating arbitrary on-chain state. +//! - Cleaning up some old storage items that are no longer needed. //! //! ## Single Block Migrations //! @@ -88,9 +88,9 @@ //! //! Prior to deploying migrations, it is critical to perform additional checks to ensure that when //! run in our real runtime they will not brick the chain due to: -//! - Panicking -//! - Touching too many storage keys and resulting in an excessively large PoV -//! - Taking too long to execute +//! - Panicking. +//! - Touching too many storage keys and resulting in an excessively large PoV. +//! - Taking too long to execute. //! //! [`try-runtime-cli`](https://github.com/paritytech/try-runtime-cli) has a sub-command //! [`on-runtime-upgrade`](https://paritytech.github.io/try-runtime-cli/try_runtime_core/commands/enum.Action.html#variant.OnRuntimeUpgrade) @@ -129,7 +129,9 @@ //! //! Suitable for migrations which could use arbitrary amounts of block weight. //! -//! TODO: Link to multi block migration example/s once PR is merged (). +//! See the +//! [multi-block-migrations example](https://github.com/paritytech/polkadot-sdk/tree/0d7d2177807ec6b3094f4491a45b0bc0d74d3c8b/substrate/frame/examples/multi-block-migrations) +//! for reference. //! //! [`OnRuntimeUpgrade`]: frame_support::traits::OnRuntimeUpgrade //! [`StorageVersion`]: frame_support::traits::StorageVersion diff --git a/docs/sdk/src/reference_docs/frame_storage_derives.rs b/docs/sdk/src/reference_docs/frame_storage_derives.rs index 3d9edef398a072839f82c21be76b74da6cf20ff2..4fbfb4a5cc839b8e4c0af4efd9db5e20613abc17 100644 --- a/docs/sdk/src/reference_docs/frame_storage_derives.rs +++ b/docs/sdk/src/reference_docs/frame_storage_derives.rs @@ -1,6 +1,9 @@ -//!
-//! In all examples, a few lines of boilerplate have been hidden from each snippet for conciseness. -//!
+//! # Frame storage derives +//! +//! > **Note:** +//! > +//! > 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: //! @@ -134,7 +137,7 @@ //! - [`frame::prelude::PartialOrdNoBound`] //! - [`frame::prelude::OrdNoBound`] //! -//! The above traits are almost certainly needed for your tests: To print your type, assert equality +//! 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`]. diff --git a/docs/sdk/src/reference_docs/frame_system_accounts.rs b/docs/sdk/src/reference_docs/frame_system_accounts.rs index 523fe704308497d3116d36cfca086a617b3a9d3b..c93e1196ea7e8cf9de1fdc589a71345fc0d6e072 100644 --- a/docs/sdk/src/reference_docs/frame_system_accounts.rs +++ b/docs/sdk/src/reference_docs/frame_system_accounts.rs @@ -1,6 +1,6 @@ //! # FRAME Accounts //! -//! //! 🚧 Work In Progress 🚧 +//! 🚧 Work In Progress 🚧 //! //! How `frame_system` handles accountIds. Nonce. Consumers and Providers, reference counting. diff --git a/docs/sdk/src/reference_docs/frame_tokens.rs b/docs/sdk/src/reference_docs/frame_tokens.rs index 57b493fafa59c053f2496d5e4809f7deaa0da316..a76e524ceb85490999d4cac6eeee3589f7b7ac2b 100644 --- a/docs/sdk/src/reference_docs/frame_tokens.rs +++ b/docs/sdk/src/reference_docs/frame_tokens.rs @@ -22,11 +22,11 @@ //! //! On completion of reading this doc, you should have a good understanding of: //! - The distinction between token traits and trait implementations in FRAME, and why this -//! distinction is helpful -//! - Token-related traits available in FRAME -//! - Token-related trait implementations in FRAME -//! - How to choose the right trait or trait implementation for your use case -//! - Where to go next +//! distinction is helpful. +//! - Token-related traits available in FRAME. +//! - Token-related trait implementations in FRAME. +//! - How to choose the right trait or trait implementation for your use case. +//! - Where to go next. //! //! ## Getting Started //! @@ -56,9 +56,16 @@ //! //! **Trait implementations** are concrete implementations of these traits. For example, one of the //! many traits [`pallet_balances`] implements is -//! [`fungible::Inspect`](`frame_support::traits::fungible::Inspect`)*. It provides the concrete way -//! of inspecting the total issuance, balance of accounts, etc. There can be many implementations of -//! the same traits. +//! [`fungible::Inspect`](`frame_support::traits::fungible::Inspect`)[^1]. It provides the concrete +//! way of inspecting the total issuance, balance of accounts, etc. There can be many +//! implementations of the same traits. +//! +//! [^1]: Rust Advanced Tip: The knowledge that [`pallet_balances`] implements +//! [`fungible::Inspect`](`frame_support::traits::fungible::Inspect`) is not some arcane knowledge +//! that you have to know by heart or memorize. One can simply look at the list of the implementors +//! of any trait in the Rust Doc to find all implementors (e.g. +//! [Mutate trait implementors](https://paritytech.github.io/polkadot-sdk/master/frame_support/traits/tokens/fungible/trait.Mutate.html#implementors)), +//! or use the `rust-analyzer`'s `Implementations` action. //! //! The distinction between traits and trait implementations is helpful because it allows pallets //! and other logic to be generic over their dependencies, avoiding tight coupling. @@ -68,10 +75,10 @@ //! pallet may use [`pallet_balances`] in a tightly coupled manner, directly calling methods //! on the pallet to reserve and unreserve deposits. This approach works well, //! until someone has a use case requiring that an asset from a different pallet such as -//! [`pallet_assets`] is used for the deposit. Rather than tightly couple [`pallet_preimage`] to -//! [`pallet_balances`], [`pallet_assets`], and every other token-handling pallet a user -//! could possibly specify, [`pallet_preimage`] does not specify a concrete pallet as a dependency -//! but instead accepts any dependency which implements the +//! [`pallet_assets`] is used for the deposit. Rather than tightly coupling [`pallet_preimage`] to +//! [`pallet_balances`], [`pallet_assets`], and every other token-handling pallet, a user +//! could possibly specify that [`pallet_preimage`] does not specify a concrete pallet as a +//! dependency, but instead accepts any dependency which implements the //! [`currency::ReservableCurrency`](`frame_support::traits::tokens::currency::ReservableCurrency`) //! trait, namely via its [`Config::Currency`](`pallet_preimage::pallet::Config::Currency`) //! associated type. This allows [`pallet_preimage`] to support any arbitrary pallet implementing @@ -81,15 +88,6 @@ //! Read more about coupling, and the benefits of loose coupling //! [here](crate::reference_docs::frame_pallet_coupling). //! -//! ##### *Rust Advanced Tip -//! -//! The knowledge that [`pallet_balances`] implements -//! [`fungible::Inspect`](`frame_support::traits::fungible::Inspect`) is not some arcane knowledge -//! that you have to know by heart or memorize. One can simply look at the list of the implementors -//! of any trait in the Rust Doc to find all implementors (e.g. -//! ), -//! or use the `rust-analyzer` `Implementations` action. -//! //! ## Fungible Token Traits in FRAME //! //! The [`fungible`](`frame_support::traits::fungible`) crate contains the latest set of FRAME diff --git a/docs/sdk/src/reference_docs/metadata.rs b/docs/sdk/src/reference_docs/metadata.rs index 96f92ac0c412ba252092170e0788680300385901..485614088140e693f2dffce3a9a711582c888032 100644 --- a/docs/sdk/src/reference_docs/metadata.rs +++ b/docs/sdk/src/reference_docs/metadata.rs @@ -21,5 +21,5 @@ //! //! A few noteworthy tools that inspect the (FRAME-based) metadata of a chain: //! -//! -//! +//! - +//! - diff --git a/docs/sdk/src/reference_docs/mod.rs b/docs/sdk/src/reference_docs/mod.rs index c69c79365427e25726a95e17913f535a244fe368..7f2edb08d46e98e2cdc56944b4a1e54a097b8719 100644 --- a/docs/sdk/src/reference_docs/mod.rs +++ b/docs/sdk/src/reference_docs/mod.rs @@ -7,14 +7,15 @@ //! //! ## What is a "reference document"? //! -//! First, see [why we use rust-docs for everything](crate#why-rust-docs) and our documentation -//! [principles](crate#principles). We acknowledge that as much of the crucial information should be -//! embedded in the low level rust-docs. Then, high level scenarios should be covered in -//! [`crate::guides`]. Finally, we acknowledge that there is a category of information that is: +//! First, see [why we use rust-docs for everything](crate::meta_contributing#why-rust-docs) and our +//! documentation [principles](crate::meta_contributing#principles). We acknowledge that as much of +//! the crucial information should be embedded in the low level rust-docs. Then, high level +//! scenarios should be covered in [`crate::guides`]. Finally, we acknowledge that there is a +//! category of information that is: //! -//! 1. crucial to know. -//! 2. is too high level to be in the rust-doc of any one `type`, `trait` or `fn`. -//! 3. is too low level to be encompassed in a [`crate::guides`]. +//! 1. Crucial to know. +//! 2. Is too high level to be in the rust-doc of any one `type`, `trait` or `fn`. +//! 3. Is too low level to be encompassed in a [`crate::guides`]. //! //! We call this class of documents "reference documents". Our goal should be to minimize the number //! of "reference" docs, as they incur maintenance burden. @@ -52,8 +53,8 @@ pub mod frame_storage_derives; /// Learn about how to write safe and defensive code in your FRAME runtime. pub mod defensive_programming; -/// Learn about composite enums and other runtime level types, such as "RuntimeEvent" and -/// "RuntimeCall". +/// Learn about composite enums and other runtime level types, such as `RuntimeEvent` and +/// `RuntimeCall`. pub mod frame_runtime_types; /// Learn about how to make a pallet/runtime that is fee-less and instead uses another mechanism to diff --git a/docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs b/docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs index 379b0c11b2ad077eb320f72225e513d1b9ed6d67..4a0ba3ca48f5a374f92424aa039330721efcc4d2 100644 --- a/docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs +++ b/docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs @@ -32,21 +32,14 @@ //! //! ## Comparative Table //! -//! | Aspect | Runtime -//! | Smart Contracts | +//! | Aspect | Runtime | Smart Contracts | //! |-----------------------|-------------------------------------------------------------------------|----------------------------------------------------------------------| -//! | **Design Philosophy** | Core logic of a blockchain, allowing broad and deep customization. -//! | Designed for DApps deployed on the blockchain runtime.| | **Development Complexity** | Requires in-depth knowledge of Rust and Substrate. Suitable for complex blockchain architectures. | Easier to develop with knowledge of Smart Contract languages like Solidity or [ink!](https://use.ink/). | -//! | **Upgradeability and Flexibility** | Offers comprehensive upgradeability with migration logic -//! and on-chain governance, allowing modifications to the entire blockchain logic without hard -//! forks. | Less flexible in upgrade migrations but offers more straightforward deployment and -//! iteration. | | **Performance and Efficiency** | More efficient, optimized for specific needs of -//! the blockchain. | Can be less efficient due to its generic nature (e.g. the overhead of a -//! virtual machine). | | **Security Considerations** | Security flaws can affect the entire -//! blockchain. | Security risks usually localized to the individual -//! contract. | | **Weighing and Metering** | Operations can be weighed, allowing for precise -//! benchmarking. | Execution is metered, allowing for measurement of resource -//! consumption. | +//! | **Design Philosophy** | Core logic of a blockchain, allowing broad and deep customization. | Designed for DApps deployed on the blockchain runtime. | +//! | **Development Complexity** | Requires in-depth knowledge of Rust and Substrate. Suitable for complex blockchain architectures. | Easier to develop with knowledge of Smart Contract languages like Solidity or [ink!](https://use.ink/). | +//! | **Upgradeability and Flexibility** | Offers comprehensive upgradeability with migration logic and on-chain governance, allowing modifications to the entire blockchain logic without hard forks. | Less flexible in upgrade migrations but offers more straightforward deployment and iteration. | +//! | **Performance and Efficiency** | More efficient, optimized for specific needs of the blockchain. | Can be less efficient due to its generic nature (e.g. the overhead of a virtual machine). | +//! | **Security Considerations** | Security flaws can affect the entire blockchain. | Security risks usually localized to the individual contract. | +//! | **Weighing and Metering** | Operations can be weighed, allowing for precise benchmarking. | Execution is metered, allowing for measurement of resource consumption. | //! //! We will now explore these differences in more detail. //! diff --git a/docs/sdk/src/reference_docs/trait_based_programming.rs b/docs/sdk/src/reference_docs/trait_based_programming.rs index ace3138807071a35dfaf4ea75e3321960f05137e..90b38f63a5809028c3172fe23199a635128ebc11 100644 --- a/docs/sdk/src/reference_docs/trait_based_programming.rs +++ b/docs/sdk/src/reference_docs/trait_based_programming.rs @@ -196,7 +196,7 @@ mod with_system { mod fully_qualified { use super::with_system::*; - // Simple of using fully qualified syntax. + // Example of using fully qualified syntax. type AccountIdOf = ::AccountId; } diff --git a/docs/sdk/src/reference_docs/umbrella_crate.rs b/docs/sdk/src/reference_docs/umbrella_crate.rs index 0b3445cfc4bc0ce27b6dcb144618dd7001e6f20a..1074cde37693d3aed03474ab3b89743ec538c188 100644 --- a/docs/sdk/src/reference_docs/umbrella_crate.rs +++ b/docs/sdk/src/reference_docs/umbrella_crate.rs @@ -25,7 +25,7 @@ //! - `runtime`: As described above, enable all `no-std` crates. //! - `node`: As described above, enable all `std` crates. //! - There does *not* exist a dedicated docs feature. To generate docs, enable the `runtime` and -//! `node` feature. For docs.rs the manifest contains specific configuration to make it show up +//! `node` feature. For `docs.rs` the manifest contains specific configuration to make it show up //! all re-exports. //! //! There is a specific [`zepter`](https://github.com/ggwpez/zepter) check in place to ensure that @@ -77,7 +77,7 @@ //! ``` //! //! Apart from this, no issues are known. There could be some bugs with how macros locate their own -//! re-exports. Please compile issues that arise from using this crate. +//! re-exports. Please [report issues](https://github.com/paritytech/polkadot-sdk/issues) that arise from using this crate. //! //! ## Dependencies //! diff --git a/docs/sdk/src/reference_docs/wasm_meta_protocol.rs b/docs/sdk/src/reference_docs/wasm_meta_protocol.rs index 0e91e65c55e36d99d6dfbe03e7cda3af09dad942..55b5cb204dc2d32b707d0fce9dab5b2ade347715 100644 --- a/docs/sdk/src/reference_docs/wasm_meta_protocol.rs +++ b/docs/sdk/src/reference_docs/wasm_meta_protocol.rs @@ -29,7 +29,7 @@ //! Rust to different hardware targets. //! //! This design enables all Substrate-based chains to be fork-less-ly upgradeable, because the -//! Runtime can be updates on the fly, within the execution of a block, and the node is (for the +//! Runtime can be updated on the fly, within the execution of a block, and the node is (for the //! most part) oblivious to the change that is happening. //! //! Therefore, the high-level architecture of a any Substrate-based chain can be demonstrated as @@ -82,7 +82,7 @@ //! //! ## State //! -//! From the previous sections, we know that the a database component is part of the node, not the +//! From the previous sections, we know that the database component is part of the node, not the //! runtime. We also hinted that a set of host functions ([`sp_io::storage`]) are how the runtime //! issues commands to the node to read/write to the state. Let's dive deeper into this. //! @@ -143,13 +143,13 @@ //! At some point, based on the consensus algorithm's rules, the node decides to import (aka. //! *validate*) a block. //! -//! * First, the node will then fetch the state of the parent hash of the block that wishes to be +//! * First, the node will fetch the state of the parent hash of the block that wishes to be //! imported. //! * The runtime is fetched from this state, and placed into a WASM execution environment. -//! * The [`sp_api::Core::execute_block`] runtime API is called and the blocked is passed in as an +//! * The [`sp_api::Core::execute_block`] runtime API is called and the block is passed in as an //! argument. //! * The runtime will then execute the block, and update the state accordingly. Any state update is -//! issues via the [`sp_io::storage`] host functions. +//! issued via the [`sp_io::storage`] host functions. //! * Both the runtime and node will check the state-root of the state after the block execution to //! match the one claimed in the block header. //! diff --git a/master.wasm b/master.wasm deleted file mode 100644 index 7ebb14371243afa4956a107374b27a4e686f0360..0000000000000000000000000000000000000000 Binary files a/master.wasm and /dev/null differ diff --git a/modified.wasm b/modified.wasm deleted file mode 100644 index 7ebb14371243afa4956a107374b27a4e686f0360..0000000000000000000000000000000000000000 Binary files a/modified.wasm and /dev/null differ diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index 65985c0a5db930cf94922a6c8fde6e549021e7ef..bc0187bf49228a2bf5e691c4fddce89ede9dc225 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -52,7 +52,7 @@ assert_matches = { workspace = true } kvdb-memorydb = { workspace = true } polkadot-primitives-test-helpers = { workspace = true } log = { workspace = true, default-features = true } -env_logger = { workspace = true } +sp-tracing = { workspace = true } polkadot-subsystem-bench = { workspace = true } 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/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index 64ae86bc013a5714868e2abcdd228f1f2b456af9..b912449baa4dcf55a5b22ae5a0e3dd33e6a10847 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -543,11 +543,7 @@ fn test_harness>( config: HarnessConfig, test: impl FnOnce(TestHarness) -> T, ) { - let _ = env_logger::builder() - .is_test(true) - .filter(Some("polkadot_node_core_approval_voting"), log::LevelFilter::Trace) - .filter(Some(LOG_TARGET), log::LevelFilter::Trace) - .try_init(); + sp_tracing::init_for_tests(); let HarnessConfig { sync_oracle, sync_oracle_handle, clock, backend, assignment_criteria } = config; diff --git a/polkadot/node/core/av-store/Cargo.toml b/polkadot/node/core/av-store/Cargo.toml index 4274c8b576a3dc82cefbc22a7619bfe3206c181d..c867180e541bbf013cc874450e132c08f87981a5 100644 --- a/polkadot/node/core/av-store/Cargo.toml +++ b/polkadot/node/core/av-store/Cargo.toml @@ -29,9 +29,9 @@ polkadot-node-jaeger = { workspace = true, default-features = true } [dev-dependencies] log = { workspace = true, default-features = true } -env_logger = { workspace = true } assert_matches = { workspace = true } kvdb-memorydb = { workspace = true } +sp-tracing = { workspace = true } sp-core = { workspace = true, default-features = true } polkadot-node-subsystem-util = { workspace = true, default-features = true } diff --git a/polkadot/node/core/av-store/src/tests.rs b/polkadot/node/core/av-store/src/tests.rs index 04a223730bcd68b178925f3c8b04963b30854651..958917a3104fdb3101b6bb81a63e8370a73474f9 100644 --- a/polkadot/node/core/av-store/src/tests.rs +++ b/polkadot/node/core/av-store/src/tests.rs @@ -122,11 +122,7 @@ fn test_harness>( store: Arc, test: impl FnOnce(VirtualOverseer) -> T, ) { - let _ = env_logger::builder() - .is_test(true) - .filter(Some("polkadot_node_core_av_store"), log::LevelFilter::Trace) - .filter(Some(LOG_TARGET), log::LevelFilter::Trace) - .try_init(); + sp_tracing::init_for_tests(); let pool = sp_core::testing::TaskExecutor::new(); let (context, virtual_overseer) = diff --git a/polkadot/node/core/candidate-validation/Cargo.toml b/polkadot/node/core/candidate-validation/Cargo.toml index e1a98f80783fa472309d012eb097ad28dac72d46..fcacc38cae65cb6b6bd8fe56a247c38a06fb05a1 100644 --- a/polkadot/node/core/candidate-validation/Cargo.toml +++ b/polkadot/node/core/candidate-validation/Cargo.toml @@ -15,7 +15,8 @@ futures = { workspace = true } futures-timer = { workspace = true } gum = { workspace = true, default-features = true } -sp-maybe-compressed-blob = { workspace = true, default-features = true } +sp-keystore = { workspace = true } +sp-application-crypto = { workspace = true } codec = { features = ["bit-vec", "derive"], workspace = true } polkadot-primitives = { workspace = true, default-features = true } @@ -34,5 +35,6 @@ 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-maybe-compressed-blob = { workspace = true, default-features = 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..103d29e8d269429be3dc94fa3f0e4d85d4c98a67 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -27,9 +27,7 @@ use polkadot_node_core_pvf::{ InternalValidationError, InvalidCandidate as WasmInvalidCandidate, PossiblyInvalidError, PrepareError, PrepareJobKind, PvfPrepData, ValidationError, ValidationHost, }; -use polkadot_node_primitives::{ - BlockData, InvalidCandidate, PoV, ValidationResult, POV_BOMB_LIMIT, VALIDATION_CODE_BOMB_LIMIT, -}; +use polkadot_node_primitives::{InvalidCandidate, PoV, ValidationResult}; use polkadot_node_subsystem::{ errors::RuntimeApiError, messages::{ @@ -39,25 +37,27 @@ use polkadot_node_subsystem::{ overseer, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, SubsystemResult, SubsystemSender, }; -use polkadot_node_subsystem_util::executor_params_at_relay_parent; -use polkadot_parachain_primitives::primitives::{ - ValidationParams, ValidationResult as WasmValidationResult, -}; +use polkadot_node_subsystem_util as util; +use polkadot_overseer::ActiveLeavesUpdate; +use polkadot_parachain_primitives::primitives::ValidationResult as WasmValidationResult; use polkadot_primitives::{ executor_params::{ 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 +88,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 +111,7 @@ pub struct Config { /// The candidate validation subsystem. pub struct CandidateValidationSubsystem { + keystore: KeystorePtr, #[allow(missing_docs)] pub metrics: Metrics, #[allow(missing_docs)] @@ -122,10 +123,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 +135,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 +225,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 +256,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 +304,237 @@ 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 = PvfPrepData::from_code( + validation_code.0, + executor_params.clone(), + timeout, + PrepareJobKind::Prechecking, + ); + + 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,43 +615,35 @@ 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); - 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, - timeout, - PrepareJobKind::Prechecking, - ), - Err(e) => { - gum::debug!(target: LOG_TARGET, err=?e, "precheck: cannot decompress validation code"); - return PreCheckOutcome::Invalid - }, - }; + let pvf = PvfPrepData::from_code( + validation_code.0, + executor_params, + timeout, + PrepareJobKind::Prechecking, + ); match validation_backend.precheck_pvf(pvf).await { Ok(_) => PreCheckOutcome::Valid, @@ -622,41 +851,7 @@ async fn validate_candidate_exhaustive( return Ok(ValidationResult::Invalid(e)) } - let raw_validation_code = match sp_maybe_compressed_blob::decompress( - &validation_code.0, - VALIDATION_CODE_BOMB_LIMIT, - ) { - Ok(code) => code, - Err(e) => { - gum::info!(target: LOG_TARGET, ?para_id, err=?e, "Invalid candidate (validation code)"); - - // Code already passed pre-checking, if decompression fails now this most likely means - // some local corruption happened. - return Err(ValidationFailed("Code decompression failed".to_string())) - }, - }; - metrics.observe_code_size(raw_validation_code.len()); - - metrics.observe_pov_size(pov.block_data.0.len(), true); - let raw_block_data = - match sp_maybe_compressed_blob::decompress(&pov.block_data.0, POV_BOMB_LIMIT) { - Ok(block_data) => BlockData(block_data.to_vec()), - Err(e) => { - gum::info!(target: LOG_TARGET, ?para_id, err=?e, "Invalid candidate (PoV code)"); - - // If the PoV is invalid, the candidate certainly is. - return Ok(ValidationResult::Invalid(InvalidCandidate::PoVDecompressionFailure)) - }, - }; - metrics.observe_pov_size(raw_block_data.0.len(), false); - - let params = ValidationParams { - parent_head: persisted_validation_data.parent_head.clone(), - block_data: raw_block_data, - relay_parent_number: persisted_validation_data.relay_parent_number, - relay_parent_storage_root: persisted_validation_data.relay_parent_storage_root, - }; - + let persisted_validation_data = Arc::new(persisted_validation_data); let result = match exec_kind { // Retry is disabled to reduce the chance of nondeterministic blocks getting backed and // honest backers getting slashed. @@ -664,7 +859,7 @@ async fn validate_candidate_exhaustive( let prep_timeout = pvf_prep_timeout(&executor_params, PvfPrepKind::Prepare); let exec_timeout = pvf_exec_timeout(&executor_params, exec_kind); let pvf = PvfPrepData::from_code( - raw_validation_code.to_vec(), + validation_code.0, executor_params, prep_timeout, PrepareJobKind::Compilation, @@ -674,7 +869,8 @@ async fn validate_candidate_exhaustive( .validate_candidate( pvf, exec_timeout, - params.encode(), + persisted_validation_data.clone(), + pov, polkadot_node_core_pvf::Priority::Normal, ) .await @@ -682,9 +878,10 @@ async fn validate_candidate_exhaustive( PvfExecKind::Approval => validation_backend .validate_candidate_with_retry( - raw_validation_code.to_vec(), + validation_code.0, pvf_exec_timeout(&executor_params, exec_kind), - params, + persisted_validation_data.clone(), + pov, executor_params, PVF_APPROVAL_EXECUTION_RETRY_DELAY, polkadot_node_core_pvf::Priority::Critical, @@ -710,6 +907,8 @@ async fn validate_candidate_exhaustive( Ok(ValidationResult::Invalid(InvalidCandidate::Timeout)), Err(ValidationError::Invalid(WasmInvalidCandidate::WorkerReportedInvalid(e))) => Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError(e))), + Err(ValidationError::Invalid(WasmInvalidCandidate::PoVDecompressionFailure)) => + Ok(ValidationResult::Invalid(InvalidCandidate::PoVDecompressionFailure)), Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)) => Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError( "ambiguous worker death".to_string(), @@ -756,7 +955,7 @@ async fn validate_candidate_exhaustive( // invalid. Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch)) } else { - Ok(ValidationResult::Valid(outputs, persisted_validation_data)) + Ok(ValidationResult::Valid(outputs, (*persisted_validation_data).clone())) } }, } @@ -769,7 +968,8 @@ trait ValidationBackend { &mut self, pvf: PvfPrepData, exec_timeout: Duration, - encoded_params: Vec, + pvd: Arc, + pov: Arc, // The priority for the preparation job. prepare_priority: polkadot_node_core_pvf::Priority, ) -> Result; @@ -784,9 +984,10 @@ trait ValidationBackend { /// preparation. async fn validate_candidate_with_retry( &mut self, - raw_validation_code: Vec, + code: Vec, exec_timeout: Duration, - params: ValidationParams, + pvd: Arc, + pov: Arc, executor_params: ExecutorParams, retry_delay: Duration, // The priority for the preparation job. @@ -795,7 +996,7 @@ trait ValidationBackend { let prep_timeout = pvf_prep_timeout(&executor_params, PvfPrepKind::Prepare); // Construct the PVF a single time, since it is an expensive operation. Cloning it is cheap. let pvf = PvfPrepData::from_code( - raw_validation_code, + code, executor_params, prep_timeout, PrepareJobKind::Compilation, @@ -806,7 +1007,13 @@ trait ValidationBackend { // Use `Priority::Critical` as finality trumps parachain liveliness. let mut validation_result = self - .validate_candidate(pvf.clone(), exec_timeout, params.encode(), prepare_priority) + .validate_candidate( + pvf.clone(), + exec_timeout, + pvd.clone(), + pov.clone(), + prepare_priority, + ) .await; if validation_result.is_ok() { return validation_result @@ -879,10 +1086,14 @@ trait ValidationBackend { validation_result ); - // Encode the params again when re-trying. We expect the retry case to be relatively - // rare, and we want to avoid unconditionally cloning data. validation_result = self - .validate_candidate(pvf.clone(), new_timeout, params.encode(), prepare_priority) + .validate_candidate( + pvf.clone(), + new_timeout, + pvd.clone(), + pov.clone(), + prepare_priority, + ) .await; } } @@ -891,6 +1102,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] @@ -900,13 +1113,13 @@ impl ValidationBackend for ValidationHost { &mut self, pvf: PvfPrepData, exec_timeout: Duration, - encoded_params: Vec, + pvd: Arc, + pov: Arc, // The priority for the preparation job. prepare_priority: polkadot_node_core_pvf::Priority, ) -> Result { let (tx, rx) = oneshot::channel(); - if let Err(err) = - self.execute_pvf(pvf, exec_timeout, encoded_params, prepare_priority, tx).await + if let Err(err) = self.execute_pvf(pvf, exec_timeout, pvd, pov, prepare_priority, tx).await { return Err(InternalValidationError::HostCommunication(format!( "cannot send pvf to the validation host, it might have shut down: {:?}", @@ -933,6 +1146,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/metrics.rs b/polkadot/node/core/candidate-validation/src/metrics.rs index 28fc957ddb1a7acd0b5c67f4a52e70bf5e56f734..1459907aa5999980dd82ec0e08a5839959167cef 100644 --- a/polkadot/node/core/candidate-validation/src/metrics.rs +++ b/polkadot/node/core/candidate-validation/src/metrics.rs @@ -23,8 +23,6 @@ pub(crate) struct MetricsInner { pub(crate) validate_from_chain_state: prometheus::Histogram, pub(crate) validate_from_exhaustive: prometheus::Histogram, pub(crate) validate_candidate_exhaustive: prometheus::Histogram, - pub(crate) pov_size: prometheus::HistogramVec, - pub(crate) code_size: prometheus::Histogram, } /// Candidate validation metrics. @@ -70,21 +68,6 @@ impl Metrics { .as_ref() .map(|metrics| metrics.validate_candidate_exhaustive.start_timer()) } - - pub fn observe_code_size(&self, code_size: usize) { - if let Some(metrics) = &self.0 { - metrics.code_size.observe(code_size as f64); - } - } - - pub fn observe_pov_size(&self, pov_size: usize, compressed: bool) { - if let Some(metrics) = &self.0 { - metrics - .pov_size - .with_label_values(&[if compressed { "true" } else { "false" }]) - .observe(pov_size as f64); - } - } } impl metrics::Metrics for Metrics { @@ -121,33 +104,6 @@ impl metrics::Metrics for Metrics { ))?, registry, )?, - pov_size: prometheus::register( - prometheus::HistogramVec::new( - prometheus::HistogramOpts::new( - "polkadot_parachain_candidate_validation_pov_size", - "The compressed and decompressed size of the proof of validity of a candidate", - ) - .buckets( - prometheus::exponential_buckets(16384.0, 2.0, 10) - .expect("arguments are always valid; qed"), - ), - &["compressed"], - )?, - registry, - )?, - code_size: prometheus::register( - prometheus::Histogram::with_opts( - prometheus::HistogramOpts::new( - "polkadot_parachain_candidate_validation_code_size", - "The size of the decompressed WASM validation blob used for checking a candidate", - ) - .buckets( - prometheus::exponential_buckets(16384.0, 2.0, 10) - .expect("arguments are always valid; qed"), - ), - )?, - registry, - )?, }; Ok(Metrics(Some(metrics))) } diff --git a/polkadot/node/core/candidate-validation/src/tests.rs b/polkadot/node/core/candidate-validation/src/tests.rs index 491ed7a335d8fb5a8a7531e64267e664e3bf91d3..55282fdf4ee1da540f8aa95f272ccee0352a7390 100644 --- a/polkadot/node/core/candidate-validation/src/tests.rs +++ b/polkadot/node/core/candidate-validation/src/tests.rs @@ -14,16 +14,26 @@ // 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_primitives::{BlockData, VALIDATION_CODE_BOMB_LIMIT}; 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() { @@ -376,7 +386,8 @@ impl ValidationBackend for MockValidateCandidateBackend { &mut self, _pvf: PvfPrepData, _timeout: Duration, - _encoded_params: Vec, + _pvd: Arc, + _pov: Arc, _prepare_priority: polkadot_node_core_pvf::Priority, ) -> Result { // This is expected to panic if called more times than expected, indicating an error in the @@ -390,6 +401,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] @@ -937,115 +952,6 @@ fn compressed_code_works() { assert_matches!(v, Ok(ValidationResult::Valid(_, _))); } -#[test] -fn code_decompression_failure_is_error() { - let validation_data = PersistedValidationData { max_pov_size: 1024, ..Default::default() }; - let pov = PoV { block_data: BlockData(vec![1; 32]) }; - let head_data = HeadData(vec![1, 1, 1]); - - let raw_code = vec![2u8; VALIDATION_CODE_BOMB_LIMIT + 1]; - let validation_code = - sp_maybe_compressed_blob::compress(&raw_code, VALIDATION_CODE_BOMB_LIMIT + 1) - .map(ValidationCode) - .unwrap(); - - let descriptor = make_valid_candidate_descriptor( - ParaId::from(1_u32), - dummy_hash(), - validation_data.hash(), - pov.hash(), - validation_code.hash(), - head_data.hash(), - dummy_hash(), - Sr25519Keyring::Alice, - ); - - let validation_result = WasmValidationResult { - head_data, - new_validation_code: None, - upward_messages: Default::default(), - horizontal_messages: Default::default(), - processed_downward_messages: 0, - hrmp_watermark: 0, - }; - - let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; - - let pool = TaskExecutor::new(); - let (_ctx, _ctx_handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context::< - AllMessages, - _, - >(pool.clone()); - - let v = executor::block_on(validate_candidate_exhaustive( - MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), - validation_data, - validation_code, - candidate_receipt, - Arc::new(pov), - ExecutorParams::default(), - PvfExecKind::Backing, - &Default::default(), - )); - - assert_matches!(v, Err(_)); -} - -#[test] -fn pov_decompression_failure_is_invalid() { - let validation_data = - PersistedValidationData { max_pov_size: POV_BOMB_LIMIT as u32, ..Default::default() }; - let head_data = HeadData(vec![1, 1, 1]); - - let raw_block_data = vec![2u8; POV_BOMB_LIMIT + 1]; - let pov = sp_maybe_compressed_blob::compress(&raw_block_data, POV_BOMB_LIMIT + 1) - .map(|raw| PoV { block_data: BlockData(raw) }) - .unwrap(); - - let validation_code = ValidationCode(vec![2; 16]); - - let descriptor = make_valid_candidate_descriptor( - ParaId::from(1_u32), - dummy_hash(), - validation_data.hash(), - pov.hash(), - validation_code.hash(), - head_data.hash(), - dummy_hash(), - Sr25519Keyring::Alice, - ); - - let validation_result = WasmValidationResult { - head_data, - new_validation_code: None, - upward_messages: Default::default(), - horizontal_messages: Default::default(), - processed_downward_messages: 0, - hrmp_watermark: 0, - }; - - let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; - - let pool = TaskExecutor::new(); - let (_ctx, _ctx_handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context::< - AllMessages, - _, - >(pool.clone()); - - let v = executor::block_on(validate_candidate_exhaustive( - MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), - validation_data, - validation_code, - candidate_receipt, - Arc::new(pov), - ExecutorParams::default(), - PvfExecKind::Backing, - &Default::default(), - )); - - assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::PoVDecompressionFailure))); -} - struct MockPreCheckBackend { result: Result<(), PrepareError>, } @@ -1062,7 +968,8 @@ impl ValidationBackend for MockPreCheckBackend { &mut self, _pvf: PvfPrepData, _timeout: Duration, - _encoded_params: Vec, + _pvd: Arc, + _pov: Arc, _prepare_priority: polkadot_node_core_pvf::Priority, ) -> Result { unreachable!() @@ -1071,6 +978,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] @@ -1132,70 +1043,6 @@ fn precheck_works() { executor::block_on(test_fut); } -#[test] -fn precheck_invalid_pvf_blob_compression() { - let relay_parent = [3; 32].into(); - - let raw_code = vec![2u8; VALIDATION_CODE_BOMB_LIMIT + 1]; - let validation_code = - sp_maybe_compressed_blob::compress(&raw_code, VALIDATION_CODE_BOMB_LIMIT + 1) - .map(ValidationCode) - .unwrap(); - let validation_code_hash = validation_code.hash(); - - let pool = TaskExecutor::new(); - let (mut ctx, mut ctx_handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context::< - AllMessages, - _, - >(pool.clone()); - - let (check_fut, check_result) = precheck_pvf( - ctx.sender(), - MockPreCheckBackend::with_hardcoded_result(Ok(())), - relay_parent, - validation_code_hash, - ) - .remote_handle(); - - let test_fut = async move { - assert_matches!( - ctx_handle.recv().await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - rp, - RuntimeApiRequest::ValidationCodeByHash( - vch, - tx - ), - )) => { - assert_eq!(vch, validation_code_hash); - assert_eq!(rp, relay_parent); - - let _ = tx.send(Ok(Some(validation_code.clone()))); - } - ); - assert_matches!( - ctx_handle.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) - ) => { - tx.send(Ok(1u32.into())).unwrap(); - } - ); - assert_matches!( - ctx_handle.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(_, tx)) - ) => { - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - } - ); - assert_matches!(check_result.await, PreCheckOutcome::Invalid); - }; - - let test_fut = future::join(test_fut, check_fut); - executor::block_on(test_fut); -} - #[test] fn precheck_properly_classifies_outcomes() { let inner = |prepare_result, precheck_outcome| { @@ -1263,3 +1110,629 @@ 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, + _pvd: Arc, + _pov: Arc, + _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/prospective-parachains/Cargo.toml b/polkadot/node/core/prospective-parachains/Cargo.toml index 97da5a1e94a07947765ddc8311b23c8d03cb4f79..705014e67a05eff6a8c5954bdb0834faef10cc0e 100644 --- a/polkadot/node/core/prospective-parachains/Cargo.toml +++ b/polkadot/node/core/prospective-parachains/Cargo.toml @@ -12,24 +12,18 @@ workspace = true [dependencies] futures = { workspace = true } gum = { workspace = true, default-features = true } -codec = { workspace = true, default-features = true } thiserror = { workspace = true } fatality = { workspace = true } -bitvec = { 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 } [dev-dependencies] 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-tracing = { 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 } +rand = { workspace = true } rstest = { workspace = true } diff --git a/polkadot/node/core/prospective-parachains/src/error.rs b/polkadot/node/core/prospective-parachains/src/error.rs index 2b0933ab1c7e03e1a020d3cdc2c4953dfd9d294a..4b332b9c5de59aa49081bfeb3e8b2b7335c98717 100644 --- a/polkadot/node/core/prospective-parachains/src/error.rs +++ b/polkadot/node/core/prospective-parachains/src/error.rs @@ -30,18 +30,6 @@ use fatality::Nested; #[allow(missing_docs)] #[fatality::fatality(splitable)] pub enum Error { - #[fatal] - #[error("SubsystemError::Context error: {0}")] - SubsystemContext(String), - - #[fatal] - #[error("Spawning a task failed: {0}")] - SpawnFailed(SubsystemError), - - #[fatal] - #[error("Participation worker receiver exhausted.")] - ParticipationWorkerReceiverExhausted, - #[fatal] #[error("Receiving message from overseer failed: {0}")] SubsystemReceive(#[source] SubsystemError), @@ -55,9 +43,6 @@ pub enum Error { #[error(transparent)] ChainApi(#[from] ChainApiError), - #[error(transparent)] - Subsystem(SubsystemError), - #[error("Request to chain API subsystem dropped")] ChainApiRequestCanceled(oneshot::Canceled), 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..b060897d439168e4dd04acd1e3e896429d7c3ed4 100644 --- a/polkadot/node/core/prospective-parachains/src/fragment_chain/mod.rs +++ b/polkadot/node/core/prospective-parachains/src/fragment_chain/mod.rs @@ -18,41 +18,58 @@ //! //! # Overview //! -//! This module exposes two main types: [`FragmentChain`] and [`CandidateStorage`] which are meant -//! to be used in close conjunction. Each fragment chain is associated with a particular -//! relay-parent and each node in the chain represents a candidate. Each parachain has a single -//! candidate storage, but can have one chain for each relay chain block in the view. -//! Therefore, the same candidate can be present in multiple fragment chains of a parachain. One of -//! the purposes of the candidate storage is to deduplicate the large candidate data that is being -//! referenced from multiple fragment chains. +//! The main type exposed by this module is the [`FragmentChain`]. //! -//! A chain has an associated [`Scope`] which defines limits on candidates within the chain. -//! Candidates themselves have their own [`Constraints`] which are either the constraints from the -//! scope, or, if there are previous nodes in the chain, a modified version of the previous -//! candidate's constraints. +//! Each fragment chain is associated with a particular relay-parent (an active leaf) and has a +//! [`Scope`], which contains the allowed relay parents (up to `allowed_ancestry_len`), the pending +//! availability candidates and base constraints derived from the latest included candidate. Each +//! parachain has a single `FragmentChain` for each active leaf where it's scheduled. //! -//! Another use of the `CandidateStorage` is to keep a record of candidates which may not be yet -//! included in any chain, but which may become part of a chain in the future. This is needed for -//! elastic scaling, so that we may parallelise the backing process across different groups. As long -//! as some basic constraints are not violated by an unconnected candidate (like the relay parent -//! being in scope), we proceed with the backing process, hoping that its predecessors will be -//! backed soon enough. This is commonly called a potential candidate. Note that not all potential -//! candidates will be maintained in the CandidateStorage. The total number of connected + potential -//! candidates will be at most max_candidate_depth + 1. +//! A fragment chain consists mainly of the current best backable chain (we'll call this the best +//! chain) and a storage of unconnected potential candidates (we'll call this the unconnected +//! storage). +//! +//! The best chain contains all the candidates pending availability and a subsequent chain +//! of candidates that have reached the backing quorum and are better than any other backable forks +//! according to the fork selection rule (more on this rule later). It has a length of size at most +//! `max_candidate_depth + 1`. +//! +//! The unconnected storage keeps a record of seconded/backable candidates that may be +//! added to the best chain in the future. +//! Once a candidate is seconded, it becomes part of this unconnected storage. +//! Only after it is backed it may be added to the best chain (but not necessarily). It's only +//! added if it builds on the latest candidate in the chain and if there isn't a better backable +//! candidate according to the fork selection rule. +//! +//! An important thing to note is that the candidates present in the unconnected storage may have +//! any/no relationship between them. In other words, they may form N trees and may even form +//! cycles. This is needed so that we may begin validating candidates for which we don't yet know +//! their parent (so we may parallelize the backing process across different groups for elastic +//! scaling) and so that we accept parachain forks. +//! +//! We accept parachain forks only if the fork selection rule allows for it. In other words, if we +//! have a backed candidate, we begin seconding/validating a fork only if it has a lower candidate +//! hash. Once both forks are backed, we discard the one with the higher candidate hash. +//! We assume all validators pick the same fork according to the fork selection rule. If we decided +//! to not accept parachain forks, candidates could end up getting only half of the backing votes or +//! even less (for forks of larger arity). This would affect the validator rewards. Still, we don't +//! guarantee that a fork-producing parachains will be able to fully use elastic scaling. +//! +//! Once a candidate is backed and becomes part of the best chain, we can trim from the +//! unconnected storage candidates which constitute forks on the best chain and no longer have +//! potential. //! //! This module also makes use of types provided by the Inclusion Emulator module, such as //! [`Fragment`] and [`Constraints`]. These perform the actual job of checking for validity of //! prospective fragments. //! -//! # Parachain forks +//! # Fork choice rule //! -//! Parachains are expected to not create forks, hence the use of fragment chains as opposed to -//! fragment trees. If parachains do create forks, their performance in regards to async backing and -//! elastic scaling will suffer, because different validators will have different views of the -//! future. +//! The motivation for the fork choice rule is described in the previous chapter. //! -//! This is a compromise we can make - collators which want to use async backing and elastic scaling -//! need to cooperate for the highest throughput. +//! The current rule is: choose the candidate with the lower candidate hash. +//! The candidate hash is quite random and finding a candidate with a lower hash in order to favour +//! it would essentially mean solving a proof of work problem. //! //! # Parachain cycles //! @@ -65,70 +82,117 @@ //! resolved by having candidates reference their parent by candidate hash. //! //! However, dealing with cycles increases complexity during the backing/inclusion process for no -//! practical reason. Therefore, fragment chains will not accept such candidates. +//! practical reason. +//! These cycles may be accepted by fragment chains while candidates are part of the unconnected +//! storage, but they will definitely not make it to the best chain. //! //! On the other hand, enforcing that a parachain will NEVER be acyclic would be very complicated //! (looping through the entire parachain's history on every new candidate or changing the candidate //! receipt to reference the parent's candidate hash). //! +//! Therefore, we don't provide a guarantee that a cycle-producing parachain will work (although in +//! practice they probably will if the cycle length is larger than the number of assigned cores +//! multiplied by two). +//! //! # Spam protection //! -//! As long as the [`CandidateStorage`] has bounded input on the number of candidates supplied, -//! [`FragmentChain`] complexity is bounded. This means that higher-level code needs to be selective -//! about limiting the amount of candidates that are considered. +//! As long as the supplied number of candidates is bounded, [`FragmentChain`] complexity is +//! bounded. This means that higher-level code needs to be selective about limiting the amount of +//! candidates that are considered. +//! +//! Practically speaking, the collator-protocol will not allow more than `max_candidate_depth + 1` +//! collations to be fetched at a relay parent and statement-distribution will not allow more than +//! `max_candidate_depth + 1` seconded candidates at a relay parent per each validator in the +//! backing group. Considering the `allowed_ancestry_len` configuration value, the number of +//! candidates in a `FragmentChain` (including its unconnected storage) should not exceed: +//! +//! `allowed_ancestry_len * (max_candidate_depth + 1) * backing_group_size`. //! //! The code in this module is not designed for speed or efficiency, but conceptual simplicity. //! Our assumption is that the amount of candidates and parachains we consider will be reasonably //! bounded and in practice will not exceed a few thousand at any time. This naive implementation //! will still perform fairly well under these conditions, despite being somewhat wasteful of //! memory. +//! +//! Still, the expensive candidate data (CandidateCommitments) are wrapped in an `Arc` and shared +//! across fragment chains of the same para on different active leaves. #[cfg(test)] mod tests; use std::{ + cmp::{min, Ordering}, collections::{ hash_map::{Entry, HashMap}, - BTreeMap, HashSet, + BTreeMap, HashSet, VecDeque, }, sync::Arc, }; use super::LOG_TARGET; -use polkadot_node_subsystem::messages::{Ancestors, HypotheticalCandidate}; +use polkadot_node_subsystem::messages::Ancestors; use polkadot_node_subsystem_util::inclusion_emulator::{ - ConstraintModifications, Constraints, Fragment, ProspectiveCandidate, RelayChainBlockInfo, + self, ConstraintModifications, Constraints, Fragment, HypotheticalOrConcreteCandidate, + ProspectiveCandidate, RelayChainBlockInfo, }; use polkadot_primitives::{ - BlockNumber, CandidateHash, CommittedCandidateReceipt, Hash, HeadData, Id as ParaId, - PersistedValidationData, + BlockNumber, CandidateCommitments, CandidateHash, CommittedCandidateReceipt, Hash, HeadData, + PersistedValidationData, ValidationCodeHash, }; +use thiserror::Error; + +/// Fragment chain related errors. +#[derive(Debug, Clone, PartialEq, Error)] +pub(crate) enum Error { + #[error("Candidate already known")] + CandidateAlreadyKnown, + #[error("Candidate's parent head is equal to its output head. Would introduce a cycle.")] + ZeroLengthCycle, + #[error("Candidate would introduce a cycle")] + Cycle, + #[error("Candidate would introduce two paths to the same output state")] + MultiplePaths, + #[error("Attempting to directly introduce a Backed candidate. It should first be introduced as Seconded")] + IntroduceBackedCandidate, + #[error("Relay parent {0:?} of the candidate precedes the relay parent {1:?} of a pending availability candidate")] + RelayParentPrecedesCandidatePendingAvailability(Hash, Hash), + #[error("Candidate would introduce a fork with a pending availability candidate: {0:?}")] + ForkWithCandidatePendingAvailability(CandidateHash), + #[error("Fork selection rule favours another candidate: {0:?}")] + ForkChoiceRule(CandidateHash), + #[error("Could not find parent of the candidate")] + ParentCandidateNotFound, + #[error("Could not compute candidate constraints: {0:?}")] + ComputeConstraints(inclusion_emulator::ModificationError), + #[error("Candidate violates constraints: {0:?}")] + CheckAgainstConstraints(inclusion_emulator::FragmentValidityError), + #[error("Relay parent would move backwards from the latest candidate in the chain")] + RelayParentMovedBackwards, + #[error(transparent)] + CandidateEntry(#[from] CandidateEntryError), + #[error("Relay parent {0:?} not in scope. Earliest relay parent allowed {1:?}")] + RelayParentNotInScope(Hash, Hash), +} -/// Kinds of failures to import a candidate into storage. -#[derive(Debug, Clone, PartialEq)] -pub enum CandidateStorageInsertionError { - /// An error indicating that a supplied candidate didn't match the persisted - /// validation data provided alongside it. - PersistedValidationDataMismatch, - /// The candidate was already known. - CandidateAlreadyKnown(CandidateHash), +/// The rule for selecting between two backed candidate forks, when adding to the chain. +/// All validators should adhere to this rule, in order to not lose out on rewards in case of +/// forking parachains. +fn fork_selection_rule(hash1: &CandidateHash, hash2: &CandidateHash) -> Ordering { + hash1.cmp(hash2) } -/// Stores candidates and information about them such as their relay-parents and their backing -/// states. +/// Utility for storing candidates and information about them such as their relay-parents and their +/// backing states. This does not assume any restriction on whether or not the candidates form a +/// chain. Useful for storing all kinds of candidates. #[derive(Clone, Default)] pub(crate) struct CandidateStorage { - // Index from head data hash to candidate hashes with that head data as a parent. Purely for + // Index from head data hash to candidate hashes with that head data as a parent. Useful for // efficiency when responding to `ProspectiveValidationDataRequest`s or when trying to find a // new candidate to push to a chain. - // Even though having multiple candidates with same parent would be invalid for a parachain, it - // could happen across different relay chain forks, hence the HashSet. by_parent_head: HashMap>, - // Index from head data hash to candidate hashes outputting that head data. Purely for + // Index from head data hash to candidate hashes outputting that head data. For // efficiency when responding to `ProspectiveValidationDataRequest`s. - // Even though having multiple candidates with same output would be invalid for a parachain, - // it could happen across different relay chain forks. by_output_head: HashMap>, // Index from candidate hash to fragment node. @@ -136,65 +200,59 @@ pub(crate) struct CandidateStorage { } impl CandidateStorage { - /// Introduce a new candidate. - pub fn add_candidate( + /// Introduce a new pending availability candidate. + pub fn add_pending_availability_candidate( &mut self, + candidate_hash: CandidateHash, candidate: CommittedCandidateReceipt, persisted_validation_data: PersistedValidationData, - state: CandidateState, - ) -> Result { - let candidate_hash = candidate.hash(); - if self.by_candidate_hash.contains_key(&candidate_hash) { - return Err(CandidateStorageInsertionError::CandidateAlreadyKnown(candidate_hash)) - } + ) -> Result<(), Error> { + let entry = CandidateEntry::new( + candidate_hash, + candidate, + persisted_validation_data, + CandidateState::Backed, + )?; - if persisted_validation_data.hash() != candidate.descriptor.persisted_validation_data_hash { - return Err(CandidateStorageInsertionError::PersistedValidationDataMismatch) - } + self.add_candidate_entry(entry) + } - let entry = CandidateEntry { - candidate_hash, - parent_head_data_hash: persisted_validation_data.parent_head.hash(), - output_head_data_hash: candidate.commitments.head_data.hash(), - relay_parent: candidate.descriptor.relay_parent, - 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, - }), - }; + /// Return the number of stored candidates. + pub fn len(&self) -> usize { + self.by_candidate_hash.len() + } + + /// Introduce a new candidate entry. + fn add_candidate_entry(&mut self, candidate: CandidateEntry) -> Result<(), Error> { + let candidate_hash = candidate.candidate_hash; + if self.by_candidate_hash.contains_key(&candidate_hash) { + return Err(Error::CandidateAlreadyKnown) + } self.by_parent_head - .entry(entry.parent_head_data_hash()) + .entry(candidate.parent_head_data_hash) .or_default() .insert(candidate_hash); self.by_output_head - .entry(entry.output_head_data_hash()) + .entry(candidate.output_head_data_hash) .or_default() .insert(candidate_hash); - // sanity-checked already. - self.by_candidate_hash.insert(candidate_hash, entry); + self.by_candidate_hash.insert(candidate_hash, candidate); - Ok(candidate_hash) + Ok(()) } /// Remove a candidate from the store. - pub fn remove_candidate(&mut self, candidate_hash: &CandidateHash) { + fn remove_candidate(&mut self, candidate_hash: &CandidateHash) { if let Some(entry) = self.by_candidate_hash.remove(candidate_hash) { - if let Entry::Occupied(mut e) = self.by_parent_head.entry(entry.parent_head_data_hash()) - { + if let Entry::Occupied(mut e) = self.by_parent_head.entry(entry.parent_head_data_hash) { e.get_mut().remove(&candidate_hash); if e.get().is_empty() { e.remove(); } } - if let Entry::Occupied(mut e) = self.by_output_head.entry(entry.output_head_data_hash()) - { + if let Entry::Occupied(mut e) = self.by_output_head.entry(entry.output_head_data_hash) { e.get_mut().remove(&candidate_hash); if e.get().is_empty() { e.remove(); @@ -204,7 +262,7 @@ impl CandidateStorage { } /// Note that an existing candidate has been backed. - pub fn mark_backed(&mut self, candidate_hash: &CandidateHash) { + fn mark_backed(&mut self, candidate_hash: &CandidateHash) { if let Some(entry) = self.by_candidate_hash.get_mut(candidate_hash) { gum::trace!(target: LOG_TARGET, ?candidate_hash, "Candidate marked as backed"); entry.state = CandidateState::Backed; @@ -213,38 +271,18 @@ impl CandidateStorage { } } - /// Whether a candidate is recorded as being backed. - pub fn is_backed(&self, candidate_hash: &CandidateHash) -> bool { - self.by_candidate_hash - .get(candidate_hash) - .map_or(false, |e| e.state == CandidateState::Backed) - } - /// Whether a candidate is contained within the storage already. - pub fn contains(&self, candidate_hash: &CandidateHash) -> bool { + fn contains(&self, candidate_hash: &CandidateHash) -> bool { self.by_candidate_hash.contains_key(candidate_hash) } - /// Return an iterator over the stored candidates. - pub fn candidates(&self) -> impl Iterator { + /// Return an iterator over references to the stored candidates, in arbitrary order. + fn candidates(&self) -> impl Iterator { self.by_candidate_hash.values() } - /// Retain only candidates which pass the predicate. - pub(crate) fn retain(&mut self, pred: impl Fn(&CandidateHash) -> bool) { - self.by_candidate_hash.retain(|h, _v| pred(h)); - self.by_parent_head.retain(|_parent, children| { - children.retain(|h| pred(h)); - !children.is_empty() - }); - self.by_output_head.retain(|_output, candidates| { - candidates.retain(|h| pred(h)); - !candidates.is_empty() - }); - } - - /// Get head-data by hash. - pub(crate) fn head_data_by_hash(&self, hash: &Hash) -> Option<&HeadData> { + /// Try getting head-data by hash. + fn head_data_by_hash(&self, hash: &Hash) -> Option<&HeadData> { // First, search for candidates outputting this head data and extract the head data // from their commitments if they exist. // @@ -264,16 +302,8 @@ impl CandidateStorage { }) } - /// Returns candidate's relay parent, if present. - pub(crate) fn relay_parent_of_candidate(&self, candidate_hash: &CandidateHash) -> Option { - self.by_candidate_hash.get(candidate_hash).map(|entry| entry.relay_parent) - } - - /// Returns the candidates which have the given head data hash as parent. - /// We don't allow forks in a parachain, but we may have multiple candidates with same parent - /// across different relay chain forks. That's why it returns an iterator (but only one will be - /// valid and used in the end). - fn possible_para_children<'a>( + /// Returns the backed candidates which have the given head data hash as parent. + fn possible_backed_para_children<'a>( &'a self, parent_head_hash: &'a Hash, ) -> impl Iterator + 'a { @@ -282,12 +312,11 @@ impl CandidateStorage { .get(parent_head_hash) .into_iter() .flat_map(|hashes| hashes.iter()) - .filter_map(move |h| by_candidate_hash.get(h)) - } - - #[cfg(test)] - pub fn len(&self) -> (usize, usize) { - (self.by_parent_head.len(), self.by_candidate_hash.len()) + .filter_map(move |h| { + by_candidate_hash.get(h).and_then(|candidate| { + (candidate.state == CandidateState::Backed).then_some(candidate) + }) + }) } } @@ -295,14 +324,24 @@ impl CandidateStorage { /// /// Candidates aren't even considered until they've at least been seconded. #[derive(Debug, PartialEq, Clone)] -pub(crate) enum CandidateState { +enum CandidateState { /// The candidate has been seconded. Seconded, /// The candidate has been completely backed by the group. Backed, } +#[derive(Debug, Clone, PartialEq, Error)] +/// Possible errors when construcing a candidate entry. +pub enum CandidateEntryError { + #[error("Candidate does not match the persisted validation data provided alongside it")] + PersistedValidationDataMismatch, + #[error("Candidate's parent head is equal to its output head. Would introduce a cycle")] + ZeroLengthCycle, +} + #[derive(Debug, Clone)] +/// Representation of a candidate into the [`CandidateStorage`]. pub(crate) struct CandidateEntry { candidate_hash: CandidateHash, parent_head_data_hash: Hash, @@ -313,16 +352,79 @@ pub(crate) struct CandidateEntry { } impl CandidateEntry { + /// Create a new seconded candidate entry. + pub fn new_seconded( + candidate_hash: CandidateHash, + candidate: CommittedCandidateReceipt, + persisted_validation_data: PersistedValidationData, + ) -> Result { + Self::new(candidate_hash, candidate, persisted_validation_data, CandidateState::Seconded) + } + pub fn hash(&self) -> CandidateHash { self.candidate_hash } - pub fn parent_head_data_hash(&self) -> Hash { + fn new( + candidate_hash: CandidateHash, + candidate: CommittedCandidateReceipt, + persisted_validation_data: PersistedValidationData, + state: CandidateState, + ) -> Result { + if persisted_validation_data.hash() != candidate.descriptor.persisted_validation_data_hash { + return Err(CandidateEntryError::PersistedValidationDataMismatch) + } + + let parent_head_data_hash = persisted_validation_data.parent_head.hash(); + let output_head_data_hash = candidate.commitments.head_data.hash(); + + if parent_head_data_hash == output_head_data_hash { + return Err(CandidateEntryError::ZeroLengthCycle) + } + + Ok(Self { + candidate_hash, + parent_head_data_hash, + output_head_data_hash, + relay_parent: candidate.descriptor.relay_parent, + state, + candidate: Arc::new(ProspectiveCandidate { + commitments: candidate.commitments, + persisted_validation_data, + pov_hash: candidate.descriptor.pov_hash, + validation_code_hash: candidate.descriptor.validation_code_hash, + }), + }) + } +} + +impl HypotheticalOrConcreteCandidate for CandidateEntry { + fn commitments(&self) -> Option<&CandidateCommitments> { + Some(&self.candidate.commitments) + } + + fn persisted_validation_data(&self) -> Option<&PersistedValidationData> { + Some(&self.candidate.persisted_validation_data) + } + + fn validation_code_hash(&self) -> Option<&ValidationCodeHash> { + Some(&self.candidate.validation_code_hash) + } + + fn parent_head_data_hash(&self) -> Hash { self.parent_head_data_hash } - pub fn output_head_data_hash(&self) -> Hash { - self.output_head_data_hash + fn output_head_data_hash(&self) -> Option { + Some(self.output_head_data_hash) + } + + fn relay_parent(&self) -> Hash { + self.relay_parent + } + + fn candidate_hash(&self) -> CandidateHash { + self.candidate_hash } } @@ -339,8 +441,6 @@ pub(crate) struct PendingAvailability { /// The scope of a [`FragmentChain`]. #[derive(Debug, Clone)] pub(crate) struct Scope { - /// The assigned para id of this `FragmentChain`. - para: ParaId, /// The relay parent we're currently building on top of. relay_parent: RelayChainBlockInfo, /// The other relay parents candidates are allowed to build upon, mapped by the block number. @@ -358,10 +458,14 @@ pub(crate) struct Scope { /// An error variant indicating that ancestors provided to a scope /// had unexpected order. #[derive(Debug)] -pub struct UnexpectedAncestor { +pub(crate) struct UnexpectedAncestor { /// The block number that this error occurred at. + /// Allow as dead code, but it's being read in logs. + #[allow(dead_code)] pub number: BlockNumber, /// The previous seen block number, which did not match `number`. + /// Allow as dead code, but it's being read in logs. + #[allow(dead_code)] pub prev: BlockNumber, } @@ -383,7 +487,6 @@ impl Scope { /// /// It is allowed to provide zero ancestors. pub fn with_ancestors( - para: ParaId, relay_parent: RelayChainBlockInfo, base_constraints: Constraints, pending_availability: Vec, @@ -410,7 +513,6 @@ impl Scope { } Ok(Scope { - para, relay_parent, base_constraints, pending_availability, @@ -438,24 +540,29 @@ impl Scope { self.ancestors_by_hash.get(hash).map(|info| info.clone()) } + /// Get the base constraints of the scope + pub fn base_constraints(&self) -> &Constraints { + &self.base_constraints + } + /// Whether the candidate in question is one pending availability in this scope. - pub fn get_pending_availability( + fn get_pending_availability( &self, candidate_hash: &CandidateHash, ) -> Option<&PendingAvailability> { self.pending_availability.iter().find(|c| &c.candidate_hash == candidate_hash) } - - /// Get the base constraints of the scope - pub fn base_constraints(&self) -> &Constraints { - &self.base_constraints - } } -pub struct FragmentNode { +#[cfg_attr(test, derive(Clone))] +/// A node that is part of a `BackedChain`. It holds constraints based on the ancestors in the +/// chain. +struct FragmentNode { fragment: Fragment, candidate_hash: CandidateHash, cumulative_modifications: ConstraintModifications, + parent_head_data_hash: Hash, + output_head_data_hash: Hash, } impl FragmentNode { @@ -464,211 +571,336 @@ impl FragmentNode { } } -/// Response given by `can_add_candidate_as_potential` -#[derive(PartialEq, Debug)] -pub enum PotentialAddition { - /// Can be added as either connected or unconnected candidate. - Anyhow, - /// Can only be added as a connected candidate to the chain. - IfConnected, - /// Cannot be added. - None, +impl From<&FragmentNode> for CandidateEntry { + fn from(node: &FragmentNode) -> Self { + // We don't need to perform the checks done in `CandidateEntry::new()`, since a + // `FragmentNode` always comes from a `CandidateEntry` + Self { + candidate_hash: node.candidate_hash, + parent_head_data_hash: node.parent_head_data_hash, + output_head_data_hash: node.output_head_data_hash, + candidate: node.fragment.candidate_clone(), + relay_parent: node.relay_parent(), + // A fragment node is always backed. + state: CandidateState::Backed, + } + } } -/// This is a chain of candidates based on some underlying storage of candidates and a scope. +/// A candidate chain of backed/backable candidates. +/// Includes the candidates pending availability and candidates which may be backed on-chain. +#[derive(Default)] +#[cfg_attr(test, derive(Clone))] +struct BackedChain { + // Holds the candidate chain. + chain: Vec, + // Index from head data hash to the candidate hash with that head data as a parent. + // Only contains the candidates present in the `chain`. + by_parent_head: HashMap, + // Index from head data hash to the candidate hash outputting that head data. + // Only contains the candidates present in the `chain`. + by_output_head: HashMap, + // A set of the candidate hashes in the `chain`. + candidates: HashSet, +} + +impl BackedChain { + fn push(&mut self, candidate: FragmentNode) { + self.candidates.insert(candidate.candidate_hash); + self.by_parent_head + .insert(candidate.parent_head_data_hash, candidate.candidate_hash); + self.by_output_head + .insert(candidate.output_head_data_hash, candidate.candidate_hash); + self.chain.push(candidate); + } + + fn clear(&mut self) -> Vec { + self.by_parent_head.clear(); + self.by_output_head.clear(); + self.candidates.clear(); + + std::mem::take(&mut self.chain) + } + + fn revert_to_parent_hash<'a>( + &'a mut self, + parent_head_data_hash: &Hash, + ) -> impl Iterator + 'a { + let mut found_index = None; + for index in 0..self.chain.len() { + let node = &self.chain[0]; + + if found_index.is_some() { + self.by_parent_head.remove(&node.parent_head_data_hash); + self.by_output_head.remove(&node.output_head_data_hash); + self.candidates.remove(&node.candidate_hash); + } else if &node.output_head_data_hash == parent_head_data_hash { + found_index = Some(index); + } + } + + if let Some(index) = found_index { + self.chain.drain(min(index + 1, self.chain.len())..) + } else { + // Don't remove anything, but use drain to satisfy the compiler. + self.chain.drain(0..0) + } + } + + fn contains(&self, hash: &CandidateHash) -> bool { + self.candidates.contains(hash) + } +} + +/// This is the fragment chain specific to an active leaf. /// -/// All nodes in the chain must be either pending availability or within the scope. Within the scope -/// means it's built off of the relay-parent or an ancestor. +/// It holds the current best backable candidate chain, as well as potential candidates +/// which could become connected to the chain in the future or which could even overwrite the +/// existing chain. +#[cfg_attr(test, derive(Clone))] pub(crate) struct FragmentChain { + // The current scope, which dictates the on-chain operating constraints that all future + // candidates must adhere to. scope: Scope, - chain: Vec, - - candidates: HashSet, + // The current best chain of backable candidates. It only contains candidates which build on + // top of each other and which have reached the backing quorum. In the presence of potential + // forks, this chain will pick a fork according to the `fork_selection_rule`. + best_chain: BackedChain, - // Index from head data hash to candidate hashes with that head data as a parent. - by_parent_head: HashMap, - // Index from head data hash to candidate hashes outputting that head data. - by_output_head: HashMap, + // The potential candidate storage. Contains candidates which are not yet part of the `chain` + // but may become in the future. These can form any tree shape as well as contain any + // unconnected candidates for which we don't know the parent. + unconnected: CandidateStorage, } impl FragmentChain { - /// Create a new [`FragmentChain`] with given scope and populated from the storage. - pub fn populate(scope: Scope, storage: &CandidateStorage) -> Self { - gum::trace!( - target: LOG_TARGET, - relay_parent = ?scope.relay_parent.hash, - relay_parent_num = scope.relay_parent.number, - para_id = ?scope.para, - ancestors = scope.ancestors.len(), - "Instantiating Fragment Chain", - ); - + /// Create a new [`FragmentChain`] with the given scope and populate it with the candidates + /// pending availability. + pub fn init(scope: Scope, mut candidates_pending_availability: CandidateStorage) -> Self { let mut fragment_chain = Self { scope, - chain: Vec::new(), - candidates: HashSet::new(), - by_parent_head: HashMap::new(), - by_output_head: HashMap::new(), + best_chain: BackedChain::default(), + unconnected: CandidateStorage::default(), }; - fragment_chain.populate_chain(storage); + // We only need to populate the best backable chain. Candidates pending availability must + // form a chain with the latest included head. + fragment_chain.populate_chain(&mut candidates_pending_availability); fragment_chain } - /// Get the scope of the Fragment Chain. + /// Populate the [`FragmentChain`] given the new candidates pending availability and the + /// optional previous fragment chain (of the previous relay parent). + pub fn populate_from_previous(&mut self, prev_fragment_chain: &FragmentChain) { + let mut prev_storage = prev_fragment_chain.unconnected.clone(); + + for candidate in prev_fragment_chain.best_chain.chain.iter() { + // If they used to be pending availability, don't add them. This is fine + // because: + // - if they still are pending availability, they have already been added to the new + // storage. + // - if they were included, no point in keeping them. + // + // This cannot happen for the candidates in the unconnected storage. The pending + // availability candidates will always be part of the best chain. + if prev_fragment_chain + .scope + .get_pending_availability(&candidate.candidate_hash) + .is_none() + { + let _ = prev_storage.add_candidate_entry(candidate.into()); + } + } + + // First populate the best backable chain. + self.populate_chain(&mut prev_storage); + + // Now that we picked the best backable chain, trim the forks generated by candidates which + // are not present in the best chain. + self.trim_uneligible_forks(&mut prev_storage, None); + + // Finally, keep any candidates which haven't been trimmed but still have potential. + self.populate_unconnected_potential_candidates(prev_storage); + } + + /// Get the scope of the [`FragmentChain`]. pub fn scope(&self) -> &Scope { &self.scope } - /// Returns the number of candidates in the chain - pub(crate) fn len(&self) -> usize { - self.candidates.len() + /// Returns the number of candidates in the best backable chain. + pub fn best_chain_len(&self) -> usize { + self.best_chain.chain.len() } - /// Whether the candidate exists. - pub(crate) fn contains_candidate(&self, candidate: &CandidateHash) -> bool { - self.candidates.contains(candidate) + /// Returns the number of candidates in unconnected potential storage. + pub fn unconnected_len(&self) -> usize { + self.unconnected.len() + } + + /// Whether the candidate exists as part of the unconnected potential candidates. + pub fn contains_unconnected_candidate(&self, candidate: &CandidateHash) -> bool { + self.unconnected.contains(candidate) } /// Return a vector of the chain's candidate hashes, in-order. - pub(crate) fn to_vec(&self) -> Vec { - self.chain.iter().map(|candidate| candidate.candidate_hash).collect() + pub fn best_chain_vec(&self) -> Vec { + self.best_chain.chain.iter().map(|candidate| candidate.candidate_hash).collect() } - /// Try accumulating more candidates onto the chain. - /// - /// Candidates can only be added if they build on the already existing chain. - pub(crate) fn extend_from_storage(&mut self, storage: &CandidateStorage) { - self.populate_chain(storage); + /// Return a vector of the unconnected potential candidate hashes, in arbitrary order. + pub fn unconnected(&self) -> impl Iterator { + self.unconnected.candidates() } - /// Returns the hypothetical state of a candidate with the given hash and parent head data - /// in regards to the existing chain. - /// - /// Returns true if either: - /// - the candidate is already present - /// - the candidate can be added to the chain - /// - the candidate could potentially be added to the chain in the future (its ancestors are - /// still unknown but it doesn't violate other rules). - /// - /// If this returns false, the candidate could never be added to the current chain (not now, not - /// ever) - pub(crate) fn hypothetical_membership( + /// Return whether this candidate is backed in this chain or the unconnected storage. + pub fn is_candidate_backed(&self, hash: &CandidateHash) -> bool { + self.best_chain.candidates.contains(hash) || + matches!( + self.unconnected.by_candidate_hash.get(hash), + Some(candidate) if candidate.state == CandidateState::Backed + ) + } + + /// Mark a candidate as backed. This can trigger a recreation of the best backable chain. + pub fn candidate_backed(&mut self, newly_backed_candidate: &CandidateHash) { + // Already backed. + if self.best_chain.candidates.contains(newly_backed_candidate) { + return + } + let Some(parent_head_hash) = self + .unconnected + .by_candidate_hash + .get(newly_backed_candidate) + .map(|entry| entry.parent_head_data_hash) + else { + // Candidate is not in unconnected storage. + return + }; + + // Mark the candidate hash. + self.unconnected.mark_backed(newly_backed_candidate); + + // Revert to parent_head_hash + if !self.revert_to(&parent_head_hash) { + // If nothing was reverted, there is nothing we can do for now. + return + } + + let mut prev_storage = std::mem::take(&mut self.unconnected); + + // Populate the chain. + self.populate_chain(&mut prev_storage); + + // Now that we picked the best backable chain, trim the forks generated by candidates + // which are not present in the best chain. We can start trimming from this candidate + // onwards. + self.trim_uneligible_forks(&mut prev_storage, Some(parent_head_hash)); + + // Finally, keep any candidates which haven't been trimmed but still have potential. + self.populate_unconnected_potential_candidates(prev_storage); + } + + /// Checks if this candidate could be added in the future to this chain. + /// This will return `Error::CandidateAlreadyKnown` if the candidate is already in the chain or + /// the unconnected candidate storage. + pub fn can_add_candidate_as_potential( &self, - candidate: HypotheticalCandidate, - candidate_storage: &CandidateStorage, - ) -> bool { + candidate: &impl HypotheticalOrConcreteCandidate, + ) -> Result<(), Error> { let candidate_hash = candidate.candidate_hash(); - // If we've already used this candidate in the chain - if self.candidates.contains(&candidate_hash) { - return true + if self.best_chain.contains(&candidate_hash) || self.unconnected.contains(&candidate_hash) { + return Err(Error::CandidateAlreadyKnown) } - let can_add_as_potential = self.can_add_candidate_as_potential( - candidate_storage, - &candidate.candidate_hash(), - &candidate.relay_parent(), - candidate.parent_head_data_hash(), - candidate.output_head_data_hash(), - ); + self.check_potential(candidate) + } - if can_add_as_potential == PotentialAddition::None { - return false + /// Try adding a seconded candidate, if the candidate has potential. It will never be added to + /// the chain directly in the seconded state, it will only be part of the unconnected storage. + pub fn try_adding_seconded_candidate( + &mut self, + candidate: &CandidateEntry, + ) -> Result<(), Error> { + if candidate.state == CandidateState::Backed { + return Err(Error::IntroduceBackedCandidate); } - let Some(candidate_relay_parent) = self.scope.ancestor(&candidate.relay_parent()) else { - // can_add_candidate_as_potential already checked for this, but just to be safe. - return false - }; + self.can_add_candidate_as_potential(candidate)?; - let identity_modifications = ConstraintModifications::identity(); - let cumulative_modifications = if let Some(last_candidate) = self.chain.last() { - &last_candidate.cumulative_modifications - } else { - &identity_modifications - }; + // This clone is cheap, as it uses an Arc for the expensive stuff. + // We can't consume the candidate because other fragment chains may use it also. + self.unconnected.add_candidate_entry(candidate.clone())?; - let child_constraints = - match self.scope.base_constraints.apply_modifications(&cumulative_modifications) { - Err(e) => { - gum::debug!( - target: LOG_TARGET, - new_parent_head = ?cumulative_modifications.required_parent, - ?candidate_hash, - err = ?e, - "Failed to apply modifications", - ); - - return false - }, - Ok(c) => c, - }; + Ok(()) + } - let parent_head_hash = candidate.parent_head_data_hash(); - if parent_head_hash == child_constraints.required_parent.hash() { - // We do additional checks for complete candidates. - if let HypotheticalCandidate::Complete { - ref receipt, - ref persisted_validation_data, - .. - } = candidate - { - if Fragment::check_against_constraints( - &candidate_relay_parent, - &child_constraints, - &receipt.commitments, - &receipt.descriptor().validation_code_hash, - persisted_validation_data, - ) - .is_err() - { - gum::debug!( - target: LOG_TARGET, - "Fragment::check_against_constraints() returned error", - ); - return false - } - } + /// Try getting the full head data associated with this hash. + pub fn get_head_data_by_hash(&self, head_data_hash: &Hash) -> Option { + // First, see if this is the head data of the latest included candidate. + let required_parent = &self.scope.base_constraints().required_parent; + if &required_parent.hash() == head_data_hash { + return Some(required_parent.clone()) + } - // If we got this far, it can be added to the chain right now. - true - } else if can_add_as_potential == PotentialAddition::Anyhow { - // Otherwise it is or can be an unconnected candidate, but only if PotentialAddition - // does not force us to only add a connected candidate. - true - } else { - false + // Cheaply check if the head data is in the best backable chain. + let has_head_data_in_chain = self + .best_chain + .by_parent_head + .get(head_data_hash) + .or_else(|| self.best_chain.by_output_head.get(head_data_hash)) + .is_some(); + + if has_head_data_in_chain { + return self.best_chain.chain.iter().find_map(|candidate| { + if &candidate.parent_head_data_hash == head_data_hash { + Some( + candidate + .fragment + .candidate() + .persisted_validation_data + .parent_head + .clone(), + ) + } else if &candidate.output_head_data_hash == head_data_hash { + Some(candidate.fragment.candidate().commitments.head_data.clone()) + } else { + None + } + }); } + + // Lastly, try getting the head data from the unconnected candidates. + self.unconnected.head_data_by_hash(head_data_hash).cloned() } - /// Select `count` candidates after the given `ancestors` which pass - /// the predicate and have not already been backed on chain. + /// Select `count` candidates after the given `ancestors` which can be backed on chain next. /// /// The intention of the `ancestors` is to allow queries on the basis of /// one or more candidates which were previously pending availability becoming /// available or candidates timing out. - pub(crate) fn find_backable_chain( + pub fn find_backable_chain( &self, ancestors: Ancestors, count: u32, - pred: impl Fn(&CandidateHash) -> bool, - ) -> Vec { + ) -> Vec<(CandidateHash, Hash)> { if count == 0 { return vec![] } let base_pos = self.find_ancestor_path(ancestors); - let actual_end_index = std::cmp::min(base_pos + (count as usize), self.chain.len()); + let actual_end_index = + std::cmp::min(base_pos + (count as usize), self.best_chain.chain.len()); let mut res = Vec::with_capacity(actual_end_index - base_pos); - for elem in &self.chain[base_pos..actual_end_index] { - if self.scope.get_pending_availability(&elem.candidate_hash).is_none() && - pred(&elem.candidate_hash) - { - res.push(elem.candidate_hash); + for elem in &self.best_chain.chain[base_pos..actual_end_index] { + // Only supply candidates which are not yet pending availability. `ancestors` should + // have already contained them, but check just in case. + if self.scope.get_pending_availability(&elem.candidate_hash).is_none() { + res.push((elem.candidate_hash, elem.relay_parent())); } else { break } @@ -681,11 +913,11 @@ impl FragmentChain { // Stops when the ancestors are all used or when a node in the chain is not present in the // ancestor set. Returns the index in the chain were the search stopped. fn find_ancestor_path(&self, mut ancestors: Ancestors) -> usize { - if self.chain.is_empty() { + if self.best_chain.chain.is_empty() { return 0; } - for (index, candidate) in self.chain.iter().enumerate() { + for (index, candidate) in self.best_chain.chain.iter().enumerate() { if !ancestors.remove(&candidate.candidate_hash) { return index } @@ -693,16 +925,16 @@ impl FragmentChain { // This means that we found the entire chain in the ancestor set. There won't be anything // left to back. - self.chain.len() + self.best_chain.chain.len() } - // Return the earliest relay parent a new candidate can have in order to be added to the chain. - // This is the relay parent of the last candidate in the chain. + // Return the earliest relay parent a new candidate can have in order to be added to the chain + // right now. This is the relay parent of the last candidate in the chain. // The value returned may not be valid if we want to add a candidate pending availability, which // may have a relay parent which is out of scope. Special handling is needed in that case. // `None` is returned if the candidate's relay parent info cannot be found. fn earliest_relay_parent(&self) -> Option { - if let Some(last_candidate) = self.chain.last() { + if let Some(last_candidate) = self.best_chain.chain.last() { self.scope.ancestor(&last_candidate.relay_parent()).or_else(|| { // if the relay-parent is out of scope _and_ it is in the chain, // it must be a candidate pending availability. @@ -715,152 +947,239 @@ impl FragmentChain { } } - // Checks if this candidate could be added in the future to this chain. - // This assumes that the chain does not already contain this candidate. It may or may not be - // present in the `CandidateStorage`. - // Even if the candidate is a potential candidate, this function will indicate that it can be - // kept only if there's enough room for it. - pub(crate) fn can_add_candidate_as_potential( - &self, - storage: &CandidateStorage, - candidate_hash: &CandidateHash, - relay_parent: &Hash, - parent_head_hash: Hash, - output_head_hash: Option, - ) -> PotentialAddition { - // If we've got enough candidates for the configured depth, no point in adding more. - if self.chain.len() > self.scope.max_depth { - return PotentialAddition::None - } + // Return the earliest relay parent a potential candidate may have for it to ever be added to + // the chain. This is the relay parent of the last candidate pending availability or the + // earliest relay parent in scope. + fn earliest_relay_parent_pending_availability(&self) -> RelayChainBlockInfo { + self.best_chain + .chain + .iter() + .rev() + .find_map(|candidate| { + self.scope + .get_pending_availability(&candidate.candidate_hash) + .map(|c| c.relay_parent.clone()) + }) + .unwrap_or_else(|| self.scope.earliest_relay_parent()) + } - if !self.check_potential(relay_parent, parent_head_hash, output_head_hash) { - return PotentialAddition::None - } + // Populate the unconnected potential candidate storage starting from a previous storage. + fn populate_unconnected_potential_candidates(&mut self, old_storage: CandidateStorage) { + for candidate in old_storage.by_candidate_hash.into_values() { + // Sanity check, all pending availability candidates should be already present in the + // chain. + if self.scope.get_pending_availability(&candidate.candidate_hash).is_some() { + continue + } - let present_in_storage = storage.contains(candidate_hash); + match self.can_add_candidate_as_potential(&candidate) { + Ok(()) => { + let _ = self.unconnected.add_candidate_entry(candidate); + }, + // Swallow these errors as they can legitimately happen when pruning stale + // candidates. + Err(_) => {}, + }; + } + } - let unconnected = self - .find_unconnected_potential_candidates( - storage, - present_in_storage.then_some(candidate_hash), - ) - .len(); + // Check whether a candidate outputting this head data would introduce a cycle or multiple paths + // to the same state. Trivial 0-length cycles are checked in `CandidateEntry::new`. + fn check_cycles_or_invalid_tree(&self, output_head_hash: &Hash) -> Result<(), Error> { + // this should catch a cycle where this candidate would point back to the parent of some + // candidate in the chain. + if self.best_chain.by_parent_head.contains_key(output_head_hash) { + return Err(Error::Cycle) + } - if (self.chain.len() + unconnected) < self.scope.max_depth { - PotentialAddition::Anyhow - } else if (self.chain.len() + unconnected) == self.scope.max_depth { - // If we've only one slot left to fill, it must be filled with a connected candidate. - PotentialAddition::IfConnected - } else { - PotentialAddition::None + // multiple paths to the same state, which can't happen for a chain. + if self.best_chain.by_output_head.contains_key(output_head_hash) { + return Err(Error::MultiplePaths) } + + Ok(()) } - // The candidates which are present in `CandidateStorage`, are not part of this chain but could - // become part of this chain in the future. Capped at the max depth minus the existing chain - // length. - // If `ignore_candidate` is supplied and found in storage, it won't be counted. - pub(crate) fn find_unconnected_potential_candidates( + // Checks the potential of a candidate to be added to the chain now or in the future. + // It works both with concrete candidates for which we have the full PVD and committed receipt, + // but also does some more basic checks for incomplete candidates (before even fetching them). + fn check_potential( &self, - storage: &CandidateStorage, - ignore_candidate: Option<&CandidateHash>, - ) -> Vec { - let mut candidates = vec![]; - for candidate in storage.candidates() { - if let Some(ignore_candidate) = ignore_candidate { - if ignore_candidate == &candidate.candidate_hash { - continue - } - } - // We stop at max_depth + 1 with the search. There's no point in looping further. - if (self.chain.len() + candidates.len()) > self.scope.max_depth { - break - } - if !self.candidates.contains(&candidate.candidate_hash) && - self.check_potential( - &candidate.relay_parent, - candidate.candidate.persisted_validation_data.parent_head.hash(), - Some(candidate.candidate.commitments.head_data.hash()), - ) { - candidates.push(candidate.candidate_hash); + candidate: &impl HypotheticalOrConcreteCandidate, + ) -> Result<(), Error> { + let relay_parent = candidate.relay_parent(); + let parent_head_hash = candidate.parent_head_data_hash(); + + // trivial 0-length cycle. + if let Some(output_head_hash) = candidate.output_head_data_hash() { + if parent_head_hash == output_head_hash { + return Err(Error::ZeroLengthCycle) } } - candidates - } + // Check if the relay parent is in scope. + let Some(relay_parent) = self.scope.ancestor(&relay_parent) else { + return Err(Error::RelayParentNotInScope( + relay_parent, + self.scope.earliest_relay_parent().hash, + )) + }; - // Check if adding a candidate which transitions `parent_head_hash` to `output_head_hash` would - // introduce a fork or a cycle in the parachain. - // `output_head_hash` is optional because we sometimes make this check before retrieving the - // collation. - fn is_fork_or_cycle(&self, parent_head_hash: Hash, output_head_hash: Option) -> bool { - if self.by_parent_head.contains_key(&parent_head_hash) { - // fork. our parent has another child already - return true + // Check if the relay parent moved backwards from the latest candidate pending availability. + let earliest_rp_of_pending_availability = self.earliest_relay_parent_pending_availability(); + if relay_parent.number < earliest_rp_of_pending_availability.number { + return Err(Error::RelayParentPrecedesCandidatePendingAvailability( + relay_parent.hash, + earliest_rp_of_pending_availability.hash, + )) } - if let Some(output_head_hash) = output_head_hash { - if self.by_output_head.contains_key(&output_head_hash) { - // this is not a chain, there are multiple paths to the same state. - return true + // If it's a fork with a backed candidate in the current chain. + if let Some(other_candidate) = self.best_chain.by_parent_head.get(&parent_head_hash) { + if self.scope().get_pending_availability(other_candidate).is_some() { + // Cannot accept a fork with a candidate pending availability. + return Err(Error::ForkWithCandidatePendingAvailability(*other_candidate)) } - // trivial 0-length cycle. - if parent_head_hash == output_head_hash { - return true - } - - // this should catch any other cycles. our output state cannot already be the parent - // state of another candidate, unless this is a cycle, since the already added - // candidates form a chain. - if self.by_parent_head.contains_key(&output_head_hash) { - return true + // If the candidate is backed and in the current chain, accept only a candidate + // according to the fork selection rule. + if fork_selection_rule(other_candidate, &candidate.candidate_hash()) == Ordering::Less { + return Err(Error::ForkChoiceRule(*other_candidate)) } } - false - } + // Try seeing if the parent candidate is in the current chain or if it is the latest + // included candidate. If so, get the constraints the candidate must satisfy. + let (constraints, maybe_min_relay_parent_number) = + if let Some(parent_candidate) = self.best_chain.by_output_head.get(&parent_head_hash) { + let Some(parent_candidate) = + self.best_chain.chain.iter().find(|c| &c.candidate_hash == parent_candidate) + else { + // Should never really happen. + return Err(Error::ParentCandidateNotFound) + }; - // Checks the potential of a candidate to be added to the chain in the future. - // Verifies that the relay parent is in scope and not moving backwards and that we're not - // introducing forks or cycles with other candidates in the chain. - // `output_head_hash` is optional because we sometimes make this check before retrieving the - // collation. - fn check_potential( - &self, - relay_parent: &Hash, - parent_head_hash: Hash, - output_head_hash: Option, - ) -> bool { - if self.is_fork_or_cycle(parent_head_hash, output_head_hash) { - return false + ( + self.scope + .base_constraints + .apply_modifications(&parent_candidate.cumulative_modifications) + .map_err(Error::ComputeConstraints)?, + self.scope.ancestor(&parent_candidate.relay_parent()).map(|rp| rp.number), + ) + } else if self.scope.base_constraints.required_parent.hash() == parent_head_hash { + // It builds on the latest included candidate. + (self.scope.base_constraints.clone(), None) + } else { + // If the parent is not yet part of the chain, there's nothing else we can check for + // now. + return Ok(()) + }; + + // Check for cycles or invalid tree transitions. + if let Some(ref output_head_hash) = candidate.output_head_data_hash() { + self.check_cycles_or_invalid_tree(output_head_hash)?; } - let Some(earliest_rp) = self.earliest_relay_parent() else { return false }; + // Check against constraints if we have a full concrete candidate. + if let (Some(commitments), Some(pvd), Some(validation_code_hash)) = ( + candidate.commitments(), + candidate.persisted_validation_data(), + candidate.validation_code_hash(), + ) { + Fragment::check_against_constraints( + &relay_parent, + &constraints, + commitments, + validation_code_hash, + pvd, + ) + .map_err(Error::CheckAgainstConstraints)?; + } - let Some(relay_parent) = self.scope.ancestor(relay_parent) else { return false }; + if relay_parent.number < constraints.min_relay_parent_number { + return Err(Error::RelayParentMovedBackwards) + } - if relay_parent.number < earliest_rp.number { - return false // relay parent moved backwards. + if let Some(earliest_rp) = maybe_min_relay_parent_number { + if relay_parent.number < earliest_rp { + return Err(Error::RelayParentMovedBackwards) + } } - true + Ok(()) } - // Populate the fragment chain with candidates from CandidateStorage. - // Can be called by the constructor or when introducing a new candidate. - // If we're introducing a new candidate onto an existing chain, we may introduce more than one, - // since we may connect already existing candidates to the chain. - fn populate_chain(&mut self, storage: &CandidateStorage) { - let mut cumulative_modifications = if let Some(last_candidate) = self.chain.last() { - last_candidate.cumulative_modifications.clone() + // Once the backable chain was populated, trim the forks generated by candidates which + // are not present in the best chain. Fan this out into a full breadth-first search. + // If `starting_point` is `Some()`, start the search from the candidates having this parent head + // hash. + fn trim_uneligible_forks(&self, storage: &mut CandidateStorage, starting_point: Option) { + // Start out with the candidates in the chain. They are all valid candidates. + let mut queue: VecDeque<_> = if let Some(starting_point) = starting_point { + [(starting_point, true)].into_iter().collect() } else { - ConstraintModifications::identity() + if self.best_chain.chain.is_empty() { + [(self.scope.base_constraints.required_parent.hash(), true)] + .into_iter() + .collect() + } else { + self.best_chain.chain.iter().map(|c| (c.parent_head_data_hash, true)).collect() + } }; + // To make sure that cycles don't make us loop forever, keep track of the visited parent + // heads. + let mut visited = HashSet::new(); + + while let Some((parent, parent_has_potential)) = queue.pop_front() { + visited.insert(parent); + + let Some(children) = storage.by_parent_head.get(&parent) else { continue }; + // Cannot remove while iterating so store them here temporarily. + let mut to_remove = vec![]; + + for child_hash in children.iter() { + let Some(child) = storage.by_candidate_hash.get(child_hash) else { continue }; + + // Already visited this parent. Either is a cycle or multiple paths that lead to the + // same candidate. Either way, stop this branch to avoid looping forever. + if visited.contains(&child.output_head_data_hash) { + continue + } + + // Only keep a candidate if its full ancestry was already kept as potential and this + // candidate itself has potential. + if parent_has_potential && self.check_potential(child).is_ok() { + queue.push_back((child.output_head_data_hash, true)); + } else { + // Otherwise, remove this candidate and continue looping for its children, but + // mark the parent's potential as `false`. We only want to remove its + // children. + to_remove.push(*child_hash); + queue.push_back((child.output_head_data_hash, false)); + } + } + + for hash in to_remove { + storage.remove_candidate(&hash); + } + } + } + + // Populate the fragment chain with candidates from the supplied `CandidateStorage`. + // Can be called by the constructor or when backing a new candidate. + // When this is called, it may cause the previous chain to be completely erased or it may add + // more than one candidate. + fn populate_chain(&mut self, storage: &mut CandidateStorage) { + let mut cumulative_modifications = + if let Some(last_candidate) = self.best_chain.chain.last() { + last_candidate.cumulative_modifications.clone() + } else { + ConstraintModifications::identity() + }; let Some(mut earliest_rp) = self.earliest_relay_parent() else { return }; loop { - if self.chain.len() > self.scope.max_depth { + if self.best_chain.chain.len() > self.scope.max_depth { break; } @@ -880,113 +1199,157 @@ impl FragmentChain { }; let required_head_hash = child_constraints.required_parent.hash(); - // Even though we don't allow parachain forks under the same active leaf, they may still - // appear under different relay chain forks, hence the iterator below. - let possible_children = storage.possible_para_children(&required_head_hash); - let mut added_child = false; - for candidate in possible_children { - // Add one node to chain if - // 1. it does not introduce a fork or a cycle. - // 2. parent hash is correct. - // 3. relay-parent does not move backwards. - // 4. all non-pending-availability candidates have relay-parent in scope. - // 5. candidate outputs fulfill constraints - - if self.is_fork_or_cycle( - candidate.parent_head_data_hash(), - Some(candidate.output_head_data_hash()), - ) { - continue - } - let pending = self.scope.get_pending_availability(&candidate.candidate_hash); - let Some(relay_parent) = pending - .map(|p| p.relay_parent.clone()) - .or_else(|| self.scope.ancestor(&candidate.relay_parent)) - else { - continue - }; - - // require: candidates don't move backwards - // and only pending availability candidates can be out-of-scope. - // - // earliest_rp can be before the earliest relay parent in the scope - // when the parent is a pending availability candidate as well, but - // only other pending candidates can have a relay parent out of scope. - let min_relay_parent_number = pending - .map(|p| match self.chain.len() { - 0 => p.relay_parent.number, - _ => earliest_rp.number, - }) - .unwrap_or_else(|| earliest_rp.number); - - if relay_parent.number < min_relay_parent_number { - continue // relay parent moved backwards. - } + // Select the few possible backed/backable children which can be added to the chain + // right now. + let possible_children = storage + .possible_backed_para_children(&required_head_hash) + .filter_map(|candidate| { + // Only select a candidate if: + // 1. it does not introduce a fork or a cycle. + // 2. parent hash is correct. + // 3. relay-parent does not move backwards. + // 4. all non-pending-availability candidates have relay-parent in scope. + // 5. candidate outputs fulfill constraints + + let pending = self.scope.get_pending_availability(&candidate.candidate_hash); + let Some(relay_parent) = pending + .map(|p| p.relay_parent.clone()) + .or_else(|| self.scope.ancestor(&candidate.relay_parent)) + else { + return None + }; + + if self.check_cycles_or_invalid_tree(&candidate.output_head_data_hash).is_err() + { + return None + } - // don't add candidates if they're already present in the chain. - // this can never happen, as candidates can only be duplicated if there's a cycle - // and we shouldn't have allowed for a cycle to be chained. - if self.contains_candidate(&candidate.candidate_hash) { - continue - } + // require: candidates don't move backwards + // and only pending availability candidates can be out-of-scope. + // + // earliest_rp can be before the earliest relay parent in the scope + // when the parent is a pending availability candidate as well, but + // only other pending candidates can have a relay parent out of scope. + let min_relay_parent_number = pending + .map(|p| match self.best_chain.chain.len() { + 0 => p.relay_parent.number, + _ => earliest_rp.number, + }) + .unwrap_or_else(|| earliest_rp.number); + + if relay_parent.number < min_relay_parent_number { + return None // relay parent moved backwards. + } - let fragment = { - let mut constraints = child_constraints.clone(); - if let Some(ref p) = pending { - // overwrite for candidates pending availability as a special-case. - constraints.min_relay_parent_number = p.relay_parent.number; + // don't add candidates if they're already present in the chain. + // this can never happen, as candidates can only be duplicated if there's a + // cycle and we shouldn't have allowed for a cycle to be chained. + if self.best_chain.contains(&candidate.candidate_hash) { + return None } - let f = Fragment::new( - relay_parent.clone(), - constraints, - // It's cheap to clone because it's wrapped in an Arc - candidate.candidate.clone(), - ); - - match f { - Ok(f) => f, - Err(e) => { - gum::debug!( - target: LOG_TARGET, - err = ?e, - ?relay_parent, - candidate_hash = ?candidate.candidate_hash, - "Failed to instantiate fragment", - ); - - break - }, + let fragment = { + let mut constraints = child_constraints.clone(); + if let Some(ref p) = pending { + // overwrite for candidates pending availability as a special-case. + constraints.min_relay_parent_number = p.relay_parent.number; + } + + let f = Fragment::new( + relay_parent.clone(), + constraints, + // It's cheap to clone because it's wrapped in an Arc + candidate.candidate.clone(), + ); + + match f { + Ok(f) => f, + Err(e) => { + gum::debug!( + target: LOG_TARGET, + err = ?e, + ?relay_parent, + candidate_hash = ?candidate.candidate_hash, + "Failed to instantiate fragment", + ); + + return None + }, + } + }; + + Some(( + fragment, + candidate.candidate_hash, + candidate.output_head_data_hash, + candidate.parent_head_data_hash, + )) + }); + + // Choose the best candidate. + let best_candidate = + possible_children.min_by(|(_, ref child1, _, _), (_, ref child2, _, _)| { + // Always pick a candidate pending availability as best. + if self.scope.get_pending_availability(child1).is_some() { + Ordering::Less + } else if self.scope.get_pending_availability(child2).is_some() { + Ordering::Greater + } else { + // Otherwise, use the fork selection rule. + fork_selection_rule(child1, child2) } - }; + }); + + if let Some((fragment, candidate_hash, output_head_data_hash, parent_head_data_hash)) = + best_candidate + { + // Remove the candidate from storage. + storage.remove_candidate(&candidate_hash); // Update the cumulative constraint modifications. cumulative_modifications.stack(fragment.constraint_modifications()); // Update the earliest rp - earliest_rp = relay_parent; + earliest_rp = fragment.relay_parent().clone(); let node = FragmentNode { fragment, - candidate_hash: candidate.candidate_hash, + candidate_hash, + parent_head_data_hash, + output_head_data_hash, cumulative_modifications: cumulative_modifications.clone(), }; - self.chain.push(node); - self.candidates.insert(candidate.candidate_hash); - // We've already checked for forks and cycles. - self.by_parent_head - .insert(candidate.parent_head_data_hash(), candidate.candidate_hash); - self.by_output_head - .insert(candidate.output_head_data_hash(), candidate.candidate_hash); - added_child = true; - // We can only add one child for a candidate. (it's a chain, not a tree) - break; - } - - if !added_child { + // Add the candidate to the chain now. + self.best_chain.push(node); + } else { break } } } + + // Revert the best backable chain so that the last candidate will be one outputting the given + // `parent_head_hash`. If the `parent_head_hash` is exactly the required parent of the base + // constraints (builds on the latest included candidate), revert the entire chain. + // Return false if we couldn't find the parent head hash. + fn revert_to(&mut self, parent_head_hash: &Hash) -> bool { + let mut removed_items = None; + if &self.scope.base_constraints.required_parent.hash() == parent_head_hash { + removed_items = Some(self.best_chain.clear()); + } + + if removed_items.is_none() && self.best_chain.by_output_head.contains_key(parent_head_hash) + { + removed_items = Some(self.best_chain.revert_to_parent_hash(parent_head_hash).collect()); + } + + let Some(removed_items) = removed_items else { return false }; + + // Even if it's empty, we need to return true, because we'll be able to add a new candidate + // to the chain. + for node in &removed_items { + let _ = self.unconnected.add_candidate_entry(node.into()); + } + true + } } diff --git a/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs b/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs index 26ee94d59d8ebd50bda29218c85b38476f077111..9886d19e5224efddf1ec13b630c9a4af2bd079e4 100644 --- a/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs +++ b/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs @@ -17,8 +17,12 @@ use super::*; use assert_matches::assert_matches; use polkadot_node_subsystem_util::inclusion_emulator::InboundHrmpLimitations; -use polkadot_primitives::{BlockNumber, CandidateCommitments, CandidateDescriptor, HeadData}; +use polkadot_primitives::{ + BlockNumber, CandidateCommitments, CandidateDescriptor, HeadData, Id as ParaId, +}; use polkadot_primitives_test_helpers as test_helpers; +use rand::{seq::SliceRandom, thread_rng}; +use std::ops::Range; fn make_constraints( min_relay_parent_number: BlockNumber, @@ -54,7 +58,7 @@ fn make_committed_candidate( let persisted_validation_data = PersistedValidationData { parent_head, relay_parent_number, - relay_parent_storage_root: Hash::repeat_byte(69), + relay_parent_storage_root: Hash::zero(), max_pov_size: 1_000_000, }; @@ -83,9 +87,20 @@ fn make_committed_candidate( (persisted_validation_data, candidate) } +fn populate_chain_from_previous_storage( + scope: &Scope, + storage: &CandidateStorage, +) -> FragmentChain { + let mut chain = FragmentChain::init(scope.clone(), CandidateStorage::default()); + let mut prev_chain = chain.clone(); + prev_chain.unconnected = storage.clone(); + + chain.populate_from_previous(&prev_chain); + chain +} + #[test] fn scope_rejects_ancestors_that_skip_blocks() { - let para_id = ParaId::from(5u32); let relay_parent = RelayChainBlockInfo { number: 10, hash: Hash::repeat_byte(10), @@ -104,7 +119,6 @@ fn scope_rejects_ancestors_that_skip_blocks() { assert_matches!( Scope::with_ancestors( - para_id, relay_parent, base_constraints, pending_availability, @@ -117,7 +131,6 @@ fn scope_rejects_ancestors_that_skip_blocks() { #[test] fn scope_rejects_ancestor_for_0_block() { - let para_id = ParaId::from(5u32); let relay_parent = RelayChainBlockInfo { number: 0, hash: Hash::repeat_byte(0), @@ -136,7 +149,6 @@ fn scope_rejects_ancestor_for_0_block() { assert_matches!( Scope::with_ancestors( - para_id, relay_parent, base_constraints, pending_availability, @@ -149,7 +161,6 @@ fn scope_rejects_ancestor_for_0_block() { #[test] fn scope_only_takes_ancestors_up_to_min() { - let para_id = ParaId::from(5u32); let relay_parent = RelayChainBlockInfo { number: 5, hash: Hash::repeat_byte(0), @@ -179,7 +190,6 @@ fn scope_only_takes_ancestors_up_to_min() { let pending_availability = Vec::new(); let scope = Scope::with_ancestors( - para_id, relay_parent, base_constraints, pending_availability, @@ -194,7 +204,6 @@ fn scope_only_takes_ancestors_up_to_min() { #[test] fn scope_rejects_unordered_ancestors() { - let para_id = ParaId::from(5u32); let relay_parent = RelayChainBlockInfo { number: 5, hash: Hash::repeat_byte(0), @@ -225,7 +234,6 @@ fn scope_rejects_unordered_ancestors() { assert_matches!( Scope::with_ancestors( - para_id, relay_parent, base_constraints, pending_availability, @@ -257,718 +265,695 @@ fn candidate_storage_methods() { let mut wrong_pvd = pvd.clone(); wrong_pvd.max_pov_size = 0; assert_matches!( - storage.add_candidate(candidate.clone(), wrong_pvd, CandidateState::Seconded), - Err(CandidateStorageInsertionError::PersistedValidationDataMismatch) + CandidateEntry::new( + candidate_hash, + candidate.clone(), + wrong_pvd.clone(), + CandidateState::Seconded + ), + Err(CandidateEntryError::PersistedValidationDataMismatch) + ); + assert_matches!( + CandidateEntry::new_seconded(candidate_hash, candidate.clone(), wrong_pvd), + Err(CandidateEntryError::PersistedValidationDataMismatch) ); + // Zero-length cycle. + { + let mut candidate = candidate.clone(); + candidate.commitments.head_data = HeadData(vec![1; 10]); + let mut pvd = pvd.clone(); + pvd.parent_head = HeadData(vec![1; 10]); + candidate.descriptor.persisted_validation_data_hash = pvd.hash(); + assert_matches!( + CandidateEntry::new_seconded(candidate_hash, candidate, pvd), + Err(CandidateEntryError::ZeroLengthCycle) + ); + } assert!(!storage.contains(&candidate_hash)); - assert_eq!(storage.possible_para_children(&parent_head_hash).count(), 0); - assert_eq!(storage.relay_parent_of_candidate(&candidate_hash), None); + assert_eq!(storage.possible_backed_para_children(&parent_head_hash).count(), 0); assert_eq!(storage.head_data_by_hash(&candidate.descriptor.para_head), None); assert_eq!(storage.head_data_by_hash(&parent_head_hash), None); - assert_eq!(storage.is_backed(&candidate_hash), false); - // Add a valid candidate - storage - .add_candidate(candidate.clone(), pvd.clone(), CandidateState::Seconded) - .unwrap(); + // Add a valid candidate. + let candidate_entry = CandidateEntry::new( + candidate_hash, + candidate.clone(), + pvd.clone(), + CandidateState::Seconded, + ) + .unwrap(); + storage.add_candidate_entry(candidate_entry.clone()).unwrap(); assert!(storage.contains(&candidate_hash)); - assert_eq!(storage.possible_para_children(&parent_head_hash).count(), 1); - assert_eq!(storage.possible_para_children(&candidate.descriptor.para_head).count(), 0); - assert_eq!(storage.relay_parent_of_candidate(&candidate_hash), Some(relay_parent)); + assert_eq!(storage.possible_backed_para_children(&parent_head_hash).count(), 0); + assert_eq!(storage.possible_backed_para_children(&candidate.descriptor.para_head).count(), 0); assert_eq!( storage.head_data_by_hash(&candidate.descriptor.para_head).unwrap(), &candidate.commitments.head_data ); assert_eq!(storage.head_data_by_hash(&parent_head_hash).unwrap(), &pvd.parent_head); - assert_eq!(storage.is_backed(&candidate_hash), false); + // Now mark it as backed + storage.mark_backed(&candidate_hash); + // Marking it twice is fine. storage.mark_backed(&candidate_hash); - assert_eq!(storage.is_backed(&candidate_hash), true); + assert_eq!( + storage + .possible_backed_para_children(&parent_head_hash) + .map(|c| c.candidate_hash) + .collect::>(), + vec![candidate_hash] + ); + assert_eq!(storage.possible_backed_para_children(&candidate.descriptor.para_head).count(), 0); // Re-adding a candidate fails. assert_matches!( - storage.add_candidate(candidate.clone(), pvd.clone(), CandidateState::Seconded), - Err(CandidateStorageInsertionError::CandidateAlreadyKnown(hash)) if candidate_hash == hash + storage.add_candidate_entry(candidate_entry), + Err(Error::CandidateAlreadyKnown) ); // Remove candidate and re-add it later in backed state. storage.remove_candidate(&candidate_hash); assert!(!storage.contains(&candidate_hash)); - assert_eq!(storage.possible_para_children(&parent_head_hash).count(), 0); - assert_eq!(storage.relay_parent_of_candidate(&candidate_hash), None); + + // Removing it twice is fine. + storage.remove_candidate(&candidate_hash); + assert!(!storage.contains(&candidate_hash)); + assert_eq!(storage.possible_backed_para_children(&parent_head_hash).count(), 0); assert_eq!(storage.head_data_by_hash(&candidate.descriptor.para_head), None); assert_eq!(storage.head_data_by_hash(&parent_head_hash), None); - assert_eq!(storage.is_backed(&candidate_hash), false); storage - .add_candidate(candidate.clone(), pvd.clone(), CandidateState::Backed) + .add_pending_availability_candidate(candidate_hash, candidate.clone(), pvd) .unwrap(); - assert_eq!(storage.is_backed(&candidate_hash), true); - - // Test retain - storage.retain(|_| true); assert!(storage.contains(&candidate_hash)); - storage.retain(|_| false); - assert!(!storage.contains(&candidate_hash)); - assert_eq!(storage.possible_para_children(&parent_head_hash).count(), 0); - assert_eq!(storage.relay_parent_of_candidate(&candidate_hash), None); - assert_eq!(storage.head_data_by_hash(&candidate.descriptor.para_head), None); - assert_eq!(storage.head_data_by_hash(&parent_head_hash), None); - assert_eq!(storage.is_backed(&candidate_hash), false); + + assert_eq!( + storage + .possible_backed_para_children(&parent_head_hash) + .map(|c| c.candidate_hash) + .collect::>(), + vec![candidate_hash] + ); + assert_eq!(storage.possible_backed_para_children(&candidate.descriptor.para_head).count(), 0); + + // Now add a second candidate in Seconded state. This will be a fork. + let (pvd_2, candidate_2) = make_committed_candidate( + ParaId::from(5u32), + relay_parent, + 8, + vec![4, 5, 6].into(), + vec![2, 3, 4].into(), + 7, + ); + let candidate_hash_2 = candidate_2.hash(); + let candidate_entry_2 = + CandidateEntry::new_seconded(candidate_hash_2, candidate_2, pvd_2).unwrap(); + + storage.add_candidate_entry(candidate_entry_2).unwrap(); + assert_eq!( + storage + .possible_backed_para_children(&parent_head_hash) + .map(|c| c.candidate_hash) + .collect::>(), + vec![candidate_hash] + ); + + // Now mark it as backed. + storage.mark_backed(&candidate_hash_2); + assert_eq!( + storage + .possible_backed_para_children(&parent_head_hash) + .map(|c| c.candidate_hash) + .collect::>(), + [candidate_hash, candidate_hash_2].into_iter().collect() + ); } #[test] -fn populate_and_extend_from_storage_empty() { +fn init_and_populate_from_empty() { // Empty chain and empty storage. - let storage = CandidateStorage::default(); let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); - let pending_availability = Vec::new(); let scope = Scope::with_ancestors( - ParaId::from(2), RelayChainBlockInfo { number: 1, hash: Hash::repeat_byte(1), storage_root: Hash::repeat_byte(2), }, base_constraints, - pending_availability, + Vec::new(), 4, vec![], ) .unwrap(); - let mut chain = FragmentChain::populate(scope, &storage); - assert!(chain.to_vec().is_empty()); - - chain.extend_from_storage(&storage); - assert!(chain.to_vec().is_empty()); + let chain = FragmentChain::init(scope.clone(), CandidateStorage::default()); + assert_eq!(chain.best_chain_len(), 0); + assert_eq!(chain.unconnected_len(), 0); + + let mut new_chain = FragmentChain::init(scope, CandidateStorage::default()); + new_chain.populate_from_previous(&chain); + assert_eq!(chain.best_chain_len(), 0); + assert_eq!(chain.unconnected_len(), 0); } #[test] -fn populate_and_extend_from_storage_with_existing_empty_to_vec() { +fn test_populate_and_check_potential() { let mut storage = CandidateStorage::default(); let para_id = ParaId::from(5u32); - let relay_parent_a = Hash::repeat_byte(1); - let relay_parent_b = Hash::repeat_byte(2); - let relay_parent_c = Hash::repeat_byte(3); + let relay_parent_x = Hash::repeat_byte(1); + let relay_parent_y = Hash::repeat_byte(2); + let relay_parent_z = Hash::repeat_byte(3); + let relay_parent_x_info = + RelayChainBlockInfo { number: 0, hash: relay_parent_x, storage_root: Hash::zero() }; + let relay_parent_y_info = + RelayChainBlockInfo { number: 1, hash: relay_parent_y, storage_root: Hash::zero() }; + let relay_parent_z_info = + RelayChainBlockInfo { number: 2, hash: relay_parent_z, storage_root: Hash::zero() }; + + let ancestors = vec![ + // These need to be ordered in reverse. + relay_parent_y_info.clone(), + relay_parent_x_info.clone(), + ]; + + let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); + // Candidates A -> B -> C. They are all backed let (pvd_a, candidate_a) = make_committed_candidate( para_id, - relay_parent_a, - 0, + relay_parent_x_info.hash, + relay_parent_x_info.number, vec![0x0a].into(), vec![0x0b].into(), - 0, + relay_parent_x_info.number, ); let candidate_a_hash = candidate_a.hash(); - + let candidate_a_entry = + CandidateEntry::new(candidate_a_hash, candidate_a, pvd_a.clone(), CandidateState::Backed) + .unwrap(); + storage.add_candidate_entry(candidate_a_entry.clone()).unwrap(); let (pvd_b, candidate_b) = make_committed_candidate( para_id, - relay_parent_b, - 1, + relay_parent_y_info.hash, + relay_parent_y_info.number, vec![0x0b].into(), vec![0x0c].into(), - 1, + relay_parent_y_info.number, ); let candidate_b_hash = candidate_b.hash(); - + let candidate_b_entry = + CandidateEntry::new(candidate_b_hash, candidate_b, pvd_b, CandidateState::Backed).unwrap(); + storage.add_candidate_entry(candidate_b_entry.clone()).unwrap(); let (pvd_c, candidate_c) = make_committed_candidate( para_id, - relay_parent_c, - 2, + relay_parent_z_info.hash, + relay_parent_z_info.number, vec![0x0c].into(), vec![0x0d].into(), - 2, + relay_parent_z_info.number, ); let candidate_c_hash = candidate_c.hash(); - - let relay_parent_a_info = RelayChainBlockInfo { - number: pvd_a.relay_parent_number, - hash: relay_parent_a, - storage_root: pvd_a.relay_parent_storage_root, - }; - let relay_parent_b_info = RelayChainBlockInfo { - number: pvd_b.relay_parent_number, - hash: relay_parent_b, - storage_root: pvd_b.relay_parent_storage_root, - }; - let relay_parent_c_info = RelayChainBlockInfo { - number: pvd_c.relay_parent_number, - hash: relay_parent_c, - storage_root: pvd_c.relay_parent_storage_root, - }; - - let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); - let pending_availability = Vec::new(); - - let ancestors = vec![ - // These need to be ordered in reverse. - relay_parent_b_info.clone(), - relay_parent_a_info.clone(), - ]; - - storage - .add_candidate(candidate_a.clone(), pvd_a.clone(), CandidateState::Seconded) - .unwrap(); - storage - .add_candidate(candidate_b.clone(), pvd_b.clone(), CandidateState::Backed) - .unwrap(); - storage - .add_candidate(candidate_c.clone(), pvd_c.clone(), CandidateState::Backed) - .unwrap(); + let candidate_c_entry = + CandidateEntry::new(candidate_c_hash, candidate_c, pvd_c, CandidateState::Backed).unwrap(); + storage.add_candidate_entry(candidate_c_entry.clone()).unwrap(); // Candidate A doesn't adhere to the base constraints. { for wrong_constraints in [ // Different required parent - make_constraints(0, vec![0], vec![0x0e].into()), + make_constraints( + relay_parent_x_info.number, + vec![relay_parent_x_info.number], + vec![0x0e].into(), + ), // Min relay parent number is wrong - make_constraints(1, vec![0], vec![0x0a].into()), + make_constraints(relay_parent_y_info.number, vec![0], vec![0x0a].into()), ] { let scope = Scope::with_ancestors( - para_id, - relay_parent_c_info.clone(), + relay_parent_z_info.clone(), wrong_constraints.clone(), - pending_availability.clone(), + vec![], 4, ancestors.clone(), ) .unwrap(); - let mut chain = FragmentChain::populate(scope, &storage); + let chain = populate_chain_from_previous_storage(&scope, &storage); - assert!(chain.to_vec().is_empty()); - - chain.extend_from_storage(&storage); - assert!(chain.to_vec().is_empty()); + assert!(chain.best_chain_vec().is_empty()); // If the min relay parent number is wrong, candidate A can never become valid. // Otherwise, if only the required parent doesn't match, candidate A is still a // potential candidate. - if wrong_constraints.min_relay_parent_number == 1 { - assert_eq!( - chain.can_add_candidate_as_potential( - &storage, - &candidate_a.hash(), - &candidate_a.descriptor.relay_parent, - pvd_a.parent_head.hash(), - Some(candidate_a.commitments.head_data.hash()), - ), - PotentialAddition::None + if wrong_constraints.min_relay_parent_number == relay_parent_y_info.number { + // If A is not a potential candidate, its descendants will also not be added. + assert_eq!(chain.unconnected_len(), 0); + assert_matches!( + chain.can_add_candidate_as_potential(&candidate_a_entry), + Err(Error::RelayParentNotInScope(_, _)) ); + // However, if taken independently, both B and C still have potential, since we + // don't know that A doesn't. + assert!(chain.can_add_candidate_as_potential(&candidate_b_entry).is_ok()); + assert!(chain.can_add_candidate_as_potential(&candidate_c_entry).is_ok()); } else { assert_eq!( - chain.can_add_candidate_as_potential( - &storage, - &candidate_a.hash(), - &candidate_a.descriptor.relay_parent, - pvd_a.parent_head.hash(), - Some(candidate_a.commitments.head_data.hash()), - ), - PotentialAddition::Anyhow - ); - } - - // All other candidates can always be potential candidates. - for (candidate, pvd) in - [(candidate_b.clone(), pvd_b.clone()), (candidate_c.clone(), pvd_c.clone())] - { - assert_eq!( - chain.can_add_candidate_as_potential( - &storage, - &candidate.hash(), - &candidate.descriptor.relay_parent, - pvd.parent_head.hash(), - Some(candidate.commitments.head_data.hash()), - ), - PotentialAddition::Anyhow + chain.unconnected().map(|c| c.candidate_hash).collect::>(), + [candidate_a_hash, candidate_b_hash, candidate_c_hash].into_iter().collect() ); } } } - // Various max depths. + // Various depths { - // depth is 0, will only allow 1 candidate + // Depth is 0, only allows one candidate, but the others will be kept as potential. let scope = Scope::with_ancestors( - para_id, - relay_parent_c_info.clone(), + relay_parent_z_info.clone(), base_constraints.clone(), - pending_availability.clone(), + vec![], 0, ancestors.clone(), ) .unwrap(); - // Before populating the chain, all candidates are potential candidates. However, they can - // only be added as connected candidates, because only one candidates is allowed by max - // depth - let chain = FragmentChain::populate(scope.clone(), &CandidateStorage::default()); - for (candidate, pvd) in [ - (candidate_a.clone(), pvd_a.clone()), - (candidate_b.clone(), pvd_b.clone()), - (candidate_c.clone(), pvd_c.clone()), - ] { - assert_eq!( - chain.can_add_candidate_as_potential( - &CandidateStorage::default(), - &candidate.hash(), - &candidate.descriptor.relay_parent, - pvd.parent_head.hash(), - Some(candidate.commitments.head_data.hash()), - ), - PotentialAddition::IfConnected - ); - } - let mut chain = FragmentChain::populate(scope, &storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash]); - chain.extend_from_storage(&storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash]); - // since depth is maxed out, we can't add more potential candidates - // candidate A is no longer a potential candidate because it's already present. - for (candidate, pvd) in [ - (candidate_a.clone(), pvd_a.clone()), - (candidate_b.clone(), pvd_b.clone()), - (candidate_c.clone(), pvd_c.clone()), - ] { - assert_eq!( - chain.can_add_candidate_as_potential( - &storage, - &candidate.hash(), - &candidate.descriptor.relay_parent, - pvd.parent_head.hash(), - Some(candidate.commitments.head_data.hash()), - ), - PotentialAddition::None - ); - } + let chain = FragmentChain::init(scope.clone(), CandidateStorage::default()); + assert!(chain.can_add_candidate_as_potential(&candidate_a_entry).is_ok()); + assert!(chain.can_add_candidate_as_potential(&candidate_b_entry).is_ok()); + assert!(chain.can_add_candidate_as_potential(&candidate_c_entry).is_ok()); + + let chain = populate_chain_from_previous_storage(&scope, &storage); + assert_eq!(chain.best_chain_vec(), vec![candidate_a_hash]); + assert_eq!( + chain.unconnected().map(|c| c.candidate_hash).collect::>(), + [candidate_b_hash, candidate_c_hash].into_iter().collect() + ); // depth is 1, allows two candidates let scope = Scope::with_ancestors( - para_id, - relay_parent_c_info.clone(), + relay_parent_z_info.clone(), base_constraints.clone(), - pending_availability.clone(), + vec![], 1, ancestors.clone(), ) .unwrap(); - // Before populating the chain, all candidates can be added as potential. - let mut modified_storage = CandidateStorage::default(); - let chain = FragmentChain::populate(scope.clone(), &modified_storage); - for (candidate, pvd) in [ - (candidate_a.clone(), pvd_a.clone()), - (candidate_b.clone(), pvd_b.clone()), - (candidate_c.clone(), pvd_c.clone()), - ] { - assert_eq!( - chain.can_add_candidate_as_potential( - &modified_storage, - &candidate.hash(), - &candidate.descriptor.relay_parent, - pvd.parent_head.hash(), - Some(candidate.commitments.head_data.hash()), - ), - PotentialAddition::Anyhow - ); - } - // Add an unconnected candidate. We now should only allow a Connected candidate, because max - // depth only allows one more candidate. - modified_storage - .add_candidate(candidate_b.clone(), pvd_b.clone(), CandidateState::Seconded) - .unwrap(); - let chain = FragmentChain::populate(scope.clone(), &modified_storage); - for (candidate, pvd) in - [(candidate_a.clone(), pvd_a.clone()), (candidate_c.clone(), pvd_c.clone())] - { - assert_eq!( - chain.can_add_candidate_as_potential( - &modified_storage, - &candidate.hash(), - &candidate.descriptor.relay_parent, - pvd.parent_head.hash(), - Some(candidate.commitments.head_data.hash()), - ), - PotentialAddition::IfConnected - ); - } + let chain = FragmentChain::init(scope.clone(), CandidateStorage::default()); + assert!(chain.can_add_candidate_as_potential(&candidate_a_entry).is_ok()); + assert!(chain.can_add_candidate_as_potential(&candidate_b_entry).is_ok()); + assert!(chain.can_add_candidate_as_potential(&candidate_c_entry).is_ok()); - // Now try populating from all candidates. - let mut chain = FragmentChain::populate(scope, &storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); - chain.extend_from_storage(&storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); - // since depth is maxed out, we can't add more potential candidates - // candidate A and B are no longer a potential candidate because they're already present. - for (candidate, pvd) in [ - (candidate_a.clone(), pvd_a.clone()), - (candidate_b.clone(), pvd_b.clone()), - (candidate_c.clone(), pvd_c.clone()), - ] { - assert_eq!( - chain.can_add_candidate_as_potential( - &storage, - &candidate.hash(), - &candidate.descriptor.relay_parent, - pvd.parent_head.hash(), - Some(candidate.commitments.head_data.hash()), - ), - PotentialAddition::None - ); - } + let chain = populate_chain_from_previous_storage(&scope, &storage); + assert_eq!(chain.best_chain_vec(), vec![candidate_a_hash, candidate_b_hash]); + assert_eq!( + chain.unconnected().map(|c| c.candidate_hash).collect::>(), + [candidate_c_hash].into_iter().collect() + ); - // depths larger than 2, allows all candidates + // depth is larger than 2, allows all three candidates for depth in 2..6 { let scope = Scope::with_ancestors( - para_id, - relay_parent_c_info.clone(), + relay_parent_z_info.clone(), base_constraints.clone(), - pending_availability.clone(), + vec![], depth, ancestors.clone(), ) .unwrap(); - let mut chain = FragmentChain::populate(scope, &storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); - chain.extend_from_storage(&storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); - // Candidates are no longer potential candidates because they're already part of the - // chain. - for (candidate, pvd) in [ - (candidate_a.clone(), pvd_a.clone()), - (candidate_b.clone(), pvd_b.clone()), - (candidate_c.clone(), pvd_c.clone()), - ] { - assert_eq!( - chain.can_add_candidate_as_potential( - &storage, - &candidate.hash(), - &candidate.descriptor.relay_parent, - pvd.parent_head.hash(), - Some(candidate.commitments.head_data.hash()), - ), - PotentialAddition::None - ); - } + let chain = FragmentChain::init(scope.clone(), CandidateStorage::default()); + assert!(chain.can_add_candidate_as_potential(&candidate_a_entry).is_ok()); + assert!(chain.can_add_candidate_as_potential(&candidate_b_entry).is_ok()); + assert!(chain.can_add_candidate_as_potential(&candidate_c_entry).is_ok()); + + let chain = populate_chain_from_previous_storage(&scope, &storage); + assert_eq!( + chain.best_chain_vec(), + vec![candidate_a_hash, candidate_b_hash, candidate_c_hash] + ); + assert_eq!(chain.unconnected_len(), 0); } } - // Wrong relay parents + // Relay parents out of scope { - // Candidates A has relay parent out of scope. - let ancestors_without_a = vec![relay_parent_b_info.clone()]; + // Candidate A has relay parent out of scope. Candidates B and C will also be deleted since + // they form a chain with A. + let ancestors_without_x = vec![relay_parent_y_info.clone()]; let scope = Scope::with_ancestors( - para_id, - relay_parent_c_info.clone(), + relay_parent_z_info.clone(), base_constraints.clone(), - pending_availability.clone(), + vec![], 4, - ancestors_without_a, + ancestors_without_x, ) .unwrap(); + let chain = populate_chain_from_previous_storage(&scope, &storage); + assert!(chain.best_chain_vec().is_empty()); + assert_eq!(chain.unconnected_len(), 0); - let mut chain = FragmentChain::populate(scope, &storage); - assert!(chain.to_vec().is_empty()); - - chain.extend_from_storage(&storage); - assert!(chain.to_vec().is_empty()); - - // Candidate A is not a potential candidate, but candidates B and C still are. - assert_eq!( - chain.can_add_candidate_as_potential( - &storage, - &candidate_a.hash(), - &candidate_a.descriptor.relay_parent, - pvd_a.parent_head.hash(), - Some(candidate_a.commitments.head_data.hash()), - ), - PotentialAddition::None + assert_matches!( + chain.can_add_candidate_as_potential(&candidate_a_entry), + Err(Error::RelayParentNotInScope(_, _)) ); - for (candidate, pvd) in - [(candidate_b.clone(), pvd_b.clone()), (candidate_c.clone(), pvd_c.clone())] - { - assert_eq!( - chain.can_add_candidate_as_potential( - &storage, - &candidate.hash(), - &candidate.descriptor.relay_parent, - pvd.parent_head.hash(), - Some(candidate.commitments.head_data.hash()), - ), - PotentialAddition::Anyhow - ); - } + // However, if taken independently, both B and C still have potential, since we + // don't know that A doesn't. + assert!(chain.can_add_candidate_as_potential(&candidate_b_entry).is_ok()); + assert!(chain.can_add_candidate_as_potential(&candidate_c_entry).is_ok()); - // Candidate C has the same relay parent as candidate A's parent. Relay parent not allowed - // to move backwards - let mut modified_storage = storage.clone(); - modified_storage.remove_candidate(&candidate_c_hash); - let (wrong_pvd_c, wrong_candidate_c) = make_committed_candidate( - para_id, - relay_parent_a, - 1, - vec![0x0c].into(), - vec![0x0d].into(), - 2, - ); - modified_storage - .add_candidate(wrong_candidate_c.clone(), wrong_pvd_c.clone(), CandidateState::Seconded) - .unwrap(); + // Candidates A and B have relay parents out of scope. Candidate C will also be deleted + // since it forms a chain with A and B. let scope = Scope::with_ancestors( - para_id, - relay_parent_c_info.clone(), + relay_parent_z_info.clone(), base_constraints.clone(), - pending_availability.clone(), + vec![], 4, - ancestors.clone(), + vec![], ) .unwrap(); - let mut chain = FragmentChain::populate(scope, &modified_storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); - chain.extend_from_storage(&modified_storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); + let chain = populate_chain_from_previous_storage(&scope, &storage); - // Candidate C is not even a potential candidate. - assert_eq!( - chain.can_add_candidate_as_potential( - &modified_storage, - &wrong_candidate_c.hash(), - &wrong_candidate_c.descriptor.relay_parent, - wrong_pvd_c.parent_head.hash(), - Some(wrong_candidate_c.commitments.head_data.hash()), - ), - PotentialAddition::None + assert!(chain.best_chain_vec().is_empty()); + assert_eq!(chain.unconnected_len(), 0); + + assert_matches!( + chain.can_add_candidate_as_potential(&candidate_a_entry), + Err(Error::RelayParentNotInScope(_, _)) + ); + assert_matches!( + chain.can_add_candidate_as_potential(&candidate_b_entry), + Err(Error::RelayParentNotInScope(_, _)) ); + // However, if taken independently, C still has potential, since we + // don't know that A and B don't + assert!(chain.can_add_candidate_as_potential(&candidate_c_entry).is_ok()); } - // Parachain fork and cycles are not allowed. + // Parachain cycle is not allowed. Make C have the same parent as A. { - // Candidate C has the same parent as candidate B. - let mut modified_storage = storage.clone(); - modified_storage.remove_candidate(&candidate_c_hash); - let (wrong_pvd_c, wrong_candidate_c) = make_committed_candidate( - para_id, - relay_parent_c, - 2, - vec![0x0b].into(), - vec![0x0d].into(), - 2, - ); - modified_storage - .add_candidate(wrong_candidate_c.clone(), wrong_pvd_c.clone(), CandidateState::Seconded) - .unwrap(); - let scope = Scope::with_ancestors( - para_id, - relay_parent_c_info.clone(), - base_constraints.clone(), - pending_availability.clone(), - 4, - ancestors.clone(), - ) - .unwrap(); - let mut chain = FragmentChain::populate(scope, &modified_storage); - // We'll either have A->B or A->C. It's not deterministic because CandidateStorage uses - // HashSets and HashMaps. - if chain.to_vec() == vec![candidate_a_hash, candidate_b_hash] { - chain.extend_from_storage(&modified_storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); - // Candidate C is not even a potential candidate. - assert_eq!( - chain.can_add_candidate_as_potential( - &modified_storage, - &wrong_candidate_c.hash(), - &wrong_candidate_c.descriptor.relay_parent, - wrong_pvd_c.parent_head.hash(), - Some(wrong_candidate_c.commitments.head_data.hash()), - ), - PotentialAddition::None - ); - } else if chain.to_vec() == vec![candidate_a_hash, wrong_candidate_c.hash()] { - chain.extend_from_storage(&modified_storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, wrong_candidate_c.hash()]); - // Candidate B is not even a potential candidate. - assert_eq!( - chain.can_add_candidate_as_potential( - &modified_storage, - &candidate_b.hash(), - &candidate_b.descriptor.relay_parent, - pvd_b.parent_head.hash(), - Some(candidate_b.commitments.head_data.hash()), - ), - PotentialAddition::None - ); - } else { - panic!("Unexpected chain: {:?}", chain.to_vec()); - } - - // Candidate C is a 0-length cycle. - // Candidate C has the same parent as candidate B. let mut modified_storage = storage.clone(); modified_storage.remove_candidate(&candidate_c_hash); let (wrong_pvd_c, wrong_candidate_c) = make_committed_candidate( para_id, - relay_parent_c, - 2, - vec![0x0c].into(), + relay_parent_z_info.hash, + relay_parent_z_info.number, vec![0x0c].into(), - 2, + vec![0x0a].into(), + relay_parent_z_info.number, ); - modified_storage - .add_candidate(wrong_candidate_c.clone(), wrong_pvd_c.clone(), CandidateState::Seconded) - .unwrap(); - let scope = Scope::with_ancestors( - para_id, - relay_parent_c_info.clone(), - base_constraints.clone(), - pending_availability.clone(), - 4, - ancestors.clone(), + let wrong_candidate_c_entry = CandidateEntry::new( + wrong_candidate_c.hash(), + wrong_candidate_c, + wrong_pvd_c, + CandidateState::Backed, ) .unwrap(); - let mut chain = FragmentChain::populate(scope, &modified_storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); - chain.extend_from_storage(&modified_storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); - // Candidate C is not even a potential candidate. - assert_eq!( - chain.can_add_candidate_as_potential( - &modified_storage, - &wrong_candidate_c.hash(), - &wrong_candidate_c.descriptor.relay_parent, - wrong_pvd_c.parent_head.hash(), - Some(wrong_candidate_c.commitments.head_data.hash()), - ), - PotentialAddition::None - ); - - // Candidate C points back to the pre-state of candidate C. - let mut modified_storage = storage.clone(); - modified_storage.remove_candidate(&candidate_c_hash); - let (wrong_pvd_c, wrong_candidate_c) = make_committed_candidate( - para_id, - relay_parent_c, - 2, - vec![0x0c].into(), - vec![0x0b].into(), - 2, - ); - modified_storage - .add_candidate(wrong_candidate_c.clone(), wrong_pvd_c.clone(), CandidateState::Seconded) - .unwrap(); + modified_storage.add_candidate_entry(wrong_candidate_c_entry.clone()).unwrap(); let scope = Scope::with_ancestors( - para_id, - relay_parent_c_info.clone(), + relay_parent_z_info.clone(), base_constraints.clone(), - pending_availability.clone(), + vec![], 4, ancestors.clone(), ) .unwrap(); - let mut chain = FragmentChain::populate(scope, &modified_storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); - chain.extend_from_storage(&modified_storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); - // Candidate C is not even a potential candidate. - assert_eq!( - chain.can_add_candidate_as_potential( - &modified_storage, - &wrong_candidate_c.hash(), - &wrong_candidate_c.descriptor.relay_parent, - wrong_pvd_c.parent_head.hash(), - Some(wrong_candidate_c.commitments.head_data.hash()), - ), - PotentialAddition::None + + let chain = populate_chain_from_previous_storage(&scope, &modified_storage); + assert_eq!(chain.best_chain_vec(), vec![candidate_a_hash, candidate_b_hash]); + assert_eq!(chain.unconnected_len(), 0); + + assert_matches!( + chain.can_add_candidate_as_potential(&wrong_candidate_c_entry), + Err(Error::Cycle) ); + // However, if taken independently, C still has potential, since we don't know A and B. + let chain = FragmentChain::init(scope.clone(), CandidateStorage::default()); + assert!(chain.can_add_candidate_as_potential(&wrong_candidate_c_entry).is_ok()); } - // Test with candidates pending availability - { - // Valid options - for pending in [ - vec![PendingAvailability { - candidate_hash: candidate_a_hash, - relay_parent: relay_parent_a_info.clone(), - }], - vec![ - PendingAvailability { - candidate_hash: candidate_a_hash, - relay_parent: relay_parent_a_info.clone(), - }, - PendingAvailability { - candidate_hash: candidate_b_hash, - relay_parent: relay_parent_b_info.clone(), - }, - ], - vec![ - PendingAvailability { - candidate_hash: candidate_a_hash, - relay_parent: relay_parent_a_info.clone(), - }, - PendingAvailability { - candidate_hash: candidate_b_hash, - relay_parent: relay_parent_b_info.clone(), - }, - PendingAvailability { - candidate_hash: candidate_c_hash, - relay_parent: relay_parent_c_info.clone(), - }, - ], - ] { - let scope = Scope::with_ancestors( - para_id, - relay_parent_c_info.clone(), - base_constraints.clone(), - pending, - 3, - ancestors.clone(), - ) - .unwrap(); - let mut chain = FragmentChain::populate(scope, &storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); - chain.extend_from_storage(&storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); - } + // Candidate C has the same relay parent as candidate A's parent. Relay parent not allowed + // to move backwards + let mut modified_storage = storage.clone(); + modified_storage.remove_candidate(&candidate_c_hash); + let (wrong_pvd_c, wrong_candidate_c) = make_committed_candidate( + para_id, + relay_parent_x_info.hash, + relay_parent_x_info.number, + vec![0x0c].into(), + vec![0x0d].into(), + 0, + ); + let wrong_candidate_c_entry = CandidateEntry::new( + wrong_candidate_c.hash(), + wrong_candidate_c, + wrong_pvd_c, + CandidateState::Backed, + ) + .unwrap(); + modified_storage.add_candidate_entry(wrong_candidate_c_entry.clone()).unwrap(); + let scope = Scope::with_ancestors( + relay_parent_z_info.clone(), + base_constraints.clone(), + vec![], + 4, + ancestors.clone(), + ) + .unwrap(); - // Relay parents of pending availability candidates can be out of scope - // Relay parent of candidate A is out of scope. - let ancestors_without_a = vec![relay_parent_b_info.clone()]; - let scope = Scope::with_ancestors( - para_id, - relay_parent_c_info.clone(), - base_constraints.clone(), - vec![PendingAvailability { - candidate_hash: candidate_a_hash, - relay_parent: relay_parent_a_info.clone(), - }], - 4, - ancestors_without_a, - ) - .unwrap(); - let mut chain = FragmentChain::populate(scope, &storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); - chain.extend_from_storage(&storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); + let chain = populate_chain_from_previous_storage(&scope, &modified_storage); - // Even relay parents of pending availability candidates which are out of scope cannot move - // backwards. - let scope = Scope::with_ancestors( - para_id, - relay_parent_c_info.clone(), + assert_eq!(chain.best_chain_vec(), vec![candidate_a_hash, candidate_b_hash]); + assert_eq!(chain.unconnected_len(), 0); + assert_matches!( + chain.can_add_candidate_as_potential(&wrong_candidate_c_entry), + Err(Error::RelayParentMovedBackwards) + ); + + // Candidate C is an unconnected candidate. + // C's relay parent is allowed to move backwards from B's relay parent, because C may later on + // trigger a reorg and B may get removed. + let mut modified_storage = storage.clone(); + modified_storage.remove_candidate(&candidate_c_hash); + let (unconnected_pvd_c, unconnected_candidate_c) = make_committed_candidate( + para_id, + relay_parent_x_info.hash, + relay_parent_x_info.number, + vec![0x0d].into(), + vec![0x0e].into(), + 0, + ); + let unconnected_candidate_c_hash = unconnected_candidate_c.hash(); + let unconnected_candidate_c_entry = CandidateEntry::new( + unconnected_candidate_c_hash, + unconnected_candidate_c, + unconnected_pvd_c, + CandidateState::Backed, + ) + .unwrap(); + modified_storage + .add_candidate_entry(unconnected_candidate_c_entry.clone()) + .unwrap(); + let scope = Scope::with_ancestors( + relay_parent_z_info.clone(), + base_constraints.clone(), + vec![], + 4, + ancestors.clone(), + ) + .unwrap(); + let chain = FragmentChain::init(scope.clone(), CandidateStorage::default()); + assert!(chain.can_add_candidate_as_potential(&unconnected_candidate_c_entry).is_ok()); + + let chain = populate_chain_from_previous_storage(&scope, &modified_storage); + + assert_eq!(chain.best_chain_vec(), vec![candidate_a_hash, candidate_b_hash]); + assert_eq!( + chain.unconnected().map(|c| c.candidate_hash).collect::>(), + [unconnected_candidate_c_hash].into_iter().collect() + ); + + // Candidate A is a pending availability candidate and Candidate C is an unconnected candidate, + // C's relay parent is not allowed to move backwards from A's relay parent because we're sure A + // will not get removed in the future, as it's already on-chain (unless it times out + // availability, a case for which we don't care to optimise for) + + modified_storage.remove_candidate(&candidate_a_hash); + let (modified_pvd_a, modified_candidate_a) = make_committed_candidate( + para_id, + relay_parent_y_info.hash, + relay_parent_y_info.number, + vec![0x0a].into(), + vec![0x0b].into(), + relay_parent_y_info.number, + ); + let modified_candidate_a_hash = modified_candidate_a.hash(); + modified_storage + .add_candidate_entry( + CandidateEntry::new( + modified_candidate_a_hash, + modified_candidate_a, + modified_pvd_a, + CandidateState::Backed, + ) + .unwrap(), + ) + .unwrap(); + + let scope = Scope::with_ancestors( + relay_parent_z_info.clone(), + base_constraints.clone(), + vec![PendingAvailability { + candidate_hash: modified_candidate_a_hash, + relay_parent: relay_parent_y_info.clone(), + }], + 4, + ancestors.clone(), + ) + .unwrap(); + + let chain = populate_chain_from_previous_storage(&scope, &modified_storage); + assert_eq!(chain.best_chain_vec(), vec![modified_candidate_a_hash, candidate_b_hash]); + assert_eq!(chain.unconnected_len(), 0); + assert_matches!( + chain.can_add_candidate_as_potential(&unconnected_candidate_c_entry), + Err(Error::RelayParentPrecedesCandidatePendingAvailability(_, _)) + ); + + // Not allowed to fork from a candidate pending availability + let (wrong_pvd_c, wrong_candidate_c) = make_committed_candidate( + para_id, + relay_parent_y_info.hash, + relay_parent_y_info.number, + vec![0x0a].into(), + vec![0x0b2].into(), + 0, + ); + let wrong_candidate_c_hash = wrong_candidate_c.hash(); + let wrong_candidate_c_entry = CandidateEntry::new( + wrong_candidate_c_hash, + wrong_candidate_c, + wrong_pvd_c, + CandidateState::Backed, + ) + .unwrap(); + modified_storage.add_candidate_entry(wrong_candidate_c_entry.clone()).unwrap(); + + // Does not even matter if the fork selection rule would have picked up the new candidate, as + // the other is already pending availability. + assert_eq!( + fork_selection_rule(&wrong_candidate_c_hash, &modified_candidate_a_hash), + Ordering::Less + ); + + let scope = Scope::with_ancestors( + relay_parent_z_info.clone(), + base_constraints.clone(), + vec![PendingAvailability { + candidate_hash: modified_candidate_a_hash, + relay_parent: relay_parent_y_info.clone(), + }], + 4, + ancestors.clone(), + ) + .unwrap(); + + let chain = populate_chain_from_previous_storage(&scope, &modified_storage); + assert_eq!(chain.best_chain_vec(), vec![modified_candidate_a_hash, candidate_b_hash]); + assert_eq!(chain.unconnected_len(), 0); + assert_matches!( + chain.can_add_candidate_as_potential(&wrong_candidate_c_entry), + Err(Error::ForkWithCandidatePendingAvailability(_)) + ); + + // Test with candidates pending availability + { + // Valid options + for pending in [ + vec![PendingAvailability { + candidate_hash: candidate_a_hash, + relay_parent: relay_parent_x_info.clone(), + }], + vec![ + PendingAvailability { + candidate_hash: candidate_a_hash, + relay_parent: relay_parent_x_info.clone(), + }, + PendingAvailability { + candidate_hash: candidate_b_hash, + relay_parent: relay_parent_y_info.clone(), + }, + ], + vec![ + PendingAvailability { + candidate_hash: candidate_a_hash, + relay_parent: relay_parent_x_info.clone(), + }, + PendingAvailability { + candidate_hash: candidate_b_hash, + relay_parent: relay_parent_y_info.clone(), + }, + PendingAvailability { + candidate_hash: candidate_c_hash, + relay_parent: relay_parent_z_info.clone(), + }, + ], + ] { + let scope = Scope::with_ancestors( + relay_parent_z_info.clone(), + base_constraints.clone(), + pending, + 3, + ancestors.clone(), + ) + .unwrap(); + let chain = populate_chain_from_previous_storage(&scope, &storage); + assert_eq!( + chain.best_chain_vec(), + vec![candidate_a_hash, candidate_b_hash, candidate_c_hash] + ); + assert_eq!(chain.unconnected_len(), 0); + } + + // Relay parents of pending availability candidates can be out of scope + // Relay parent of candidate A is out of scope. + let ancestors_without_x = vec![relay_parent_y_info.clone()]; + let scope = Scope::with_ancestors( + relay_parent_z_info.clone(), + base_constraints.clone(), + vec![PendingAvailability { + candidate_hash: candidate_a_hash, + relay_parent: relay_parent_x_info.clone(), + }], + 4, + ancestors_without_x, + ) + .unwrap(); + let chain = populate_chain_from_previous_storage(&scope, &storage); + + assert_eq!( + chain.best_chain_vec(), + vec![candidate_a_hash, candidate_b_hash, candidate_c_hash] + ); + assert_eq!(chain.unconnected_len(), 0); + + // Even relay parents of pending availability candidates which are out of scope cannot + // move backwards. + let scope = Scope::with_ancestors( + relay_parent_z_info.clone(), base_constraints.clone(), vec![ PendingAvailability { candidate_hash: candidate_a_hash, relay_parent: RelayChainBlockInfo { - hash: relay_parent_a_info.hash, + hash: relay_parent_x_info.hash, number: 1, - storage_root: relay_parent_a_info.storage_root, + storage_root: relay_parent_x_info.storage_root, }, }, PendingAvailability { candidate_hash: candidate_b_hash, relay_parent: RelayChainBlockInfo { - hash: relay_parent_b_info.hash, + hash: relay_parent_y_info.hash, number: 0, - storage_root: relay_parent_b_info.storage_root, + storage_root: relay_parent_y_info.storage_root, }, }, ], @@ -976,271 +961,418 @@ fn populate_and_extend_from_storage_with_existing_empty_to_vec() { vec![], ) .unwrap(); - let mut chain = FragmentChain::populate(scope, &storage); - assert!(chain.to_vec().is_empty()); - - chain.extend_from_storage(&storage); - assert!(chain.to_vec().is_empty()); + let chain = populate_chain_from_previous_storage(&scope, &storage); + assert!(chain.best_chain_vec().is_empty()); + assert_eq!(chain.unconnected_len(), 0); } -} -#[test] -fn extend_from_storage_with_existing_to_vec() { - let para_id = ParaId::from(5u32); - let relay_parent_a = Hash::repeat_byte(1); - let relay_parent_b = Hash::repeat_byte(2); - let relay_parent_d = Hash::repeat_byte(3); + // More complex case: + // max_depth is 2 (a chain of max depth 3). + // A -> B -> C are the best backable chain. + // D is backed but would exceed the max depth. + // F is unconnected and seconded. + // A1 has same parent as A, is backed but has a higher candidate hash. It'll therefore be + // deleted. + // A1 has underneath a subtree that will all need to be trimmed. A1 -> B1. B1 -> C1 + // and B1 -> C2. (C1 is backed). + // A2 is seconded but is kept because it has a lower candidate hash than A. + // A2 points to B2, which is backed. + // + // Check that D, F, A2 and B2 are kept as unconnected potential candidates. - let (pvd_a, candidate_a) = make_committed_candidate( + let scope = Scope::with_ancestors( + relay_parent_z_info.clone(), + base_constraints.clone(), + vec![], + 2, + ancestors.clone(), + ) + .unwrap(); + + // Candidate D + let (pvd_d, candidate_d) = make_committed_candidate( para_id, - relay_parent_a, - 0, - vec![0x0a].into(), - vec![0x0b].into(), - 0, + relay_parent_z_info.hash, + relay_parent_z_info.number, + vec![0x0d].into(), + vec![0x0e].into(), + relay_parent_z_info.number, ); - let candidate_a_hash = candidate_a.hash(); - - let (pvd_b, candidate_b) = make_committed_candidate( + let candidate_d_hash = candidate_d.hash(); + let candidate_d_entry = + CandidateEntry::new(candidate_d_hash, candidate_d, pvd_d, CandidateState::Backed).unwrap(); + assert!(populate_chain_from_previous_storage(&scope, &storage) + .can_add_candidate_as_potential(&candidate_d_entry) + .is_ok()); + storage.add_candidate_entry(candidate_d_entry).unwrap(); + + // Candidate F + let (pvd_f, candidate_f) = make_committed_candidate( para_id, - relay_parent_b, - 1, - vec![0x0b].into(), - vec![0x0c].into(), - 1, + relay_parent_z_info.hash, + relay_parent_z_info.number, + vec![0x0f].into(), + vec![0xf1].into(), + 1000, ); - let candidate_b_hash = candidate_b.hash(); + let candidate_f_hash = candidate_f.hash(); + let candidate_f_entry = + CandidateEntry::new(candidate_f_hash, candidate_f, pvd_f, CandidateState::Seconded) + .unwrap(); + assert!(populate_chain_from_previous_storage(&scope, &storage) + .can_add_candidate_as_potential(&candidate_f_entry) + .is_ok()); + storage.add_candidate_entry(candidate_f_entry.clone()).unwrap(); - let (pvd_c, candidate_c) = make_committed_candidate( + // Candidate A1 + let (pvd_a1, candidate_a1) = make_committed_candidate( para_id, - // Use the same relay parent number as B to test that it doesn't need to change between - // candidates. - relay_parent_b, - 1, - vec![0x0c].into(), - vec![0x0d].into(), - 1, + relay_parent_x_info.hash, + relay_parent_x_info.number, + vec![0x0a].into(), + vec![0xb1].into(), + relay_parent_x_info.number, ); - let candidate_c_hash = candidate_c.hash(); + let candidate_a1_hash = candidate_a1.hash(); + let candidate_a1_entry = + CandidateEntry::new(candidate_a1_hash, candidate_a1, pvd_a1, CandidateState::Backed) + .unwrap(); + // Candidate A1 is created so that its hash is greater than the candidate A hash. + assert_eq!(fork_selection_rule(&candidate_a_hash, &candidate_a1_hash), Ordering::Less); - // Candidate D will never be added to the chain. - let (pvd_d, candidate_d) = make_committed_candidate( - para_id, - relay_parent_d, - 2, - vec![0x0e].into(), - vec![0x0f].into(), - 1, + assert_matches!( + populate_chain_from_previous_storage(&scope, &storage) + .can_add_candidate_as_potential(&candidate_a1_entry), + Err(Error::ForkChoiceRule(other)) if candidate_a_hash == other ); - let relay_parent_a_info = RelayChainBlockInfo { - number: pvd_a.relay_parent_number, - hash: relay_parent_a, - storage_root: pvd_a.relay_parent_storage_root, - }; - let relay_parent_b_info = RelayChainBlockInfo { - number: pvd_b.relay_parent_number, - hash: relay_parent_b, - storage_root: pvd_b.relay_parent_storage_root, - }; - let relay_parent_d_info = RelayChainBlockInfo { - number: pvd_d.relay_parent_number, - hash: relay_parent_d, - storage_root: pvd_d.relay_parent_storage_root, - }; + storage.add_candidate_entry(candidate_a1_entry.clone()).unwrap(); - let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); - let pending_availability = Vec::new(); + // Candidate B1. + let (pvd_b1, candidate_b1) = make_committed_candidate( + para_id, + relay_parent_x_info.hash, + relay_parent_x_info.number, + vec![0xb1].into(), + vec![0xc1].into(), + relay_parent_x_info.number, + ); + let candidate_b1_hash = candidate_b1.hash(); + let candidate_b1_entry = + CandidateEntry::new(candidate_b1_hash, candidate_b1, pvd_b1, CandidateState::Seconded) + .unwrap(); + assert!(populate_chain_from_previous_storage(&scope, &storage) + .can_add_candidate_as_potential(&candidate_b1_entry) + .is_ok()); - let ancestors = vec![ - // These need to be ordered in reverse. - relay_parent_b_info.clone(), - relay_parent_a_info.clone(), - ]; + storage.add_candidate_entry(candidate_b1_entry).unwrap(); - // Already had A and C in the storage. Introduce B, which should add both B and C to the chain - // now. - { - let mut storage = CandidateStorage::default(); - storage - .add_candidate(candidate_a.clone(), pvd_a.clone(), CandidateState::Seconded) + // Candidate C1. + let (pvd_c1, candidate_c1) = make_committed_candidate( + para_id, + relay_parent_x_info.hash, + relay_parent_x_info.number, + vec![0xc1].into(), + vec![0xd1].into(), + relay_parent_x_info.number, + ); + let candidate_c1_hash = candidate_c1.hash(); + let candidate_c1_entry = + CandidateEntry::new(candidate_c1_hash, candidate_c1, pvd_c1, CandidateState::Backed) .unwrap(); - storage - .add_candidate(candidate_c.clone(), pvd_c.clone(), CandidateState::Seconded) + assert!(populate_chain_from_previous_storage(&scope, &storage) + .can_add_candidate_as_potential(&candidate_c1_entry) + .is_ok()); + + storage.add_candidate_entry(candidate_c1_entry).unwrap(); + + // Candidate C2. + let (pvd_c2, candidate_c2) = make_committed_candidate( + para_id, + relay_parent_x_info.hash, + relay_parent_x_info.number, + vec![0xc1].into(), + vec![0xd2].into(), + relay_parent_x_info.number, + ); + let candidate_c2_hash = candidate_c2.hash(); + let candidate_c2_entry = + CandidateEntry::new(candidate_c2_hash, candidate_c2, pvd_c2, CandidateState::Seconded) .unwrap(); - storage - .add_candidate(candidate_d.clone(), pvd_d.clone(), CandidateState::Seconded) + assert!(populate_chain_from_previous_storage(&scope, &storage) + .can_add_candidate_as_potential(&candidate_c2_entry) + .is_ok()); + storage.add_candidate_entry(candidate_c2_entry).unwrap(); + + // Candidate A2. + let (pvd_a2, candidate_a2) = make_committed_candidate( + para_id, + relay_parent_x_info.hash, + relay_parent_x_info.number, + vec![0x0a].into(), + vec![0xb3].into(), + relay_parent_x_info.number, + ); + let candidate_a2_hash = candidate_a2.hash(); + let candidate_a2_entry = + CandidateEntry::new(candidate_a2_hash, candidate_a2, pvd_a2, CandidateState::Seconded) .unwrap(); + // Candidate A2 is created so that its hash is greater than the candidate A hash. + assert_eq!(fork_selection_rule(&candidate_a2_hash, &candidate_a_hash), Ordering::Less); - let scope = Scope::with_ancestors( - para_id, - relay_parent_d_info.clone(), - base_constraints.clone(), - pending_availability.clone(), - 4, - ancestors.clone(), - ) - .unwrap(); - let mut chain = FragmentChain::populate(scope, &storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash]); + assert!(populate_chain_from_previous_storage(&scope, &storage) + .can_add_candidate_as_potential(&candidate_a2_entry) + .is_ok()); - storage - .add_candidate(candidate_b.clone(), pvd_b.clone(), CandidateState::Seconded) + storage.add_candidate_entry(candidate_a2_entry).unwrap(); + + // Candidate B2. + let (pvd_b2, candidate_b2) = make_committed_candidate( + para_id, + relay_parent_y_info.hash, + relay_parent_y_info.number, + vec![0xb3].into(), + vec![0xb4].into(), + relay_parent_y_info.number, + ); + let candidate_b2_hash = candidate_b2.hash(); + let candidate_b2_entry = + CandidateEntry::new(candidate_b2_hash, candidate_b2, pvd_b2, CandidateState::Backed) .unwrap(); - chain.extend_from_storage(&storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); - } + assert!(populate_chain_from_previous_storage(&scope, &storage) + .can_add_candidate_as_potential(&candidate_b2_entry) + .is_ok()); + storage.add_candidate_entry(candidate_b2_entry).unwrap(); - // Already had A and B in the chain. Introduce C. + let chain = populate_chain_from_previous_storage(&scope, &storage); + assert_eq!(chain.best_chain_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); + assert_eq!( + chain.unconnected().map(|c| c.candidate_hash).collect::>(), + [candidate_d_hash, candidate_f_hash, candidate_a2_hash, candidate_b2_hash] + .into_iter() + .collect() + ); + // Cannot add as potential an already present candidate (whether it's in the best chain or in + // unconnected storage) + assert_matches!( + chain.can_add_candidate_as_potential(&candidate_a_entry), + Err(Error::CandidateAlreadyKnown) + ); + assert_matches!( + chain.can_add_candidate_as_potential(&candidate_f_entry), + Err(Error::CandidateAlreadyKnown) + ); + + // Simulate a best chain reorg by backing a2. { - let mut storage = CandidateStorage::default(); - storage - .add_candidate(candidate_a.clone(), pvd_a.clone(), CandidateState::Seconded) - .unwrap(); - storage - .add_candidate(candidate_b.clone(), pvd_b.clone(), CandidateState::Seconded) - .unwrap(); - storage - .add_candidate(candidate_d.clone(), pvd_d.clone(), CandidateState::Seconded) - .unwrap(); + let mut chain = chain.clone(); + chain.candidate_backed(&candidate_a2_hash); + assert_eq!(chain.best_chain_vec(), vec![candidate_a2_hash, candidate_b2_hash]); + // F is kept as it was truly unconnected. The rest will be trimmed. + assert_eq!( + chain.unconnected().map(|c| c.candidate_hash).collect::>(), + [candidate_f_hash].into_iter().collect() + ); - let scope = Scope::with_ancestors( - para_id, - relay_parent_d_info.clone(), - base_constraints.clone(), - pending_availability.clone(), - 4, - ancestors.clone(), + // A and A1 will never have potential again. + assert_matches!( + chain.can_add_candidate_as_potential(&candidate_a1_entry), + Err(Error::ForkChoiceRule(_)) + ); + assert_matches!( + chain.can_add_candidate_as_potential(&candidate_a_entry), + Err(Error::ForkChoiceRule(_)) + ); + } + + // Candidate F has an invalid hrmp watermark. however, it was not checked beforehand as we don't + // have its parent yet. Add its parent now. This will not impact anything as E is not yet part + // of the best chain. + + let (pvd_e, candidate_e) = make_committed_candidate( + para_id, + relay_parent_z_info.hash, + relay_parent_z_info.number, + vec![0x0e].into(), + vec![0x0f].into(), + relay_parent_z_info.number, + ); + let candidate_e_hash = candidate_e.hash(); + storage + .add_candidate_entry( + CandidateEntry::new(candidate_e_hash, candidate_e, pvd_e, CandidateState::Seconded) + .unwrap(), ) .unwrap(); - let mut chain = FragmentChain::populate(scope, &storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); - storage - .add_candidate(candidate_c.clone(), pvd_c.clone(), CandidateState::Seconded) - .unwrap(); - chain.extend_from_storage(&storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); - } + let chain = populate_chain_from_previous_storage(&scope, &storage); + assert_eq!(chain.best_chain_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); + assert_eq!( + chain.unconnected().map(|c| c.candidate_hash).collect::>(), + [ + candidate_d_hash, + candidate_f_hash, + candidate_a2_hash, + candidate_b2_hash, + candidate_e_hash + ] + .into_iter() + .collect() + ); + + // Simulate the fact that candidates A, B, C are now pending availability. + let scope = Scope::with_ancestors( + relay_parent_z_info.clone(), + base_constraints.clone(), + vec![ + PendingAvailability { + candidate_hash: candidate_a_hash, + relay_parent: relay_parent_x_info, + }, + PendingAvailability { + candidate_hash: candidate_b_hash, + relay_parent: relay_parent_y_info, + }, + PendingAvailability { + candidate_hash: candidate_c_hash, + relay_parent: relay_parent_z_info.clone(), + }, + ], + 2, + ancestors.clone(), + ) + .unwrap(); + + // A2 and B2 will now be trimmed + let chain = populate_chain_from_previous_storage(&scope, &storage); + assert_eq!(chain.best_chain_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); + assert_eq!( + chain.unconnected().map(|c| c.candidate_hash).collect::>(), + [candidate_d_hash, candidate_f_hash, candidate_e_hash].into_iter().collect() + ); + // Cannot add as potential an already pending availability candidate + assert_matches!( + chain.can_add_candidate_as_potential(&candidate_a_entry), + Err(Error::CandidateAlreadyKnown) + ); + + // Simulate the fact that candidates A, B and C have been included. + + let base_constraints = make_constraints(0, vec![0], HeadData(vec![0x0d])); + let scope = Scope::with_ancestors( + relay_parent_z_info.clone(), + base_constraints.clone(), + vec![], + 2, + ancestors.clone(), + ) + .unwrap(); + + let prev_chain = chain; + let mut chain = FragmentChain::init(scope, CandidateStorage::default()); + chain.populate_from_previous(&prev_chain); + assert_eq!(chain.best_chain_vec(), vec![candidate_d_hash]); + assert_eq!( + chain.unconnected().map(|c| c.candidate_hash).collect::>(), + [candidate_e_hash, candidate_f_hash].into_iter().collect() + ); + + // Mark E as backed. F will be dropped for invalid watermark. No other unconnected candidates. + chain.candidate_backed(&candidate_e_hash); + assert_eq!(chain.best_chain_vec(), vec![candidate_d_hash, candidate_e_hash]); + assert_eq!(chain.unconnected_len(), 0); + + assert_matches!( + chain.can_add_candidate_as_potential(&candidate_f_entry), + Err(Error::CheckAgainstConstraints(_)) + ); } #[test] -fn test_find_ancestor_path_and_find_backable_chain_empty_to_vec() { - let para_id = ParaId::from(5u32); +fn test_find_ancestor_path_and_find_backable_chain_empty_best_chain() { let relay_parent = Hash::repeat_byte(1); let required_parent: HeadData = vec![0xff].into(); let max_depth = 10; // Empty chain - let storage = CandidateStorage::default(); let base_constraints = make_constraints(0, vec![0], required_parent.clone()); let relay_parent_info = RelayChainBlockInfo { number: 0, hash: relay_parent, storage_root: Hash::zero() }; - let scope = Scope::with_ancestors( - para_id, - relay_parent_info, - base_constraints, - vec![], - max_depth, - vec![], - ) - .unwrap(); - let chain = FragmentChain::populate(scope, &storage); - assert!(chain.to_vec().is_empty()); + let scope = + Scope::with_ancestors(relay_parent_info, base_constraints, vec![], max_depth, vec![]) + .unwrap(); + let chain = FragmentChain::init(scope, CandidateStorage::default()); + assert_eq!(chain.best_chain_len(), 0); assert_eq!(chain.find_ancestor_path(Ancestors::new()), 0); - assert_eq!(chain.find_backable_chain(Ancestors::new(), 2, |_| true), vec![]); + assert_eq!(chain.find_backable_chain(Ancestors::new(), 2), vec![]); // Invalid candidate. let ancestors: Ancestors = [CandidateHash::default()].into_iter().collect(); assert_eq!(chain.find_ancestor_path(ancestors.clone()), 0); - assert_eq!(chain.find_backable_chain(ancestors, 2, |_| true), vec![]); + assert_eq!(chain.find_backable_chain(ancestors, 2), vec![]); } #[test] -fn test_find_ancestor_path_and_find_backable_to_vec() { +fn test_find_ancestor_path_and_find_backable_chain() { let para_id = ParaId::from(5u32); let relay_parent = Hash::repeat_byte(1); let required_parent: HeadData = vec![0xff].into(); let max_depth = 5; let relay_parent_number = 0; - let relay_parent_storage_root = Hash::repeat_byte(69); + let relay_parent_storage_root = Hash::zero(); let mut candidates = vec![]; - - // Candidate 0 - candidates.push(make_committed_candidate( - para_id, - relay_parent, - 0, - required_parent.clone(), - vec![0].into(), - 0, - )); - // Candidate 1 - candidates.push(make_committed_candidate( - para_id, - relay_parent, - 0, - vec![0].into(), - vec![1].into(), - 0, - )); - // Candidate 2 - candidates.push(make_committed_candidate( - para_id, - relay_parent, - 0, - vec![1].into(), - vec![2].into(), - 0, - )); - // Candidate 3 - candidates.push(make_committed_candidate( - para_id, - relay_parent, - 0, - vec![2].into(), - vec![3].into(), - 0, - )); - // Candidate 4 - candidates.push(make_committed_candidate( - para_id, - relay_parent, - 0, - vec![3].into(), - vec![4].into(), - 0, - )); - // Candidate 5 + + // Candidate 0 candidates.push(make_committed_candidate( para_id, relay_parent, 0, - vec![4].into(), - vec![5].into(), + required_parent.clone(), + vec![0].into(), 0, )); - let base_constraints = make_constraints(0, vec![0], required_parent.clone()); + // Candidates 1..=5 + for index in 1..=5 { + candidates.push(make_committed_candidate( + para_id, + relay_parent, + 0, + vec![index - 1].into(), + vec![index].into(), + 0, + )); + } + let mut storage = CandidateStorage::default(); + for (pvd, candidate) in candidates.iter() { + storage + .add_candidate_entry( + CandidateEntry::new_seconded(candidate.hash(), candidate.clone(), pvd.clone()) + .unwrap(), + ) + .unwrap(); + } + + let candidates = candidates + .into_iter() + .map(|(_pvd, candidate)| candidate.hash()) + .collect::>(); + let hashes = + |range: Range| range.map(|i| (candidates[i], relay_parent)).collect::>(); + let relay_parent_info = RelayChainBlockInfo { number: relay_parent_number, hash: relay_parent, storage_root: relay_parent_storage_root, }; - for (pvd, candidate) in candidates.iter() { - storage - .add_candidate(candidate.clone(), pvd.clone(), CandidateState::Seconded) - .unwrap(); - } - let candidates = candidates.into_iter().map(|(_pvd, candidate)| candidate).collect::>(); + let base_constraints = make_constraints(0, vec![0], required_parent.clone()); let scope = Scope::with_ancestors( - para_id, relay_parent_info.clone(), base_constraints.clone(), vec![], @@ -1248,506 +1380,140 @@ fn test_find_ancestor_path_and_find_backable_to_vec() { vec![], ) .unwrap(); - let chain = FragmentChain::populate(scope, &storage); + let mut chain = populate_chain_from_previous_storage(&scope, &storage); + // For now, candidates are only seconded, not backed. So the best chain is empty and no + // candidate will be returned. assert_eq!(candidates.len(), 6); - assert_eq!(chain.to_vec().len(), 6); + assert_eq!(chain.best_chain_len(), 0); + assert_eq!(chain.unconnected_len(), 6); + + for count in 0..10 { + assert_eq!(chain.find_backable_chain(Ancestors::new(), count).len(), 0); + } + + // Do tests with only a couple of candidates being backed. + { + let mut chain = chain.clone(); + chain.candidate_backed(&&candidates[5]); + for count in 0..10 { + assert_eq!(chain.find_backable_chain(Ancestors::new(), count).len(), 0); + } + chain.candidate_backed(&&candidates[3]); + chain.candidate_backed(&&candidates[4]); + for count in 0..10 { + assert_eq!(chain.find_backable_chain(Ancestors::new(), count).len(), 0); + } + + chain.candidate_backed(&&candidates[1]); + for count in 0..10 { + assert_eq!(chain.find_backable_chain(Ancestors::new(), count).len(), 0); + } + + chain.candidate_backed(&&candidates[0]); + assert_eq!(chain.find_backable_chain(Ancestors::new(), 1), hashes(0..1)); + for count in 2..10 { + assert_eq!(chain.find_backable_chain(Ancestors::new(), count), hashes(0..2)); + } + + // Now back the missing piece. + chain.candidate_backed(&&candidates[2]); + assert_eq!(chain.best_chain_len(), 6); + for count in 0..10 { + assert_eq!( + chain.find_backable_chain(Ancestors::new(), count), + (0..6) + .take(count as usize) + .map(|i| (candidates[i], relay_parent)) + .collect::>() + ); + } + } + + // Now back all candidates. Back them in a random order. The result should always be the same. + let mut candidates_shuffled = candidates.clone(); + candidates_shuffled.shuffle(&mut thread_rng()); + for candidate in candidates.iter() { + chain.candidate_backed(candidate); + storage.mark_backed(candidate); + } // No ancestors supplied. assert_eq!(chain.find_ancestor_path(Ancestors::new()), 0); - assert_eq!(chain.find_backable_chain(Ancestors::new(), 0, |_| true), vec![]); - assert_eq!( - chain.find_backable_chain(Ancestors::new(), 1, |_| true), - [0].into_iter().map(|i| candidates[i].hash()).collect::>() - ); - assert_eq!( - chain.find_backable_chain(Ancestors::new(), 2, |_| true), - [0, 1].into_iter().map(|i| candidates[i].hash()).collect::>() - ); - assert_eq!( - chain.find_backable_chain(Ancestors::new(), 5, |_| true), - [0, 1, 2, 3, 4].into_iter().map(|i| candidates[i].hash()).collect::>() - ); + assert_eq!(chain.find_backable_chain(Ancestors::new(), 0), vec![]); + assert_eq!(chain.find_backable_chain(Ancestors::new(), 1), hashes(0..1)); + assert_eq!(chain.find_backable_chain(Ancestors::new(), 2), hashes(0..2)); + assert_eq!(chain.find_backable_chain(Ancestors::new(), 5), hashes(0..5)); for count in 6..10 { - assert_eq!( - chain.find_backable_chain(Ancestors::new(), count, |_| true), - [0, 1, 2, 3, 4, 5].into_iter().map(|i| candidates[i].hash()).collect::>() - ); + assert_eq!(chain.find_backable_chain(Ancestors::new(), count), hashes(0..6)); } - assert_eq!( - chain.find_backable_chain(Ancestors::new(), 7, |_| true), - [0, 1, 2, 3, 4, 5].into_iter().map(|i| candidates[i].hash()).collect::>() - ); - assert_eq!( - chain.find_backable_chain(Ancestors::new(), 10, |_| true), - [0, 1, 2, 3, 4, 5].into_iter().map(|i| candidates[i].hash()).collect::>() - ); + assert_eq!(chain.find_backable_chain(Ancestors::new(), 7), hashes(0..6)); + assert_eq!(chain.find_backable_chain(Ancestors::new(), 10), hashes(0..6)); // Ancestor which is not part of the chain. Will be ignored. let ancestors: Ancestors = [CandidateHash::default()].into_iter().collect(); assert_eq!(chain.find_ancestor_path(ancestors.clone()), 0); - assert_eq!( - chain.find_backable_chain(ancestors, 4, |_| true), - [0, 1, 2, 3].into_iter().map(|i| candidates[i].hash()).collect::>() - ); - let ancestors: Ancestors = - [candidates[1].hash(), CandidateHash::default()].into_iter().collect(); + assert_eq!(chain.find_backable_chain(ancestors, 4), hashes(0..4)); + + let ancestors: Ancestors = [candidates[1], CandidateHash::default()].into_iter().collect(); assert_eq!(chain.find_ancestor_path(ancestors.clone()), 0); - assert_eq!( - chain.find_backable_chain(ancestors, 4, |_| true), - [0, 1, 2, 3].into_iter().map(|i| candidates[i].hash()).collect::>() - ); - let ancestors: Ancestors = - [candidates[0].hash(), CandidateHash::default()].into_iter().collect(); + assert_eq!(chain.find_backable_chain(ancestors, 4), hashes(0..4)); + + let ancestors: Ancestors = [candidates[0], CandidateHash::default()].into_iter().collect(); assert_eq!(chain.find_ancestor_path(ancestors.clone()), 1); - assert_eq!( - chain.find_backable_chain(ancestors, 4, |_| true), - [1, 2, 3, 4].into_iter().map(|i| candidates[i].hash()).collect::>() - ); + assert_eq!(chain.find_backable_chain(ancestors, 4), hashes(1..5)); // Ancestors which are part of the chain but don't form a path from root. Will be ignored. - let ancestors: Ancestors = [candidates[1].hash(), candidates[2].hash()].into_iter().collect(); + let ancestors: Ancestors = [candidates[1], candidates[2]].into_iter().collect(); assert_eq!(chain.find_ancestor_path(ancestors.clone()), 0); - assert_eq!( - chain.find_backable_chain(ancestors, 4, |_| true), - [0, 1, 2, 3].into_iter().map(|i| candidates[i].hash()).collect::>() - ); + assert_eq!(chain.find_backable_chain(ancestors, 4), hashes(0..4)); // Valid ancestors. - let ancestors: Ancestors = [candidates[2].hash(), candidates[0].hash(), candidates[1].hash()] - .into_iter() - .collect(); + let ancestors: Ancestors = [candidates[2], candidates[0], candidates[1]].into_iter().collect(); assert_eq!(chain.find_ancestor_path(ancestors.clone()), 3); - assert_eq!( - chain.find_backable_chain(ancestors.clone(), 2, |_| true), - [3, 4].into_iter().map(|i| candidates[i].hash()).collect::>() - ); + assert_eq!(chain.find_backable_chain(ancestors.clone(), 2), hashes(3..5)); for count in 3..10 { - assert_eq!( - chain.find_backable_chain(ancestors.clone(), count, |_| true), - [3, 4, 5].into_iter().map(|i| candidates[i].hash()).collect::>() - ); + assert_eq!(chain.find_backable_chain(ancestors.clone(), count), hashes(3..6)); } // Valid ancestors with candidates which have been omitted due to timeouts - let ancestors: Ancestors = [candidates[0].hash(), candidates[2].hash()].into_iter().collect(); + let ancestors: Ancestors = [candidates[0], candidates[2]].into_iter().collect(); assert_eq!(chain.find_ancestor_path(ancestors.clone()), 1); - assert_eq!( - chain.find_backable_chain(ancestors.clone(), 3, |_| true), - [1, 2, 3].into_iter().map(|i| candidates[i].hash()).collect::>() - ); - assert_eq!( - chain.find_backable_chain(ancestors.clone(), 4, |_| true), - [1, 2, 3, 4].into_iter().map(|i| candidates[i].hash()).collect::>() - ); + assert_eq!(chain.find_backable_chain(ancestors.clone(), 3), hashes(1..4)); + assert_eq!(chain.find_backable_chain(ancestors.clone(), 4), hashes(1..5)); for count in 5..10 { - assert_eq!( - chain.find_backable_chain(ancestors.clone(), count, |_| true), - [1, 2, 3, 4, 5].into_iter().map(|i| candidates[i].hash()).collect::>() - ); + assert_eq!(chain.find_backable_chain(ancestors.clone(), count), hashes(1..6)); } - let ancestors: Ancestors = [candidates[0].hash(), candidates[1].hash(), candidates[3].hash()] - .into_iter() - .collect(); + let ancestors: Ancestors = [candidates[0], candidates[1], candidates[3]].into_iter().collect(); assert_eq!(chain.find_ancestor_path(ancestors.clone()), 2); - assert_eq!( - chain.find_backable_chain(ancestors.clone(), 4, |_| true), - [2, 3, 4, 5].into_iter().map(|i| candidates[i].hash()).collect::>() - ); + assert_eq!(chain.find_backable_chain(ancestors.clone(), 4), hashes(2..6)); // Requested count is 0. - assert_eq!(chain.find_backable_chain(ancestors, 0, |_| true), vec![]); - - // Stop when we've found a candidate for which pred returns false. - let ancestors: Ancestors = [candidates[2].hash(), candidates[0].hash(), candidates[1].hash()] - .into_iter() - .collect(); - for count in 1..10 { - assert_eq!( - // Stop at 4. - chain.find_backable_chain(ancestors.clone(), count, |hash| hash != - &candidates[4].hash()), - [3].into_iter().map(|i| candidates[i].hash()).collect::>() - ); - } + assert_eq!(chain.find_backable_chain(ancestors, 0), vec![]); // Stop when we've found a candidate which is pending availability { let scope = Scope::with_ancestors( - para_id, relay_parent_info.clone(), base_constraints, // Mark the third candidate as pending availability vec![PendingAvailability { - candidate_hash: candidates[3].hash(), + candidate_hash: candidates[3], relay_parent: relay_parent_info, }], max_depth, vec![], ) .unwrap(); - let chain = FragmentChain::populate(scope, &storage); - let ancestors: Ancestors = - [candidates[0].hash(), candidates[1].hash()].into_iter().collect(); + let chain = populate_chain_from_previous_storage(&scope, &storage); + let ancestors: Ancestors = [candidates[0], candidates[1]].into_iter().collect(); assert_eq!( // Stop at 4. - chain.find_backable_chain(ancestors.clone(), 3, |_| true), - [2].into_iter().map(|i| candidates[i].hash()).collect::>() - ); - } -} - -#[test] -fn hypothetical_membership() { - let mut storage = CandidateStorage::default(); - - let para_id = ParaId::from(5u32); - let relay_parent_a = Hash::repeat_byte(1); - - let (pvd_a, candidate_a) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0a].into(), - vec![0x0b].into(), - 0, - ); - let candidate_a_hash = candidate_a.hash(); - - let (pvd_b, candidate_b) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0b].into(), - vec![0x0c].into(), - 0, - ); - let candidate_b_hash = candidate_b.hash(); - - let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); - - let relay_parent_a_info = RelayChainBlockInfo { - number: pvd_a.relay_parent_number, - hash: relay_parent_a, - storage_root: pvd_a.relay_parent_storage_root, - }; - - let max_depth = 4; - storage.add_candidate(candidate_a, pvd_a, CandidateState::Seconded).unwrap(); - storage.add_candidate(candidate_b, pvd_b, CandidateState::Seconded).unwrap(); - let scope = Scope::with_ancestors( - para_id, - relay_parent_a_info.clone(), - base_constraints.clone(), - vec![], - max_depth, - vec![], - ) - .unwrap(); - let chain = FragmentChain::populate(scope, &storage); - - assert_eq!(chain.to_vec().len(), 2); - - // Check candidates which are already present - assert!(chain.hypothetical_membership( - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0a]).hash(), - candidate_relay_parent: relay_parent_a, - candidate_para: para_id, - candidate_hash: candidate_a_hash, - }, - &storage, - )); - assert!(chain.hypothetical_membership( - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0b]).hash(), - candidate_relay_parent: relay_parent_a, - candidate_para: para_id, - candidate_hash: candidate_b_hash, - }, - &storage, - )); - - // Forks not allowed. - assert!(!chain.hypothetical_membership( - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0a]).hash(), - candidate_relay_parent: relay_parent_a, - candidate_para: para_id, - candidate_hash: CandidateHash(Hash::repeat_byte(21)), - }, - &storage, - )); - assert!(!chain.hypothetical_membership( - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0b]).hash(), - candidate_relay_parent: relay_parent_a, - candidate_para: para_id, - candidate_hash: CandidateHash(Hash::repeat_byte(22)), - }, - &storage, - )); - - // Unknown candidate which builds on top of the current chain. - assert!(chain.hypothetical_membership( - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0c]).hash(), - candidate_relay_parent: relay_parent_a, - candidate_para: para_id, - candidate_hash: CandidateHash(Hash::repeat_byte(23)), - }, - &storage, - )); - - // Unknown unconnected candidate which may be valid. - assert!(chain.hypothetical_membership( - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0e]).hash(), - candidate_relay_parent: relay_parent_a, - candidate_para: para_id, - candidate_hash: CandidateHash(Hash::repeat_byte(23)), - }, - &storage, - )); - - // The number of unconnected candidates is limited (chain.len() + unconnected) <= max_depth - { - // C will be an unconnected candidate. - let (pvd_c, candidate_c) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0e].into(), - vec![0x0f].into(), - 0, - ); - let candidate_c_hash = candidate_c.hash(); - - // Add an invalid candidate in the storage. This would introduce a fork. Just to test that - // it's ignored. - let (invalid_pvd, invalid_candidate) = make_committed_candidate( - para_id, - relay_parent_a, - 1, - vec![0x0a].into(), - vec![0x0b].into(), - 0, + chain.find_backable_chain(ancestors.clone(), 3), + hashes(2..3) ); - - let scope = Scope::with_ancestors( - para_id, - relay_parent_a_info, - base_constraints, - vec![], - 2, - vec![], - ) - .unwrap(); - let mut storage = storage.clone(); - storage.add_candidate(candidate_c, pvd_c, CandidateState::Seconded).unwrap(); - - let chain = FragmentChain::populate(scope, &storage); - assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); - - storage - .add_candidate(invalid_candidate, invalid_pvd, CandidateState::Seconded) - .unwrap(); - - // Check that C is accepted as a potential unconnected candidate. - assert!(!chain.hypothetical_membership( - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0e]).hash(), - candidate_relay_parent: relay_parent_a, - candidate_hash: candidate_c_hash, - candidate_para: para_id - }, - &storage, - )); - - // Since C is already an unconnected candidate in the storage. - assert!(!chain.hypothetical_membership( - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0f]).hash(), - candidate_relay_parent: relay_parent_a, - candidate_para: para_id, - candidate_hash: CandidateHash(Hash::repeat_byte(23)), - }, - &storage, - )); } } - -#[test] -fn hypothetical_membership_stricter_on_complete_candidates() { - let storage = CandidateStorage::default(); - - let para_id = ParaId::from(5u32); - let relay_parent_a = Hash::repeat_byte(1); - - let (pvd_a, candidate_a) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0a].into(), - vec![0x0b].into(), - 1000, // watermark is illegal - ); - - let candidate_a_hash = candidate_a.hash(); - - let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); - let pending_availability = Vec::new(); - - let relay_parent_a_info = RelayChainBlockInfo { - number: pvd_a.relay_parent_number, - hash: relay_parent_a, - storage_root: pvd_a.relay_parent_storage_root, - }; - - let max_depth = 4; - let scope = Scope::with_ancestors( - para_id, - relay_parent_a_info, - base_constraints, - pending_availability, - max_depth, - vec![], - ) - .unwrap(); - let chain = FragmentChain::populate(scope, &storage); - - assert!(chain.hypothetical_membership( - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0a]).hash(), - candidate_relay_parent: relay_parent_a, - candidate_para: para_id, - candidate_hash: candidate_a_hash, - }, - &storage, - )); - - assert!(!chain.hypothetical_membership( - HypotheticalCandidate::Complete { - receipt: Arc::new(candidate_a), - persisted_validation_data: pvd_a, - candidate_hash: candidate_a_hash, - }, - &storage, - )); -} - -#[test] -fn hypothetical_membership_with_pending_availability_in_scope() { - let mut storage = CandidateStorage::default(); - - let para_id = ParaId::from(5u32); - let relay_parent_a = Hash::repeat_byte(1); - let relay_parent_b = Hash::repeat_byte(2); - let relay_parent_c = Hash::repeat_byte(3); - - let (pvd_a, candidate_a) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0a].into(), - vec![0x0b].into(), - 0, - ); - let candidate_a_hash = candidate_a.hash(); - - let (pvd_b, candidate_b) = make_committed_candidate( - para_id, - relay_parent_b, - 1, - vec![0x0b].into(), - vec![0x0c].into(), - 1, - ); - - // Note that relay parent `a` is not allowed. - let base_constraints = make_constraints(1, vec![], vec![0x0a].into()); - - let relay_parent_a_info = RelayChainBlockInfo { - number: pvd_a.relay_parent_number, - hash: relay_parent_a, - storage_root: pvd_a.relay_parent_storage_root, - }; - let pending_availability = vec![PendingAvailability { - candidate_hash: candidate_a_hash, - relay_parent: relay_parent_a_info, - }]; - - let relay_parent_b_info = RelayChainBlockInfo { - number: pvd_b.relay_parent_number, - hash: relay_parent_b, - storage_root: pvd_b.relay_parent_storage_root, - }; - let relay_parent_c_info = RelayChainBlockInfo { - number: pvd_b.relay_parent_number + 1, - hash: relay_parent_c, - storage_root: Hash::zero(), - }; - - let max_depth = 4; - storage.add_candidate(candidate_a, pvd_a, CandidateState::Seconded).unwrap(); - storage.add_candidate(candidate_b, pvd_b, CandidateState::Backed).unwrap(); - storage.mark_backed(&candidate_a_hash); - - let scope = Scope::with_ancestors( - para_id, - relay_parent_c_info, - base_constraints, - pending_availability, - max_depth, - vec![relay_parent_b_info], - ) - .unwrap(); - let chain = FragmentChain::populate(scope, &storage); - - assert_eq!(chain.to_vec().len(), 2); - - let candidate_d_hash = CandidateHash(Hash::repeat_byte(0xAA)); - - assert!(chain.hypothetical_membership( - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0a]).hash(), - candidate_relay_parent: relay_parent_a, - candidate_hash: candidate_a_hash, - candidate_para: para_id - }, - &storage, - )); - - assert!(!chain.hypothetical_membership( - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0a]).hash(), - candidate_relay_parent: relay_parent_c, - candidate_para: para_id, - candidate_hash: candidate_d_hash, - }, - &storage, - )); - - assert!(!chain.hypothetical_membership( - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0b]).hash(), - candidate_relay_parent: relay_parent_c, - candidate_para: para_id, - candidate_hash: candidate_d_hash, - }, - &storage, - )); - - assert!(chain.hypothetical_membership( - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0c]).hash(), - candidate_relay_parent: relay_parent_b, - candidate_para: para_id, - candidate_hash: candidate_d_hash, - }, - &storage, - )); -} diff --git a/polkadot/node/core/prospective-parachains/src/lib.rs b/polkadot/node/core/prospective-parachains/src/lib.rs index e4b6deffdf4a5280e23c8c4a81bdf2ae56bbb422..ecb1f3a476ecc698915d4bb0779c7211a3a4e9d2 100644 --- a/polkadot/node/core/prospective-parachains/src/lib.rs +++ b/polkadot/node/core/prospective-parachains/src/lib.rs @@ -26,9 +26,11 @@ //! //! This subsystem also handles concerns such as the relay-chain being forkful and session changes. +#![deny(unused_crate_dependencies)] + use std::collections::{HashMap, HashSet}; -use fragment_chain::{FragmentChain, PotentialAddition}; +use fragment_chain::CandidateStorage; use futures::{channel::oneshot, prelude::*}; use polkadot_node_subsystem::{ @@ -41,6 +43,7 @@ use polkadot_node_subsystem::{ overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, }; use polkadot_node_subsystem_util::{ + backing_implicit_view::{BlockInfoProspectiveParachains as BlockInfo, View as ImplicitView}, inclusion_emulator::{Constraints, RelayChainBlockInfo}, request_session_index_for_child, runtime::{prospective_parachains_mode, ProspectiveParachainsMode}, @@ -55,8 +58,7 @@ use polkadot_primitives::{ use crate::{ error::{FatalError, FatalResult, JfyiError, JfyiErrorResult, Result}, fragment_chain::{ - CandidateState, CandidateStorage, CandidateStorageInsertionError, - Scope as FragmentChainScope, + CandidateEntry, Error as FragmentChainError, FragmentChain, Scope as FragmentChainScope, }, }; @@ -71,20 +73,33 @@ use self::metrics::Metrics; const LOG_TARGET: &str = "parachain::prospective-parachains"; struct RelayBlockViewData { - // Scheduling info for paras and upcoming paras. + // The fragment chains for current and upcoming scheduled paras. fragment_chains: HashMap, - pending_availability: HashSet, } struct View { - // Active or recent relay-chain blocks by block hash. - active_leaves: HashMap, - candidate_storage: HashMap, + // Per relay parent fragment chains. These includes all relay parents under the implicit view. + per_relay_parent: HashMap, + // The hashes of the currently active leaves. This is a subset of the keys in + // `per_relay_parent`. + active_leaves: HashSet, + // The backing implicit view. + implicit_view: ImplicitView, } impl View { + // Initialize with empty values. fn new() -> Self { - View { active_leaves: HashMap::new(), candidate_storage: HashMap::new() } + View { + per_relay_parent: HashMap::new(), + active_leaves: HashSet::new(), + implicit_view: ImplicitView::default(), + } + } + + // Get the fragment chains of this leaf. + fn get_fragment_chains(&self, leaf: &Hash) -> Option<&HashMap> { + self.per_relay_parent.get(&leaf).map(|view_data| &view_data.fragment_chains) } } @@ -142,9 +157,9 @@ async fn run_iteration( FromOrchestra::Signal(OverseerSignal::BlockFinalized(..)) => {}, FromOrchestra::Communication { msg } => match msg { ProspectiveParachainsMessage::IntroduceSecondedCandidate(request, tx) => - handle_introduce_seconded_candidate(&mut *ctx, view, request, tx, metrics).await, + handle_introduce_seconded_candidate(view, request, tx, metrics).await, ProspectiveParachainsMessage::CandidateBacked(para, candidate_hash) => - handle_candidate_backed(&mut *ctx, view, para, candidate_hash).await, + handle_candidate_backed(view, para, candidate_hash, metrics).await, ProspectiveParachainsMessage::GetBackableCandidates( relay_parent, para, @@ -170,17 +185,32 @@ async fn handle_active_leaves_update( update: ActiveLeavesUpdate, metrics: &Metrics, ) -> JfyiErrorResult<()> { - // 1. clean up inactive leaves - // 2. determine all scheduled paras at the new block - // 3. construct new fragment chain for each para for each new leaf - // 4. prune candidate storage. + // For any new active leaf: + // - determine the scheduled paras + // - pre-populate the candidate storage with pending availability candidates and candidates from + // the parent leaf + // - populate the fragment chain + // - add it to the implicit view + // + // Then mark the newly-deactivated leaves as deactivated and update the implicit view. + // Finally, remove any relay parents that are no longer part of the implicit view. + + let _timer = metrics.time_handle_active_leaves_update(); - for deactivated in &update.deactivated { - view.active_leaves.remove(deactivated); - } + gum::trace!( + target: LOG_TARGET, + activated = ?update.activated, + deactivated = ?update.deactivated, + "Handle ActiveLeavesUpdate" + ); let mut temp_header_cache = HashMap::new(); + // There can only be one newly activated leaf, `update.activated` is an `Option`. for activated in update.activated.into_iter() { + if update.deactivated.contains(&activated.hash) { + continue + } + let hash = activated.hash; let mode = prospective_parachains_mode(ctx.sender(), hash) @@ -199,38 +229,34 @@ async fn handle_active_leaves_update( return Ok(()) }; - let scheduled_paras = fetch_upcoming_paras(&mut *ctx, hash).await?; + let scheduled_paras = fetch_upcoming_paras(ctx, hash).await?; - let block_info: RelayChainBlockInfo = - match fetch_block_info(&mut *ctx, &mut temp_header_cache, hash).await? { - None => { - gum::warn!( - target: LOG_TARGET, - block_hash = ?hash, - "Failed to get block info for newly activated leaf block." - ); + let block_info = match fetch_block_info(ctx, &mut temp_header_cache, hash).await? { + None => { + gum::warn!( + target: LOG_TARGET, + block_hash = ?hash, + "Failed to get block info for newly activated leaf block." + ); - // `update.activated` is an option, but we can use this - // to exit the 'loop' and skip this block without skipping - // pruning logic. - continue - }, - Some(info) => info, - }; + // `update.activated` is an option, but we can use this + // to exit the 'loop' and skip this block without skipping + // pruning logic. + continue + }, + Some(info) => info, + }; let ancestry = - fetch_ancestry(&mut *ctx, &mut temp_header_cache, hash, allowed_ancestry_len).await?; + fetch_ancestry(ctx, &mut temp_header_cache, hash, allowed_ancestry_len).await?; - let mut all_pending_availability = HashSet::new(); + let prev_fragment_chains = + ancestry.first().and_then(|prev_leaf| view.get_fragment_chains(&prev_leaf.hash)); - // Find constraints. let mut fragment_chains = HashMap::new(); for para in scheduled_paras { - let candidate_storage = - view.candidate_storage.entry(para).or_insert_with(CandidateStorage::default); - - let backing_state = fetch_backing_state(&mut *ctx, hash, para).await?; - + // Find constraints and pending availability candidates. + let backing_state = fetch_backing_state(ctx, hash, para).await?; let Some((constraints, pending_availability)) = backing_state else { // This indicates a runtime conflict of some kind. gum::debug!( @@ -243,8 +269,6 @@ async fn handle_active_leaves_update( continue }; - all_pending_availability.extend(pending_availability.iter().map(|c| c.candidate_hash)); - let pending_availability = preprocess_candidates_pending_availability( ctx, &mut temp_header_cache, @@ -254,16 +278,18 @@ async fn handle_active_leaves_update( .await?; let mut compact_pending = Vec::with_capacity(pending_availability.len()); + let mut pending_availability_storage = CandidateStorage::default(); + for c in pending_availability { - let res = candidate_storage.add_candidate( + let candidate_hash = c.compact.candidate_hash; + let res = pending_availability_storage.add_pending_availability_candidate( + candidate_hash, c.candidate, c.persisted_validation_data, - CandidateState::Backed, ); - let candidate_hash = c.compact.candidate_hash; match res { - Ok(_) | Err(CandidateStorageInsertionError::CandidateAlreadyKnown(_)) => {}, + Ok(_) | Err(FragmentChainError::CandidateAlreadyKnown) => {}, Err(err) => { gum::warn!( target: LOG_TARGET, @@ -280,119 +306,138 @@ async fn handle_active_leaves_update( compact_pending.push(c.compact); } - let scope = FragmentChainScope::with_ancestors( - para, - block_info.clone(), + let scope = match FragmentChainScope::with_ancestors( + block_info.clone().into(), constraints, compact_pending, max_candidate_depth, - ancestry.iter().cloned(), - ) - .expect("ancestors are provided in reverse order and correctly; qed"); + ancestry + .iter() + .map(|a| RelayChainBlockInfo::from(a.clone())) + .collect::>(), + ) { + Ok(scope) => scope, + Err(unexpected_ancestors) => { + gum::warn!( + target: LOG_TARGET, + para_id = ?para, + max_candidate_depth, + ?ancestry, + leaf = ?hash, + "Relay chain ancestors have wrong order: {:?}", + unexpected_ancestors + ); + continue + }, + }; gum::trace!( target: LOG_TARGET, relay_parent = ?hash, min_relay_parent = scope.earliest_relay_parent().number, para_id = ?para, + ancestors = ?ancestry, "Creating fragment chain" ); - let chain = FragmentChain::populate(scope, &*candidate_storage); + let number_of_pending_candidates = pending_availability_storage.len(); + + // Init the fragment chain with the pending availability candidates. + let mut chain = FragmentChain::init(scope, pending_availability_storage); + + if chain.best_chain_len() < number_of_pending_candidates { + gum::warn!( + target: LOG_TARGET, + relay_parent = ?hash, + para_id = ?para, + "Not all pending availability candidates could be introduced. Actual vs expected count: {}, {}", + chain.best_chain_len(), + number_of_pending_candidates + ) + } + + // If we know the previous fragment chain, use that for further populating the fragment + // chain. + if let Some(prev_fragment_chain) = + prev_fragment_chains.and_then(|chains| chains.get(¶)) + { + chain.populate_from_previous(prev_fragment_chain); + } gum::trace!( target: LOG_TARGET, relay_parent = ?hash, para_id = ?para, - "Populated fragment chain with {} candidates", - chain.len() + "Populated fragment chain with {} candidates: {:?}", + chain.best_chain_len(), + chain.best_chain_vec() + ); + + gum::trace!( + target: LOG_TARGET, + relay_parent = ?hash, + para_id = ?para, + "Potential candidate storage for para: {:?}", + chain.unconnected().map(|candidate| candidate.hash()).collect::>() ); fragment_chains.insert(para, chain); } - view.active_leaves.insert( - hash, - RelayBlockViewData { fragment_chains, pending_availability: all_pending_availability }, - ); - } + view.per_relay_parent.insert(hash, RelayBlockViewData { fragment_chains }); - if !update.deactivated.is_empty() { - // This has potential to be a hotspot. - prune_view_candidate_storage(view, metrics); - } + view.active_leaves.insert(hash); - Ok(()) -} + view.implicit_view + .activate_leaf_from_prospective_parachains(block_info, &ancestry); + } -fn prune_view_candidate_storage(view: &mut View, metrics: &Metrics) { - let _timer = metrics.time_prune_view_candidate_storage(); + for deactivated in update.deactivated { + view.active_leaves.remove(&deactivated); + view.implicit_view.deactivate_leaf(deactivated); + } - let active_leaves = &view.active_leaves; - let mut live_candidates = HashSet::new(); - let mut live_paras = HashSet::new(); - for sub_view in active_leaves.values() { - live_candidates.extend(sub_view.pending_availability.iter().cloned()); + { + let remaining: HashSet<_> = view.implicit_view.all_allowed_relay_parents().collect(); - for (para_id, fragment_chain) in &sub_view.fragment_chains { - live_candidates.extend(fragment_chain.to_vec()); - live_paras.insert(*para_id); - } + view.per_relay_parent.retain(|r, _| remaining.contains(&r)); } - let connected_candidates_count = live_candidates.len(); - for (leaf, sub_view) in active_leaves.iter() { - for (para_id, fragment_chain) in &sub_view.fragment_chains { - if let Some(storage) = view.candidate_storage.get(para_id) { - let unconnected_potential = - fragment_chain.find_unconnected_potential_candidates(storage, None); - if !unconnected_potential.is_empty() { - gum::trace!( - target: LOG_TARGET, - ?leaf, - "Keeping {} unconnected candidates for paraid {} in storage: {:?}", - unconnected_potential.len(), - para_id, - unconnected_potential - ); + if metrics.0.is_some() { + let mut active_connected = 0; + let mut active_unconnected = 0; + let mut candidates_in_implicit_view = 0; + + for (hash, RelayBlockViewData { fragment_chains, .. }) in view.per_relay_parent.iter() { + if view.active_leaves.contains(hash) { + for chain in fragment_chains.values() { + active_connected += chain.best_chain_len(); + active_unconnected += chain.unconnected_len(); + } + } else { + for chain in fragment_chains.values() { + candidates_in_implicit_view += chain.best_chain_len(); + candidates_in_implicit_view += chain.unconnected_len(); } - live_candidates.extend(unconnected_potential); } } - } - - view.candidate_storage.retain(|para_id, storage| { - if !live_paras.contains(¶_id) { - return false - } - - storage.retain(|h| live_candidates.contains(&h)); - - // Even if `storage` is now empty, we retain. - // This maintains a convenient invariant that para-id storage exists - // as long as there's an active head which schedules the para. - true - }); - for (para_id, storage) in view.candidate_storage.iter() { - gum::trace!( - target: LOG_TARGET, - "Keeping a total of {} connected candidates for paraid {} in storage", - storage.candidates().count(), - para_id, - ); + metrics.record_candidate_count(active_connected as u64, active_unconnected as u64); + metrics.record_candidate_count_in_implicit_view(candidates_in_implicit_view as u64); } - metrics.record_candidate_storage_size( - connected_candidates_count as u64, - live_candidates.len().saturating_sub(connected_candidates_count) as u64, - ); + let num_active_leaves = view.active_leaves.len() as u64; + let num_inactive_leaves = + (view.per_relay_parent.len() as u64).saturating_sub(num_active_leaves); + metrics.record_leaves_count(num_active_leaves, num_inactive_leaves); + + Ok(()) } struct ImportablePendingAvailability { candidate: CommittedCandidateReceipt, persisted_validation_data: PersistedValidationData, - compact: crate::fragment_chain::PendingAvailability, + compact: fragment_chain::PendingAvailability, } #[overseer::contextbounds(ProspectiveParachains, prefix = self::overseer)] @@ -435,9 +480,9 @@ async fn preprocess_candidates_pending_availability( relay_parent_number: relay_parent.number, relay_parent_storage_root: relay_parent.storage_root, }, - compact: crate::fragment_chain::PendingAvailability { + compact: fragment_chain::PendingAvailability { candidate_hash: pending.candidate_hash, - relay_parent, + relay_parent: relay_parent.into(), }, }); @@ -447,9 +492,7 @@ async fn preprocess_candidates_pending_availability( Ok(importable) } -#[overseer::contextbounds(ProspectiveParachains, prefix = self::overseer)] -async fn handle_introduce_seconded_candidate( - _ctx: &mut Context, +async fn handle_introduce_seconded_candidate( view: &mut View, request: IntroduceSecondedCandidateRequest, tx: oneshot::Sender, @@ -463,167 +506,163 @@ async fn handle_introduce_seconded_candidate( persisted_validation_data: pvd, } = request; - let Some(storage) = view.candidate_storage.get_mut(¶) else { - gum::warn!( - target: LOG_TARGET, - para_id = ?para, - candidate_hash = ?candidate.hash(), - "Received seconded candidate for inactive para", - ); + let candidate_hash = candidate.hash(); + let candidate_entry = match CandidateEntry::new_seconded(candidate_hash, candidate, pvd) { + Ok(candidate) => candidate, + Err(err) => { + gum::warn!( + target: LOG_TARGET, + para = ?para, + "Cannot add seconded candidate: {}", + err + ); - let _ = tx.send(false); - return + let _ = tx.send(false); + return + }, }; - let parent_head_hash = pvd.parent_head.hash(); - let output_head_hash = Some(candidate.commitments.head_data.hash()); + let mut added = false; + let mut para_scheduled = false; + // We don't iterate only through the active leaves. We also update the deactivated parents in + // the implicit view, so that their upcoming children may see these candidates. + for (relay_parent, rp_data) in view.per_relay_parent.iter_mut() { + let Some(chain) = rp_data.fragment_chains.get_mut(¶) else { continue }; + let is_active_leaf = view.active_leaves.contains(relay_parent); - // We first introduce the candidate in the storage and then try to extend the chain. - // If the candidate gets included in the chain, we can keep it in storage. - // If it doesn't, check that it's still a potential candidate in at least one fragment chain. - // If it's not, we can remove it. + para_scheduled = true; - let candidate_hash = - match storage.add_candidate(candidate.clone(), pvd, CandidateState::Seconded) { - Ok(c) => c, - Err(CandidateStorageInsertionError::CandidateAlreadyKnown(_)) => { + match chain.try_adding_seconded_candidate(&candidate_entry) { + Ok(()) => { gum::debug!( target: LOG_TARGET, - para = ?para, - "Attempting to introduce an already known candidate: {:?}", - candidate.hash() + ?para, + ?relay_parent, + ?is_active_leaf, + "Added seconded candidate {:?}", + candidate_hash ); - // Candidate already known. - let _ = tx.send(true); - return + added = true; }, - Err(CandidateStorageInsertionError::PersistedValidationDataMismatch) => { - // We can't log the candidate hash without either doing more ~expensive - // hashing but this branch indicates something is seriously wrong elsewhere - // so it's doubtful that it would affect debugging. - - gum::warn!( + Err(FragmentChainError::CandidateAlreadyKnown) => { + gum::debug!( target: LOG_TARGET, - para = ?para, - "Received seconded candidate had mismatching validation data", + ?para, + ?relay_parent, + ?is_active_leaf, + "Attempting to introduce an already known candidate: {:?}", + candidate_hash ); - - let _ = tx.send(false); - return + added = true; }, - }; - - let mut keep_in_storage = false; - for (relay_parent, leaf_data) in view.active_leaves.iter_mut() { - if let Some(chain) = leaf_data.fragment_chains.get_mut(¶) { - gum::trace!( - target: LOG_TARGET, - para = ?para, - ?relay_parent, - "Candidates in chain before trying to introduce a new one: {:?}", - chain.to_vec() - ); - chain.extend_from_storage(&*storage); - if chain.contains_candidate(&candidate_hash) { - keep_in_storage = true; - - gum::trace!( + Err(err) => { + gum::debug!( target: LOG_TARGET, + ?para, ?relay_parent, - para = ?para, ?candidate_hash, - "Added candidate to chain.", - ); - } else { - match chain.can_add_candidate_as_potential( - &storage, - &candidate_hash, - &candidate.descriptor.relay_parent, - parent_head_hash, - output_head_hash, - ) { - PotentialAddition::Anyhow => { - gum::trace!( - target: LOG_TARGET, - para = ?para, - ?relay_parent, - ?candidate_hash, - "Kept candidate as unconnected potential.", - ); - - keep_in_storage = true; - }, - _ => { - gum::trace!( - target: LOG_TARGET, - para = ?para, - ?relay_parent, - "Not introducing a new candidate: {:?}", - candidate_hash - ); - }, - } - } + ?is_active_leaf, + "Cannot introduce seconded candidate: {}", + err + ) + }, } } - // If there is at least one leaf where this candidate can be added or potentially added in the - // future, keep it in storage. - if !keep_in_storage { - storage.remove_candidate(&candidate_hash); + if !para_scheduled { + gum::warn!( + target: LOG_TARGET, + para_id = ?para, + ?candidate_hash, + "Received seconded candidate for inactive para", + ); + } + if !added { gum::debug!( target: LOG_TARGET, para = ?para, candidate = ?candidate_hash, - "Newly-seconded candidate cannot be kept under any active leaf", + "Newly-seconded candidate cannot be kept under any relay parent", ); } - let _ = tx.send(keep_in_storage); + let _ = tx.send(added); } -#[overseer::contextbounds(ProspectiveParachains, prefix = self::overseer)] -async fn handle_candidate_backed( - _ctx: &mut Context, +async fn handle_candidate_backed( view: &mut View, para: ParaId, candidate_hash: CandidateHash, + metrics: &Metrics, ) { - let Some(storage) = view.candidate_storage.get_mut(¶) else { - gum::warn!( - target: LOG_TARGET, - para_id = ?para, - ?candidate_hash, - "Received instruction to back a candidate for unscheduled para", - ); + let _timer = metrics.time_candidate_backed(); - return - }; + let mut found_candidate = false; + let mut found_para = false; + + // We don't iterate only through the active leaves. We also update the deactivated parents in + // the implicit view, so that their upcoming children may see these candidates. + for (relay_parent, rp_data) in view.per_relay_parent.iter_mut() { + let Some(chain) = rp_data.fragment_chains.get_mut(¶) else { continue }; + let is_active_leaf = view.active_leaves.contains(relay_parent); + + found_para = true; + if chain.is_candidate_backed(&candidate_hash) { + gum::debug!( + target: LOG_TARGET, + ?para, + ?candidate_hash, + ?is_active_leaf, + "Received redundant instruction to mark as backed an already backed candidate", + ); + found_candidate = true; + } else if chain.contains_unconnected_candidate(&candidate_hash) { + found_candidate = true; + // Mark the candidate as backed. This can recreate the fragment chain. + chain.candidate_backed(&candidate_hash); + + gum::trace!( + target: LOG_TARGET, + ?relay_parent, + ?para, + ?is_active_leaf, + "Candidate backed. Candidate chain for para: {:?}", + chain.best_chain_vec() + ); + + gum::trace!( + target: LOG_TARGET, + ?relay_parent, + ?para, + ?is_active_leaf, + "Potential candidate storage for para: {:?}", + chain.unconnected().map(|candidate| candidate.hash()).collect::>() + ); + } + } - if !storage.contains(&candidate_hash) { + if !found_para { gum::warn!( target: LOG_TARGET, - para_id = ?para, + ?para, ?candidate_hash, - "Received instruction to back unknown candidate", + "Received instruction to back a candidate for unscheduled para", ); return } - if storage.is_backed(&candidate_hash) { + if !found_candidate { + // This can be harmless. It can happen if we received a better backed candidate before and + // dropped this other candidate already. gum::debug!( target: LOG_TARGET, - para_id = ?para, + ?para, ?candidate_hash, - "Received redundant instruction to mark candidate as backed", + "Received instruction to back unknown candidate", ); - - return } - - storage.mark_backed(&candidate_hash); } fn answer_get_backable_candidates( @@ -634,7 +673,7 @@ fn answer_get_backable_candidates( ancestors: Ancestors, tx: oneshot::Sender>, ) { - let Some(data) = view.active_leaves.get(&relay_parent) else { + if !view.active_leaves.contains(&relay_parent) { gum::debug!( target: LOG_TARGET, ?relay_parent, @@ -644,26 +683,25 @@ fn answer_get_backable_candidates( let _ = tx.send(vec![]); return - }; - - let Some(chain) = data.fragment_chains.get(¶) else { + } + let Some(data) = view.per_relay_parent.get(&relay_parent) else { gum::debug!( target: LOG_TARGET, ?relay_parent, para_id = ?para, - "Requested backable candidate for inactive para." + "Requested backable candidate for inexistent relay-parent." ); let _ = tx.send(vec![]); return }; - let Some(storage) = view.candidate_storage.get(¶) else { - gum::warn!( + let Some(chain) = data.fragment_chains.get(¶) else { + gum::debug!( target: LOG_TARGET, ?relay_parent, para_id = ?para, - "No candidate storage for active para", + "Requested backable candidate for inactive para." ); let _ = tx.send(vec![]); @@ -674,38 +712,19 @@ fn answer_get_backable_candidates( target: LOG_TARGET, ?relay_parent, para_id = ?para, - "Candidate storage for para: {:?}", - storage.candidates().map(|candidate| candidate.hash()).collect::>() + "Candidate chain for para: {:?}", + chain.best_chain_vec() ); gum::trace!( target: LOG_TARGET, ?relay_parent, para_id = ?para, - "Candidate chain for para: {:?}", - chain.to_vec() + "Potential candidate storage for para: {:?}", + chain.unconnected().map(|candidate| candidate.hash()).collect::>() ); - let backable_candidates: Vec<_> = chain - .find_backable_chain(ancestors.clone(), count, |candidate| storage.is_backed(candidate)) - .into_iter() - .filter_map(|child_hash| { - storage.relay_parent_of_candidate(&child_hash).map_or_else( - || { - // Here, we'd actually need to trim all of the candidates that follow. Or - // not, the runtime will do this. Impossible scenario anyway. - gum::error!( - target: LOG_TARGET, - ?child_hash, - para_id = ?para, - "Candidate is present in fragment chain but not in candidate's storage!", - ); - None - }, - |parent_hash| Some((child_hash, parent_hash)), - ) - }) - .collect(); + let backable_candidates = chain.find_backable_chain(ancestors.clone(), count); if backable_candidates.is_empty() { gum::trace!( @@ -742,19 +761,32 @@ fn answer_hypothetical_membership_request( } let required_active_leaf = request.fragment_chain_relay_parent; - for (active_leaf, leaf_view) in view + for active_leaf in view .active_leaves .iter() - .filter(|(h, _)| required_active_leaf.as_ref().map_or(true, |x| h == &x)) + .filter(|h| required_active_leaf.as_ref().map_or(true, |x| h == &x)) { + let Some(leaf_view) = view.per_relay_parent.get(&active_leaf) else { continue }; for &mut (ref candidate, ref mut membership) in &mut response { let para_id = &candidate.candidate_para(); let Some(fragment_chain) = leaf_view.fragment_chains.get(para_id) else { continue }; - let Some(candidate_storage) = view.candidate_storage.get(para_id) else { continue }; - if fragment_chain.hypothetical_membership(candidate.clone(), candidate_storage) { - membership.push(*active_leaf); - } + let res = fragment_chain.can_add_candidate_as_potential(candidate); + match res { + Err(FragmentChainError::CandidateAlreadyKnown) | Ok(()) => { + membership.push(*active_leaf); + }, + Err(err) => { + gum::debug!( + target: LOG_TARGET, + para = ?para_id, + leaf = ?active_leaf, + candidate = ?candidate.candidate_hash(), + "Candidate is not a hypothetical member: {}", + err + ) + }, + }; } } @@ -767,9 +799,11 @@ fn answer_minimum_relay_parents_request( tx: oneshot::Sender>, ) { let mut v = Vec::new(); - if let Some(leaf_data) = view.active_leaves.get(&relay_parent) { - for (para_id, fragment_chain) in &leaf_data.fragment_chains { - v.push((*para_id, fragment_chain.scope().earliest_relay_parent().number)); + if view.active_leaves.contains(&relay_parent) { + if let Some(leaf_data) = view.per_relay_parent.get(&relay_parent) { + for (para_id, fragment_chain) in &leaf_data.fragment_chains { + v.push((*para_id, fragment_chain.scope().earliest_relay_parent().number)); + } } } @@ -781,37 +815,21 @@ fn answer_prospective_validation_data_request( request: ProspectiveValidationDataRequest, tx: oneshot::Sender>, ) { - // 1. Try to get the head-data from the candidate store if known. - // 2. Otherwise, it might exist as the base in some relay-parent and we can find it by iterating - // fragment chains. - // 3. Otherwise, it is unknown. - // 4. Also try to find the relay parent block info by scanning fragment chains. - // 5. If head data and relay parent block info are found - success. Otherwise, failure. - - let storage = match view.candidate_storage.get(&request.para_id) { - None => { - let _ = tx.send(None); - return - }, - Some(s) => s, - }; + // Try getting the needed data from any fragment chain. let (mut head_data, parent_head_data_hash) = match request.parent_head_data { - ParentHeadData::OnlyHash(parent_head_data_hash) => ( - storage.head_data_by_hash(&parent_head_data_hash).map(|x| x.clone()), - parent_head_data_hash, - ), + ParentHeadData::OnlyHash(parent_head_data_hash) => (None, parent_head_data_hash), ParentHeadData::WithData { head_data, hash } => (Some(head_data), hash), }; let mut relay_parent_info = None; let mut max_pov_size = None; - for fragment_chain in view - .active_leaves - .values() - .filter_map(|x| x.fragment_chains.get(&request.para_id)) - { + for fragment_chain in view.active_leaves.iter().filter_map(|x| { + view.per_relay_parent + .get(&x) + .and_then(|data| data.fragment_chains.get(&request.para_id)) + }) { if head_data.is_some() && relay_parent_info.is_some() && max_pov_size.is_some() { break } @@ -819,10 +837,7 @@ fn answer_prospective_validation_data_request( relay_parent_info = fragment_chain.scope().ancestor(&request.candidate_relay_parent); } if head_data.is_none() { - let required_parent = &fragment_chain.scope().base_constraints().required_parent; - if required_parent.hash() == parent_head_data_hash { - head_data = Some(required_parent.clone()); - } + head_data = fragment_chain.get_head_data_by_hash(&parent_head_data_hash); } if max_pov_size.is_none() { let contains_ancestor = @@ -925,7 +940,7 @@ async fn fetch_ancestry( cache: &mut HashMap, relay_hash: Hash, ancestors: usize, -) -> JfyiErrorResult> { +) -> JfyiErrorResult> { if ancestors == 0 { return Ok(Vec::new()) } @@ -1004,12 +1019,13 @@ async fn fetch_block_info( ctx: &mut Context, cache: &mut HashMap, relay_hash: Hash, -) -> JfyiErrorResult> { +) -> JfyiErrorResult> { let header = fetch_block_header_with_cache(ctx, cache, relay_hash).await?; - Ok(header.map(|header| RelayChainBlockInfo { + Ok(header.map(|header| BlockInfo { hash: relay_hash, number: header.number, + parent_hash: header.parent_hash, storage_root: header.state_root, })) } diff --git a/polkadot/node/core/prospective-parachains/src/metrics.rs b/polkadot/node/core/prospective-parachains/src/metrics.rs index 5abd9f56f306cdad515b93c794a51de516417b88..78561bc878ac8f76b54ac772a65469f5c06a4c0a 100644 --- a/polkadot/node/core/prospective-parachains/src/metrics.rs +++ b/polkadot/node/core/prospective-parachains/src/metrics.rs @@ -17,15 +17,18 @@ use polkadot_node_subsystem::prometheus::Opts; use polkadot_node_subsystem_util::metrics::{ self, - prometheus::{self, GaugeVec, U64}, + prometheus::{self, Gauge, GaugeVec, U64}, }; #[derive(Clone)] pub(crate) struct MetricsInner { - prune_view_candidate_storage: prometheus::Histogram, - introduce_seconded_candidate: prometheus::Histogram, - hypothetical_membership: prometheus::Histogram, - candidate_storage_count: prometheus::GaugeVec, + time_active_leaves_update: prometheus::Histogram, + time_introduce_seconded_candidate: prometheus::Histogram, + time_candidate_backed: prometheus::Histogram, + time_hypothetical_membership: prometheus::Histogram, + candidate_count: prometheus::GaugeVec, + active_leaves_count: prometheus::GaugeVec, + implicit_view_candidate_count: prometheus::Gauge, } /// Candidate backing metrics. @@ -33,13 +36,11 @@ pub(crate) struct MetricsInner { pub struct Metrics(pub(crate) Option); impl Metrics { - /// Provide a timer for handling `prune_view_candidate_storage` which observes on drop. - pub fn time_prune_view_candidate_storage( + /// Provide a timer for handling `ActiveLeavesUpdate` which observes on drop. + pub fn time_handle_active_leaves_update( &self, ) -> Option { - self.0 - .as_ref() - .map(|metrics| metrics.prune_view_candidate_storage.start_timer()) + self.0.as_ref().map(|metrics| metrics.time_active_leaves_update.start_timer()) } /// Provide a timer for handling `IntroduceSecondedCandidate` which observes on drop. @@ -48,31 +49,47 @@ impl Metrics { ) -> Option { self.0 .as_ref() - .map(|metrics| metrics.introduce_seconded_candidate.start_timer()) + .map(|metrics| metrics.time_introduce_seconded_candidate.start_timer()) + } + + /// Provide a timer for handling `CandidateBacked` which observes on drop. + pub fn time_candidate_backed(&self) -> Option { + self.0.as_ref().map(|metrics| metrics.time_candidate_backed.start_timer()) } /// Provide a timer for handling `GetHypotheticalMembership` which observes on drop. pub fn time_hypothetical_membership_request( &self, ) -> Option { - self.0.as_ref().map(|metrics| metrics.hypothetical_membership.start_timer()) + self.0 + .as_ref() + .map(|metrics| metrics.time_hypothetical_membership.start_timer()) } - /// Record the size of the candidate storage. First param is the connected candidates count, - /// second param is the unconnected candidates count. - pub fn record_candidate_storage_size(&self, connected_count: u64, unconnected_count: u64) { + /// Record number of candidates across all fragment chains. First param is the connected + /// candidates count, second param is the unconnected candidates count. + pub fn record_candidate_count(&self, connected_count: u64, unconnected_count: u64) { self.0.as_ref().map(|metrics| { + metrics.candidate_count.with_label_values(&["connected"]).set(connected_count); metrics - .candidate_storage_count - .with_label_values(&["connected"]) - .set(connected_count) + .candidate_count + .with_label_values(&["unconnected"]) + .set(unconnected_count); }); + } + /// Record the number of candidates present in the implicit view of the subsystem. + pub fn record_candidate_count_in_implicit_view(&self, count: u64) { self.0.as_ref().map(|metrics| { - metrics - .candidate_storage_count - .with_label_values(&["unconnected"]) - .set(unconnected_count) + metrics.implicit_view_candidate_count.set(count); + }); + } + + /// Record the number of active/inactive leaves kept by the subsystem. + pub fn record_leaves_count(&self, active_count: u64, inactive_count: u64) { + self.0.as_ref().map(|metrics| { + metrics.active_leaves_count.with_label_values(&["active"]).set(active_count); + metrics.active_leaves_count.with_label_values(&["inactive"]).set(inactive_count); }); } } @@ -80,37 +97,61 @@ impl Metrics { impl metrics::Metrics for Metrics { fn try_register(registry: &prometheus::Registry) -> Result { let metrics = MetricsInner { - prune_view_candidate_storage: prometheus::register( + time_active_leaves_update: prometheus::register( prometheus::Histogram::with_opts(prometheus::HistogramOpts::new( - "polkadot_parachain_prospective_parachains_prune_view_candidate_storage", - "Time spent within `prospective_parachains::prune_view_candidate_storage`", + "polkadot_parachain_prospective_parachains_time_active_leaves_update", + "Time spent within `prospective_parachains::handle_active_leaves_update`", ))?, registry, )?, - introduce_seconded_candidate: prometheus::register( + time_introduce_seconded_candidate: prometheus::register( prometheus::Histogram::with_opts(prometheus::HistogramOpts::new( - "polkadot_parachain_prospective_parachains_introduce_seconded_candidate", + "polkadot_parachain_prospective_parachains_time_introduce_seconded_candidate", "Time spent within `prospective_parachains::handle_introduce_seconded_candidate`", ))?, registry, )?, - hypothetical_membership: prometheus::register( + time_candidate_backed: prometheus::register( prometheus::Histogram::with_opts(prometheus::HistogramOpts::new( - "polkadot_parachain_prospective_parachains_hypothetical_membership", + "polkadot_parachain_prospective_parachains_time_candidate_backed", + "Time spent within `prospective_parachains::handle_candidate_backed`", + ))?, + registry, + )?, + time_hypothetical_membership: prometheus::register( + prometheus::Histogram::with_opts(prometheus::HistogramOpts::new( + "polkadot_parachain_prospective_parachains_time_hypothetical_membership", "Time spent responding to `GetHypotheticalMembership`", ))?, registry, )?, - candidate_storage_count: prometheus::register( + candidate_count: prometheus::register( GaugeVec::new( Opts::new( - "polkadot_parachain_prospective_parachains_candidate_storage_count", - "Number of candidates present in the candidate storage, split by connected and unconnected" + "polkadot_parachain_prospective_parachains_candidate_count", + "Number of candidates present across all fragment chains, split by connected and unconnected" ), &["type"], )?, registry, )?, + active_leaves_count: prometheus::register( + GaugeVec::new( + Opts::new( + "polkadot_parachain_prospective_parachains_active_leaves_count", + "Number of leaves kept by the subsystem, split by active/inactive" + ), + &["type"], + )?, + registry, + )?, + implicit_view_candidate_count: prometheus::register( + Gauge::new( + "polkadot_parachain_prospective_parachains_implicit_view_candidate_count", + "Number of candidates present in the implicit view" + )?, + registry + )?, }; Ok(Metrics(Some(metrics))) } diff --git a/polkadot/node/core/prospective-parachains/src/tests.rs b/polkadot/node/core/prospective-parachains/src/tests.rs index 221fbf4c4e60365855b24bcfff7d89cfbcc6d205..14a093239e8ecbaa1fd6c4e3c294fddb21795af7 100644 --- a/polkadot/node/core/prospective-parachains/src/tests.rs +++ b/polkadot/node/core/prospective-parachains/src/tests.rs @@ -111,6 +111,8 @@ fn get_parent_hash(hash: Hash) -> Hash { fn test_harness>( test: impl FnOnce(VirtualOverseer) -> T, ) -> View { + sp_tracing::init_for_tests(); + let pool = sp_core::testing::TaskExecutor::new(); let (mut context, virtual_overseer) = @@ -203,6 +205,32 @@ async fn activate_leaf( activate_leaf_with_params(virtual_overseer, leaf, test_state, ASYNC_BACKING_PARAMETERS).await; } +async fn activate_leaf_with_parent_hash_fn( + virtual_overseer: &mut VirtualOverseer, + leaf: &TestLeaf, + test_state: &TestState, + parent_hash_fn: impl Fn(Hash) -> Hash, +) { + let TestLeaf { number, hash, .. } = leaf; + + let activated = new_leaf(*hash, *number); + + virtual_overseer + .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work( + activated, + )))) + .await; + + handle_leaf_activation( + virtual_overseer, + leaf, + test_state, + ASYNC_BACKING_PARAMETERS, + parent_hash_fn, + ) + .await; +} + async fn activate_leaf_with_params( virtual_overseer: &mut VirtualOverseer, leaf: &TestLeaf, @@ -219,7 +247,14 @@ async fn activate_leaf_with_params( )))) .await; - handle_leaf_activation(virtual_overseer, leaf, test_state, async_backing_params).await; + handle_leaf_activation( + virtual_overseer, + leaf, + test_state, + async_backing_params, + get_parent_hash, + ) + .await; } async fn handle_leaf_activation( @@ -227,6 +262,7 @@ async fn handle_leaf_activation( leaf: &TestLeaf, test_state: &TestState, async_backing_params: AsyncBackingParams, + parent_hash_fn: impl Fn(Hash) -> Hash, ) { let TestLeaf { number, hash, para_data } = leaf; @@ -281,7 +317,7 @@ async fn handle_leaf_activation( let min_min = para_data.iter().map(|(_, data)| data.min_relay_parent).min().unwrap_or(*number); let ancestry_len = number - min_min; let ancestry_hashes: Vec = - std::iter::successors(Some(*hash), |h| Some(get_parent_hash(*h))) + std::iter::successors(Some(*hash), |h| Some(parent_hash_fn(*h))) .skip(1) .take(ancestry_len as usize) .collect(); @@ -307,16 +343,20 @@ async fn handle_leaf_activation( ); } + let mut used_relay_parents = HashSet::new(); for (hash, number) in ancestry_iter { - send_block_header(virtual_overseer, hash, number).await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionIndexForChild(tx)) - ) if parent == hash => { - tx.send(Ok(1)).unwrap(); - } - ); + if !used_relay_parents.contains(&hash) { + send_block_header(virtual_overseer, hash, number).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionIndexForChild(tx)) + ) if parent == hash => { + tx.send(Ok(1)).unwrap(); + } + ); + used_relay_parents.insert(hash); + } } let paras: HashSet<_> = test_state.claim_queue.values().flatten().collect(); @@ -353,12 +393,16 @@ async fn handle_leaf_activation( ); for pending in pending_availability { - send_block_header( - virtual_overseer, - pending.descriptor.relay_parent, - pending.relay_parent_number, - ) - .await; + if !used_relay_parents.contains(&pending.descriptor.relay_parent) { + send_block_header( + virtual_overseer, + pending.descriptor.relay_parent, + pending.relay_parent_number, + ) + .await; + + used_relay_parents.insert(pending.descriptor.relay_parent); + } } } @@ -513,6 +557,26 @@ async fn get_pvd( assert_eq!(resp, expected_pvd); } +macro_rules! make_and_back_candidate { + ($test_state:ident, $virtual_overseer:ident, $leaf:ident, $parent:expr, $index:expr) => {{ + let (mut candidate, pvd) = make_candidate( + $leaf.hash, + $leaf.number, + 1.into(), + $parent.commitments.head_data.clone(), + HeadData(vec![$index]), + $test_state.validation_code_hash, + ); + // Set a field to make this candidate unique. + candidate.descriptor.para_head = Hash::from_low_u64_le($index); + let candidate_hash = candidate.hash(); + introduce_seconded_candidate(&mut $virtual_overseer, candidate.clone(), pvd).await; + back_candidate(&mut $virtual_overseer, &candidate, candidate_hash).await; + + (candidate, candidate_hash) + }}; +} + #[test] fn should_do_no_work_if_async_backing_disabled_for_leaf() { async fn activate_leaf_async_backing_disabled(virtual_overseer: &mut VirtualOverseer) { @@ -542,7 +606,6 @@ fn should_do_no_work_if_async_backing_disabled_for_leaf() { }); assert!(view.active_leaves.is_empty()); - assert!(view.candidate_storage.is_empty()); } // Send some candidates and make sure all are found: @@ -718,10 +781,6 @@ fn introduce_candidates_basic() { }); assert_eq!(view.active_leaves.len(), 3); - assert_eq!(view.candidate_storage.len(), 2); - // Two parents and two candidates per para. - assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (2, 2)); - assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (2, 2)); } #[test] @@ -766,28 +825,36 @@ fn introduce_candidate_multiple_times() { 1.into(), Ancestors::default(), 5, - response_a, + response_a.clone(), ) .await; - // Introduce the same candidate multiple times. It'll return true but it won't be added. - // We'll check below that the candidate count remains 1. + // Introduce the same candidate multiple times. It'll return true but it will only be added + // once. for _ in 0..5 { introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a.clone()) .await; } + // Check candidate tree membership. + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + Ancestors::default(), + 5, + response_a, + ) + .await; + virtual_overseer }); assert_eq!(view.active_leaves.len(), 1); - assert_eq!(view.candidate_storage.len(), 2); - assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (1, 1)); - assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (0, 0)); } #[test] -fn fragment_chain_length_is_bounded() { +fn fragment_chain_best_chain_length_is_bounded() { let test_state = TestState::default(); let view = test_harness(|mut virtual_overseer| async move { // Leaf A @@ -835,12 +902,11 @@ fn fragment_chain_length_is_bounded() { ); // Introduce candidates A and B. Since max depth is 1, only these two will be allowed. - introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a.clone()) - .await; - introduce_seconded_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b.clone()) - .await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a).await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b).await; - // Back candidates. Otherwise, we cannot check membership with GetBackableCandidates. + // Back candidates. Otherwise, we cannot check membership with GetBackableCandidates and + // they won't be part of the best chain. back_candidate(&mut virtual_overseer, &candidate_a, candidate_a.hash()).await; back_candidate(&mut virtual_overseer, &candidate_b, candidate_b.hash()).await; @@ -855,103 +921,25 @@ fn fragment_chain_length_is_bounded() { ) .await; - // Introducing C will fail. - introduce_seconded_candidate_failed(&mut virtual_overseer, candidate_c, pvd_c.clone()) - .await; - - virtual_overseer - }); - - assert_eq!(view.active_leaves.len(), 1); - assert_eq!(view.candidate_storage.len(), 2); - assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (2, 2)); - assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (0, 0)); -} - -#[test] -fn unconnected_candidate_count_is_bounded() { - let test_state = TestState::default(); - let view = test_harness(|mut virtual_overseer| async move { - // Leaf A - let leaf_a = TestLeaf { - number: 100, - hash: Hash::from_low_u64_be(130), - para_data: vec![ - (1.into(), PerParaData::new(97, HeadData(vec![1, 2, 3]))), - (2.into(), PerParaData::new(100, HeadData(vec![2, 3, 4]))), - ], - }; - // Activate leaves. - activate_leaf_with_params( - &mut virtual_overseer, - &leaf_a, - &test_state, - AsyncBackingParams { max_candidate_depth: 1, allowed_ancestry_len: 3 }, - ) - .await; - - // Candidates A, B and C are all potential candidates but don't form a chain. - let (candidate_a, pvd_a) = make_candidate( - leaf_a.hash, - leaf_a.number, - 1.into(), - HeadData(vec![1]), - HeadData(vec![2]), - test_state.validation_code_hash, - ); - let (candidate_b, pvd_b) = make_candidate( - leaf_a.hash, - leaf_a.number, - 1.into(), - HeadData(vec![3]), - HeadData(vec![4]), - test_state.validation_code_hash, - ); - let (candidate_c, pvd_c) = make_candidate( - leaf_a.hash, - leaf_a.number, - 1.into(), - HeadData(vec![4]), - HeadData(vec![5]), - test_state.validation_code_hash, - ); - - // Introduce candidates A and B. Although max depth is 1 (which should allow for two - // candidates), only 1 is allowed, because the last candidate must be a connected candidate. - introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a.clone()) - .await; - introduce_seconded_candidate_failed( - &mut virtual_overseer, - candidate_b.clone(), - pvd_b.clone(), - ) - .await; - - // Back candidates. Otherwise, we cannot check membership with GetBackableCandidates. - back_candidate(&mut virtual_overseer, &candidate_a, candidate_a.hash()).await; + // Introducing C will not fail. It will be kept as unconnected storage. + introduce_seconded_candidate(&mut virtual_overseer, candidate_c.clone(), pvd_c).await; + // When being backed, candidate C will be dropped. + back_candidate(&mut virtual_overseer, &candidate_c, candidate_c.hash()).await; - // Check candidate tree membership. Should be empty. get_backable_candidates( &mut virtual_overseer, &leaf_a, 1.into(), Ancestors::default(), 5, - vec![], + vec![(candidate_a.hash(), leaf_a.hash), (candidate_b.hash(), leaf_a.hash)], ) .await; - // Introducing C will also fail. - introduce_seconded_candidate_failed(&mut virtual_overseer, candidate_c, pvd_c.clone()) - .await; - virtual_overseer }); assert_eq!(view.active_leaves.len(), 1); - assert_eq!(view.candidate_storage.len(), 2); - assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (1, 1)); - assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (0, 0)); } // Send some candidates, check if the candidate won't be found once its relay parent leaves the @@ -1178,7 +1166,6 @@ fn introduce_candidate_parent_leaving_view() { }); assert_eq!(view.active_leaves.len(), 0); - assert_eq!(view.candidate_storage.len(), 0); } // Introduce a candidate to multiple forks, see how the membership is returned. @@ -1249,13 +1236,12 @@ fn introduce_candidate_on_multiple_forks() { }); assert_eq!(view.active_leaves.len(), 2); - assert_eq!(view.candidate_storage.len(), 2); - assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (1, 1)); - assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (0, 0)); } #[test] fn unconnected_candidates_become_connected() { + // This doesn't test all the complicated cases with many unconnected candidates, as it's more + // extensively tested in the `fragment_chain::tests` module. let test_state = TestState::default(); let view = test_harness(|mut virtual_overseer| async move { // Leaf A @@ -1351,9 +1337,6 @@ fn unconnected_candidates_become_connected() { }); assert_eq!(view.active_leaves.len(), 1); - assert_eq!(view.candidate_storage.len(), 2); - assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (4, 4)); - assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (0, 0)); } // Backs some candidates and tests `GetBackableCandidates` when requesting a single candidate. @@ -1435,6 +1418,10 @@ fn check_backable_query_single_candidate() { back_candidate(&mut virtual_overseer, &candidate_a, candidate_hash_a).await; back_candidate(&mut virtual_overseer, &candidate_b, candidate_hash_b).await; + // Back an unknown candidate. It doesn't return anything but it's ignored. Will not have any + // effect on the backable candidates. + back_candidate(&mut virtual_overseer, &candidate_b, CandidateHash(Hash::random())).await; + // Should not get any backable candidates for the other para. get_backable_candidates( &mut virtual_overseer, @@ -1490,35 +1477,11 @@ fn check_backable_query_single_candidate() { }); assert_eq!(view.active_leaves.len(), 1); - assert_eq!(view.candidate_storage.len(), 2); - // Two parents and two candidates on para 1. - assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (2, 2)); - assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (0, 0)); } // Backs some candidates and tests `GetBackableCandidates` when requesting a multiple candidates. #[test] fn check_backable_query_multiple_candidates() { - macro_rules! make_and_back_candidate { - ($test_state:ident, $virtual_overseer:ident, $leaf:ident, $parent:expr, $index:expr) => {{ - let (mut candidate, pvd) = make_candidate( - $leaf.hash, - $leaf.number, - 1.into(), - $parent.commitments.head_data.clone(), - HeadData(vec![$index]), - $test_state.validation_code_hash, - ); - // Set a field to make this candidate unique. - candidate.descriptor.para_head = Hash::from_low_u64_le($index); - let candidate_hash = candidate.hash(); - introduce_seconded_candidate(&mut $virtual_overseer, candidate.clone(), pvd).await; - back_candidate(&mut $virtual_overseer, &candidate, candidate_hash).await; - - (candidate, candidate_hash) - }}; - } - let test_state = TestState::default(); let view = test_harness(|mut virtual_overseer| async move { // Leaf A @@ -1786,10 +1749,6 @@ fn check_backable_query_multiple_candidates() { }); assert_eq!(view.active_leaves.len(), 1); - assert_eq!(view.candidate_storage.len(), 2); - // 4 candidates on para 1. - assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (4, 4)); - assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (0, 0)); } // Test hypothetical membership query. @@ -1885,11 +1844,13 @@ fn check_hypothetical_membership_query() { introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a.clone()) .await; - // Get membership of candidates after adding A. C is not a potential candidate because we - // may only add one more candidate, which must be a connected candidate. - for (candidate, pvd) in - [(candidate_a.clone(), pvd_a.clone()), (candidate_b.clone(), pvd_b.clone())] - { + // Get membership of candidates after adding A. They all are still unconnected candidates + // (not part of the best backable chain). + for (candidate, pvd) in [ + (candidate_a.clone(), pvd_a.clone()), + (candidate_b.clone(), pvd_b.clone()), + (candidate_c.clone(), pvd_c.clone()), + ] { get_hypothetical_membership( &mut virtual_overseer, candidate.hash(), @@ -1900,14 +1861,24 @@ fn check_hypothetical_membership_query() { .await; } - get_hypothetical_membership( - &mut virtual_overseer, - candidate_c.hash(), - candidate_c.clone(), - pvd_c.clone(), - vec![], - ) - .await; + // Back A. Now A is part of the best chain the rest can be added as unconnected. + + back_candidate(&mut virtual_overseer, &candidate_a, candidate_a.hash()).await; + + for (candidate, pvd) in [ + (candidate_a.clone(), pvd_a.clone()), + (candidate_b.clone(), pvd_b.clone()), + (candidate_c.clone(), pvd_c.clone()), + ] { + get_hypothetical_membership( + &mut virtual_overseer, + candidate.hash(), + candidate, + pvd, + vec![leaf_a.hash, leaf_b.hash], + ) + .await; + } // Candidate D has invalid relay parent. let (candidate_d, pvd_d) = make_candidate( @@ -1920,14 +1891,17 @@ fn check_hypothetical_membership_query() { ); introduce_seconded_candidate_failed(&mut virtual_overseer, candidate_d, pvd_d).await; - // Add candidate B. + // Add candidate B and back it. introduce_seconded_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b.clone()) .await; + back_candidate(&mut virtual_overseer, &candidate_b, candidate_b.hash()).await; // Get membership of candidates after adding B. - for (candidate, pvd) in - [(candidate_a.clone(), pvd_a.clone()), (candidate_b.clone(), pvd_b.clone())] - { + for (candidate, pvd) in [ + (candidate_a.clone(), pvd_a.clone()), + (candidate_b.clone(), pvd_b.clone()), + (candidate_c.clone(), pvd_c.clone()), + ] { get_hypothetical_membership( &mut virtual_overseer, candidate.hash(), @@ -1938,24 +1912,10 @@ fn check_hypothetical_membership_query() { .await; } - get_hypothetical_membership( - &mut virtual_overseer, - candidate_c.hash(), - candidate_c.clone(), - pvd_c.clone(), - vec![], - ) - .await; - - // Add candidate C. It will fail because we have enough candidates for the configured depth. - introduce_seconded_candidate_failed(&mut virtual_overseer, candidate_c, pvd_c).await; - virtual_overseer }); assert_eq!(view.active_leaves.len(), 2); - assert_eq!(view.candidate_storage.len(), 2); - assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (2, 2)); } #[test] @@ -2005,6 +1965,16 @@ fn check_pvd_query() { test_state.validation_code_hash, ); + // Candidate E. + let (candidate_e, pvd_e) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![5]), + HeadData(vec![6]), + test_state.validation_code_hash, + ); + // Get pvd of candidate A before adding it. get_pvd( &mut virtual_overseer, @@ -2067,20 +2037,20 @@ fn check_pvd_query() { introduce_seconded_candidate(&mut virtual_overseer, candidate_c, pvd_c.clone()).await; // Get pvd of candidate C after adding it. - get_pvd( - &mut virtual_overseer, - 1.into(), - leaf_a.hash, - HeadData(vec![2]), - Some(pvd_c.clone()), - ) - .await; + get_pvd(&mut virtual_overseer, 1.into(), leaf_a.hash, HeadData(vec![2]), Some(pvd_c)).await; + + // Get pvd of candidate E before adding it. It won't be found, as we don't have its parent. + get_pvd(&mut virtual_overseer, 1.into(), leaf_a.hash, HeadData(vec![5]), None).await; + + // Add candidate E and check again. Should succeed this time. + introduce_seconded_candidate(&mut virtual_overseer, candidate_e, pvd_e.clone()).await; + + get_pvd(&mut virtual_overseer, 1.into(), leaf_a.hash, HeadData(vec![5]), Some(pvd_e)).await; virtual_overseer }); assert_eq!(view.active_leaves.len(), 1); - assert_eq!(view.candidate_storage.len(), 2); } // Test simultaneously activating and deactivating leaves, and simultaneously deactivating @@ -2150,6 +2120,7 @@ fn correctly_updates_leaves(#[case] runtime_api_version: u32) { &leaf_c, &test_state, ASYNC_BACKING_PARAMETERS, + get_parent_hash, ) .await; @@ -2171,13 +2142,6 @@ fn correctly_updates_leaves(#[case] runtime_api_version: u32) { virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update))) .await; - handle_leaf_activation( - &mut virtual_overseer, - &leaf_a, - &test_state, - ASYNC_BACKING_PARAMETERS, - ) - .await; // Remove the leaf again. Send some unnecessary hashes. let update = ActiveLeavesUpdate { @@ -2192,7 +2156,322 @@ fn correctly_updates_leaves(#[case] runtime_api_version: u32) { }); assert_eq!(view.active_leaves.len(), 0); - assert_eq!(view.candidate_storage.len(), 0); +} + +#[test] +fn handle_active_leaves_update_gets_candidates_from_parent() { + let para_id = ParaId::from(1); + let mut test_state = TestState::default(); + test_state.claim_queue = test_state + .claim_queue + .into_iter() + .filter(|(_, paras)| matches!(paras.front(), Some(para) if para == ¶_id)) + .collect(); + assert_eq!(test_state.claim_queue.len(), 1); + let view = test_harness(|mut virtual_overseer| async move { + // Leaf A + let leaf_a = TestLeaf { + number: 100, + hash: Hash::from_low_u64_be(130), + para_data: vec![(para_id, PerParaData::new(97, HeadData(vec![1, 2, 3])))], + }; + // Activate leaf A. + activate_leaf(&mut virtual_overseer, &leaf_a, &test_state).await; + + // Candidates A, B, C and D all form a chain + let (candidate_a, pvd_a) = make_candidate( + leaf_a.hash, + leaf_a.number, + para_id, + HeadData(vec![1, 2, 3]), + HeadData(vec![1]), + test_state.validation_code_hash, + ); + let candidate_hash_a = candidate_a.hash(); + introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a).await; + back_candidate(&mut virtual_overseer, &candidate_a, candidate_hash_a).await; + + let (candidate_b, candidate_hash_b) = + make_and_back_candidate!(test_state, virtual_overseer, leaf_a, &candidate_a, 2); + let (candidate_c, candidate_hash_c) = + make_and_back_candidate!(test_state, virtual_overseer, leaf_a, &candidate_b, 3); + let (candidate_d, candidate_hash_d) = + make_and_back_candidate!(test_state, virtual_overseer, leaf_a, &candidate_c, 4); + + let mut all_candidates_resp = vec![ + (candidate_hash_a, leaf_a.hash), + (candidate_hash_b, leaf_a.hash), + (candidate_hash_c, leaf_a.hash), + (candidate_hash_d, leaf_a.hash), + ]; + + // Check candidate tree membership. + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + para_id, + Ancestors::default(), + 5, + all_candidates_resp.clone(), + ) + .await; + + // Activate leaf B, which makes candidates A and B pending availability. + // Leaf B + let leaf_b = TestLeaf { + number: 101, + hash: Hash::from_low_u64_be(129), + para_data: vec![( + para_id, + PerParaData::new_with_pending( + 98, + HeadData(vec![1, 2, 3]), + vec![ + CandidatePendingAvailability { + candidate_hash: candidate_a.hash(), + descriptor: candidate_a.descriptor.clone(), + commitments: candidate_a.commitments.clone(), + relay_parent_number: leaf_a.number, + max_pov_size: MAX_POV_SIZE, + }, + CandidatePendingAvailability { + candidate_hash: candidate_b.hash(), + descriptor: candidate_b.descriptor.clone(), + commitments: candidate_b.commitments.clone(), + relay_parent_number: leaf_a.number, + max_pov_size: MAX_POV_SIZE, + }, + ], + ), + )], + }; + // Activate leaf B. + activate_leaf(&mut virtual_overseer, &leaf_b, &test_state).await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_b, + para_id, + Ancestors::default(), + 5, + vec![], + ) + .await; + + get_backable_candidates( + &mut virtual_overseer, + &leaf_b, + para_id, + [candidate_a.hash(), candidate_b.hash()].into_iter().collect(), + 5, + vec![(candidate_c.hash(), leaf_a.hash), (candidate_d.hash(), leaf_a.hash)], + ) + .await; + + get_backable_candidates( + &mut virtual_overseer, + &leaf_b, + para_id, + Ancestors::default(), + 5, + vec![], + ) + .await; + + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + para_id, + Ancestors::default(), + 5, + all_candidates_resp.clone(), + ) + .await; + + // Now deactivate leaf A. + deactivate_leaf(&mut virtual_overseer, leaf_a.hash).await; + + get_backable_candidates( + &mut virtual_overseer, + &leaf_b, + para_id, + Ancestors::default(), + 5, + vec![], + ) + .await; + + get_backable_candidates( + &mut virtual_overseer, + &leaf_b, + para_id, + [candidate_a.hash(), candidate_b.hash()].into_iter().collect(), + 5, + vec![(candidate_c.hash(), leaf_a.hash), (candidate_d.hash(), leaf_a.hash)], + ) + .await; + + // Now add leaf C, which will be a sibling (fork) of leaf B. It should also inherit the + // candidates of leaf A (their common parent). + let leaf_c = TestLeaf { + number: 101, + hash: Hash::from_low_u64_be(12), + para_data: vec![( + para_id, + PerParaData::new_with_pending(98, HeadData(vec![1, 2, 3]), vec![]), + )], + }; + + activate_leaf_with_parent_hash_fn(&mut virtual_overseer, &leaf_c, &test_state, |hash| { + if hash == leaf_c.hash { + leaf_a.hash + } else { + get_parent_hash(hash) + } + }) + .await; + + get_backable_candidates( + &mut virtual_overseer, + &leaf_b, + para_id, + [candidate_a.hash(), candidate_b.hash()].into_iter().collect(), + 5, + vec![(candidate_c.hash(), leaf_a.hash), (candidate_d.hash(), leaf_a.hash)], + ) + .await; + + get_backable_candidates( + &mut virtual_overseer, + &leaf_c, + para_id, + Ancestors::new(), + 5, + all_candidates_resp.clone(), + ) + .await; + + // Deactivate C and add another candidate that will be present on the deactivated parent A. + // When activating C again it should also get the new candidate. Deactivated leaves are + // still updated with new candidates. + deactivate_leaf(&mut virtual_overseer, leaf_c.hash).await; + + let (candidate_e, _) = + make_and_back_candidate!(test_state, virtual_overseer, leaf_a, &candidate_d, 5); + activate_leaf_with_parent_hash_fn(&mut virtual_overseer, &leaf_c, &test_state, |hash| { + if hash == leaf_c.hash { + leaf_a.hash + } else { + get_parent_hash(hash) + } + }) + .await; + + get_backable_candidates( + &mut virtual_overseer, + &leaf_b, + para_id, + [candidate_a.hash(), candidate_b.hash()].into_iter().collect(), + 5, + vec![ + (candidate_c.hash(), leaf_a.hash), + (candidate_d.hash(), leaf_a.hash), + (candidate_e.hash(), leaf_a.hash), + ], + ) + .await; + + all_candidates_resp.push((candidate_e.hash(), leaf_a.hash)); + get_backable_candidates( + &mut virtual_overseer, + &leaf_c, + para_id, + Ancestors::new(), + 5, + all_candidates_resp, + ) + .await; + + // Querying the backable candidates for deactivated leaf won't work. + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + para_id, + Ancestors::new(), + 5, + vec![], + ) + .await; + + virtual_overseer + }); + + assert_eq!(view.active_leaves.len(), 2); + assert_eq!(view.per_relay_parent.len(), 3); +} + +#[test] +fn handle_active_leaves_update_bounded_implicit_view() { + let para_id = ParaId::from(1); + let mut test_state = TestState::default(); + test_state.claim_queue = test_state + .claim_queue + .into_iter() + .filter(|(_, paras)| matches!(paras.front(), Some(para) if para == ¶_id)) + .collect(); + assert_eq!(test_state.claim_queue.len(), 1); + + let mut leaves = vec![TestLeaf { + number: 100, + hash: Hash::from_low_u64_be(130), + para_data: vec![( + para_id, + PerParaData::new(100 - ALLOWED_ANCESTRY_LEN, HeadData(vec![1, 2, 3])), + )], + }]; + + for index in 1..10 { + let prev_leaf = &leaves[index - 1]; + leaves.push(TestLeaf { + number: prev_leaf.number - 1, + hash: get_parent_hash(prev_leaf.hash), + para_data: vec![( + para_id, + PerParaData::new( + prev_leaf.number - 1 - ALLOWED_ANCESTRY_LEN, + HeadData(vec![1, 2, 3]), + ), + )], + }); + } + leaves.reverse(); + + let view = test_harness(|mut virtual_overseer| async { + // Activate first 10 leaves. + for leaf in &leaves[0..10] { + activate_leaf(&mut virtual_overseer, leaf, &test_state).await; + } + + // Now deactivate first 9 leaves. + for leaf in &leaves[0..9] { + deactivate_leaf(&mut virtual_overseer, leaf.hash).await; + } + + virtual_overseer + }); + + // Only latest leaf is active. + assert_eq!(view.active_leaves.len(), 1); + // We keep allowed_ancestry_len implicit leaves. The latest leaf is also present here. + assert_eq!( + view.per_relay_parent.len() as u32, + ASYNC_BACKING_PARAMETERS.allowed_ancestry_len + 1 + ); + + assert_eq!(view.active_leaves, [leaves[9].hash].into_iter().collect()); + assert_eq!( + view.per_relay_parent.into_keys().collect::>(), + leaves[6..].into_iter().map(|l| l.hash).collect::>() + ); } #[test] @@ -2251,7 +2530,8 @@ fn persists_pending_availability_candidate() { ); let candidate_hash_b = candidate_b.hash(); - introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a).await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a.clone()) + .await; back_candidate(&mut virtual_overseer, &candidate_a, candidate_hash_a).await; let candidate_a_pending_av = CandidatePendingAvailability { @@ -2275,6 +2555,15 @@ fn persists_pending_availability_candidate() { }; activate_leaf(&mut virtual_overseer, &leaf_b, &test_state).await; + get_hypothetical_membership( + &mut virtual_overseer, + candidate_hash_a, + candidate_a, + pvd_a, + vec![leaf_a.hash, leaf_b.hash], + ) + .await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b).await; back_candidate(&mut virtual_overseer, &candidate_b, candidate_hash_b).await; diff --git a/polkadot/node/core/provisioner/src/lib.rs b/polkadot/node/core/provisioner/src/lib.rs index 3f622a60a059bbdb3062a90bd93d2661ad96d326..ffc5859b7756cad5a2818138d6c8921a617f36ea 100644 --- a/polkadot/node/core/provisioner/src/lib.rs +++ b/polkadot/node/core/provisioner/src/lib.rs @@ -273,7 +273,7 @@ async fn handle_communication( let span = state.span.child("provisionable-data"); let _timer = metrics.time_provisionable_data(); - gum::trace!(target: LOG_TARGET, ?relay_parent, "Received provisionable data."); + gum::trace!(target: LOG_TARGET, ?relay_parent, "Received provisionable data: {:?}", &data); note_provisionable_data(state, &span, data); } @@ -794,9 +794,11 @@ async fn select_candidates( relay_parent: Hash, sender: &mut impl overseer::ProvisionerSenderTrait, ) -> Result, Error> { - gum::trace!(target: LOG_TARGET, + gum::trace!( + target: LOG_TARGET, leaf_hash=?relay_parent, - "before GetBackedCandidates"); + "before GetBackedCandidates" + ); let selected_candidates = match prospective_parachains_mode { ProspectiveParachainsMode::Enabled { .. } => diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index 7444f7927f568359fe2a33392468b1f38d1e400f..d603af04bf061fc16dfb00979e3aaf85b21adb60 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -60,7 +60,7 @@ 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 = { workspace = true, default-features = true } diff --git a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs index 97a03e6596d16e2d10219331e58dd2d19647b531..342128b7cca21d5fd00544062e1cb35ba4126239 100644 --- a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs +++ b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs @@ -116,7 +116,7 @@ fn host_prepare_rococo_runtime(c: &mut Criterion) { cfg.prepare_workers_hard_max_num = 1; }) .await, - pvf.clone().code(), + pvf.clone().maybe_compressed_code(), ) }, |result| async move { diff --git a/polkadot/node/core/pvf/common/Cargo.toml b/polkadot/node/core/pvf/common/Cargo.toml index 18b3f959c95513763addc9ddf4ff82783e5c1a02..bf663b4cfcea65847a8d2c2efed5191e7b640d9c 100644 --- a/polkadot/node/core/pvf/common/Cargo.toml +++ b/polkadot/node/core/pvf/common/Cargo.toml @@ -42,6 +42,8 @@ seccompiler = "0.4.0" [dev-dependencies] assert_matches = { workspace = true } + +[target.'cfg(target_os = "linux")'.dev-dependencies] tempfile = { workspace = true } [features] diff --git a/polkadot/node/core/pvf/common/src/error.rs b/polkadot/node/core/pvf/common/src/error.rs index 7ee05448d3c5cb64f54d8ed64dd865da1ad8c87a..b0cdba9501dbeec396c2262da8d02f2627992ed0 100644 --- a/polkadot/node/core/pvf/common/src/error.rs +++ b/polkadot/node/core/pvf/common/src/error.rs @@ -94,6 +94,10 @@ pub enum PrepareError { #[codec(index = 11)] #[error("prepare: error interfacing with the kernel: {0}")] Kernel(String), + /// Code blob failed to decompress + #[codec(index = 12)] + #[error("prepare: could not decompress code blob: {0}")] + CouldNotDecompressCodeBlob(String), } impl PrepareError { @@ -106,7 +110,11 @@ impl PrepareError { pub fn is_deterministic(&self) -> bool { use PrepareError::*; match self { - Prevalidation(_) | Preparation(_) | JobError(_) | OutOfMemory => true, + Prevalidation(_) | + Preparation(_) | + JobError(_) | + OutOfMemory | + CouldNotDecompressCodeBlob(_) => true, IoErr(_) | JobDied { .. } | CreateTmpFile(_) | diff --git a/polkadot/node/core/pvf/common/src/execute.rs b/polkadot/node/core/pvf/common/src/execute.rs index 46862f9f80b60324185363c595e221582ce53b1e..cff3f3b86e95265956ef935427a570e8565a7d7f 100644 --- a/polkadot/node/core/pvf/common/src/execute.rs +++ b/polkadot/node/core/pvf/common/src/execute.rs @@ -35,6 +35,8 @@ pub struct WorkerResponse { pub job_response: JobResponse, /// The amount of CPU time taken by the job. pub duration: Duration, + /// The uncompressed PoV size. + pub pov_size: u32, } /// An error occurred in the worker process. @@ -77,6 +79,8 @@ pub enum JobResponse { RuntimeConstruction(String), /// The candidate is invalid. InvalidCandidate(String), + /// PoV decompression failed + PoVDecompressionFailure, } impl JobResponse { diff --git a/polkadot/node/core/pvf/common/src/prepare.rs b/polkadot/node/core/pvf/common/src/prepare.rs index 81e165a7b8a499432b4b766b43b9400172ba5822..4cd1beb309918b1dedb7e3a0e7ee2dd03794c50d 100644 --- a/polkadot/node/core/pvf/common/src/prepare.rs +++ b/polkadot/node/core/pvf/common/src/prepare.rs @@ -44,6 +44,8 @@ pub struct PrepareStats { pub cpu_time_elapsed: std::time::Duration, /// The observed memory statistics for the preparation job. pub memory_stats: MemoryStats, + /// The decompressed Wasm code length observed during the preparation. + pub observed_wasm_code_len: u32, } /// Helper struct to contain all the memory stats, including `MemoryAllocationStats` and, if diff --git a/polkadot/node/core/pvf/common/src/pvf.rs b/polkadot/node/core/pvf/common/src/pvf.rs index e2ac36a2406ac28213107d1e0b42d8f215e04ea3..4019a8d8b0d0031a1a44b345b59124a994606d32 100644 --- a/polkadot/node/core/pvf/common/src/pvf.rs +++ b/polkadot/node/core/pvf/common/src/pvf.rs @@ -26,9 +26,9 @@ use std::{fmt, sync::Arc, time::Duration}; /// Should be cheap to clone. #[derive(Clone, Encode, Decode)] pub struct PvfPrepData { - /// Wasm code (uncompressed) - code: Arc>, - /// Wasm code hash + /// Wasm code (maybe compressed) + maybe_compressed_code: Arc>, + /// Wasm code hash. code_hash: ValidationCodeHash, /// Executor environment parameters for the session for which artifact is prepared executor_params: Arc, @@ -46,20 +46,20 @@ impl PvfPrepData { prep_timeout: Duration, prep_kind: PrepareJobKind, ) -> Self { - let code = Arc::new(code); - let code_hash = sp_crypto_hashing::blake2_256(&code).into(); + let maybe_compressed_code = Arc::new(code); + let code_hash = sp_crypto_hashing::blake2_256(&maybe_compressed_code).into(); let executor_params = Arc::new(executor_params); - Self { code, code_hash, executor_params, prep_timeout, prep_kind } + Self { maybe_compressed_code, code_hash, executor_params, prep_timeout, prep_kind } } - /// Returns validation code hash for the PVF + /// Returns validation code hash pub fn code_hash(&self) -> ValidationCodeHash { self.code_hash } - /// Returns PVF code - pub fn code(&self) -> Arc> { - self.code.clone() + /// Returns PVF code blob + pub fn maybe_compressed_code(&self) -> Arc> { + self.maybe_compressed_code.clone() } /// Returns executor params diff --git a/polkadot/node/core/pvf/execute-worker/Cargo.toml b/polkadot/node/core/pvf/execute-worker/Cargo.toml index f24b66dc4a0e8ba20f6b7a8205c7092a47c30245..6ad340d25612860f87469497c332079e11eda266 100644 --- a/polkadot/node/core/pvf/execute-worker/Cargo.toml +++ b/polkadot/node/core/pvf/execute-worker/Cargo.toml @@ -19,8 +19,11 @@ libc = { workspace = true } codec = { features = ["derive"], workspace = true } polkadot-node-core-pvf-common = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } polkadot-parachain-primitives = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } +sp-maybe-compressed-blob = { workspace = true, default-features = true } + [features] builder = [] diff --git a/polkadot/node/core/pvf/execute-worker/src/lib.rs b/polkadot/node/core/pvf/execute-worker/src/lib.rs index 35858ab36cec3fd2990403ae0afcf848e5cb317e..4b7c167cc9ec322f070e9e964fecc5b782d68063 100644 --- a/polkadot/node/core/pvf/execute-worker/src/lib.rs +++ b/polkadot/node/core/pvf/execute-worker/src/lib.rs @@ -22,6 +22,7 @@ pub use polkadot_node_core_pvf_common::{ error::ExecuteError, executor_interface::execute_artifact, }; +use polkadot_parachain_primitives::primitives::ValidationParams; // NOTE: Initializing logging in e.g. tests will not have an effect in the workers, as they are // separate spawned processes. Run with e.g. `RUST_LOG=parachain::pvf-execute-worker=trace`. @@ -50,8 +51,9 @@ use polkadot_node_core_pvf_common::{ }, worker_dir, }; +use polkadot_node_primitives::{BlockData, PoV, POV_BOMB_LIMIT}; use polkadot_parachain_primitives::primitives::ValidationResult; -use polkadot_primitives::ExecutorParams; +use polkadot_primitives::{ExecutorParams, PersistedValidationData}; use std::{ io::{self, Read}, os::{ @@ -85,8 +87,23 @@ fn recv_execute_handshake(stream: &mut UnixStream) -> io::Result { Ok(handshake) } -fn recv_request(stream: &mut UnixStream) -> io::Result<(Vec, Duration)> { - let params = framed_recv_blocking(stream)?; +fn recv_request(stream: &mut UnixStream) -> io::Result<(PersistedValidationData, PoV, Duration)> { + let pvd = framed_recv_blocking(stream)?; + let pvd = PersistedValidationData::decode(&mut &pvd[..]).map_err(|_| { + io::Error::new( + io::ErrorKind::Other, + "execute pvf recv_request: failed to decode persisted validation data".to_string(), + ) + })?; + + let pov = framed_recv_blocking(stream)?; + let pov = PoV::decode(&mut &pov[..]).map_err(|_| { + io::Error::new( + io::ErrorKind::Other, + "execute pvf recv_request: failed to decode PoV".to_string(), + ) + })?; + let execution_timeout = framed_recv_blocking(stream)?; let execution_timeout = Duration::decode(&mut &execution_timeout[..]).map_err(|_| { io::Error::new( @@ -94,7 +111,7 @@ fn recv_request(stream: &mut UnixStream) -> io::Result<(Vec, Duration)> { "execute pvf recv_request: failed to decode duration".to_string(), ) })?; - Ok((params, execution_timeout)) + Ok((pvd, pov, execution_timeout)) } /// Sends an error to the host and returns the original error wrapped in `io::Error`. @@ -149,7 +166,7 @@ pub fn worker_entrypoint( let execute_thread_stack_size = max_stack_size(&executor_params); loop { - let (params, execution_timeout) = recv_request(&mut stream).map_err(|e| { + let (pvd, pov, execution_timeout) = recv_request(&mut stream).map_err(|e| { map_and_send_err!( e, InternalValidationError::HostCommunication, @@ -197,7 +214,33 @@ pub fn worker_entrypoint( let stream_fd = stream.as_raw_fd(); let compiled_artifact_blob = Arc::new(compiled_artifact_blob); - let params = Arc::new(params); + + let raw_block_data = + match sp_maybe_compressed_blob::decompress(&pov.block_data.0, POV_BOMB_LIMIT) { + Ok(data) => data, + Err(_) => { + send_result::( + &mut stream, + Ok(WorkerResponse { + job_response: JobResponse::PoVDecompressionFailure, + duration: Duration::ZERO, + pov_size: 0, + }), + worker_info, + )?; + continue; + }, + }; + + let pov_size = raw_block_data.len() as u32; + + let params = ValidationParams { + parent_head: pvd.parent_head.clone(), + block_data: BlockData(raw_block_data.to_vec()), + relay_parent_number: pvd.relay_parent_number, + relay_parent_storage_root: pvd.relay_parent_storage_root, + }; + let params = Arc::new(params.encode()); cfg_if::cfg_if! { if #[cfg(target_os = "linux")] { @@ -214,6 +257,7 @@ pub fn worker_entrypoint( worker_info, security_status.can_unshare_user_namespace_and_change_root, usage_before, + pov_size, )? } else { // Fall back to using fork. @@ -228,6 +272,7 @@ pub fn worker_entrypoint( execute_thread_stack_size, worker_info, usage_before, + pov_size, )? }; } else { @@ -242,6 +287,7 @@ pub fn worker_entrypoint( execute_thread_stack_size, worker_info, usage_before, + pov_size, )?; } } @@ -300,6 +346,7 @@ fn handle_clone( worker_info: &WorkerInfo, have_unshare_newuser: bool, usage_before: Usage, + pov_size: u32, ) -> io::Result> { use polkadot_node_core_pvf_common::worker::security; @@ -329,6 +376,7 @@ fn handle_clone( worker_info, child, usage_before, + pov_size, execution_timeout, ), Err(security::clone::Error::Clone(errno)) => @@ -347,6 +395,7 @@ fn handle_fork( execute_worker_stack_size: usize, worker_info: &WorkerInfo, usage_before: Usage, + pov_size: u32, ) -> io::Result> { // SAFETY: new process is spawned within a single threaded process. This invariant // is enforced by tests. @@ -367,6 +416,7 @@ fn handle_fork( worker_info, child, usage_before, + pov_size, execution_timeout, ), Err(errno) => Ok(Err(internal_error_from_errno("fork", errno))), @@ -513,6 +563,7 @@ fn handle_parent_process( worker_info: &WorkerInfo, job_pid: Pid, usage_before: Usage, + pov_size: u32, timeout: Duration, ) -> io::Result> { // the read end will wait until all write ends have been closed, @@ -578,7 +629,7 @@ fn handle_parent_process( )))); } - Ok(Ok(WorkerResponse { job_response, duration: cpu_tv })) + Ok(Ok(WorkerResponse { job_response, pov_size, duration: cpu_tv })) }, Err(job_error) => { gum::warn!( diff --git a/polkadot/node/core/pvf/prepare-worker/Cargo.toml b/polkadot/node/core/pvf/prepare-worker/Cargo.toml index 9e0d01fc438b0257b87b9bf6791f466d8691049e..56235bd82192f2e671eb0b9e08006a186966a814 100644 --- a/polkadot/node/core/pvf/prepare-worker/Cargo.toml +++ b/polkadot/node/core/pvf/prepare-worker/Cargo.toml @@ -23,10 +23,12 @@ nix = { features = ["process", "resource", "sched"], workspace = true } codec = { features = ["derive"], workspace = true } polkadot-node-core-pvf-common = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } sc-executor-common = { workspace = true, default-features = true } sc-executor-wasmtime = { workspace = true, default-features = true } +sp-maybe-compressed-blob = { workspace = true, default-features = true } [target.'cfg(target_os = "linux")'.dependencies] tikv-jemallocator = "0.5.0" diff --git a/polkadot/node/core/pvf/prepare-worker/benches/prepare_rococo_runtime.rs b/polkadot/node/core/pvf/prepare-worker/benches/prepare_rococo_runtime.rs index d531c90b64b578e31f42a13f2399b4343469fa6d..49b30dc33ceb7695f0c6aba19279d6ed870edb7b 100644 --- a/polkadot/node/core/pvf/prepare-worker/benches/prepare_rococo_runtime.rs +++ b/polkadot/node/core/pvf/prepare-worker/benches/prepare_rococo_runtime.rs @@ -24,7 +24,11 @@ use polkadot_primitives::ExecutorParams; use std::time::Duration; fn do_prepare_runtime(pvf: PvfPrepData) { - let blob = match prevalidate(&pvf.code()) { + let maybe_compressed_code = pvf.maybe_compressed_code(); + let raw_validation_code = + sp_maybe_compressed_blob::decompress(&maybe_compressed_code, usize::MAX).unwrap(); + + let blob = match prevalidate(&raw_validation_code) { Err(err) => panic!("{:?}", err), Ok(b) => b, }; diff --git a/polkadot/node/core/pvf/prepare-worker/src/lib.rs b/polkadot/node/core/pvf/prepare-worker/src/lib.rs index ef33d11720eb5a7c4b7fa11b3484acbd5ad84d43..f8ebb6effcecdc4d3e71a95bbdaecfe51705352e 100644 --- a/polkadot/node/core/pvf/prepare-worker/src/lib.rs +++ b/polkadot/node/core/pvf/prepare-worker/src/lib.rs @@ -38,6 +38,7 @@ use polkadot_node_core_pvf_common::{ executor_interface::{prepare, prevalidate}, worker::{pipe2_cloexec, PipeFd, WorkerInfo}, }; +use polkadot_node_primitives::VALIDATION_CODE_BOMB_LIMIT; use codec::{Decode, Encode}; use polkadot_node_core_pvf_common::{ @@ -105,6 +106,12 @@ impl AsRef<[u8]> for CompiledArtifact { } } +#[derive(Encode, Decode)] +pub struct PrepareOutcome { + pub compiled_artifact: CompiledArtifact, + pub observed_wasm_code_len: u32, +} + /// Get a worker request. fn recv_request(stream: &mut UnixStream) -> io::Result { let pvf = framed_recv_blocking(stream)?; @@ -294,14 +301,23 @@ pub fn worker_entrypoint( ); } -fn prepare_artifact(pvf: PvfPrepData) -> Result { - let blob = match prevalidate(&pvf.code()) { +fn prepare_artifact(pvf: PvfPrepData) -> Result { + let maybe_compressed_code = pvf.maybe_compressed_code(); + let raw_validation_code = + sp_maybe_compressed_blob::decompress(&maybe_compressed_code, VALIDATION_CODE_BOMB_LIMIT) + .map_err(|e| PrepareError::CouldNotDecompressCodeBlob(e.to_string()))?; + let observed_wasm_code_len = raw_validation_code.len() as u32; + + let blob = match prevalidate(&raw_validation_code) { Err(err) => return Err(PrepareError::Prevalidation(format!("{:?}", err))), Ok(b) => b, }; match prepare(blob, &pvf.executor_params()) { - Ok(compiled_artifact) => Ok(CompiledArtifact::new(compiled_artifact)), + Ok(compiled_artifact) => Ok(PrepareOutcome { + compiled_artifact: CompiledArtifact::new(compiled_artifact), + observed_wasm_code_len, + }), Err(err) => Err(PrepareError::Preparation(format!("{:?}", err))), } } @@ -322,6 +338,7 @@ fn runtime_construction_check( struct JobResponse { artifact: CompiledArtifact, memory_stats: MemoryStats, + observed_wasm_code_len: u32, } #[cfg(target_os = "linux")] @@ -500,11 +517,11 @@ fn handle_child_process( "prepare worker", move || { #[allow(unused_mut)] - let mut result = prepare_artifact(pvf); + let mut result = prepare_artifact(pvf).map(|o| (o,)); // Get the `ru_maxrss` stat. If supported, call getrusage for the thread. #[cfg(target_os = "linux")] - let mut result = result.map(|artifact| (artifact, get_max_rss_thread())); + let mut result = result.map(|outcome| (outcome.0, get_max_rss_thread())); // If we are pre-checking, check for runtime construction errors. // @@ -513,7 +530,10 @@ fn handle_child_process( // anyway. if let PrepareJobKind::Prechecking = prepare_job_kind { result = result.and_then(|output| { - runtime_construction_check(output.0.as_ref(), &executor_params)?; + runtime_construction_check( + output.0.compiled_artifact.as_ref(), + &executor_params, + )?; Ok(output) }); } @@ -553,9 +573,9 @@ fn handle_child_process( Ok(ok) => { cfg_if::cfg_if! { if #[cfg(target_os = "linux")] { - let (artifact, max_rss) = ok; + let (PrepareOutcome { compiled_artifact, observed_wasm_code_len }, max_rss) = ok; } else { - let artifact = ok; + let (PrepareOutcome { compiled_artifact, observed_wasm_code_len },) = ok; } } @@ -574,7 +594,11 @@ fn handle_child_process( peak_tracked_alloc: if peak_alloc > 0 { peak_alloc as u64 } else { 0u64 }, }; - Ok(JobResponse { artifact, memory_stats }) + Ok(JobResponse { + artifact: compiled_artifact, + observed_wasm_code_len, + memory_stats, + }) }, } }, @@ -665,7 +689,7 @@ fn handle_parent_process( match result { Err(err) => Err(err), - Ok(JobResponse { artifact, memory_stats }) => { + Ok(JobResponse { artifact, memory_stats, observed_wasm_code_len }) => { // The exit status should have been zero if no error occurred. if exit_status != 0 { return Err(PrepareError::JobError(format!( @@ -696,7 +720,11 @@ fn handle_parent_process( let checksum = blake3::hash(&artifact.as_ref()).to_hex().to_string(); Ok(PrepareWorkerSuccess { checksum, - stats: PrepareStats { memory_stats, cpu_time_elapsed: cpu_tv }, + stats: PrepareStats { + memory_stats, + cpu_time_elapsed: cpu_tv, + observed_wasm_code_len, + }, }) }, } diff --git a/polkadot/node/core/pvf/src/error.rs b/polkadot/node/core/pvf/src/error.rs index 8dc96305eadb8f3ced1231889f5fa6c5ffaeac57..a0634106052d7fb197c0662854415190a59a0e70 100644 --- a/polkadot/node/core/pvf/src/error.rs +++ b/polkadot/node/core/pvf/src/error.rs @@ -52,6 +52,9 @@ pub enum InvalidCandidate { /// PVF execution (compilation is not included) took more time than was allotted. #[error("invalid: hard timeout")] HardTimeout, + /// Proof-of-validity failed to decompress correctly + #[error("invalid: PoV failed to decompress")] + PoVDecompressionFailure, } /// Possibly transient issue that may resolve after retries. diff --git a/polkadot/node/core/pvf/src/execute/queue.rs b/polkadot/node/core/pvf/src/execute/queue.rs index bb00a5a652d6434cd06327803d9ce51a3d5c1e93..11031bf1074a297e246a4e341efe8488a2692b1b 100644 --- a/polkadot/node/core/pvf/src/execute/queue.rs +++ b/polkadot/node/core/pvf/src/execute/queue.rs @@ -34,12 +34,14 @@ use polkadot_node_core_pvf_common::{ execute::{JobResponse, WorkerError, WorkerResponse}, SecurityStatus, }; -use polkadot_primitives::{ExecutorParams, ExecutorParamsHash}; +use polkadot_node_primitives::PoV; +use polkadot_primitives::{ExecutorParams, ExecutorParamsHash, PersistedValidationData}; use slotmap::HopSlotMap; use std::{ collections::VecDeque, fmt, path::PathBuf, + sync::Arc, time::{Duration, Instant}, }; @@ -68,7 +70,8 @@ pub enum FromQueue { #[derive(Debug)] pub struct PendingExecutionRequest { pub exec_timeout: Duration, - pub params: Vec, + pub pvd: Arc, + pub pov: Arc, pub executor_params: ExecutorParams, pub result_tx: ResultSender, } @@ -76,7 +79,8 @@ pub struct PendingExecutionRequest { struct ExecuteJob { artifact: ArtifactPathId, exec_timeout: Duration, - params: Vec, + pvd: Arc, + pov: Arc, executor_params: ExecutorParams, result_tx: ResultSender, waiting_since: Instant, @@ -293,18 +297,20 @@ async fn purge_dead(metrics: &Metrics, workers: &mut Workers) { fn handle_to_queue(queue: &mut Queue, to_queue: ToQueue) { let ToQueue::Enqueue { artifact, pending_execution_request } = to_queue; - let PendingExecutionRequest { exec_timeout, params, executor_params, result_tx } = + let PendingExecutionRequest { exec_timeout, pvd, pov, executor_params, result_tx } = pending_execution_request; gum::debug!( target: LOG_TARGET, validation_code_hash = ?artifact.id.code_hash, "enqueueing an artifact for execution", ); + queue.metrics.observe_pov_size(pov.block_data.0.len(), true); queue.metrics.execute_enqueued(); let job = ExecuteJob { artifact, exec_timeout, - params, + pvd, + pov, executor_params, result_tx, waiting_since: Instant::now(), @@ -352,15 +358,19 @@ async fn handle_job_finish( artifact_id: ArtifactId, result_tx: ResultSender, ) { - let (idle_worker, result, duration, sync_channel) = match worker_result { + let (idle_worker, result, duration, sync_channel, pov_size) = match worker_result { Ok(WorkerInterfaceResponse { worker_response: - WorkerResponse { job_response: JobResponse::Ok { result_descriptor }, duration }, + WorkerResponse { + job_response: JobResponse::Ok { result_descriptor }, + duration, + pov_size, + }, idle_worker, }) => { // TODO: propagate the soft timeout - (Some(idle_worker), Ok(result_descriptor), Some(duration), None) + (Some(idle_worker), Ok(result_descriptor), Some(duration), None, Some(pov_size)) }, Ok(WorkerInterfaceResponse { worker_response: WorkerResponse { job_response: JobResponse::InvalidCandidate(err), .. }, @@ -370,6 +380,18 @@ async fn handle_job_finish( Err(ValidationError::Invalid(InvalidCandidate::WorkerReportedInvalid(err))), None, None, + None, + ), + Ok(WorkerInterfaceResponse { + worker_response: + WorkerResponse { job_response: JobResponse::PoVDecompressionFailure, .. }, + idle_worker, + }) => ( + Some(idle_worker), + Err(ValidationError::Invalid(InvalidCandidate::PoVDecompressionFailure)), + None, + None, + None, ), Ok(WorkerInterfaceResponse { worker_response: @@ -393,39 +415,46 @@ async fn handle_job_finish( ))), None, Some(result_rx), + None, ) }, Err(WorkerInterfaceError::InternalError(err)) | Err(WorkerInterfaceError::WorkerError(WorkerError::InternalError(err))) => - (None, Err(ValidationError::Internal(err)), None, None), + (None, Err(ValidationError::Internal(err)), None, None, None), // Either the worker or the job timed out. Kill the worker in either case. Treated as // definitely-invalid, because if we timed out, there's no time left for a retry. Err(WorkerInterfaceError::HardTimeout) | Err(WorkerInterfaceError::WorkerError(WorkerError::JobTimedOut)) => - (None, Err(ValidationError::Invalid(InvalidCandidate::HardTimeout)), None, None), + (None, Err(ValidationError::Invalid(InvalidCandidate::HardTimeout)), None, None, None), // "Maybe invalid" errors (will retry). Err(WorkerInterfaceError::CommunicationErr(_err)) => ( None, Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)), None, None, + None, ), Err(WorkerInterfaceError::WorkerError(WorkerError::JobDied { err, .. })) => ( None, Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousJobDeath(err))), None, None, + None, ), Err(WorkerInterfaceError::WorkerError(WorkerError::JobError(err))) => ( None, Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::JobError(err.to_string()))), None, None, + None, ), }; queue.metrics.execute_finished(); + if let Some(pov_size) = pov_size { + queue.metrics.observe_pov_size(pov_size as usize, false) + } if let Err(ref err) = result { gum::warn!( target: LOG_TARGET, @@ -573,7 +602,8 @@ fn assign(queue: &mut Queue, worker: Worker, job: ExecuteJob) { idle, job.artifact.clone(), job.exec_timeout, - job.params, + job.pvd, + job.pov, ) .await; QueueEvent::StartWork(worker, result, job.artifact.id, job.result_tx) diff --git a/polkadot/node/core/pvf/src/execute/worker_interface.rs b/polkadot/node/core/pvf/src/execute/worker_interface.rs index d15d7c15426ebd63d33aaf1166bc8f000e28eb7a..77bd6bedd75c7f9932bc548d019870f87a1e201e 100644 --- a/polkadot/node/core/pvf/src/execute/worker_interface.rs +++ b/polkadot/node/core/pvf/src/execute/worker_interface.rs @@ -32,8 +32,9 @@ use polkadot_node_core_pvf_common::{ execute::{Handshake, WorkerError, WorkerResponse}, worker_dir, SecurityStatus, }; -use polkadot_primitives::ExecutorParams; -use std::{path::Path, time::Duration}; +use polkadot_node_primitives::PoV; +use polkadot_primitives::{ExecutorParams, PersistedValidationData}; +use std::{path::Path, sync::Arc, time::Duration}; use tokio::{io, net::UnixStream}; /// Spawns a new worker with the given program path that acts as the worker and the spawn timeout. @@ -123,7 +124,8 @@ pub async fn start_work( worker: IdleWorker, artifact: ArtifactPathId, execution_timeout: Duration, - validation_params: Vec, + pvd: Arc, + pov: Arc, ) -> Result { let IdleWorker { mut stream, pid, worker_dir } = worker; @@ -137,18 +139,16 @@ pub async fn start_work( ); with_worker_dir_setup(worker_dir, pid, &artifact.path, |worker_dir| async move { - send_request(&mut stream, &validation_params, execution_timeout).await.map_err( - |error| { - gum::warn!( - target: LOG_TARGET, - worker_pid = %pid, - validation_code_hash = ?artifact.id.code_hash, - "failed to send an execute request: {}", - error, - ); - Error::InternalError(InternalValidationError::HostCommunication(error.to_string())) - }, - )?; + send_request(&mut stream, pvd, pov, execution_timeout).await.map_err(|error| { + gum::warn!( + target: LOG_TARGET, + worker_pid = %pid, + validation_code_hash = ?artifact.id.code_hash, + "failed to send an execute request: {}", + error, + ); + Error::InternalError(InternalValidationError::HostCommunication(error.to_string())) + })?; // We use a generous timeout here. This is in addition to the one in the child process, in // case the child stalls. We have a wall clock timeout here in the host, but a CPU timeout @@ -288,10 +288,12 @@ async fn send_execute_handshake(stream: &mut UnixStream, handshake: Handshake) - async fn send_request( stream: &mut UnixStream, - validation_params: &[u8], + pvd: Arc, + pov: Arc, execution_timeout: Duration, ) -> io::Result<()> { - framed_send(stream, validation_params).await?; + framed_send(stream, &pvd.encode()).await?; + framed_send(stream, &pov.encode()).await?; framed_send(stream, &execution_timeout.encode()).await } diff --git a/polkadot/node/core/pvf/src/host.rs b/polkadot/node/core/pvf/src/host.rs index 462631d33b525a7d77817de87711a650517d4204..44a4cba2fbf864d16117ee98ff4034e2469f55a2 100644 --- a/polkadot/node/core/pvf/src/host.rs +++ b/polkadot/node/core/pvf/src/host.rs @@ -36,11 +36,14 @@ use polkadot_node_core_pvf_common::{ prepare::PrepareSuccess, pvf::PvfPrepData, }; +use polkadot_node_primitives::PoV; use polkadot_node_subsystem::{SubsystemError, SubsystemResult}; use polkadot_parachain_primitives::primitives::ValidationResult; +use polkadot_primitives::PersistedValidationData; use std::{ collections::HashMap, path::PathBuf, + sync::Arc, time::{Duration, SystemTime}, }; @@ -108,7 +111,8 @@ impl ValidationHost { &mut self, pvf: PvfPrepData, exec_timeout: Duration, - params: Vec, + pvd: Arc, + pov: Arc, priority: Priority, result_tx: ResultSender, ) -> Result<(), String> { @@ -116,7 +120,8 @@ impl ValidationHost { .send(ToHost::ExecutePvf(ExecutePvfInputs { pvf, exec_timeout, - params, + pvd, + pov, priority, result_tx, })) @@ -147,7 +152,8 @@ enum ToHost { struct ExecutePvfInputs { pvf: PvfPrepData, exec_timeout: Duration, - params: Vec, + pvd: Arc, + pov: Arc, priority: Priority, result_tx: ResultSender, } @@ -539,7 +545,7 @@ async fn handle_execute_pvf( awaiting_prepare: &mut AwaitingPrepare, inputs: ExecutePvfInputs, ) -> Result<(), Fatal> { - let ExecutePvfInputs { pvf, exec_timeout, params, priority, result_tx } = inputs; + let ExecutePvfInputs { pvf, exec_timeout, pvd, pov, priority, result_tx } = inputs; let artifact_id = ArtifactId::from_pvf_prep_data(&pvf); let executor_params = (*pvf.executor_params()).clone(); @@ -558,7 +564,8 @@ async fn handle_execute_pvf( artifact: ArtifactPathId::new(artifact_id, path), pending_execution_request: PendingExecutionRequest { exec_timeout, - params, + pvd, + pov, executor_params, result_tx, }, @@ -587,7 +594,8 @@ async fn handle_execute_pvf( artifact_id, PendingExecutionRequest { exec_timeout, - params, + pvd, + pov, executor_params, result_tx, }, @@ -598,7 +606,7 @@ async fn handle_execute_pvf( ArtifactState::Preparing { .. } => { awaiting_prepare.add( artifact_id, - PendingExecutionRequest { exec_timeout, params, executor_params, result_tx }, + PendingExecutionRequest { exec_timeout, pvd, pov, executor_params, result_tx }, ); }, ArtifactState::FailedToProcess { last_time_failed, num_failures, error } => { @@ -627,7 +635,8 @@ async fn handle_execute_pvf( artifact_id, PendingExecutionRequest { exec_timeout, - params, + pvd, + pov, executor_params, result_tx, }, @@ -648,7 +657,7 @@ async fn handle_execute_pvf( pvf, priority, artifact_id, - PendingExecutionRequest { exec_timeout, params, executor_params, result_tx }, + PendingExecutionRequest { exec_timeout, pvd, pov, executor_params, result_tx }, ) .await?; } @@ -770,7 +779,7 @@ async fn handle_prepare_done( // It's finally time to dispatch all the execution requests that were waiting for this artifact // to be prepared. let pending_requests = awaiting_prepare.take(&artifact_id); - for PendingExecutionRequest { exec_timeout, params, executor_params, result_tx } in + for PendingExecutionRequest { exec_timeout, pvd, pov, executor_params, result_tx } in pending_requests { if result_tx.is_canceled() { @@ -793,7 +802,8 @@ async fn handle_prepare_done( artifact: ArtifactPathId::new(artifact_id.clone(), &path), pending_execution_request: PendingExecutionRequest { exec_timeout, - params, + pvd, + pov, executor_params, result_tx, }, @@ -967,6 +977,8 @@ pub(crate) mod tests { use assert_matches::assert_matches; use futures::future::BoxFuture; use polkadot_node_core_pvf_common::prepare::PrepareStats; + use polkadot_node_primitives::BlockData; + use sp_core::H256; const TEST_EXECUTION_TIMEOUT: Duration = Duration::from_secs(3); pub(crate) const TEST_PREPARATION_TIMEOUT: Duration = Duration::from_secs(30); @@ -1223,12 +1235,21 @@ pub(crate) mod tests { async fn execute_pvf_requests() { let mut test = Builder::default().build(); let mut host = test.host_handle(); + let pvd = Arc::new(PersistedValidationData { + parent_head: Default::default(), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }); + let pov1 = Arc::new(PoV { block_data: BlockData(b"pov1".to_vec()) }); + let pov2 = Arc::new(PoV { block_data: BlockData(b"pov2".to_vec()) }); let (result_tx, result_rx_pvf_1_1) = oneshot::channel(); host.execute_pvf( PvfPrepData::from_discriminator(1), TEST_EXECUTION_TIMEOUT, - b"pvf1".to_vec(), + pvd.clone(), + pov1.clone(), Priority::Normal, result_tx, ) @@ -1239,7 +1260,8 @@ pub(crate) mod tests { host.execute_pvf( PvfPrepData::from_discriminator(1), TEST_EXECUTION_TIMEOUT, - b"pvf1".to_vec(), + pvd.clone(), + pov1, Priority::Critical, result_tx, ) @@ -1250,7 +1272,8 @@ pub(crate) mod tests { host.execute_pvf( PvfPrepData::from_discriminator(2), TEST_EXECUTION_TIMEOUT, - b"pvf2".to_vec(), + pvd, + pov2, Priority::Normal, result_tx, ) @@ -1382,6 +1405,13 @@ pub(crate) mod tests { async fn test_prepare_done() { let mut test = Builder::default().build(); let mut host = test.host_handle(); + let pvd = Arc::new(PersistedValidationData { + parent_head: Default::default(), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }); + let pov = Arc::new(PoV { block_data: BlockData(b"pov".to_vec()) }); // Test mixed cases of receiving execute and precheck requests // for the same PVF. @@ -1391,7 +1421,8 @@ pub(crate) mod tests { host.execute_pvf( PvfPrepData::from_discriminator(1), TEST_EXECUTION_TIMEOUT, - b"pvf2".to_vec(), + pvd.clone(), + pov.clone(), Priority::Critical, result_tx, ) @@ -1438,7 +1469,8 @@ pub(crate) mod tests { host.execute_pvf( PvfPrepData::from_discriminator(2), TEST_EXECUTION_TIMEOUT, - b"pvf2".to_vec(), + pvd, + pov, Priority::Critical, result_tx, ) @@ -1534,13 +1566,21 @@ pub(crate) mod tests { async fn test_execute_prepare_retry() { let mut test = Builder::default().build(); let mut host = test.host_handle(); + let pvd = Arc::new(PersistedValidationData { + parent_head: Default::default(), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }); + let pov = Arc::new(PoV { block_data: BlockData(b"pov".to_vec()) }); // Submit a execute request that fails. let (result_tx, result_rx) = oneshot::channel(); host.execute_pvf( PvfPrepData::from_discriminator(1), TEST_EXECUTION_TIMEOUT, - b"pvf".to_vec(), + pvd.clone(), + pov.clone(), Priority::Critical, result_tx, ) @@ -1570,7 +1610,8 @@ pub(crate) mod tests { host.execute_pvf( PvfPrepData::from_discriminator(1), TEST_EXECUTION_TIMEOUT, - b"pvf".to_vec(), + pvd.clone(), + pov.clone(), Priority::Critical, result_tx_2, ) @@ -1592,7 +1633,8 @@ pub(crate) mod tests { host.execute_pvf( PvfPrepData::from_discriminator(1), TEST_EXECUTION_TIMEOUT, - b"pvf".to_vec(), + pvd.clone(), + pov.clone(), Priority::Critical, result_tx_3, ) @@ -1636,13 +1678,21 @@ pub(crate) mod tests { async fn test_execute_prepare_no_retry() { let mut test = Builder::default().build(); let mut host = test.host_handle(); + let pvd = Arc::new(PersistedValidationData { + parent_head: Default::default(), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }); + let pov = Arc::new(PoV { block_data: BlockData(b"pov".to_vec()) }); // Submit an execute request that fails. let (result_tx, result_rx) = oneshot::channel(); host.execute_pvf( PvfPrepData::from_discriminator(1), TEST_EXECUTION_TIMEOUT, - b"pvf".to_vec(), + pvd.clone(), + pov.clone(), Priority::Critical, result_tx, ) @@ -1672,7 +1722,8 @@ pub(crate) mod tests { host.execute_pvf( PvfPrepData::from_discriminator(1), TEST_EXECUTION_TIMEOUT, - b"pvf".to_vec(), + pvd.clone(), + pov.clone(), Priority::Critical, result_tx_2, ) @@ -1694,7 +1745,8 @@ pub(crate) mod tests { host.execute_pvf( PvfPrepData::from_discriminator(1), TEST_EXECUTION_TIMEOUT, - b"pvf".to_vec(), + pvd.clone(), + pov.clone(), Priority::Critical, result_tx_3, ) @@ -1755,12 +1807,20 @@ pub(crate) mod tests { async fn cancellation() { let mut test = Builder::default().build(); let mut host = test.host_handle(); + let pvd = Arc::new(PersistedValidationData { + parent_head: Default::default(), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }); + let pov = Arc::new(PoV { block_data: BlockData(b"pov".to_vec()) }); let (result_tx, result_rx) = oneshot::channel(); host.execute_pvf( PvfPrepData::from_discriminator(1), TEST_EXECUTION_TIMEOUT, - b"pvf1".to_vec(), + pvd, + pov, Priority::Normal, result_tx, ) diff --git a/polkadot/node/core/pvf/src/metrics.rs b/polkadot/node/core/pvf/src/metrics.rs index bc8d300037fe8e1d7c70b575d99b101b8343e94b..c59cab4641805eca5dac8d60e554e21b79c97606 100644 --- a/polkadot/node/core/pvf/src/metrics.rs +++ b/polkadot/node/core/pvf/src/metrics.rs @@ -105,6 +105,21 @@ impl Metrics { .observe((memory_stats.peak_tracked_alloc / 1024) as f64); } } + + pub(crate) fn observe_code_size(&self, code_size: usize) { + if let Some(metrics) = &self.0 { + metrics.code_size.observe(code_size as f64); + } + } + + pub(crate) fn observe_pov_size(&self, pov_size: usize, compressed: bool) { + if let Some(metrics) = &self.0 { + metrics + .pov_size + .with_label_values(&[if compressed { "true" } else { "false" }]) + .observe(pov_size as f64); + } + } } #[derive(Clone)] @@ -129,6 +144,8 @@ struct MetricsInner { preparation_max_resident: prometheus::Histogram, // Peak allocation value, tracked by tracking-allocator preparation_peak_tracked_allocation: prometheus::Histogram, + pov_size: prometheus::HistogramVec, + code_size: prometheus::Histogram, } impl metrics::Metrics for Metrics { @@ -323,6 +340,35 @@ impl metrics::Metrics for Metrics { )?, registry, )?, + // The following metrics was moved here from the candidate valiidation subsystem. + // Names are kept to avoid breaking dashboards and stuff. + pov_size: prometheus::register( + prometheus::HistogramVec::new( + prometheus::HistogramOpts::new( + "polkadot_parachain_candidate_validation_pov_size", + "The compressed and decompressed size of the proof of validity of a candidate", + ) + .buckets( + prometheus::exponential_buckets(16384.0, 2.0, 10) + .expect("arguments are always valid; qed"), + ), + &["compressed"], + )?, + registry, + )?, + code_size: prometheus::register( + prometheus::Histogram::with_opts( + prometheus::HistogramOpts::new( + "polkadot_parachain_candidate_validation_code_size", + "The size of the decompressed WASM validation blob used for checking a candidate", + ) + .buckets( + prometheus::exponential_buckets(16384.0, 2.0, 10) + .expect("arguments are always valid; qed"), + ), + )?, + registry, + )?, }; Ok(Metrics(Some(inner))) } diff --git a/polkadot/node/core/pvf/src/prepare/worker_interface.rs b/polkadot/node/core/pvf/src/prepare/worker_interface.rs index 22ee93319d84db14ed53a89efe872c7121d87cbd..d29d2717c4b6e38239c8357a711a2899f4010274 100644 --- a/polkadot/node/core/pvf/src/prepare/worker_interface.rs +++ b/polkadot/node/core/pvf/src/prepare/worker_interface.rs @@ -211,7 +211,7 @@ async fn handle_response( // https://github.com/paritytech/polkadot-sdk/issues/2399 let PrepareWorkerSuccess { checksum: _, - stats: PrepareStats { cpu_time_elapsed, memory_stats }, + stats: PrepareStats { cpu_time_elapsed, memory_stats, observed_wasm_code_len }, } = match result.clone() { Ok(result) => result, // Timed out on the child. This should already be logged by the child. @@ -221,6 +221,8 @@ async fn handle_response( Err(err) => return Outcome::Concluded { worker, result: Err(err) }, }; + metrics.observe_code_size(observed_wasm_code_len as usize); + if cpu_time_elapsed > preparation_timeout { // The job didn't complete within the timeout. gum::warn!( @@ -267,7 +269,11 @@ async fn handle_response( result: Ok(PrepareSuccess { path: artifact_path, size, - stats: PrepareStats { cpu_time_elapsed, memory_stats: memory_stats.clone() }, + stats: PrepareStats { + cpu_time_elapsed, + memory_stats: memory_stats.clone(), + observed_wasm_code_len, + }, }), }, Err(err) => { diff --git a/polkadot/node/core/pvf/tests/it/adder.rs b/polkadot/node/core/pvf/tests/it/adder.rs index 455e8c36c88d7c6718a2ce949c0fc961455d06f4..1a95a28fe07732f51d5a8bdd988ee51c79e66a3e 100644 --- a/polkadot/node/core/pvf/tests/it/adder.rs +++ b/polkadot/node/core/pvf/tests/it/adder.rs @@ -18,29 +18,33 @@ use super::TestHost; use codec::{Decode, Encode}; +use polkadot_node_primitives::PoV; use polkadot_parachain_primitives::primitives::{ - BlockData as GenericBlockData, HeadData as GenericHeadData, RelayChainBlockNumber, - ValidationParams, + BlockData as GenericBlockData, HeadData as GenericHeadData, }; +use polkadot_primitives::PersistedValidationData; +use sp_core::H256; use test_parachain_adder::{hash_state, BlockData, HeadData}; #[tokio::test] async fn execute_good_block_on_parent() { let parent_head = HeadData { number: 0, parent_hash: [0; 32], post_state: hash_state(0) }; - let block_data = BlockData { state: 0, add: 512 }; + let pvd = PersistedValidationData { + parent_head: GenericHeadData(parent_head.encode()), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }; + let pov = PoV { block_data: GenericBlockData(block_data.encode()) }; let host = TestHost::new().await; let ret = host .validate_candidate( test_parachain_adder::wasm_binary_unwrap(), - ValidationParams { - parent_head: GenericHeadData(parent_head.encode()), - block_data: GenericBlockData(block_data.encode()), - relay_parent_number: 1, - relay_parent_storage_root: Default::default(), - }, + pvd, + pov, Default::default(), ) .await @@ -63,18 +67,20 @@ async fn execute_good_chain_on_parent() { for (number, add) in (0..10).enumerate() { let parent_head = HeadData { number: number as u64, parent_hash, post_state: hash_state(last_state) }; - let block_data = BlockData { state: last_state, add }; + let pvd = PersistedValidationData { + parent_head: GenericHeadData(parent_head.encode()), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }; + let pov = PoV { block_data: GenericBlockData(block_data.encode()) }; let ret = host .validate_candidate( test_parachain_adder::wasm_binary_unwrap(), - ValidationParams { - parent_head: GenericHeadData(parent_head.encode()), - block_data: GenericBlockData(block_data.encode()), - relay_parent_number: number as RelayChainBlockNumber + 1, - relay_parent_storage_root: Default::default(), - }, + pvd, + pov, Default::default(), ) .await @@ -94,23 +100,25 @@ async fn execute_good_chain_on_parent() { #[tokio::test] async fn execute_bad_block_on_parent() { let parent_head = HeadData { number: 0, parent_hash: [0; 32], post_state: hash_state(0) }; - let block_data = BlockData { state: 256, // start state is wrong. add: 256, }; + let pvd = PersistedValidationData { + parent_head: GenericHeadData(parent_head.encode()), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }; + let pov = PoV { block_data: GenericBlockData(block_data.encode()) }; let host = TestHost::new().await; let _err = host .validate_candidate( test_parachain_adder::wasm_binary_unwrap(), - ValidationParams { - parent_head: GenericHeadData(parent_head.encode()), - block_data: GenericBlockData(block_data.encode()), - relay_parent_number: 1, - relay_parent_storage_root: Default::default(), - }, + pvd, + pov, Default::default(), ) .await @@ -124,15 +132,18 @@ async fn stress_spawn() { async fn execute(host: std::sync::Arc) { let parent_head = HeadData { number: 0, parent_hash: [0; 32], post_state: hash_state(0) }; let block_data = BlockData { state: 0, add: 512 }; + let pvd = PersistedValidationData { + parent_head: GenericHeadData(parent_head.encode()), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }; + let pov = PoV { block_data: GenericBlockData(block_data.encode()) }; let ret = host .validate_candidate( test_parachain_adder::wasm_binary_unwrap(), - ValidationParams { - parent_head: GenericHeadData(parent_head.encode()), - block_data: GenericBlockData(block_data.encode()), - relay_parent_number: 1, - relay_parent_storage_root: Default::default(), - }, + pvd, + pov, Default::default(), ) .await @@ -161,15 +172,18 @@ async fn execute_can_run_serially() { async fn execute(host: std::sync::Arc) { let parent_head = HeadData { number: 0, parent_hash: [0; 32], post_state: hash_state(0) }; let block_data = BlockData { state: 0, add: 512 }; + let pvd = PersistedValidationData { + parent_head: GenericHeadData(parent_head.encode()), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }; + let pov = PoV { block_data: GenericBlockData(block_data.encode()) }; let ret = host .validate_candidate( test_parachain_adder::wasm_binary_unwrap(), - ValidationParams { - parent_head: GenericHeadData(parent_head.encode()), - block_data: GenericBlockData(block_data.encode()), - relay_parent_number: 1, - relay_parent_storage_root: Default::default(), - }, + pvd, + pov, Default::default(), ) .await diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index d62a1aef230990057c5c408a840f51bc66a5029f..a4a0853189579ce96cf96d49f685c3de7de5af00 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -17,7 +17,6 @@ //! General PVF host integration tests checking the functionality of the PVF host itself. use assert_matches::assert_matches; -use codec::Encode as _; #[cfg(all(feature = "ci-only-tests", target_os = "linux"))] use polkadot_node_core_pvf::SecurityStatus; use polkadot_node_core_pvf::{ @@ -25,10 +24,14 @@ use polkadot_node_core_pvf::{ PossiblyInvalidError, PrepareError, PrepareJobKind, PvfPrepData, ValidationError, ValidationHost, JOB_TIMEOUT_WALL_CLOCK_FACTOR, }; -use polkadot_parachain_primitives::primitives::{BlockData, ValidationParams, ValidationResult}; -use polkadot_primitives::{ExecutorParam, ExecutorParams, PvfExecKind, PvfPrepKind}; +use polkadot_node_primitives::{PoV, POV_BOMB_LIMIT, VALIDATION_CODE_BOMB_LIMIT}; +use polkadot_parachain_primitives::primitives::{BlockData, ValidationResult}; +use polkadot_primitives::{ + ExecutorParam, ExecutorParams, PersistedValidationData, PvfExecKind, PvfPrepKind, +}; +use sp_core::H256; -use std::{io::Write, time::Duration}; +use std::{io::Write, sync::Arc, time::Duration}; use tokio::sync::Mutex; mod adder; @@ -80,9 +83,6 @@ impl TestHost { ) -> Result<(), PrepareError> { let (result_tx, result_rx) = futures::channel::oneshot::channel(); - let code = sp_maybe_compressed_blob::decompress(code, 16 * 1024 * 1024) - .expect("Compression works"); - self.host .lock() .await @@ -103,14 +103,12 @@ impl TestHost { async fn validate_candidate( &self, code: &[u8], - params: ValidationParams, + pvd: PersistedValidationData, + pov: PoV, executor_params: ExecutorParams, ) -> Result { let (result_tx, result_rx) = futures::channel::oneshot::channel(); - let code = sp_maybe_compressed_blob::decompress(code, 16 * 1024 * 1024) - .expect("Compression works"); - self.host .lock() .await @@ -122,7 +120,8 @@ impl TestHost { PrepareJobKind::Compilation, ), TEST_EXECUTION_TIMEOUT, - params.encode(), + Arc::new(pvd), + Arc::new(pov), polkadot_node_core_pvf::Priority::Normal, result_tx, ) @@ -159,19 +158,17 @@ async fn prepare_job_terminates_on_timeout() { #[tokio::test] async fn execute_job_terminates_on_timeout() { let host = TestHost::new().await; + let pvd = PersistedValidationData { + parent_head: Default::default(), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }; + let pov = PoV { block_data: BlockData(Vec::new()) }; let start = std::time::Instant::now(); let result = host - .validate_candidate( - test_parachain_halt::wasm_binary_unwrap(), - ValidationParams { - block_data: BlockData(Vec::new()), - parent_head: Default::default(), - relay_parent_number: 1, - relay_parent_storage_root: Default::default(), - }, - Default::default(), - ) + .validate_candidate(test_parachain_halt::wasm_binary_unwrap(), pvd, pov, Default::default()) .await; match result { @@ -189,24 +186,23 @@ async fn execute_job_terminates_on_timeout() { async fn ensure_parallel_execution() { // Run some jobs that do not complete, thus timing out. let host = TestHost::new().await; + let pvd = PersistedValidationData { + parent_head: Default::default(), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }; + let pov = PoV { block_data: BlockData(Vec::new()) }; let execute_pvf_future_1 = host.validate_candidate( test_parachain_halt::wasm_binary_unwrap(), - ValidationParams { - block_data: BlockData(Vec::new()), - parent_head: Default::default(), - relay_parent_number: 1, - relay_parent_storage_root: Default::default(), - }, + pvd.clone(), + pov.clone(), Default::default(), ); let execute_pvf_future_2 = host.validate_candidate( test_parachain_halt::wasm_binary_unwrap(), - ValidationParams { - block_data: BlockData(Vec::new()), - parent_head: Default::default(), - relay_parent_number: 1, - relay_parent_storage_root: Default::default(), - }, + pvd, + pov, Default::default(), ); @@ -237,6 +233,13 @@ async fn execute_queue_doesnt_stall_if_workers_died() { cfg.execute_workers_max_num = 5; }) .await; + let pvd = PersistedValidationData { + parent_head: Default::default(), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }; + let pov = PoV { block_data: BlockData(Vec::new()) }; // Here we spawn 8 validation jobs for the `halt` PVF and share those between 5 workers. The // first five jobs should timeout and the workers killed. For the next 3 jobs a new batch of @@ -245,12 +248,8 @@ async fn execute_queue_doesnt_stall_if_workers_died() { futures::future::join_all((0u8..=8).map(|_| { host.validate_candidate( test_parachain_halt::wasm_binary_unwrap(), - ValidationParams { - block_data: BlockData(Vec::new()), - parent_head: Default::default(), - relay_parent_number: 1, - relay_parent_storage_root: Default::default(), - }, + pvd.clone(), + pov.clone(), Default::default(), ) })) @@ -275,6 +274,13 @@ async fn execute_queue_doesnt_stall_with_varying_executor_params() { cfg.execute_workers_max_num = 2; }) .await; + let pvd = PersistedValidationData { + parent_head: Default::default(), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }; + let pov = PoV { block_data: BlockData(Vec::new()) }; let executor_params_1 = ExecutorParams::default(); let executor_params_2 = ExecutorParams::from(&[ExecutorParam::StackLogicalMax(1024)][..]); @@ -288,12 +294,8 @@ async fn execute_queue_doesnt_stall_with_varying_executor_params() { futures::future::join_all((0u8..6).map(|i| { host.validate_candidate( test_parachain_halt::wasm_binary_unwrap(), - ValidationParams { - block_data: BlockData(Vec::new()), - parent_head: Default::default(), - relay_parent_number: 1, - relay_parent_storage_root: Default::default(), - }, + pvd.clone(), + pov.clone(), match i % 3 { 0 => executor_params_1.clone(), _ => executor_params_2.clone(), @@ -324,6 +326,13 @@ async fn execute_queue_doesnt_stall_with_varying_executor_params() { async fn deleting_prepared_artifact_does_not_dispute() { let host = TestHost::new().await; let cache_dir = host.cache_dir.path(); + let pvd = PersistedValidationData { + parent_head: Default::default(), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }; + let pov = PoV { block_data: BlockData(Vec::new()) }; let _stats = host .precheck_pvf(test_parachain_halt::wasm_binary_unwrap(), Default::default()) @@ -347,16 +356,7 @@ async fn deleting_prepared_artifact_does_not_dispute() { // Try to validate, artifact should get recreated. let result = host - .validate_candidate( - test_parachain_halt::wasm_binary_unwrap(), - ValidationParams { - block_data: BlockData(Vec::new()), - parent_head: Default::default(), - relay_parent_number: 1, - relay_parent_storage_root: Default::default(), - }, - Default::default(), - ) + .validate_candidate(test_parachain_halt::wasm_binary_unwrap(), pvd, pov, Default::default()) .await; assert_matches!(result, Err(ValidationError::Invalid(InvalidCandidate::HardTimeout))); @@ -367,6 +367,13 @@ async fn deleting_prepared_artifact_does_not_dispute() { async fn corrupted_prepared_artifact_does_not_dispute() { let host = TestHost::new().await; let cache_dir = host.cache_dir.path(); + let pvd = PersistedValidationData { + parent_head: Default::default(), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }; + let pov = PoV { block_data: BlockData(Vec::new()) }; let _stats = host .precheck_pvf(test_parachain_halt::wasm_binary_unwrap(), Default::default()) @@ -400,16 +407,7 @@ async fn corrupted_prepared_artifact_does_not_dispute() { // Try to validate, artifact should get removed because of the corruption. let result = host - .validate_candidate( - test_parachain_halt::wasm_binary_unwrap(), - ValidationParams { - block_data: BlockData(Vec::new()), - parent_head: Default::default(), - relay_parent_number: 1, - relay_parent_storage_root: Default::default(), - }, - Default::default(), - ) + .validate_candidate(test_parachain_halt::wasm_binary_unwrap(), pvd, pov, Default::default()) .await; assert_matches!( @@ -523,20 +521,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 } }; @@ -655,3 +650,65 @@ async fn artifact_does_reprepare_on_meaningful_exec_parameter_change() { assert_eq!(cache_dir_contents.len(), 3); // new artifact has been added } + +// Checks that we cannot prepare oversized compressed code +#[tokio::test] +async fn invalid_compressed_code_fails_prechecking() { + let host = TestHost::new().await; + let raw_code = vec![2u8; VALIDATION_CODE_BOMB_LIMIT + 1]; + let validation_code = + sp_maybe_compressed_blob::compress(&raw_code, VALIDATION_CODE_BOMB_LIMIT + 1).unwrap(); + + let res = host.precheck_pvf(&validation_code, Default::default()).await; + + assert_matches!(res, Err(PrepareError::CouldNotDecompressCodeBlob(_))); +} + +// Checks that we cannot validate with oversized compressed code +#[tokio::test] +async fn invalid_compressed_code_fails_validation() { + let host = TestHost::new().await; + let pvd = PersistedValidationData { + parent_head: Default::default(), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }; + let pov = PoV { block_data: BlockData(Vec::new()) }; + + let raw_code = vec![2u8; VALIDATION_CODE_BOMB_LIMIT + 1]; + let validation_code = + sp_maybe_compressed_blob::compress(&raw_code, VALIDATION_CODE_BOMB_LIMIT + 1).unwrap(); + + let result = host.validate_candidate(&validation_code, pvd, pov, Default::default()).await; + + assert_matches!( + result, + Err(ValidationError::Preparation(PrepareError::CouldNotDecompressCodeBlob(_))) + ); +} + +// Checks that we cannot validate with an oversized PoV +#[tokio::test] +async fn invalid_compressed_pov_fails_validation() { + let host = TestHost::new().await; + let pvd = PersistedValidationData { + parent_head: Default::default(), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }; + let raw_block_data = vec![1u8; POV_BOMB_LIMIT + 1]; + let block_data = + sp_maybe_compressed_blob::compress(&raw_block_data, POV_BOMB_LIMIT + 1).unwrap(); + let pov = PoV { block_data: BlockData(block_data) }; + + let result = host + .validate_candidate(test_parachain_halt::wasm_binary_unwrap(), pvd, pov, Default::default()) + .await; + + assert_matches!( + result, + Err(ValidationError::Invalid(InvalidCandidate::PoVDecompressionFailure)) + ); +} diff --git a/polkadot/node/core/pvf/tests/it/process.rs b/polkadot/node/core/pvf/tests/it/process.rs index b8fd2cdce0ce67e0b1cfbfc57634bfa4d8c63d46..b3023c8a45c3b3087015e714c22f9bd0474d251e 100644 --- a/polkadot/node/core/pvf/tests/it/process.rs +++ b/polkadot/node/core/pvf/tests/it/process.rs @@ -23,11 +23,14 @@ use codec::Encode; use polkadot_node_core_pvf::{ InvalidCandidate, PossiblyInvalidError, PrepareError, ValidationError, }; +use polkadot_node_primitives::PoV; use polkadot_parachain_primitives::primitives::{ - BlockData as GenericBlockData, HeadData as GenericHeadData, ValidationParams, + BlockData as GenericBlockData, HeadData as GenericHeadData, }; +use polkadot_primitives::PersistedValidationData; use procfs::process; use rusty_fork::rusty_fork_test; +use sp_core::H256; use std::{future::Future, sync::Arc, time::Duration}; use test_parachain_adder::{hash_state, BlockData, HeadData}; @@ -125,15 +128,18 @@ rusty_fork_test! { test_wrapper(|host, _sid| async move { let parent_head = HeadData { number: 0, parent_hash: [0; 32], post_state: hash_state(0) }; let block_data = BlockData { state: 0, add: 512 }; + let pvd = PersistedValidationData { + parent_head: GenericHeadData(parent_head.encode()), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }; + let pov = PoV { block_data: GenericBlockData(block_data.encode()) }; host .validate_candidate( test_parachain_adder::wasm_binary_unwrap(), - ValidationParams { - parent_head: GenericHeadData(parent_head.encode()), - block_data: GenericBlockData(block_data.encode()), - relay_parent_number: 1, - relay_parent_storage_root: Default::default(), - }, + pvd, + pov, Default::default(), ) .await @@ -166,17 +172,20 @@ rusty_fork_test! { // Prepare the artifact ahead of time. let binary = test_parachain_halt::wasm_binary_unwrap(); host.precheck_pvf(binary, Default::default()).await.unwrap(); + let pvd = PersistedValidationData { + parent_head: GenericHeadData(HeadData::default().encode()), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }; + let pov = PoV { block_data: GenericBlockData(Vec::new()) }; let (result, _) = futures::join!( // Choose an job that would normally take the entire timeout. host.validate_candidate( binary, - ValidationParams { - block_data: GenericBlockData(Vec::new()), - parent_head: Default::default(), - relay_parent_number: 1, - relay_parent_storage_root: Default::default(), - }, + pvd, + pov, Default::default(), ), // Send a stop signal to pause the worker. @@ -218,17 +227,20 @@ rusty_fork_test! { // Prepare the artifact ahead of time. let binary = test_parachain_halt::wasm_binary_unwrap(); host.precheck_pvf(binary, Default::default()).await.unwrap(); + let pvd = PersistedValidationData { + parent_head: GenericHeadData(HeadData::default().encode()), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }; + let pov = PoV { block_data: GenericBlockData(Vec::new()) }; let (result, _) = futures::join!( // Choose an job that would normally take the entire timeout. host.validate_candidate( binary, - ValidationParams { - block_data: GenericBlockData(Vec::new()), - parent_head: Default::default(), - relay_parent_number: 1, - relay_parent_storage_root: Default::default(), - }, + pvd, + pov, Default::default(), ), // Run a future that kills the job while it's running. @@ -274,17 +286,20 @@ rusty_fork_test! { // Prepare the artifact ahead of time. let binary = test_parachain_halt::wasm_binary_unwrap(); host.precheck_pvf(binary, Default::default()).await.unwrap(); + let pvd = PersistedValidationData { + parent_head: GenericHeadData(HeadData::default().encode()), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }; + let pov = PoV { block_data: GenericBlockData(Vec::new()) }; let (result, _) = futures::join!( // Choose a job that would normally take the entire timeout. host.validate_candidate( binary, - ValidationParams { - block_data: GenericBlockData(Vec::new()), - parent_head: Default::default(), - relay_parent_number: 1, - relay_parent_storage_root: Default::default(), - }, + pvd, + pov, Default::default(), ), // Run a future that kills the job while it's running. @@ -342,17 +357,20 @@ rusty_fork_test! { // Prepare the artifact ahead of time. let binary = test_parachain_halt::wasm_binary_unwrap(); host.precheck_pvf(binary, Default::default()).await.unwrap(); + let pvd = PersistedValidationData { + parent_head: GenericHeadData(HeadData::default().encode()), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }; + let pov = PoV { block_data: GenericBlockData(Vec::new()) }; let _ = futures::join!( // Choose a job that would normally take the entire timeout. host.validate_candidate( binary, - ValidationParams { - block_data: GenericBlockData(Vec::new()), - parent_head: Default::default(), - relay_parent_number: 1, - relay_parent_storage_root: Default::default(), - }, + pvd, + pov, Default::default(), ), // Run a future that tests the thread count while the worker is running. diff --git a/polkadot/node/network/approval-distribution/Cargo.toml b/polkadot/node/network/approval-distribution/Cargo.toml index a85cde303b61bfb9281c022b68ea220af18251e6..1bd3d51b5c933f2b7fe5bf5396687f3e7c59bca7 100644 --- a/polkadot/node/network/approval-distribution/Cargo.toml +++ b/polkadot/node/network/approval-distribution/Cargo.toml @@ -37,5 +37,5 @@ schnorrkel = { workspace = true } # rand_core should match schnorrkel rand_core = { workspace = true } rand_chacha = { workspace = true, default-features = true } -env_logger = { workspace = true } +sp-tracing = { 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 d48fb08a311c7496556eec797cbd2bd751a1472a..3462aaef1f6969c3fe0a4d93845c732675b418e5 100644 --- a/polkadot/node/network/approval-distribution/src/lib.rs +++ b/polkadot/node/network/approval-distribution/src/lib.rs @@ -320,7 +320,7 @@ enum Resend { /// It tracks metadata about our view of the unfinalized chain, /// which assignments and approvals we have seen, and our peers' views. #[derive(Default)] -struct State { +pub struct State { /// These two fields are used in conjunction to construct a view over the unfinalized chain. blocks_by_number: BTreeMap>, blocks: HashMap, @@ -662,9 +662,13 @@ enum PendingMessage { #[overseer::contextbounds(ApprovalDistribution, prefix = self::overseer)] impl State { - async fn handle_network_msg( + async fn handle_network_msg< + N: overseer::SubsystemSender, + A: overseer::SubsystemSender, + >( &mut self, - ctx: &mut Context, + approval_voting_sender: &mut A, + network_sender: &mut N, metrics: &Metrics, event: NetworkBridgeEvent, rng: &mut (impl CryptoRng + Rng), @@ -689,7 +693,7 @@ impl State { }, NetworkBridgeEvent::NewGossipTopology(topology) => { self.handle_new_session_topology( - ctx, + network_sender, topology.session, topology.topology, topology.local_index, @@ -697,7 +701,7 @@ impl State { .await; }, NetworkBridgeEvent::PeerViewChange(peer_id, view) => { - self.handle_peer_view_change(ctx, metrics, peer_id, view, rng).await; + self.handle_peer_view_change(network_sender, metrics, peer_id, view, rng).await; }, NetworkBridgeEvent::OurViewChange(view) => { gum::trace!(target: LOG_TARGET, ?view, "Own view change"); @@ -720,7 +724,15 @@ impl State { }); }, NetworkBridgeEvent::PeerMessage(peer_id, message) => { - self.process_incoming_peer_message(ctx, metrics, peer_id, message, rng).await; + self.process_incoming_peer_message( + approval_voting_sender, + network_sender, + metrics, + peer_id, + message, + rng, + ) + .await; }, NetworkBridgeEvent::UpdatedAuthorityIds(peer_id, authority_ids) => { gum::debug!(target: LOG_TARGET, ?peer_id, ?authority_ids, "Update Authority Ids"); @@ -743,7 +755,7 @@ impl State { let view_intersection = View::new(intersection.cloned(), view.finalized_number); Self::unify_with_peer( - ctx.sender(), + network_sender, metrics, &mut self.blocks, &self.topologies, @@ -761,9 +773,13 @@ impl State { } } - async fn handle_new_blocks( + async fn handle_new_blocks< + N: overseer::SubsystemSender, + A: overseer::SubsystemSender, + >( &mut self, - ctx: &mut Context, + approval_voting_sender: &mut A, + network_sender: &mut N, metrics: &Metrics, metas: Vec, rng: &mut (impl CryptoRng + Rng), @@ -814,12 +830,11 @@ impl State { ); { - let sender = ctx.sender(); for (peer_id, PeerEntry { view, version }) in self.peer_views.iter() { let intersection = view.iter().filter(|h| new_hashes.contains(h)); let view_intersection = View::new(intersection.cloned(), view.finalized_number); Self::unify_with_peer( - sender, + network_sender, metrics, &mut self.blocks, &self.topologies, @@ -866,7 +881,8 @@ impl State { match message { PendingMessage::Assignment(assignment, claimed_indices) => { self.import_and_circulate_assignment( - ctx, + approval_voting_sender, + network_sender, metrics, MessageSource::Peer(peer_id), assignment, @@ -877,7 +893,8 @@ impl State { }, PendingMessage::Approval(approval_vote) => { self.import_and_circulate_approval( - ctx, + approval_voting_sender, + network_sender, metrics, MessageSource::Peer(peer_id), approval_vote, @@ -889,12 +906,12 @@ impl State { } } - self.enable_aggression(ctx, Resend::Yes, metrics).await; + self.enable_aggression(network_sender, Resend::Yes, metrics).await; } - async fn handle_new_session_topology( + async fn handle_new_session_topology>( &mut self, - ctx: &mut Context, + network_sender: &mut N, session: SessionIndex, topology: SessionGridTopology, local_index: Option, @@ -908,7 +925,7 @@ impl State { let topology = self.topologies.get_topology(session).expect("just inserted above; qed"); adjust_required_routing_and_propagate( - ctx, + network_sender, &mut self.blocks, &self.topologies, |block_entry| block_entry.session == session, @@ -926,14 +943,17 @@ impl State { .await; } - async fn process_incoming_assignments( + async fn process_incoming_assignments( &mut self, - ctx: &mut Context, + approval_voting_sender: &mut A, + network_sender: &mut N, metrics: &Metrics, peer_id: PeerId, assignments: Vec<(IndirectAssignmentCertV2, CandidateBitfield)>, rng: &mut R, ) where + A: overseer::SubsystemSender, + N: overseer::SubsystemSender, R: CryptoRng + Rng, { for (assignment, claimed_indices) in assignments { @@ -956,7 +976,8 @@ impl State { } self.import_and_circulate_assignment( - ctx, + approval_voting_sender, + network_sender, metrics, MessageSource::Peer(peer_id), assignment, @@ -968,9 +989,13 @@ impl State { } // Entry point for processing an approval coming from a peer. - async fn process_incoming_approvals( + async fn process_incoming_approvals< + N: overseer::SubsystemSender, + A: overseer::SubsystemSender, + >( &mut self, - ctx: &mut Context, + approval_voting_sender: &mut A, + network_sender: &mut N, metrics: &Metrics, peer_id: PeerId, approvals: Vec, @@ -1001,7 +1026,8 @@ impl State { } self.import_and_circulate_approval( - ctx, + approval_voting_sender, + network_sender, metrics, MessageSource::Peer(peer_id), approval_vote, @@ -1010,9 +1036,10 @@ impl State { } } - async fn process_incoming_peer_message( + async fn process_incoming_peer_message( &mut self, - ctx: &mut Context, + approval_voting_sender: &mut A, + network_sender: &mut N, metrics: &Metrics, peer_id: PeerId, msg: Versioned< @@ -1022,6 +1049,8 @@ impl State { >, rng: &mut R, ) where + A: overseer::SubsystemSender, + N: overseer::SubsystemSender, R: CryptoRng + Rng, { match msg { @@ -1033,10 +1062,11 @@ impl State { "Processing assignments from a peer", ); let sanitized_assignments = - self.sanitize_v2_assignments(peer_id, ctx.sender(), assignments).await; + self.sanitize_v2_assignments(peer_id, network_sender, assignments).await; self.process_incoming_assignments( - ctx, + approval_voting_sender, + network_sender, metrics, peer_id, sanitized_assignments, @@ -1054,10 +1084,11 @@ impl State { ); let sanitized_assignments = - self.sanitize_v1_assignments(peer_id, ctx.sender(), assignments).await; + self.sanitize_v1_assignments(peer_id, network_sender, assignments).await; self.process_incoming_assignments( - ctx, + approval_voting_sender, + network_sender, metrics, peer_id, sanitized_assignments, @@ -1067,25 +1098,37 @@ impl State { }, Versioned::V3(protocol_v3::ApprovalDistributionMessage::Approvals(approvals)) => { let sanitized_approvals = - self.sanitize_v2_approvals(peer_id, ctx.sender(), approvals).await; - self.process_incoming_approvals(ctx, metrics, peer_id, sanitized_approvals) - .await; + self.sanitize_v2_approvals(peer_id, network_sender, approvals).await; + self.process_incoming_approvals( + approval_voting_sender, + network_sender, + metrics, + peer_id, + sanitized_approvals, + ) + .await; }, Versioned::V1(protocol_v1::ApprovalDistributionMessage::Approvals(approvals)) | Versioned::V2(protocol_v2::ApprovalDistributionMessage::Approvals(approvals)) => { let sanitized_approvals = - self.sanitize_v1_approvals(peer_id, ctx.sender(), approvals).await; - self.process_incoming_approvals(ctx, metrics, peer_id, sanitized_approvals) - .await; + self.sanitize_v1_approvals(peer_id, network_sender, approvals).await; + self.process_incoming_approvals( + approval_voting_sender, + network_sender, + metrics, + peer_id, + sanitized_approvals, + ) + .await; }, } } // handle a peer view change: requires that the peer is already connected // and has an entry in the `PeerData` struct. - async fn handle_peer_view_change( + async fn handle_peer_view_change, R>( &mut self, - ctx: &mut Context, + network_sender: &mut N, metrics: &Metrics, peer_id: PeerId, view: View, @@ -1132,7 +1175,7 @@ impl State { } Self::unify_with_peer( - ctx.sender(), + network_sender, metrics, &mut self.blocks, &self.topologies, @@ -1146,9 +1189,9 @@ impl State { .await; } - async fn handle_block_finalized( + async fn handle_block_finalized>( &mut self, - ctx: &mut Context, + network_sender: &mut N, metrics: &Metrics, finalized_number: BlockNumber, ) { @@ -1172,18 +1215,21 @@ impl State { // If a block was finalized, this means we may need to move our aggression // forward to the now oldest block(s). - self.enable_aggression(ctx, Resend::No, metrics).await; + self.enable_aggression(network_sender, Resend::No, metrics).await; } - async fn import_and_circulate_assignment( + async fn import_and_circulate_assignment( &mut self, - ctx: &mut Context, + approval_voting_sender: &mut A, + network_sender: &mut N, metrics: &Metrics, source: MessageSource, assignment: IndirectAssignmentCertV2, claimed_candidate_indices: CandidateBitfield, rng: &mut R, ) where + A: overseer::SubsystemSender, + N: overseer::SubsystemSender, R: CryptoRng + Rng, { let _span = self @@ -1218,7 +1264,7 @@ impl State { if !self.recent_outdated_blocks.is_recent_outdated(&block_hash) { modify_reputation( &mut self.reputation, - ctx.sender(), + network_sender, peer_id, COST_UNEXPECTED_MESSAGE, ) @@ -1255,7 +1301,7 @@ impl State { modify_reputation( &mut self.reputation, - ctx.sender(), + network_sender, peer_id, COST_DUPLICATE_MESSAGE, ) @@ -1283,7 +1329,7 @@ impl State { ); modify_reputation( &mut self.reputation, - ctx.sender(), + network_sender, peer_id, COST_UNEXPECTED_MESSAGE, ) @@ -1296,7 +1342,7 @@ impl State { if entry.knowledge.contains(&message_subject, message_kind) { modify_reputation( &mut self.reputation, - ctx.sender(), + network_sender, peer_id, BENEFIT_VALID_MESSAGE, ) @@ -1311,12 +1357,13 @@ impl State { let (tx, rx) = oneshot::channel(); - ctx.send_message(ApprovalVotingMessage::CheckAndImportAssignment( - assignment.clone(), - claimed_candidate_indices.clone(), - tx, - )) - .await; + approval_voting_sender + .send_message(ApprovalVotingMessage::CheckAndImportAssignment( + assignment.clone(), + claimed_candidate_indices.clone(), + tx, + )) + .await; let timer = metrics.time_awaiting_approval_voting(); let result = match rx.await { @@ -1339,7 +1386,7 @@ impl State { AssignmentCheckResult::Accepted => { modify_reputation( &mut self.reputation, - ctx.sender(), + network_sender, peer_id, BENEFIT_VALID_MESSAGE_FIRST, ) @@ -1375,7 +1422,7 @@ impl State { ); modify_reputation( &mut self.reputation, - ctx.sender(), + network_sender, peer_id, COST_ASSIGNMENT_TOO_FAR_IN_THE_FUTURE, ) @@ -1394,7 +1441,7 @@ impl State { ); modify_reputation( &mut self.reputation, - ctx.sender(), + network_sender, peer_id, COST_INVALID_MESSAGE, ) @@ -1526,14 +1573,16 @@ impl State { }) .collect::>(); - send_assignments_batched(ctx.sender(), assignments, &peers).await; + send_assignments_batched(network_sender, assignments, &peers).await; } } // Checks if an approval can be processed. // Returns true if we can continue with processing the approval and false otherwise. - async fn check_approval_can_be_processed( - ctx: &mut Context, + async fn check_approval_can_be_processed< + N: overseer::SubsystemSender, + >( + network_sender: &mut N, assignments_knowledge_key: &Vec<(MessageSubject, MessageKind)>, approval_knowledge_key: &(MessageSubject, MessageKind), entry: &mut BlockEntry, @@ -1549,7 +1598,8 @@ impl State { ?message_subject, "Unknown approval assignment", ); - modify_reputation(reputation, ctx.sender(), peer_id, COST_UNEXPECTED_MESSAGE).await; + modify_reputation(reputation, network_sender, peer_id, COST_UNEXPECTED_MESSAGE) + .await; metrics.on_approval_unknown_assignment(); return false } @@ -1573,7 +1623,7 @@ impl State { modify_reputation( reputation, - ctx.sender(), + network_sender, peer_id, COST_DUPLICATE_MESSAGE, ) @@ -1590,7 +1640,8 @@ impl State { ?approval_knowledge_key, "Approval from a peer is out of view", ); - modify_reputation(reputation, ctx.sender(), peer_id, COST_UNEXPECTED_MESSAGE).await; + modify_reputation(reputation, network_sender, peer_id, COST_UNEXPECTED_MESSAGE) + .await; metrics.on_approval_out_of_view(); }, } @@ -1605,16 +1656,20 @@ impl State { // We already processed this approval no need to continue. gum::trace!(target: LOG_TARGET, ?peer_id, ?approval_knowledge_key, "Known approval"); metrics.on_approval_good_known(); - modify_reputation(reputation, ctx.sender(), peer_id, BENEFIT_VALID_MESSAGE).await; + modify_reputation(reputation, network_sender, peer_id, BENEFIT_VALID_MESSAGE).await; false } else { true } } - async fn import_and_circulate_approval( + async fn import_and_circulate_approval< + N: overseer::SubsystemSender, + A: overseer::SubsystemSender, + >( &mut self, - ctx: &mut Context, + approval_voting_sender: &mut A, + network_sender: &mut N, metrics: &Metrics, source: MessageSource, vote: IndirectSignedApprovalVoteV2, @@ -1652,7 +1707,7 @@ impl State { ); modify_reputation( &mut self.reputation, - ctx.sender(), + network_sender, peer_id, COST_UNEXPECTED_MESSAGE, ) @@ -1672,7 +1727,7 @@ impl State { if let Some(peer_id) = source.peer_id() { if !Self::check_approval_can_be_processed( - ctx, + network_sender, &assignments_knowledge_keys, &approval_knwowledge_key, entry, @@ -1687,7 +1742,8 @@ impl State { let (tx, rx) = oneshot::channel(); - ctx.send_message(ApprovalVotingMessage::CheckAndImportApproval(vote.clone(), tx)) + approval_voting_sender + .send_message(ApprovalVotingMessage::CheckAndImportApproval(vote.clone(), tx)) .await; let timer = metrics.time_awaiting_approval_voting(); @@ -1711,7 +1767,7 @@ impl State { ApprovalCheckResult::Accepted => { modify_reputation( &mut self.reputation, - ctx.sender(), + network_sender, peer_id, BENEFIT_VALID_MESSAGE_FIRST, ) @@ -1729,7 +1785,7 @@ impl State { ApprovalCheckResult::Bad(error) => { modify_reputation( &mut self.reputation, - ctx.sender(), + network_sender, peer_id, COST_INVALID_MESSAGE, ) @@ -1831,7 +1887,7 @@ impl State { num_peers = peers.len(), "Sending an approval to peers", ); - send_approvals_batched(ctx.sender(), approvals, &peers).await; + send_approvals_batched(network_sender, approvals, &peers).await; } } @@ -1882,7 +1938,7 @@ impl State { } async fn unify_with_peer( - sender: &mut impl overseer::ApprovalDistributionSenderTrait, + sender: &mut impl overseer::SubsystemSender, metrics: &Metrics, entries: &mut HashMap, topologies: &SessionGridTopologies, @@ -2027,9 +2083,9 @@ impl State { // // In order to switch to using approval lag as a trigger we need a request/response protocol // to fetch votes from validators rather than use gossip. - async fn enable_aggression( + async fn enable_aggression>( &mut self, - ctx: &mut Context, + network_sender: &mut N, resend: Resend, metrics: &Metrics, ) { @@ -2058,7 +2114,7 @@ impl State { gum::debug!(target: LOG_TARGET, min_age, max_age, "Aggression enabled",); adjust_required_routing_and_propagate( - ctx, + network_sender, &mut self.blocks, &self.topologies, |block_entry| { @@ -2086,7 +2142,7 @@ impl State { .await; adjust_required_routing_and_propagate( - ctx, + network_sender, &mut self.blocks, &self.topologies, |block_entry| { @@ -2137,7 +2193,7 @@ impl State { async fn sanitize_v1_assignments( &mut self, peer_id: PeerId, - sender: &mut impl overseer::ApprovalDistributionSenderTrait, + sender: &mut impl overseer::SubsystemSender, assignments: Vec<(IndirectAssignmentCert, CandidateIndex)>, ) -> Vec<(IndirectAssignmentCertV2, CandidateBitfield)> { let mut sanitized_assignments = Vec::new(); @@ -2172,7 +2228,7 @@ impl State { async fn sanitize_v2_assignments( &mut self, peer_id: PeerId, - sender: &mut impl overseer::ApprovalDistributionSenderTrait, + sender: &mut impl overseer::SubsystemSender, assignments: Vec<(IndirectAssignmentCertV2, CandidateBitfield)>, ) -> Vec<(IndirectAssignmentCertV2, CandidateBitfield)> { let mut sanitized_assignments = Vec::new(); @@ -2216,7 +2272,7 @@ impl State { async fn sanitize_v1_approvals( &mut self, peer_id: PeerId, - sender: &mut impl overseer::ApprovalDistributionSenderTrait, + sender: &mut impl overseer::SubsystemSender, approval: Vec, ) -> Vec { let mut sanitized_approvals = Vec::new(); @@ -2243,7 +2299,7 @@ impl State { async fn sanitize_v2_approvals( &mut self, peer_id: PeerId, - sender: &mut impl overseer::ApprovalDistributionSenderTrait, + sender: &mut impl overseer::SubsystemSender, approval: Vec, ) -> Vec { let mut sanitized_approvals = Vec::new(); @@ -2280,8 +2336,12 @@ impl State { // Note that the required routing of a message can be modified even if the // topology is unknown yet. #[overseer::contextbounds(ApprovalDistribution, prefix = self::overseer)] -async fn adjust_required_routing_and_propagate( - ctx: &mut Context, +async fn adjust_required_routing_and_propagate< + N: overseer::SubsystemSender, + BlockFilter, + RoutingModifier, +>( + network_sender: &mut N, blocks: &mut HashMap, topologies: &SessionGridTopologies, block_filter: BlockFilter, @@ -2363,7 +2423,7 @@ async fn adjust_required_routing_and_propagate, peer_id: PeerId, rep: Rep, ) { @@ -2414,7 +2474,6 @@ impl ApprovalDistribution { async fn run(self, ctx: Context) { let mut state = State::default(); - // According to the docs of `rand`, this is a ChaCha12 RNG in practice // and will always be chosen for strong performance and security properties. let mut rng = rand::rngs::StdRng::from_entropy(); @@ -2431,7 +2490,8 @@ impl ApprovalDistribution { ) { let new_reputation_delay = || futures_timer::Delay::new(reputation_interval).fuse(); let mut reputation_delay = new_reputation_delay(); - + let mut approval_voting_sender = ctx.sender().clone(); + let mut network_sender = ctx.sender().clone(); loop { select! { _ = reputation_delay => { @@ -2446,35 +2506,65 @@ impl ApprovalDistribution { return }, }; - match message { - FromOrchestra::Communication { msg } => - Self::handle_incoming(&mut ctx, state, msg, &self.metrics, rng).await, - FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update)) => { - gum::trace!(target: LOG_TARGET, "active leaves signal (ignored)"); - // the relay chain blocks relevant to the approval subsystems - // are those that are available, but not finalized yet - // activated and deactivated heads hence are irrelevant to this subsystem, other than - // for tracing purposes. - if let Some(activated) = update.activated { - let head = activated.hash; - let approval_distribution_span = - jaeger::PerLeafSpan::new(activated.span, "approval-distribution"); - state.spans.insert(head, approval_distribution_span); - } - }, - FromOrchestra::Signal(OverseerSignal::BlockFinalized(_hash, number)) => { - gum::trace!(target: LOG_TARGET, number = %number, "finalized signal"); - state.handle_block_finalized(&mut ctx, &self.metrics, number).await; - }, - FromOrchestra::Signal(OverseerSignal::Conclude) => return, - } + + + self.handle_from_orchestra(message, &mut approval_voting_sender, &mut network_sender, state, rng).await; + }, } } } - async fn handle_incoming( - ctx: &mut Context, + /// Handles a from orchestra message received by approval distribution subystem. + pub async fn handle_from_orchestra< + N: overseer::SubsystemSender, + A: overseer::SubsystemSender, + >( + &self, + message: FromOrchestra, + approval_voting_sender: &mut A, + network_sender: &mut N, + state: &mut State, + rng: &mut (impl CryptoRng + Rng), + ) { + match message { + FromOrchestra::Communication { msg } => + Self::handle_incoming( + approval_voting_sender, + network_sender, + state, + msg, + &self.metrics, + rng, + ) + .await, + FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update)) => { + gum::trace!(target: LOG_TARGET, "active leaves signal (ignored)"); + // the relay chain blocks relevant to the approval subsystems + // are those that are available, but not finalized yet + // activated and deactivated heads hence are irrelevant to this subsystem, other + // than for tracing purposes. + if let Some(activated) = update.activated { + let head = activated.hash; + let approval_distribution_span = + jaeger::PerLeafSpan::new(activated.span, "approval-distribution"); + state.spans.insert(head, approval_distribution_span); + } + }, + FromOrchestra::Signal(OverseerSignal::BlockFinalized(_hash, number)) => { + gum::trace!(target: LOG_TARGET, number = %number, "finalized signal"); + state.handle_block_finalized(network_sender, &self.metrics, number).await; + }, + FromOrchestra::Signal(OverseerSignal::Conclude) => return, + } + } + + async fn handle_incoming< + N: overseer::SubsystemSender, + A: overseer::SubsystemSender, + >( + approval_voting_sender: &mut A, + network_sender: &mut N, state: &mut State, msg: ApprovalDistributionMessage, metrics: &Metrics, @@ -2482,10 +2572,14 @@ impl ApprovalDistribution { ) { match msg { ApprovalDistributionMessage::NetworkBridgeUpdate(event) => { - state.handle_network_msg(ctx, metrics, event, rng).await; + state + .handle_network_msg(approval_voting_sender, network_sender, metrics, event, rng) + .await; }, ApprovalDistributionMessage::NewBlocks(metas) => { - state.handle_new_blocks(ctx, metrics, metas, rng).await; + state + .handle_new_blocks(approval_voting_sender, network_sender, metrics, metas, rng) + .await; }, ApprovalDistributionMessage::DistributeAssignment(cert, candidate_indices) => { let _span = state @@ -2506,7 +2600,8 @@ impl ApprovalDistribution { state .import_and_circulate_assignment( - ctx, + approval_voting_sender, + network_sender, &metrics, MessageSource::Local, cert, @@ -2524,7 +2619,13 @@ impl ApprovalDistribution { ); state - .import_and_circulate_approval(ctx, metrics, MessageSource::Local, vote) + .import_and_circulate_approval( + approval_voting_sender, + network_sender, + metrics, + MessageSource::Local, + vote, + ) .await; }, ApprovalDistributionMessage::GetApprovalSignatures(indices, tx) => { @@ -2579,7 +2680,7 @@ pub const MAX_APPROVAL_BATCH_SIZE: usize = ensure_size_not_zero( // Low level helper for sending assignments. async fn send_assignments_batched_inner( - sender: &mut impl overseer::ApprovalDistributionSenderTrait, + sender: &mut impl overseer::SubsystemSender, batch: impl IntoIterator, peers: Vec, peer_version: ValidationVersion, @@ -2634,7 +2735,7 @@ async fn send_assignments_batched_inner( /// destination, such that the subsystem doesn't get stuck for long processing a batch /// of assignments and can `select!` other tasks. pub(crate) async fn send_assignments_batched( - sender: &mut impl overseer::ApprovalDistributionSenderTrait, + network_sender: &mut impl overseer::SubsystemSender, v2_assignments: impl IntoIterator + Clone, peers: &[(PeerId, ProtocolVersion)], ) { @@ -2658,7 +2759,7 @@ pub(crate) async fn send_assignments_batched( let batch: Vec<_> = v1_batches.by_ref().take(MAX_ASSIGNMENT_BATCH_SIZE).collect(); if !v1_peers.is_empty() { send_assignments_batched_inner( - sender, + network_sender, batch.clone(), v1_peers.clone(), ValidationVersion::V1, @@ -2668,7 +2769,7 @@ pub(crate) async fn send_assignments_batched( if !v2_peers.is_empty() { send_assignments_batched_inner( - sender, + network_sender, batch, v2_peers.clone(), ValidationVersion::V2, @@ -2683,15 +2784,20 @@ pub(crate) async fn send_assignments_batched( while v3.peek().is_some() { let batch = v3.by_ref().take(MAX_ASSIGNMENT_BATCH_SIZE).collect::>(); - send_assignments_batched_inner(sender, batch, v3_peers.clone(), ValidationVersion::V3) - .await; + send_assignments_batched_inner( + network_sender, + batch, + v3_peers.clone(), + ValidationVersion::V3, + ) + .await; } } } /// Send approvals while honoring the `max_notification_size` of the protocol and peer version. pub(crate) async fn send_approvals_batched( - sender: &mut impl overseer::ApprovalDistributionSenderTrait, + sender: &mut impl overseer::SubsystemSender, approvals: impl IntoIterator + Clone, peers: &[(PeerId, ProtocolVersion)], ) { diff --git a/polkadot/node/network/approval-distribution/src/tests.rs b/polkadot/node/network/approval-distribution/src/tests.rs index 2d08807f97b60b817657a53af6a351002c04ff73..3ea722c51a927defd51bddfdfdd6a55249b91d9c 100644 --- a/polkadot/node/network/approval-distribution/src/tests.rs +++ b/polkadot/node/network/approval-distribution/src/tests.rs @@ -50,10 +50,7 @@ fn test_harness>( mut state: State, test_fn: impl FnOnce(VirtualOverseer) -> T, ) -> State { - let _ = env_logger::builder() - .is_test(true) - .filter(Some(LOG_TARGET), log::LevelFilter::Trace) - .try_init(); + sp_tracing::init_for_tests(); let pool = sp_core::testing::TaskExecutor::new(); let (context, virtual_overseer) = diff --git a/polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs b/polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs index 6083a90e48126bbf5747880835f6753176be4559..4467941c849ccf36328d211745a3e858bea105fe 100644 --- a/polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs +++ b/polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs @@ -73,9 +73,9 @@ fn main() -> Result<(), String> { ("Sent to peers", 18479.9000, 0.001), ])); messages.extend(average_usage.check_cpu_usage(&[ - ("availability-distribution", 0.0127, 0.1), - ("availability-store", 0.1626, 0.1), - ("bitfield-distribution", 0.0224, 0.1), + ("availability-distribution", 0.0128, 0.1), + ("availability-store", 0.1733, 0.1), + ("bitfield-distribution", 0.0223, 0.1), ])); if messages.is_empty() { diff --git a/polkadot/node/network/availability-distribution/src/lib.rs b/polkadot/node/network/availability-distribution/src/lib.rs index ec2c01f99b0186f80a42ad635426ace626139ffc..d3185e0af809c3b92df929d265f1962884d3f096 100644 --- a/polkadot/node/network/availability-distribution/src/lib.rs +++ b/polkadot/node/network/availability-distribution/src/lib.rs @@ -25,7 +25,7 @@ use polkadot_node_subsystem::{ jaeger, messages::AvailabilityDistributionMessage, overseer, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, }; -use polkadot_primitives::Hash; +use polkadot_primitives::{BlockNumber, Hash}; use std::collections::HashMap; /// Error and [`Result`] type for this subsystem. @@ -104,7 +104,7 @@ impl AvailabilityDistributionSubsystem { /// Start processing work as passed on from the Overseer. async fn run(self, mut ctx: Context) -> std::result::Result<(), FatalError> { let Self { mut runtime, recvs, metrics, req_protocol_names } = self; - let mut spans: HashMap = HashMap::new(); + let mut spans: HashMap = HashMap::new(); let IncomingRequestReceivers { pov_req_receiver, @@ -162,7 +162,7 @@ impl AvailabilityDistributionSubsystem { }; let span = jaeger::PerLeafSpan::new(cloned_leaf.span, "availability-distribution"); - spans.insert(cloned_leaf.hash, span); + spans.insert(cloned_leaf.hash, (cloned_leaf.number, span)); log_error( requester .get_mut() @@ -172,8 +172,8 @@ impl AvailabilityDistributionSubsystem { &mut warn_freq, )?; }, - FromOrchestra::Signal(OverseerSignal::BlockFinalized(hash, _)) => { - spans.remove(&hash); + FromOrchestra::Signal(OverseerSignal::BlockFinalized(_hash, finalized_number)) => { + spans.retain(|_hash, (block_number, _span)| *block_number > finalized_number); }, FromOrchestra::Signal(OverseerSignal::Conclude) => return Ok(()), FromOrchestra::Communication { @@ -189,7 +189,7 @@ impl AvailabilityDistributionSubsystem { } => { let span = spans .get(&relay_parent) - .map(|span| span.child("fetch-pov")) + .map(|(_, span)| span.child("fetch-pov")) .unwrap_or_else(|| jaeger::Span::new(&relay_parent, "fetch-pov")) .with_trace_id(candidate_hash) .with_candidate(candidate_hash) diff --git a/polkadot/node/network/availability-distribution/src/requester/mod.rs b/polkadot/node/network/availability-distribution/src/requester/mod.rs index efbdceb43bddc6c9501fb5ed6dc3c2e42100df7b..0175161af70dfa706e02bad07ca9fabd4bb1109e 100644 --- a/polkadot/node/network/availability-distribution/src/requester/mod.rs +++ b/polkadot/node/network/availability-distribution/src/requester/mod.rs @@ -39,7 +39,9 @@ use polkadot_node_subsystem_util::{ availability_chunks::availability_chunk_index, runtime::{get_occupied_cores, RuntimeInfo}, }; -use polkadot_primitives::{CandidateHash, CoreIndex, Hash, OccupiedCore, SessionIndex}; +use polkadot_primitives::{ + BlockNumber, CandidateHash, CoreIndex, Hash, OccupiedCore, SessionIndex, +}; use super::{FatalError, Metrics, Result, LOG_TARGET}; @@ -112,14 +114,14 @@ impl Requester { ctx: &mut Context, runtime: &mut RuntimeInfo, update: ActiveLeavesUpdate, - spans: &HashMap, + spans: &HashMap, ) -> Result<()> { gum::trace!(target: LOG_TARGET, ?update, "Update fetching heads"); let ActiveLeavesUpdate { activated, deactivated } = update; if let Some(leaf) = activated { let span = spans .get(&leaf.hash) - .map(|span| span.child("update-fetching-heads")) + .map(|(_, span)| span.child("update-fetching-heads")) .unwrap_or_else(|| jaeger::Span::new(&leaf.hash, "update-fetching-heads")) .with_string_tag("leaf", format!("{:?}", leaf.hash)) .with_stage(jaeger::Stage::AvailabilityDistribution); diff --git a/polkadot/node/network/availability-distribution/src/requester/tests.rs b/polkadot/node/network/availability-distribution/src/requester/tests.rs index 09567a8f87d322f4befca53c14712b72b9b0e0fc..decb3156004ef6dc52332ef6a4998a3e33ed8ed0 100644 --- a/polkadot/node/network/availability-distribution/src/requester/tests.rs +++ b/polkadot/node/network/availability-distribution/src/requester/tests.rs @@ -208,7 +208,7 @@ fn check_ancestry_lookup_in_same_session() { test_harness(test_state.clone(), |mut ctx| async move { let chain = &test_state.relay_chain; - let spans: HashMap = HashMap::new(); + let spans: HashMap = HashMap::new(); let block_number = 1; let update = ActiveLeavesUpdate { activated: Some(new_leaf(chain[block_number], block_number as u32)), @@ -281,7 +281,7 @@ fn check_ancestry_lookup_in_different_sessions() { test_harness(test_state.clone(), |mut ctx| async move { let chain = &test_state.relay_chain; - let spans: HashMap = HashMap::new(); + let spans: HashMap = HashMap::new(); let block_number = 3; let update = ActiveLeavesUpdate { activated: Some(new_leaf(chain[block_number], block_number as u32)), diff --git a/polkadot/node/network/bitfield-distribution/Cargo.toml b/polkadot/node/network/bitfield-distribution/Cargo.toml index b1becaf319d55068a811a6cd97dbbccc9702dcbb..6d007255c574fc35aff7142e244113dd8022e56d 100644 --- a/polkadot/node/network/bitfield-distribution/Cargo.toml +++ b/polkadot/node/network/bitfield-distribution/Cargo.toml @@ -29,7 +29,6 @@ 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 = { workspace = true } +sp-tracing = { workspace = true } assert_matches = { workspace = true } rand_chacha = { workspace = true, default-features = true } diff --git a/polkadot/node/network/bitfield-distribution/src/tests.rs b/polkadot/node/network/bitfield-distribution/src/tests.rs index dc37f73ec8a12fdf2ae3a44b41fef6902e0e9998..4ed4bf6b38c50ca837456db70881f32cf4b43f5f 100644 --- a/polkadot/node/network/bitfield-distribution/src/tests.rs +++ b/polkadot/node/network/bitfield-distribution/src/tests.rs @@ -137,10 +137,7 @@ fn state_with_view( #[test] fn receive_invalid_signature() { - let _ = env_logger::builder() - .filter(None, log::LevelFilter::Trace) - .is_test(true) - .try_init(); + sp_tracing::init_for_tests(); let hash_a: Hash = [0; 32].into(); @@ -254,10 +251,7 @@ fn receive_invalid_signature() { #[test] fn receive_invalid_validator_index() { - let _ = env_logger::builder() - .filter(None, log::LevelFilter::Trace) - .is_test(true) - .try_init(); + sp_tracing::init_for_tests(); let hash_a: Hash = [0; 32].into(); let hash_b: Hash = [1; 32].into(); // other @@ -317,10 +311,7 @@ fn receive_invalid_validator_index() { #[test] fn receive_duplicate_messages() { - let _ = env_logger::builder() - .filter(None, log::LevelFilter::Trace) - .is_test(true) - .try_init(); + sp_tracing::init_for_tests(); let hash_a: Hash = [0; 32].into(); let hash_b: Hash = [1; 32].into(); @@ -442,10 +433,7 @@ fn receive_duplicate_messages() { fn delay_reputation_change() { use polkadot_node_subsystem_util::reputation::add_reputation; - let _ = env_logger::builder() - .filter(None, log::LevelFilter::Trace) - .is_test(true) - .try_init(); + sp_tracing::init_for_tests(); let hash_a: Hash = [0; 32].into(); let hash_b: Hash = [1; 32].into(); @@ -550,10 +538,7 @@ fn delay_reputation_change() { #[test] fn do_not_relay_message_twice() { - let _ = env_logger::builder() - .filter(None, log::LevelFilter::Trace) - .is_test(true) - .try_init(); + sp_tracing::init_for_tests(); let hash = Hash::random(); @@ -658,10 +643,7 @@ fn do_not_relay_message_twice() { #[test] fn changing_view() { - let _ = env_logger::builder() - .filter(None, log::LevelFilter::Trace) - .is_test(true) - .try_init(); + sp_tracing::init_for_tests(); let hash_a: Hash = [0; 32].into(); let hash_b: Hash = [1; 32].into(); @@ -833,10 +815,7 @@ fn changing_view() { #[test] fn do_not_send_message_back_to_origin() { - let _ = env_logger::builder() - .filter(None, log::LevelFilter::Trace) - .is_test(true) - .try_init(); + sp_tracing::init_for_tests(); let hash: Hash = [0; 32].into(); @@ -920,10 +899,7 @@ fn do_not_send_message_back_to_origin() { #[test] fn topology_test() { - let _ = env_logger::builder() - .filter(None, log::LevelFilter::Trace) - .is_test(true) - .try_init(); + sp_tracing::init_for_tests(); let hash: Hash = [0; 32].into(); 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 56965ce6ba404c2e6fc2b189ce75ac9122cbf67c..7745c42f78a173b2c835f4b575171bd25146341e 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -962,6 +962,21 @@ fn update_our_view( ) }; + let our_view = OurView::new( + live_heads.iter().take(MAX_VIEW_HEADS).cloned().map(|a| (a.hash, a.span)), + finalized_number, + ); + + dispatch_validation_event_to_all_unbounded( + NetworkBridgeEvent::OurViewChange(our_view.clone()), + ctx.sender(), + ); + + dispatch_collation_event_to_all_unbounded( + NetworkBridgeEvent::OurViewChange(our_view), + ctx.sender(), + ); + let v1_validation_peers = filter_by_peer_version(&validation_peers, ValidationVersion::V1.into()); let v1_collation_peers = filter_by_peer_version(&collation_peers, CollationVersion::V1.into()); @@ -1007,21 +1022,6 @@ fn update_our_view( metrics, notification_sinks, ); - - let our_view = OurView::new( - live_heads.iter().take(MAX_VIEW_HEADS).cloned().map(|a| (a.hash, a.span)), - finalized_number, - ); - - dispatch_validation_event_to_all_unbounded( - NetworkBridgeEvent::OurViewChange(our_view.clone()), - ctx.sender(), - ); - - dispatch_collation_event_to_all_unbounded( - NetworkBridgeEvent::OurViewChange(our_view), - ctx.sender(), - ); } // Handle messages on a specific v1 peer-set. The peer is expected to be connected on that diff --git a/polkadot/node/network/bridge/src/rx/tests.rs b/polkadot/node/network/bridge/src/rx/tests.rs index 392ff7391a1c1ddded8cfde1bce96adc3a27476a..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, 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 d41fc7ebe8ddb292aadd281c0b34288d8eb49e10..8a7c384dcbe8b72acb895a253d0b4022b66fc147 100644 --- a/polkadot/node/network/collator-protocol/Cargo.toml +++ b/polkadot/node/network/collator-protocol/Cargo.toml @@ -29,8 +29,7 @@ thiserror = { workspace = true } tokio-util = { workspace = true } [dev-dependencies] -log = { workspace = true, default-features = true } -env_logger = { workspace = true } +sp-tracing = { workspace = true } assert_matches = { workspace = true } rstest = { workspace = true } diff --git a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs index 13601ca7a0056508f06fdd3f2ed717ee4d2ea4b4..74a151c168dcab581d66e4f7be3530d703e0fdd9 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs @@ -239,11 +239,7 @@ fn test_harness>( reputation: ReputationAggregator, test: impl FnOnce(TestHarness) -> T, ) { - let _ = env_logger::builder() - .is_test(true) - .filter(Some("polkadot_collator_protocol"), log::LevelFilter::Trace) - .filter(Some(LOG_TARGET), log::LevelFilter::Trace) - .try_init(); + let _ = sp_tracing::init_for_tests(); let pool = sp_core::testing::TaskExecutor::new(); diff --git a/polkadot/node/network/collator-protocol/src/validator_side/tests/mod.rs b/polkadot/node/network/collator-protocol/src/validator_side/tests/mod.rs index 44e25efd4dfcd30536fca2dc766dc1f18b1851b4..86c8bcb6bdcdbcad7fb7fbf6f1d73666331348ff 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/tests/mod.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/tests/mod.rs @@ -156,11 +156,7 @@ fn test_harness>( reputation: ReputationAggregator, test: impl FnOnce(TestHarness) -> T, ) { - let _ = env_logger::builder() - .is_test(true) - .filter(Some("polkadot_collator_protocol"), log::LevelFilter::Trace) - .filter(Some(LOG_TARGET), log::LevelFilter::Trace) - .try_init(); + sp_tracing::init_for_tests(); let pool = sp_core::testing::TaskExecutor::new(); 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/statement-distribution/src/v2/mod.rs b/polkadot/node/network/statement-distribution/src/v2/mod.rs index 47d350849b206913b9e493cd9befd6086d0c4e7b..109c29f520c5b3ff6f7d5b2ee5b778b98333cb6e 100644 --- a/polkadot/node/network/statement-distribution/src/v2/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/mod.rs @@ -2237,7 +2237,9 @@ async fn fragment_chain_update_inner( // 2. find out which are in the frontier gum::debug!( target: LOG_TARGET, - "Calling getHypotheticalMembership from statement distribution" + active_leaf_hash = ?active_leaf_hash, + "Calling getHypotheticalMembership from statement distribution for candidates: {:?}", + &hypotheticals.iter().map(|hypo| hypo.candidate_hash()).collect::>() ); let candidate_memberships = { let (tx, rx) = oneshot::channel(); diff --git a/polkadot/node/overseer/src/lib.rs b/polkadot/node/overseer/src/lib.rs index 4e13d5eda76f61c646ad0814e1ec3d8068a11ca1..baaff9c7c9f63c5cff812e5ae01097ca538c4d75 100644 --- a/polkadot/node/overseer/src/lib.rs +++ b/polkadot/node/overseer/src/lib.rs @@ -466,7 +466,7 @@ pub async fn forward_events>(client: Arc

, mut hand message_capacity=2048, )] pub struct Overseer { - #[subsystem(blocking, CandidateValidationMessage, sends: [ + #[subsystem(CandidateValidationMessage, sends: [ RuntimeApiMessage, ])] candidate_validation: CandidateValidation, diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index 660b504e97fbb1bc11c1bfd57011931157e4770d..24c69582731b7cbc7857beda75f0dddac77708b3 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.14.0"; +pub const NODE_VERSION: &'static str = "1.15.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 c0ddbf7dcfc36d89591567a88075c2344b025b04..216aa10e8acb8697ec78fb6e860d8d2f92c93b58 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -149,7 +149,7 @@ xcm-runtime-apis = { workspace = true, default-features = true } polkadot-test-client = { workspace = true } polkadot-node-subsystem-test-helpers = { workspace = true } polkadot-primitives-test-helpers = { workspace = true } -env_logger = { workspace = true } +sp-tracing = { workspace = true } assert_matches = { workspace = true } serial_test = { workspace = true } tempfile = { workspace = true } 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/chain_spec.rs b/polkadot/node/service/src/chain_spec.rs index 0358bc300ab06289b428c480439cc33a5fcae7ed..f930476a5541af602b3f9a6e14cab9b9ba580182 100644 --- a/polkadot/node/service/src/chain_spec.rs +++ b/polkadot/node/service/src/chain_spec.rs @@ -658,7 +658,8 @@ fn westend_local_testnet_genesis() -> serde_json::Value { #[cfg(feature = "westend-native")] pub fn westend_local_testnet_config() -> Result { Ok(WestendChainSpec::builder( - westend::WASM_BINARY.ok_or("Westend development wasm not available")?, + westend::fast_runtime_binary::WASM_BINARY + .ok_or("Westend development wasm not available")?, Default::default(), ) .with_name("Westend Local Testnet") diff --git a/polkadot/node/service/src/fake_runtime_api.rs b/polkadot/node/service/src/fake_runtime_api.rs index e971830c95cb2de51b6d5cf25a154f8a9a701deb..cdef39d5bdf1805d1066fdeba9cb09f0037261b1 100644 --- a/polkadot/node/service/src/fake_runtime_api.rs +++ b/polkadot/node/service/src/fake_runtime_api.rs @@ -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 { 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/service/src/tests.rs b/polkadot/node/service/src/tests.rs index bebd050710135a97ab616c8fe8c3ba21b6d0b9b9..195432bcb75d84a3fa1a5428efdb2d50fd76a910 100644 --- a/polkadot/node/service/src/tests.rs +++ b/polkadot/node/service/src/tests.rs @@ -70,10 +70,7 @@ fn test_harness>( case_vars: CaseVars, test: impl FnOnce(TestHarness) -> T, ) { - let _ = env_logger::builder() - .is_test(true) - .filter_level(log::LevelFilter::Trace) - .try_init(); + sp_tracing::init_for_tests(); let pool = TaskExecutor::new(); let (mut context, virtual_overseer) = diff --git a/polkadot/node/subsystem-bench/Cargo.toml b/polkadot/node/subsystem-bench/Cargo.toml index 0325613d25f9a716f9a0189e8bb9db91d9051e8c..9384f8142a97020ff17d300ba29fd523d64ecd6d 100644 --- a/polkadot/node/subsystem-bench/Cargo.toml +++ b/polkadot/node/subsystem-bench/Cargo.toml @@ -49,7 +49,7 @@ 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 = { workspace = true } +sp-tracing = { workspace = true } rand = { workspace = true, default-features = true } # `rand` only supports uniform distribution, we need normal distribution for latency. rand_distr = { workspace = true } diff --git a/polkadot/node/subsystem-bench/src/cli/subsystem-bench.rs b/polkadot/node/subsystem-bench/src/cli/subsystem-bench.rs index 346a058b9796e2ccfe0aab2b6fbbac6fb1f600d7..153efdda4056f5ffd96a9cf7692cf51b2a07f440 100644 --- a/polkadot/node/subsystem-bench/src/cli/subsystem-bench.rs +++ b/polkadot/node/subsystem-bench/src/cli/subsystem-bench.rs @@ -184,14 +184,7 @@ impl BenchCli { fn main() -> eyre::Result<()> { color_eyre::install()?; - env_logger::builder() - .filter(Some("hyper"), log::LevelFilter::Info) - // Avoid `Terminating due to subsystem exit subsystem` warnings - .filter(Some("polkadot_overseer"), log::LevelFilter::Error) - .filter(None, log::LevelFilter::Info) - .format_timestamp_millis() - .try_init() - .unwrap(); + sp_tracing::try_init_simple(); let cli: BenchCli = BenchCli::parse(); cli.launch()?; diff --git a/polkadot/node/subsystem-bench/src/lib/approval/mod.rs b/polkadot/node/subsystem-bench/src/lib/approval/mod.rs index 4ac044ea3459a225536069f0057c78b7075bc463..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,13 +61,14 @@ 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, + 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; @@ -792,6 +795,12 @@ fn build_overseer( 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()); @@ -831,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"); 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 ee45ea05c925a433394de3e3e5e2c315dac0aff2..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, ValidationCode, 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; @@ -297,6 +297,13 @@ impl MockRuntimeApi { 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-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index ee937bca05bfedbcf3e25103ebdf9c765b967401..d067ca468011d6f196efef42b012f6c8f1459cb7 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -43,13 +43,13 @@ use polkadot_node_primitives::{ }; use polkadot_primitives::{ async_backing, slashing, ApprovalVotingParams, AuthorityDiscoveryId, BackedCandidate, - BlockNumber, CandidateEvent, CandidateHash, CandidateIndex, CandidateReceipt, CollatorId, - CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, GroupIndex, - GroupRotationInfo, Hash, HeadData, Header as BlockHeader, Id as ParaId, InboundDownwardMessage, - InboundHrmpMessage, MultiDisputeStatementSet, NodeFeatures, OccupiedCoreAssumption, - PersistedValidationData, PvfCheckStatement, PvfExecKind, SessionIndex, SessionInfo, - SignedAvailabilityBitfield, SignedAvailabilityBitfields, ValidationCode, ValidationCodeHash, - ValidatorId, ValidatorIndex, ValidatorSignature, + BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, CandidateIndex, + CandidateReceipt, CollatorId, CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, + ExecutorParams, GroupIndex, GroupRotationInfo, Hash, HeadData, Header as BlockHeader, + Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, MultiDisputeStatementSet, + NodeFeatures, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, PvfExecKind, + SessionIndex, SessionInfo, SignedAvailabilityBitfield, SignedAvailabilityBitfields, + ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; use polkadot_statement_table::v2::Misbehavior; use std::{ @@ -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. @@ -1116,6 +1126,32 @@ impl HypotheticalCandidate { HypotheticalCandidate::Incomplete { .. } => None, } } + + /// Get the candidate commitments, if the candidate is complete. + pub fn commitments(&self) -> Option<&CandidateCommitments> { + match *self { + HypotheticalCandidate::Complete { ref receipt, .. } => Some(&receipt.commitments), + HypotheticalCandidate::Incomplete { .. } => None, + } + } + + /// Get the persisted validation data, if the candidate is complete. + pub fn persisted_validation_data(&self) -> Option<&PersistedValidationData> { + match *self { + HypotheticalCandidate::Complete { ref persisted_validation_data, .. } => + Some(persisted_validation_data), + HypotheticalCandidate::Incomplete { .. } => None, + } + } + + /// Get the validation code hash, if the candidate is complete. + pub fn validation_code_hash(&self) -> Option<&ValidationCodeHash> { + match *self { + HypotheticalCandidate::Complete { ref receipt, .. } => + Some(&receipt.descriptor.validation_code_hash), + HypotheticalCandidate::Incomplete { .. } => None, + } + } } /// Request specifying which candidates are either already included diff --git a/polkadot/node/subsystem-util/Cargo.toml b/polkadot/node/subsystem-util/Cargo.toml index 98ea21f250eda7874f03ba1aeffd482fedbc8808..a7157d1b5b7f46627665fb96d97f28c95fb105ec 100644 --- a/polkadot/node/subsystem-util/Cargo.toml +++ b/polkadot/node/subsystem-util/Cargo.toml @@ -45,7 +45,6 @@ parity-db = { workspace = true } [dev-dependencies] 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 = { workspace = true } diff --git a/polkadot/node/subsystem-util/src/backing_implicit_view.rs b/polkadot/node/subsystem-util/src/backing_implicit_view.rs index 23a758d25715bbd33251b5edf8835ca3625f3ffa..a805ef8165e5fe108cf292c4eff04bf8d0f7e486 100644 --- a/polkadot/node/subsystem-util/src/backing_implicit_view.rs +++ b/polkadot/node/subsystem-util/src/backing_implicit_view.rs @@ -25,6 +25,7 @@ use polkadot_primitives::{BlockNumber, Hash, Id as ParaId}; use std::collections::HashMap; use crate::{ + inclusion_emulator::RelayChainBlockInfo, request_session_index_for_child, runtime::{self, prospective_parachains_mode, recv_runtime, ProspectiveParachainsMode}, }; @@ -121,6 +122,26 @@ struct BlockInfo { parent_hash: Hash, } +/// Information about a relay-chain block, to be used when calling this module from prospective +/// parachains. +#[derive(Debug, Clone, PartialEq)] +pub struct BlockInfoProspectiveParachains { + /// The hash of the relay-chain block. + pub hash: Hash, + /// The hash of the parent relay-chain block. + pub parent_hash: Hash, + /// The number of the relay-chain block. + pub number: BlockNumber, + /// The storage-root of the relay-chain block. + pub storage_root: Hash, +} + +impl From for RelayChainBlockInfo { + fn from(value: BlockInfoProspectiveParachains) -> Self { + Self { hash: value.hash, number: value.number, storage_root: value.storage_root } + } +} + impl View { /// Get an iterator over active leaves in the view. pub fn leaves(&self) -> impl Iterator { @@ -178,6 +199,61 @@ impl View { } } + /// Activate a leaf in the view. To be used by the prospective parachains subsystem. + /// + /// This will not request any additional data, as prospective parachains already provides all + /// the required info. + /// NOTE: using `activate_leaf` instead of this function will result in a + /// deadlock, as it calls prospective-parachains under the hood. + /// + /// No-op for known leaves. + pub fn activate_leaf_from_prospective_parachains( + &mut self, + leaf: BlockInfoProspectiveParachains, + ancestors: &[BlockInfoProspectiveParachains], + ) { + if self.leaves.contains_key(&leaf.hash) { + return + } + + // Retain at least `MINIMUM_RETAIN_LENGTH` blocks in storage. + // This helps to avoid Chain API calls when activating leaves in the + // same chain. + let retain_minimum = std::cmp::min( + ancestors.last().map(|a| a.number).unwrap_or(0), + leaf.number.saturating_sub(MINIMUM_RETAIN_LENGTH), + ); + + self.leaves.insert(leaf.hash, ActiveLeafPruningInfo { retain_minimum }); + let mut allowed_relay_parents = AllowedRelayParents { + allowed_relay_parents_contiguous: Vec::with_capacity(ancestors.len()), + // In this case, initialise this to an empty map, as prospective parachains already has + // this data and it won't query the implicit view for it. + minimum_relay_parents: HashMap::new(), + }; + + for ancestor in ancestors { + self.block_info_storage.insert( + ancestor.hash, + BlockInfo { + block_number: ancestor.number, + maybe_allowed_relay_parents: None, + parent_hash: ancestor.parent_hash, + }, + ); + allowed_relay_parents.allowed_relay_parents_contiguous.push(ancestor.hash); + } + + self.block_info_storage.insert( + leaf.hash, + BlockInfo { + block_number: leaf.number, + maybe_allowed_relay_parents: Some(allowed_relay_parents), + parent_hash: leaf.parent_hash, + }, + ); + } + /// Deactivate a leaf in the view. This prunes any outdated implicit ancestors as well. /// /// Returns hashes of blocks pruned from storage. diff --git a/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs b/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs index b5aef325c8b437ec43c2872f130651de65c28a52..0c3b40743495c0d219b79a1a3e19f915a1c59fed 100644 --- a/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs +++ b/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs @@ -39,8 +39,8 @@ /// /// # Usage /// -/// It's expected that the users of this module will be building up chains of -/// [`Fragment`]s and consistently pruning and adding to the chains. +/// It's expected that the users of this module will be building up chains or trees of +/// [`Fragment`]s and consistently pruning and adding to them. /// /// ## Operating Constraints /// @@ -56,55 +56,19 @@ /// /// ## Fragment Chains /// -/// For simplicity and practicality, we expect that collators of the same parachain are -/// cooperating and don't create parachain forks or cycles on the same relay chain active leaf. -/// Therefore, higher-level code should maintain one fragment chain for each active leaf (not a -/// fragment tree). If parachains do create forks, their performance in regards to async -/// backing and elastic scaling will suffer, because different validators will have different -/// predictions of the future. +/// For the sake of this module, we don't care how higher-level code is managing parachain +/// fragments, whether or not they're kept as a chain or tree. In reality, +/// prospective-parachains is maintaining for every active leaf, a chain of the "best" backable +/// candidates and a storage of potential candidates which may be added to this chain in the +/// future. /// /// As the relay-chain grows, some predictions come true and others come false. -/// And new predictions get made. These three changes correspond distinctly to the -/// 3 primary operations on fragment chains. +/// And new predictions get made. Higher-level code is responsible for adding and pruning the +/// fragments chains. /// /// Avoiding fragment-chain blowup is beyond the scope of this module. Higher-level must ensure /// proper spam protection. /// -/// ### Pruning Fragment Chains -/// -/// When the relay-chain advances, we want to compare the new constraints of that relay-parent -/// to the root of the fragment chain we have. There are 3 cases: -/// -/// 1. The root fragment is still valid under the new constraints. In this case, we do nothing. -/// This is the "prediction still uncertain" case. (Corresponds to some candidates still -/// being pending availability). -/// -/// 2. The root fragment (potentially along with a number of descendants) is invalid under the -/// new constraints because it has been included by the relay-chain. In this case, we can -/// discard the included chain and split & re-root the chain under its descendants and -/// compare to the new constraints again. This is the "prediction came true" case. -/// -/// 3. The root fragment becomes invalid under the new constraints for any reason (if for -/// example the parachain produced a fork and the block producer picked a different -/// candidate to back). In this case we can discard the entire fragment chain. This is the -/// "prediction came false" case. -/// -/// This is all a bit of a simplification because it assumes that the relay-chain advances -/// without forks and is finalized instantly. In practice, the set of fragment-chains needs to -/// be observable from the perspective of a few different possible forks of the relay-chain and -/// not pruned too eagerly. -/// -/// Note that the fragments themselves don't need to change and the only thing we care about -/// is whether the predictions they represent are still valid. -/// -/// ### Extending Fragment Chains -/// -/// As predictions fade into the past, new ones should be stacked on top. -/// -/// Every new relay-chain block is an opportunity to make a new prediction about the future. -/// Higher-level logic should decide whether to build upon an existing chain or whether -/// to create a new fragment-chain. -/// /// ### Code Upgrades /// /// Code upgrades are the main place where this emulation fails. The on-chain PVF upgrade @@ -116,10 +80,11 @@ /// /// 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_node_subsystem::messages::HypotheticalCandidate; use polkadot_primitives::{ async_backing::Constraints as PrimitiveConstraints, BlockNumber, CandidateCommitments, - CollatorId, CollatorSignature, Hash, HeadData, Id as ParaId, PersistedValidationData, - UpgradeRestriction, ValidationCodeHash, + CandidateHash, Hash, HeadData, Id as ParaId, PersistedValidationData, UpgradeRestriction, + ValidationCodeHash, }; use std::{collections::HashMap, sync::Arc}; @@ -521,18 +486,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. @@ -708,6 +668,11 @@ impl Fragment { &self.candidate } + /// Get a cheap ref-counted copy of the underlying prospective candidate. + pub fn candidate_clone(&self) -> Arc { + self.candidate.clone() + } + /// Modifications to constraints based on the outputs of the candidate. pub fn constraint_modifications(&self) -> &ConstraintModifications { &self.modifications @@ -797,13 +762,59 @@ fn validate_against_constraints( .map_err(FragmentValidityError::OutputsInvalid) } +/// Trait for a hypothetical or concrete candidate, as needed when assessing the validity of a +/// potential candidate. +pub trait HypotheticalOrConcreteCandidate { + /// Return a reference to the candidate commitments, if present. + fn commitments(&self) -> Option<&CandidateCommitments>; + /// Return a reference to the persisted validation data, if present. + fn persisted_validation_data(&self) -> Option<&PersistedValidationData>; + /// Return a reference to the validation code hash, if present. + fn validation_code_hash(&self) -> Option<&ValidationCodeHash>; + /// Return the parent head hash. + fn parent_head_data_hash(&self) -> Hash; + /// Return the output head hash, if present. + fn output_head_data_hash(&self) -> Option; + /// Return the relay parent hash. + fn relay_parent(&self) -> Hash; + /// Return the candidate hash. + fn candidate_hash(&self) -> CandidateHash; +} + +impl HypotheticalOrConcreteCandidate for HypotheticalCandidate { + fn commitments(&self) -> Option<&CandidateCommitments> { + self.commitments() + } + + fn persisted_validation_data(&self) -> Option<&PersistedValidationData> { + self.persisted_validation_data() + } + + fn validation_code_hash(&self) -> Option<&ValidationCodeHash> { + self.validation_code_hash() + } + + fn parent_head_data_hash(&self) -> Hash { + self.parent_head_data_hash() + } + + fn output_head_data_hash(&self) -> Option { + self.output_head_data_hash() + } + + fn relay_parent(&self) -> Hash { + self.relay_parent() + } + + fn candidate_hash(&self) -> CandidateHash { + self.candidate_hash() + } +} + #[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 +1173,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 +1182,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/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/primitives/src/v7/mod.rs b/polkadot/primitives/src/v7/mod.rs index 06b7046520835b5d71f554e1c7c5c357eb6a6de9..a729d8cee4c7eaa7b654c018f115b17457e17256 100644 --- a/polkadot/primitives/src/v7/mod.rs +++ b/polkadot/primitives/src/v7/mod.rs @@ -2040,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/rpc/src/lib.rs b/polkadot/rpc/src/lib.rs index 7d678ada5ff5d5da0b383765891bdaf44f65cd46..eb0133b6e8fd6bc5d07d40e1fb917066285bf1bc 100644 --- a/polkadot/rpc/src/lib.rs +++ b/polkadot/rpc/src/lib.rs @@ -124,7 +124,6 @@ where use sc_consensus_babe_rpc::{Babe, BabeApiServer}; use sc_consensus_beefy_rpc::{Beefy, BeefyApiServer}; use sc_consensus_grandpa_rpc::{Grandpa, GrandpaApiServer}; - use sc_rpc_spec_v2::chain_spec::{ChainSpec, ChainSpecApiServer}; use sc_sync_state_rpc::{SyncState, SyncStateApiServer}; use substrate_frame_rpc_system::{System, SystemApiServer}; use substrate_state_trie_migration_rpc::{StateMigration, StateMigrationApiServer}; @@ -139,11 +138,6 @@ where finality_provider, } = grandpa; - let chain_name = chain_spec.name().to_string(); - let genesis_hash = client.hash(0).ok().flatten().expect("Genesis block exists; qed"); - let properties = chain_spec.properties(); - - io.merge(ChainSpec::new(chain_name, genesis_hash, properties).into_rpc())?; io.merge(StateMigration::new(client.clone(), backend.clone(), deny_unsafe).into_rpc())?; io.merge(System::new(client.clone(), pool.clone(), deny_unsafe).into_rpc())?; io.merge(TransactionPayment::new(client.clone()).into_rpc())?; diff --git a/polkadot/runtime/common/src/impls.rs b/polkadot/runtime/common/src/impls.rs index 9d61cd018731f1b1761c520e91f8a4b6521fd41a..b6a93cf53685418fb2ffcda417a6ea16af5cafdc 100644 --- a/polkadot/runtime/common/src/impls.rs +++ b/polkadot/runtime/common/src/impls.rs @@ -51,7 +51,7 @@ where ::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); @@ -371,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(|| { @@ -425,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/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 7afdf49fe55165e87ab936fff3259317c020c1f1..cfe373e8cba2e6c186ea62d7121aff5f3d4cafa7 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -30,6 +30,7 @@ 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 = { workspace = true } pallet-authorship = { workspace = true } @@ -37,6 +38,7 @@ 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 } @@ -86,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", @@ -109,6 +112,7 @@ std = [ "sp-runtime/std", "sp-session/std", "sp-staking/std", + "sp-std?/std", "xcm-executor/std", "xcm/std", ] @@ -120,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", @@ -128,6 +133,7 @@ runtime-benchmarks = [ "sp-application-crypto", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", + "sp-std", "static_assertions", "xcm-executor/runtime-benchmarks", ] @@ -141,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 9ed007919b81be6f1f68e9f35ff6dfbc46bffc81..7ee76600b42c07bdbb011ddad1d238ec95b89bcf 100644 --- a/polkadot/runtime/parachains/src/assigner_coretime/mod.rs +++ b/polkadot/runtime/parachains/src/assigner_coretime/mod.rs @@ -28,7 +28,7 @@ mod mock_helpers; mod tests; use crate::{ - assigner_on_demand, configuration, + configuration, on_demand, paras::AssignCoretime, scheduler::common::{Assignment, AssignmentProvider}, ParaId, @@ -201,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. /// @@ -281,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())), } }) @@ -291,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(_) => {}, } } @@ -304,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 9b0cbcb2d7d698b14f818690b26f767d3a22b431..e7994b8ef820773b4f310b6285303263170a2638 100644 --- a/polkadot/runtime/parachains/src/assigner_coretime/tests.rs +++ b/polkadot/runtime/parachains/src/assigner_coretime/tests.rs @@ -20,8 +20,8 @@ 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, @@ -75,7 +75,7 @@ fn run_to_block( Scheduler::initializer_initialize(b + 1); // Update the spot traffic and revenue on every block. - OnDemandAssigner::on_initialize(b + 1); + 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); @@ -527,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/builder.rs b/polkadot/runtime/parachains/src/builder.rs index 84fb1fb1a52bf9b7d6b0d5d32cf3ebeac752ed76..1cb1f2bbe7e941c9ff4fc51cd14492fc50f8b5e6 100644 --- a/polkadot/runtime/parachains/src/builder.rs +++ b/polkadot/runtime/parachains/src/builder.rs @@ -30,21 +30,30 @@ 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, }; +/// 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]) } @@ -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/coretime/benchmarking.rs b/polkadot/runtime/parachains/src/coretime/benchmarking.rs index 028250e188ee9885ad9c2c80d66ffa12f41be9e2..6d593f1954ff1500fd59ae5d178e038dd38e01b5 100644 --- a/polkadot/runtime/parachains/src/coretime/benchmarking.rs +++ b/polkadot/runtime/parachains/src/coretime/benchmarking.rs @@ -31,20 +31,20 @@ mod benchmarks { #[benchmark] fn request_revenue_at() { let root_origin = ::RuntimeOrigin::root(); - let mhr = ::MaxHistoricalRevenue::get(); + let mhr = ::MaxHistoricalRevenue::get(); frame_system::Pallet::::set_block_number((mhr + 2).into()); - let minimum_balance = ::Currency::minimum_balance(); + let minimum_balance = ::Currency::minimum_balance(); let rev: BoundedVec< - <::Currency as frame_support::traits::Currency< + <::Currency as frame_support::traits::Currency< T::AccountId, >>::Balance, T::MaxHistoricalRevenue, > = BoundedVec::try_from((1..=mhr).map(|v| minimum_balance * v.into()).collect::>()) .unwrap(); - assigner_on_demand::Revenue::::put(rev); + on_demand::Revenue::::put(rev); - ::Currency::make_free_balance_be( - &>::account_id(), + ::Currency::make_free_balance_be( + &>::account_id(), minimum_balance * (mhr * (mhr + 1)).into(), ); diff --git a/polkadot/runtime/parachains/src/coretime/mod.rs b/polkadot/runtime/parachains/src/coretime/mod.rs index 1c38b3989232b754491f9fe00a6eb49b7433b810..fbd8935f1990233ebfded2db9f31ac4b241bebde 100644 --- a/polkadot/runtime/parachains/src/coretime/mod.rs +++ b/polkadot/runtime/parachains/src/coretime/mod.rs @@ -48,8 +48,8 @@ use xcm_executor::traits::TransactAsset; use crate::{ assigner_coretime::{self, PartsOf57600}, - assigner_on_demand, initializer::{OnNewSession, SessionChangeNotification}, + on_demand, origin::{ensure_parachain, Origin}, }; @@ -116,6 +116,7 @@ enum CoretimeCalls { #[frame_support::pallet] pub mod pallet { + use crate::configuration; use sp_runtime::traits::TryConvert; use xcm::v4::InteriorLocation; @@ -128,9 +129,7 @@ pub mod pallet { pub struct Pallet(_); #[pallet::config] - pub trait Config: - frame_system::Config + assigner_coretime::Config + assigner_on_demand::Config - { + pub trait Config: frame_system::Config + assigner_coretime::Config + on_demand::Config { type RuntimeOrigin: From<::RuntimeOrigin> + Into::RuntimeOrigin>>; type RuntimeEvent: From> + IsType<::RuntimeEvent>; @@ -308,7 +307,7 @@ impl Pallet { // When cannot be in the future. ensure!(until_bnf <= now, Error::::RequestedFutureRevenue); - let amount = >::claim_revenue_until(until_bnf); + 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(|_| { @@ -365,14 +364,15 @@ fn do_notify_revenue(when: BlockNumber, raw_revenue: Balance) -> Resu if raw_revenue > 0 { let on_demand_pot = - T::AccountToLocation::try_convert(&>::account_id()) - .map_err(|err| { + 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)?; diff --git a/polkadot/runtime/parachains/src/inclusion/mod.rs b/polkadot/runtime/parachains/src/inclusion/mod.rs index 9bc7be654014615fb66d42b48ff684be178cc69b..d7979deb3d9504a1e81d589de4aa7b9b8335a86e 100644 --- a/polkadot/runtime/parachains/src/inclusion/mod.rs +++ b/polkadot/runtime/parachains/src/inclusion/mod.rs @@ -338,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. @@ -640,6 +638,8 @@ impl Pallet { for (candidate, core) in para_candidates.iter() { let candidate_hash = candidate.candidate().hash(); + // The previous context is None, as it's already checked during candidate + // sanitization. let check_ctx = CandidateCheckContext::::new(None); let relay_parent_number = check_ctx.verify_backed_candidate( &allowed_relay_parents, @@ -719,7 +719,7 @@ impl Pallet { }) } - // Get the latest backed output head data of this para. + // Get the latest backed output head data of this para (including pending availability). pub(crate) fn para_latest_head_data(para_id: &ParaId) -> Option { match PendingAvailability::::get(para_id).and_then(|pending_candidates| { pending_candidates.back().map(|x| x.commitments.head_data.clone()) @@ -729,6 +729,16 @@ impl Pallet { } } + // Get the relay parent number of the most recent candidate (including pending availability). + pub(crate) fn para_most_recent_context(para_id: &ParaId) -> Option> { + match PendingAvailability::::get(para_id) + .and_then(|pending_candidates| pending_candidates.back().map(|x| x.relay_parent_number)) + { + Some(relay_parent_number) => Some(relay_parent_number), + None => paras::MostRecentContext::::get(para_id), + } + } + fn check_backing_votes( backed_candidate: &BackedCandidate, validators: &[ValidatorId], @@ -798,7 +808,7 @@ impl Pallet { relay_parent_number: BlockNumberFor, validation_outputs: polkadot_primitives::CandidateCommitments, ) -> bool { - let prev_context = paras::MostRecentContext::::get(para_id); + let prev_context = Self::para_most_recent_context(¶_id); let check_ctx = CandidateCheckContext::::new(prev_context); if check_ctx @@ -1219,7 +1229,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 /// @@ -1256,11 +1265,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/lib.rs b/polkadot/runtime/parachains/src/lib.rs index f2995d770e716447a5ada5b816a255b3725b2982..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; diff --git a/polkadot/runtime/parachains/src/mock.rs b/polkadot/runtime/parachains/src/mock.rs index 45576668f6d6267e414e656b411fc593e6f5450f..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, @@ -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, @@ -401,11 +400,11 @@ parameter_types! { pub const OnDemandPalletId: PalletId = PalletId(*b"py/ondmd"); } -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; } @@ -540,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) {} 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 b0ebfe77a9665bf08ea62c44b1381866372c54bb..d494a77a5c4dbeee27e510e4df35f1f78741b885 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/benchmarking.rs +++ b/polkadot/runtime/parachains/src/on_demand/benchmarking.rs @@ -94,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 94% rename from polkadot/runtime/parachains/src/assigner_on_demand/migration.rs rename to polkadot/runtime/parachains/src/on_demand/migration.rs index 03f63d7333b65adddd371168e85cdb19d95b10e2..6cc25b20afb86204aa9324949032b9df67835426 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/migration.rs +++ b/polkadot/runtime/parachains/src/on_demand/migration.rs @@ -47,7 +47,7 @@ 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(core::marker::PhantomData); @@ -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 99% rename from polkadot/runtime/parachains/src/assigner_on_demand/mod.rs rename to polkadot/runtime/parachains/src/on_demand/mod.rs index f045e957a6907b9e01be4d30c533c324f62fb907..dc046c194fd0b114ba0407878dea05d497be1f1b 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs +++ b/polkadot/runtime/parachains/src/on_demand/mod.rs @@ -66,7 +66,7 @@ use types::{ SpotTrafficCalculationErr, }; -const LOG_TARGET: &str = "runtime::parachains::assigner-on-demand"; +const LOG_TARGET: &str = "runtime::parachains::on-demand"; pub use pallet::*; diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs b/polkadot/runtime/parachains/src/on_demand/tests.rs similarity index 72% rename from polkadot/runtime/parachains/src/assigner_on_demand/tests.rs rename to polkadot/runtime/parachains/src/on_demand/tests.rs index 0bad4346cfd9d8efb42db2bd66c7d64c0213a803..9742954118103b5b46895dde5fc7456a59bf2877 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs +++ b/polkadot/runtime/parachains/src/on_demand/tests.rs @@ -17,17 +17,17 @@ use super::*; use crate::{ - assigner_on_demand::{ + initializer::SessionChangeNotification, + mock::{ + new_test_ext, Balances, OnDemand, Paras, ParasShared, RuntimeOrigin, Scheduler, System, + Test, + }, + on_demand::{ self, mock_helpers::GenesisConfigBuilder, types::{QueueIndex, ReverseQueueIndex}, Error, }, - initializer::SessionChangeNotification, - mock::{ - new_test_ext, Balances, OnDemandAssigner, Paras, ParasShared, RuntimeOrigin, Scheduler, - System, Test, - }, paras::{ParaGenesisArgs, ParaKind}, }; use alloc::collections::btree_map::BTreeMap; @@ -83,7 +83,7 @@ fn run_to_block( Scheduler::initializer_initialize(b + 1); // Update the spot traffic and revenue on every block. - OnDemandAssigner::on_initialize(b + 1); + 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); @@ -99,7 +99,7 @@ fn place_order_run_to_blocknumber(para_id: ParaId, blocknumber: Option::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)); }); } @@ -336,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 ); }); @@ -357,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 { @@ -367,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) ); }); @@ -400,30 +385,21 @@ fn push_back_assignment_works() { 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); }); } @@ -439,8 +415,8 @@ 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_run_to_101(para_a); @@ -449,22 +425,22 @@ fn affinity_prohibits_parallel_scheduling() { // 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_run_to_101(para_a); @@ -473,25 +449,25 @@ fn affinity_prohibits_parallel_scheduling() { // 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()); }); } @@ -505,7 +481,7 @@ 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 { @@ -513,46 +489,46 @@ fn affinity_changes_work() { } // 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()); }); } @@ -577,28 +553,25 @@ fn new_affinity_for_a_core_must_come_from_free_entries() { }); // 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); }, @@ -607,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); }); }); } @@ -691,7 +664,7 @@ 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 }); @@ -703,27 +676,27 @@ fn queue_status_size_fn_works() { }); // 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) }); } @@ -734,25 +707,30 @@ fn revenue_information_fetching_works() { 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 = OnDemandAssigner::claim_revenue_until(10); + 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 = OnDemandAssigner::get_revenue(); - let claim = OnDemandAssigner::claim_revenue_until(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!(claim, 0); + assert_eq!(amt, 0); - run_to_block(12, |n| if n == 12 { Some(Default::default()) } else { None }); - let claim = OnDemandAssigner::claim_revenue_until(12); + 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!(claim, revenue[0]); + 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); @@ -762,9 +740,9 @@ fn revenue_information_fetching_works() { place_order(para_a); - run_to_block(15, |n| if n == 14 { Some(Default::default()) } else { None }); + run_to_block(14, |n| if n == 14 { Some(Default::default()) } else { None }); - let revenue = OnDemandAssigner::claim_revenue_until(15); + let revenue = OnDemand::claim_revenue_until(15); // All 3 orders should be accounted for. assert_eq!(revenue, 30_000); @@ -772,13 +750,13 @@ fn revenue_information_fetching_works() { // Place one order place_order_run_to_blocknumber(para_a, Some(16)); - let revenue = OnDemandAssigner::claim_revenue_until(15); + let revenue = OnDemand::claim_revenue_until(15); // Order is not in range of the revenue_until call assert_eq!(revenue, 0); - run_to_block(21, |n| if n == 20 { Some(Default::default()) } else { None }); - let revenue = OnDemandAssigner::claim_revenue_until(21); + 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 @@ -786,8 +764,7 @@ fn revenue_information_fetching_works() { run_to_block(i, |n| if n % 10 == 0 { Some(Default::default()) } else { None }); place_order(para_a); } - run_to_block(36, |_| None); - let revenue = OnDemandAssigner::claim_revenue_until(36); + let revenue = OnDemand::claim_revenue_until(36); assert_eq!(revenue, 150_000); }); } @@ -796,7 +773,7 @@ fn revenue_information_fetching_works() { fn pot_account_is_immortal() { new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { let para_a = ParaId::from(111); - let pot = OnDemandAssigner::account_id(); + 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. @@ -807,7 +784,7 @@ fn pot_account_is_immortal() { assert!(purchase_revenue > 0); run_to_block(15, |_| None); - let _imb = ::Currency::withdraw( + let _imb = ::Currency::withdraw( &pot, purchase_revenue, WithdrawReasons::FEE, @@ -824,7 +801,7 @@ fn pot_account_is_immortal() { assert!(purchase_revenue > 0); run_to_block(25, |_| None); - let _imb = ::Currency::withdraw( + let _imb = ::Currency::withdraw( &pot, purchase_revenue, WithdrawReasons::FEE, diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/types.rs b/polkadot/runtime/parachains/src/on_demand/types.rs similarity index 99% rename from polkadot/runtime/parachains/src/assigner_on_demand/types.rs rename to polkadot/runtime/parachains/src/on_demand/types.rs index 96367b971fed52c2de43f3f997101b107e11d1ec..c87e7abaf86071f6233d4ed6532b3813c45e2a7f 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/types.rs +++ b/polkadot/runtime/parachains/src/on_demand/types.rs @@ -116,7 +116,7 @@ impl QueueStatusType { pub fn consume_index(&mut self, removed_index: QueueIndex) { if removed_index != self.smallest_index { self.freed_indices.push(removed_index.reverse()); - return; + return } let mut index = self.smallest_index.0.overflowing_add(1).0; // Even more to advance? diff --git a/polkadot/runtime/parachains/src/paras/benchmarking.rs b/polkadot/runtime/parachains/src/paras/benchmarking.rs index 630b86132ab88681ed438f6a0cdd6e2d131c5522..7bf8b833ed915df49aabcb9047ec889076836af0 100644 --- a/polkadot/runtime/parachains/src/paras/benchmarking.rs +++ b/polkadot/runtime/parachains/src/paras/benchmarking.rs @@ -24,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/mod.rs b/polkadot/runtime/parachains/src/paras/mod.rs index 3f0b8659b159977ec8e8544da4c5fc6a4cd6d4bf..a4c404de2a651d0a4359a59fa9efb66b275defe8 100644 --- a/polkadot/runtime/parachains/src/paras/mod.rs +++ b/polkadot/runtime/parachains/src/paras/mod.rs @@ -135,7 +135,7 @@ 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; @@ -1222,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 @@ -1291,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/mod.rs b/polkadot/runtime/parachains/src/paras_inherent/mod.rs index 06b511072a3ee02d9586b79d76038691075e5262..add5b939aa6125ec94f18948ba71830138a506d5 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/mod.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/mod.rs @@ -1240,22 +1240,27 @@ fn filter_unchained_candidates>>, allowed_relay_parents: &AllowedRelayParentsTracker>, ) { - let mut para_latest_head_data: BTreeMap = BTreeMap::new(); + let mut para_latest_context: BTreeMap)> = BTreeMap::new(); for para_id in candidates.keys() { - let latest_head_data = match inclusion::Pallet::::para_latest_head_data(¶_id) { - None => { - defensive!("Latest included head data for paraid {:?} is None", para_id); - continue - }, - Some(latest_head_data) => latest_head_data, + let Some(latest_head_data) = inclusion::Pallet::::para_latest_head_data(¶_id) else { + defensive!("Latest included head data for paraid {:?} is None", para_id); + continue }; - para_latest_head_data.insert(*para_id, latest_head_data); + let Some(latest_relay_parent) = inclusion::Pallet::::para_most_recent_context(¶_id) + else { + defensive!("Latest relay parent for paraid {:?} is None", para_id); + continue + }; + para_latest_context.insert(*para_id, (latest_head_data, latest_relay_parent)); } let mut para_visited_candidates: BTreeMap> = BTreeMap::new(); retain_candidates::(candidates, |para_id, candidate| { - let Some(latest_head_data) = para_latest_head_data.get(¶_id) else { return false }; + let Some((latest_head_data, latest_relay_parent)) = para_latest_context.get(¶_id) + else { + return false + }; let candidate_hash = candidate.candidate().hash(); let visited_candidates = @@ -1274,15 +1279,23 @@ fn filter_unchained_candidates::get(para_id); - let check_ctx = CandidateCheckContext::::new(prev_context); + let check_ctx = CandidateCheckContext::::new(Some(*latest_relay_parent)); - let res = match check_ctx.verify_backed_candidate( + match check_ctx.verify_backed_candidate( &allowed_relay_parents, candidate.candidate(), latest_head_data.clone(), ) { - Ok(_) => true, + Ok(relay_parent_block_number) => { + para_latest_context.insert( + para_id, + ( + candidate.candidate().commitments.head_data.clone(), + relay_parent_block_number, + ), + ); + true + }, Err(err) => { log::debug!( target: LOG_TARGET, @@ -1293,14 +1306,7 @@ fn filter_unchained_candidates::force_set_most_recent_context( + RuntimeOrigin::root(), + ParaId::from(1), + BlockNumberFor::::from(0u32), + ) + .unwrap(); + paras::Pallet::::force_set_most_recent_context( + RuntimeOrigin::root(), + ParaId::from(2), + BlockNumberFor::::from(0u32), + ) + .unwrap(); // Callback used for backing candidates let group_validators = |group_index: GroupIndex| { @@ -2086,23 +2099,21 @@ mod sanitizers { ValidationCode(vec![id as u8]), ) .unwrap(); + paras::Pallet::::force_set_most_recent_context( + RuntimeOrigin::root(), + ParaId::from(id), + BlockNumberFor::::from(0u32), + ) + .unwrap(); } // Callback used for backing candidates let group_validators = |group_index: GroupIndex| { - match group_index { - group_index if group_index == GroupIndex::from(0) => Some(vec![0]), - group_index if group_index == GroupIndex::from(1) => Some(vec![1]), - group_index if group_index == GroupIndex::from(2) => Some(vec![2]), - group_index if group_index == GroupIndex::from(3) => Some(vec![3]), - group_index if group_index == GroupIndex::from(4) => Some(vec![4]), - group_index if group_index == GroupIndex::from(5) => Some(vec![5]), - group_index if group_index == GroupIndex::from(6) => Some(vec![6]), - group_index if group_index == GroupIndex::from(7) => Some(vec![7]), - - _ => panic!("Group index out of bounds"), + if group_index.0 as usize >= validators.len() { + panic!("Group index out of bounds") + } else { + Some(vec![ValidatorIndex(group_index.0)]) } - .map(|m| m.into_iter().map(ValidatorIndex).collect::>()) }; let mut backed_candidates = vec![]; @@ -2488,18 +2499,16 @@ mod sanitizers { // Para 4 scheduled on core 7 and 8. Duplicated candidates. fn get_test_data_for_order_checks(core_index_enabled: bool) -> TestData { const RELAY_PARENT_NUM: u32 = 3; + let header = default_header(); + let relay_parent = header.hash(); - // Add the relay parent to `shared` pallet. Otherwise some code (e.g. filtering backing - // votes) won't behave correctly shared::Pallet::::add_allowed_relay_parent( - default_header().hash(), + relay_parent, Default::default(), RELAY_PARENT_NUM, 1, ); - let header = default_header(); - let relay_parent = header.hash(); let session_index = SessionIndex::from(0_u32); let keystore = LocalKeystore::in_memory(); @@ -2620,24 +2629,21 @@ mod sanitizers { ValidationCode(vec![id as u8]), ) .unwrap(); + paras::Pallet::::force_set_most_recent_context( + RuntimeOrigin::root(), + ParaId::from(id), + BlockNumberFor::::from(0u32), + ) + .unwrap(); } // Callback used for backing candidates let group_validators = |group_index: GroupIndex| { - match group_index { - group_index if group_index == GroupIndex::from(0) => Some(vec![0]), - group_index if group_index == GroupIndex::from(1) => Some(vec![1]), - group_index if group_index == GroupIndex::from(2) => Some(vec![2]), - group_index if group_index == GroupIndex::from(3) => Some(vec![3]), - group_index if group_index == GroupIndex::from(4) => Some(vec![4]), - group_index if group_index == GroupIndex::from(5) => Some(vec![5]), - group_index if group_index == GroupIndex::from(6) => Some(vec![6]), - group_index if group_index == GroupIndex::from(7) => Some(vec![7]), - group_index if group_index == GroupIndex::from(8) => Some(vec![8]), - - _ => panic!("Group index out of bounds"), + if group_index.0 as usize >= validators.len() { + panic!("Group index out of bounds") + } else { + Some(vec![ValidatorIndex(group_index.0)]) } - .map(|m| m.into_iter().map(ValidatorIndex).collect::>()) }; let mut backed_candidates = vec![]; @@ -2983,6 +2989,430 @@ mod sanitizers { } } + // Para 1 scheduled on cores 0, 1 and 2. Three candidates are supplied but their relay + // parents look like this: 3, 2, 3. + // Para 2 scheduled on cores 3, 4 and 5. Three candidates are supplied and their relay + // parents look like this: 2, 3, 3. + fn get_test_data_for_relay_parent_ordering(core_index_enabled: bool) -> TestData { + const RELAY_PARENT_NUM: u32 = 3; + let header = default_header(); + let relay_parent = header.hash(); + + let prev_relay_parent = polkadot_primitives::Header { + parent_hash: Default::default(), + number: RELAY_PARENT_NUM - 1, + state_root: Default::default(), + extrinsics_root: Default::default(), + digest: Default::default(), + } + .hash(); + + let next_relay_parent = polkadot_primitives::Header { + parent_hash: Default::default(), + number: RELAY_PARENT_NUM + 1, + state_root: Default::default(), + extrinsics_root: Default::default(), + digest: Default::default(), + } + .hash(); + + // Add the relay parent to `shared` pallet. Otherwise some code (e.g. filtering backing + // votes) won't behave correctly + shared::Pallet::::add_allowed_relay_parent( + prev_relay_parent, + Default::default(), + RELAY_PARENT_NUM - 1, + 2, + ); + + shared::Pallet::::add_allowed_relay_parent( + relay_parent, + Default::default(), + RELAY_PARENT_NUM, + 2, + ); + + shared::Pallet::::add_allowed_relay_parent( + next_relay_parent, + Default::default(), + RELAY_PARENT_NUM + 1, + 2, + ); + + let session_index = SessionIndex::from(0_u32); + + let keystore = LocalKeystore::in_memory(); + let keystore = Arc::new(keystore) as KeystorePtr; + let signing_context = SigningContext { parent_hash: relay_parent, session_index }; + + let validators = vec![ + sp_keyring::Sr25519Keyring::Alice, + sp_keyring::Sr25519Keyring::Bob, + sp_keyring::Sr25519Keyring::Charlie, + sp_keyring::Sr25519Keyring::Dave, + sp_keyring::Sr25519Keyring::Eve, + sp_keyring::Sr25519Keyring::Ferdie, + ]; + for validator in validators.iter() { + Keystore::sr25519_generate_new( + &*keystore, + PARACHAIN_KEY_TYPE_ID, + Some(&validator.to_seed()), + ) + .unwrap(); + } + + // Set active validators in `shared` pallet + let validator_ids = + validators.iter().map(|v| v.public().into()).collect::>(); + shared::Pallet::::set_active_validators_ascending(validator_ids); + + // Set the validator groups in `scheduler` + scheduler::Pallet::::set_validator_groups(vec![ + vec![ValidatorIndex(0)], + vec![ValidatorIndex(1)], + vec![ValidatorIndex(2)], + vec![ValidatorIndex(3)], + vec![ValidatorIndex(4)], + vec![ValidatorIndex(5)], + ]); + + // Update scheduler's claimqueue with the parachains + scheduler::Pallet::::set_claim_queue(BTreeMap::from([ + ( + CoreIndex::from(0), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(0) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(1), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(1) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(2), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(2) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(3), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(3) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(4), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(4) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(5), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(5) }, + RELAY_PARENT_NUM, + )]), + ), + ])); + + // Set the on-chain included head data and current code hash. + for id in 1..=2u32 { + paras::Pallet::::set_current_head(ParaId::from(id), HeadData(vec![id as u8])); + paras::Pallet::::force_set_current_code( + RuntimeOrigin::root(), + ParaId::from(id), + ValidationCode(vec![id as u8]), + ) + .unwrap(); + paras::Pallet::::force_set_most_recent_context( + RuntimeOrigin::root(), + ParaId::from(id), + BlockNumberFor::::from(0u32), + ) + .unwrap(); + } + + // Callback used for backing candidates + let group_validators = |group_index: GroupIndex| { + if group_index.0 as usize >= validators.len() { + panic!("Group index out of bounds") + } else { + Some(vec![ValidatorIndex(group_index.0)]) + } + }; + + let mut backed_candidates = vec![]; + let mut expected_backed_candidates_with_core = BTreeMap::new(); + + // Para 1 + { + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(1), + relay_parent, + pov_hash: Hash::repeat_byte(1 as u8), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(1), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), + head_data: HeadData(vec![1, 1]), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![1]), + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let prev_candidate = candidate.clone(); + let backed: BackedCandidate = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(0 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(0 as u32)), + ); + backed_candidates.push(backed.clone()); + if core_index_enabled { + expected_backed_candidates_with_core + .entry(ParaId::from(1)) + .or_insert(vec![]) + .push((backed, CoreIndex(0))); + } + + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(1), + relay_parent: prev_relay_parent, + pov_hash: Hash::repeat_byte(1 as u8), + persisted_validation_data_hash: make_persisted_validation_data_with_parent::< + Test, + >( + RELAY_PARENT_NUM - 1, + Default::default(), + prev_candidate.commitments.head_data, + ) + .hash(), + hrmp_watermark: RELAY_PARENT_NUM - 1, + validation_code: ValidationCode(vec![1]), + head_data: HeadData(vec![1, 1, 1]), + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let prev_candidate = candidate.clone(); + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(1 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(1 as u32)), + ); + backed_candidates.push(backed.clone()); + + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(1), + relay_parent, + pov_hash: Hash::repeat_byte(1 as u8), + persisted_validation_data_hash: make_persisted_validation_data_with_parent::< + Test, + >( + RELAY_PARENT_NUM, + Default::default(), + prev_candidate.commitments.head_data, + ) + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![1]), + head_data: HeadData(vec![1, 1, 1, 1]), + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(2 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(2 as u32)), + ); + backed_candidates.push(backed.clone()); + } + + // Para 2 + { + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(2), + relay_parent: prev_relay_parent, + pov_hash: Hash::repeat_byte(2 as u8), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(2), + RELAY_PARENT_NUM - 1, + Default::default(), + ) + .unwrap() + .hash(), + head_data: HeadData(vec![2, 2]), + hrmp_watermark: RELAY_PARENT_NUM - 1, + validation_code: ValidationCode(vec![2]), + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let prev_candidate = candidate.clone(); + let backed: BackedCandidate = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(3 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(3 as u32)), + ); + backed_candidates.push(backed.clone()); + if core_index_enabled { + expected_backed_candidates_with_core + .entry(ParaId::from(2)) + .or_insert(vec![]) + .push((backed, CoreIndex(3))); + } + + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(2), + relay_parent, + pov_hash: Hash::repeat_byte(2 as u8), + persisted_validation_data_hash: make_persisted_validation_data_with_parent::< + Test, + >( + RELAY_PARENT_NUM, + Default::default(), + prev_candidate.commitments.head_data, + ) + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![2]), + head_data: HeadData(vec![2, 2, 2]), + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let prev_candidate = candidate.clone(); + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(4 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(4 as u32)), + ); + backed_candidates.push(backed.clone()); + if core_index_enabled { + expected_backed_candidates_with_core + .entry(ParaId::from(2)) + .or_insert(vec![]) + .push((backed, CoreIndex(4))); + } + + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(2), + relay_parent, + pov_hash: Hash::repeat_byte(2 as u8), + persisted_validation_data_hash: make_persisted_validation_data_with_parent::< + Test, + >( + RELAY_PARENT_NUM, + Default::default(), + prev_candidate.commitments.head_data, + ) + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![2]), + head_data: HeadData(vec![2, 2, 2, 2]), + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(5 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(5 as u32)), + ); + backed_candidates.push(backed.clone()); + + if core_index_enabled { + expected_backed_candidates_with_core + .entry(ParaId::from(2)) + .or_insert(vec![]) + .push((backed, CoreIndex(5))); + } + } + + // State sanity checks + assert_eq!( + scheduler::Pallet::::scheduled_paras().collect::>(), + vec![ + (CoreIndex(0), ParaId::from(1)), + (CoreIndex(1), ParaId::from(1)), + (CoreIndex(2), ParaId::from(1)), + (CoreIndex(3), ParaId::from(2)), + (CoreIndex(4), ParaId::from(2)), + (CoreIndex(5), ParaId::from(2)), + ] + ); + let mut scheduled: BTreeMap> = BTreeMap::new(); + for (core_idx, para_id) in scheduler::Pallet::::scheduled_paras() { + scheduled.entry(para_id).or_default().insert(core_idx); + } + + assert_eq!( + shared::ActiveValidatorIndices::::get(), + vec![ + ValidatorIndex(0), + ValidatorIndex(1), + ValidatorIndex(2), + ValidatorIndex(3), + ValidatorIndex(4), + ValidatorIndex(5) + ] + ); + + TestData { + backed_candidates, + scheduled_paras: scheduled, + expected_backed_candidates_with_core, + } + } + #[rstest] #[case(false)] #[case(true)] @@ -3058,6 +3488,156 @@ mod sanitizers { }); } + #[rstest] + #[case(false)] + #[case(true)] + fn test_candidate_relay_parent_ordering(#[case] core_index_enabled: bool) { + // Para 1 scheduled on cores 0, 1 and 2. Three candidates are supplied but their relay + // parents look like this: 3, 2, 3. There are no pending availability candidates and the + // latest on-chain relay parent for this para is 0. + // Therefore, only the first candidate will get picked. + // + // Para 2 scheduled on cores 3, 4 and 5. Three candidates are supplied and their relay + // parents look like this: 2, 3, 3. There are no pending availability candidates and the + // latest on-chain relay parent for this para is 0. Therefore, all 3 will get picked. + new_test_ext(default_config()).execute_with(|| { + let TestData { + backed_candidates, + scheduled_paras: scheduled, + expected_backed_candidates_with_core, + } = get_test_data_for_relay_parent_ordering(core_index_enabled); + + assert_eq!( + sanitize_backed_candidates::( + backed_candidates.clone(), + &shared::AllowedRelayParents::::get(), + BTreeSet::new(), + scheduled, + core_index_enabled, + ), + expected_backed_candidates_with_core + ); + }); + + // Para 1 scheduled on cores 0, 1 and 2. Three candidates are supplied but their + // relay parents look like this: 3, 2, 3. There are no pending availability + // candidates but the latest on-chain relay parent for this para is 4. + // Therefore, no candidate will get picked. + // + // Para 2 scheduled on cores 3, 4 and 5. Three candidates are supplied and their relay + // parents look like this: 2, 3, 3. There are no pending availability candidates and the + // latest on-chain relay parent for this para is 2. Therefore, all 3 will get picked. + new_test_ext(default_config()).execute_with(|| { + let TestData { + backed_candidates, + scheduled_paras: scheduled, + expected_backed_candidates_with_core, + } = get_test_data_for_relay_parent_ordering(core_index_enabled); + + paras::Pallet::::force_set_most_recent_context( + RuntimeOrigin::root(), + ParaId::from(1), + BlockNumberFor::::from(4u32), + ) + .unwrap(); + + paras::Pallet::::force_set_most_recent_context( + RuntimeOrigin::root(), + ParaId::from(2), + BlockNumberFor::::from(2u32), + ) + .unwrap(); + + let res = sanitize_backed_candidates::( + backed_candidates.clone(), + &shared::AllowedRelayParents::::get(), + BTreeSet::new(), + scheduled, + core_index_enabled, + ); + + if core_index_enabled { + assert_eq!(res.len(), 1); + assert_eq!( + expected_backed_candidates_with_core.get(&ParaId::from(2)), + res.get(&ParaId::from(2)), + ); + } else { + assert!(res.is_empty()); + } + }); + + // Para 1 scheduled on cores 0, 1 and 2. Three candidates are supplied but their relay + // parents look like this: 3, 2, 3. + // The latest on-chain relay parent for this para is 0 but there is a pending + // availability candidate with relay parent 4. Therefore, no candidate will get + // picked. + // + // Para 2 scheduled on cores 3, 4 and 5. Three candidates are supplied and their relay + // parents look like this: 2, 3, 3. + // The latest on-chain relay parent for this para is 0 but there is a pending + // availability candidate with relay parent 2. Therefore, all 3 will get picked. + new_test_ext(default_config()).execute_with(|| { + let TestData { + backed_candidates, + scheduled_paras: scheduled, + expected_backed_candidates_with_core, + } = get_test_data_for_relay_parent_ordering(core_index_enabled); + + // For para 1, add a dummy pending candidate with relay parent 4. + let mut candidates = VecDeque::new(); + let mut commitments = backed_candidates[0].candidate().commitments.clone(); + commitments.head_data = paras::Heads::::get(&ParaId::from(1)).unwrap(); + candidates.push_back(inclusion::CandidatePendingAvailability::new( + CoreIndex(0), + CandidateHash(Hash::repeat_byte(1)), + backed_candidates[0].descriptor().clone(), + commitments, + Default::default(), + Default::default(), + 4, + 4, + GroupIndex(0), + )); + inclusion::PendingAvailability::::insert(ParaId::from(1), candidates); + + // For para 2, add a dummy pending candidate with relay parent 2. + let mut candidates = VecDeque::new(); + let mut commitments = backed_candidates[3].candidate().commitments.clone(); + commitments.head_data = paras::Heads::::get(&ParaId::from(2)).unwrap(); + candidates.push_back(inclusion::CandidatePendingAvailability::new( + CoreIndex(0), + CandidateHash(Hash::repeat_byte(2)), + backed_candidates[3].descriptor().clone(), + commitments, + Default::default(), + Default::default(), + 2, + 2, + GroupIndex(3), + )); + inclusion::PendingAvailability::::insert(ParaId::from(2), candidates); + + let res = sanitize_backed_candidates::( + backed_candidates.clone(), + &shared::AllowedRelayParents::::get(), + BTreeSet::new(), + scheduled, + core_index_enabled, + ); + + if core_index_enabled { + assert_eq!(res.len(), 1); + assert_eq!( + expected_backed_candidates_with_core.get(&ParaId::from(2)), + res.get(&ParaId::from(2)), + ); + } else { + assert!(res.is_empty()); + } + }); + } + // nothing is scheduled, so no paraids match, thus all backed candidates are skipped #[rstest] #[case(false, false)] diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index f93a3ad65754c7ac201841aca7098f2886da0cf8..50970965e11e6ebbd4f984ed16c21be44cd978c6 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -226,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", @@ -330,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 b67c36d71fd8721c583789a7a283868111afc037..1d0adac44af4dcbb099182ebfbc1a4a1333f8422 100644 --- a/polkadot/runtime/rococo/constants/Cargo.toml +++ b/polkadot/runtime/rococo/constants/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[package.metadata.polkadot-sdk] +exclude-from-umbrella = true + [lints] workspace = true diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 5adffbd7422f9fc0f7812318bb2548fff6e9c0e0..30b915d32deba19c47228bef82a4414845a67c95 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -53,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, @@ -166,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_014_000, + spec_version: 1_015_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 26, @@ -1096,11 +1096,11 @@ parameter_types! { 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; } @@ -1307,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! { @@ -1319,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()), ) @@ -1338,6 +1335,7 @@ impl pallet_beefy_mmr::Config for Runtime { type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum; type LeafExtra = H256; type BeefyDataProvider = ParaHeadsRootProvider; + type WeightInfo = weights::pallet_beefy_mmr::WeightInfo; } impl paras_sudo_wrapper::Config for Runtime {} @@ -1485,7 +1483,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. @@ -1632,47 +1630,45 @@ pub mod migrations { /// Unreleased migrations. Add new ones here: pub type Unreleased = ( - pallet_society::migrations::MigrateToV2, - parachains_configuration::migration::v7::MigrateToV7, - assigned_slots::migration::v1::MigrateToV1, - parachains_scheduler::migration::MigrateV1ToV2, - parachains_configuration::migration::v8::MigrateToV8, - parachains_configuration::migration::v9::MigrateToV9, - paras_registrar::migration::MigrateToV1, - pallet_referenda::migration::v1::MigrateV0ToV1, - pallet_referenda::migration::v1::MigrateV0ToV1, - - // Unlock & unreserve Gov1 funds - - pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, - pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, - pallet_tips::migrations::unreserve_deposits::UnreserveDeposits, - - // Delete all Gov v1 pallet storage key/values. - - frame_support::migrations::RemovePallet::DbWeight>, - frame_support::migrations::RemovePallet::DbWeight>, - frame_support::migrations::RemovePallet::DbWeight>, - frame_support::migrations::RemovePallet::DbWeight>, - frame_support::migrations::RemovePallet::DbWeight>, - frame_support::migrations::RemovePallet::DbWeight>, - - pallet_grandpa::migrations::MigrateV4ToV5, - parachains_configuration::migration::v10::MigrateToV10, - - // Migrate Identity pallet for Usernames - pallet_identity::migration::versioned::V0ToV1, - parachains_configuration::migration::v11::MigrateToV11, - // 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, - - // permanent - pallet_xcm::migration::MigrateToLatestXcmVersion, - - parachains_inclusion::migration::MigrateToV1, - ); + pallet_society::migrations::MigrateToV2, + parachains_configuration::migration::v7::MigrateToV7, + assigned_slots::migration::v1::MigrateToV1, + parachains_scheduler::migration::MigrateV1ToV2, + parachains_configuration::migration::v8::MigrateToV8, + parachains_configuration::migration::v9::MigrateToV9, + paras_registrar::migration::MigrateToV1, + pallet_referenda::migration::v1::MigrateV0ToV1, + pallet_referenda::migration::v1::MigrateV0ToV1, + + // Unlock & unreserve Gov1 funds + + pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, + pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, + pallet_tips::migrations::unreserve_deposits::UnreserveDeposits, + + // Delete all Gov v1 pallet storage key/values. + + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + pallet_grandpa::migrations::MigrateV4ToV5, + parachains_configuration::migration::v10::MigrateToV10, + + // Migrate Identity pallet for Usernames + pallet_identity::migration::versioned::V0ToV1, + parachains_configuration::migration::v11::MigrateToV11, + // This needs to come after the `parachains_configuration` above as we are reading the configuration. + coretime::migration::MigrateToCoretime, + parachains_configuration::migration::v12::MigrateToV12, + parachains_on_demand::migration::MigrateV0ToV1, + + // permanent + pallet_xcm::migration::MigrateToLatestXcmVersion, + parachains_inclusion::migration::MigrateToV1, + ); } /// Executive: handles dispatch to the various modules. @@ -1738,6 +1734,7 @@ mod benches { // Substrate [pallet_balances, Balances] [pallet_balances, NisCounterpartBalances] + [pallet_beefy_mmr, MmrLeaf] [frame_benchmarking::baseline, Baseline::] [pallet_bounties, Bounties] [pallet_child_bounties, ChildBounties] @@ -1746,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] @@ -2056,7 +2054,7 @@ sp_api::impl_runtime_apis! { } } - #[api_version(4)] + #[api_version(5)] impl sp_consensus_beefy::BeefyApi for Runtime { fn beefy_genesis() -> Option { pallet_beefy::GenesisBlock::::get() @@ -2082,6 +2080,31 @@ sp_api::impl_runtime_apis! { ) } + 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, @@ -2092,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)] diff --git a/polkadot/runtime/rococo/src/weights/mod.rs b/polkadot/runtime/rococo/src/weights/mod.rs index 3c6845dfb43e65e85dc33b2e288f35a9a8742e1e..cd3f4689f562e24e5dccf8b401f4ee1a6f66cef4 100644 --- a/polkadot/runtime/rococo/src/weights/mod.rs +++ b/polkadot/runtime/rococo/src/weights/mod.rs @@ -19,12 +19,14 @@ pub mod frame_system; pub mod pallet_asset_rate; pub mod pallet_balances_balances; pub mod pallet_balances_nis_counterpart_balances; +pub mod pallet_beefy_mmr; pub mod pallet_bounties; pub mod pallet_child_bounties; 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 +51,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_beefy_mmr.rs b/polkadot/runtime/rococo/src/weights/pallet_beefy_mmr.rs new file mode 100644 index 0000000000000000000000000000000000000000..317c9149ec6c57c8e1c9d5bc5deb5ee648175ada --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_beefy_mmr.rs @@ -0,0 +1,89 @@ +// 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_beefy_mmr` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-08-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, 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_beefy_mmr +// --chain=rococo-dev +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/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_beefy_mmr`. +pub struct WeightInfo(PhantomData); +impl pallet_beefy_mmr::WeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn extract_validation_context() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 7_116_000 picoseconds. + Weight::from_parts(7_343_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `Mmr::Nodes` (r:1 w:0) + /// Proof: `Mmr::Nodes` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + fn read_peak() -> Weight { + // Proof Size summary in bytes: + // Measured: `234` + // Estimated: `3505` + // Minimum execution time: 5_652_000 picoseconds. + Weight::from_parts(5_963_000, 0) + .saturating_add(Weight::from_parts(0, 3505)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `Mmr::RootHash` (r:1 w:0) + /// Proof: `Mmr::RootHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `Mmr::NumberOfLeaves` (r:1 w:0) + /// Proof: `Mmr::NumberOfLeaves` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// The range of component `n` is `[2, 512]`. + fn n_items_proof_is_non_canonical(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `226` + // Estimated: `1517` + // Minimum execution time: 11_953_000 picoseconds. + Weight::from_parts(15_978_891, 0) + .saturating_add(Weight::from_parts(0, 1517)) + // Standard Error: 1_780 + .saturating_add(Weight::from_parts(1_480_582, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2)) + } +} 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/runtime_parachains_assigner_on_demand.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_on_demand.rs similarity index 93% 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 abcc1893c29b1273bdde09a3f38f12c174bc84cc..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,7 +14,7 @@ // 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-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` @@ -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,9 +45,9 @@ 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) diff --git a/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 60c40429b1ac323e69bca1345c41c3c04c221f79..7d743b209124a51c3a09edfd84fbff4d18eb665f 100644 --- a/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-nbnwcyh-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -55,8 +55,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 23_189_000 picoseconds. - Weight::from_parts(23_896_000, 3593) + // Minimum execution time: 30_672_000 picoseconds. + Weight::from_parts(31_677_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -66,8 +66,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 50_299_000 picoseconds. - Weight::from_parts(50_962_000, 6196) + // Minimum execution time: 41_132_000 picoseconds. + Weight::from_parts(41_654_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -83,10 +83,10 @@ impl WeightInfo { /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn transfer_reserve_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `243` + // Measured: `281` // Estimated: `6196` - // Minimum execution time: 71_748_000 picoseconds. - Weight::from_parts(74_072_000, 6196) + // Minimum execution time: 97_174_000 picoseconds. + Weight::from_parts(99_537_000, 6196) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -105,16 +105,18 @@ impl WeightInfo { /// 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: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn initiate_reserve_withdraw() -> Weight { // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `3607` - // Minimum execution time: 27_806_000 picoseconds. - Weight::from_parts(28_594_000, 3607) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `281` + // Estimated: `3746` + // Minimum execution time: 67_105_000 picoseconds. + Weight::from_parts(68_659_000, 3746) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -122,8 +124,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 21_199_000 picoseconds. - Weight::from_parts(21_857_000, 3593) + // Minimum execution time: 30_780_000 picoseconds. + Weight::from_parts(31_496_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -133,27 +135,27 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 23_578_000 picoseconds. - Weight::from_parts(24_060_000, 3593) + // Minimum execution time: 23_411_000 picoseconds. + Weight::from_parts(23_891_000, 3593) .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: `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: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn deposit_reserve_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `3607` - // Minimum execution time: 48_522_000 picoseconds. - Weight::from_parts(49_640_000, 3607) + // Measured: `180` + // Estimated: `3645` + // Minimum execution time: 61_541_000 picoseconds. + Weight::from_parts(63_677_000, 3645) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -169,10 +171,10 @@ impl WeightInfo { /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn initiate_teleport() -> Weight { // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `3607` - // Minimum execution time: 50_429_000 picoseconds. - Weight::from_parts(51_295_000, 3607) + // Measured: `180` + // Estimated: `3645` + // Minimum execution time: 48_574_000 picoseconds. + Weight::from_parts(49_469_000, 3645) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } 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/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index a8a369a68e6691e88f05987986d27229843aef9d..8e34320d38f2f26edc800343cf37217977e8bad1 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -1029,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/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 9e739f4c7fe6c0de7358b5763532f761209333e7..4226595cd2ffb25cc753f85583724bc1222b2f7e 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -71,6 +71,7 @@ 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 } @@ -79,7 +80,6 @@ pallet-scheduler = { workspace = true } pallet-session = { workspace = true } pallet-society = { workspace = true } pallet-staking = { workspace = true } -pallet-staking-reward-curve = { workspace = true, default-features = true } pallet-staking-runtime-api = { workspace = true } pallet-delegated-staking = { workspace = true } pallet-state-trie-migration = { workspace = true } @@ -173,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", @@ -240,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", @@ -259,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", @@ -317,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", @@ -346,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/build.rs b/polkadot/runtime/westend/build.rs index 8ff3a4fb9112c670882cd9794d6291d74cee194f..55ccd36401293342d2dff4ccca14b674f6b1aeec 100644 --- a/polkadot/runtime/westend/build.rs +++ b/polkadot/runtime/westend/build.rs @@ -17,6 +17,10 @@ #[cfg(all(not(feature = "metadata-hash"), feature = "std"))] fn main() { 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"))] @@ -24,6 +28,11 @@ fn main() { substrate_wasm_builder::WasmBuilder::init_with_defaults() .enable_metadata_hash("WND", 12) .build(); + substrate_wasm_builder::WasmBuilder::init_with_defaults() + .set_file_name("fast_runtime_binary.rs") + .enable_feature("fast-runtime") + .enable_metadata_hash("WND", 12) + .build(); } #[cfg(not(feature = "std"))] diff --git a/polkadot/runtime/westend/constants/Cargo.toml b/polkadot/runtime/westend/constants/Cargo.toml index f9b99ea5284d3322b6e0bf100f8314000a4b5bce..27d5b19b8e77113a8f4ea5f14bfb701364308f07 100644 --- a/polkadot/runtime/westend/constants/Cargo.toml +++ b/polkadot/runtime/westend/constants/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[package.metadata.polkadot-sdk] +exclude-from-umbrella = true + [lints] workspace = true diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index f0b16e731d9e564bbf00a9378c5247151d61ca2e..a9fbbb4f33dad51f82d04ffd7d3fa7adc410c7d2 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -31,12 +31,14 @@ 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, @@ -59,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}, @@ -68,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, @@ -91,15 +93,13 @@ 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::{ 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, + ApplyExtrinsicResult, FixedU128, KeyTypeId, Percent, Permill, }; use sp_staking::SessionIndex; #[cfg(any(feature = "std", test))] @@ -156,13 +156,18 @@ impl_runtime_weights!(westend_runtime_constants); #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +#[cfg(feature = "std")] +pub mod fast_runtime_binary { + include!(concat!(env!("OUT_DIR"), "/fast_runtime_binary.rs")); +} + /// Runtime version (Westend). #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westend"), impl_name: create_runtime_str!("parity-westend"), authoring_version: 2, - spec_version: 1_014_000, + spec_version: 1_015_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 26, @@ -244,6 +249,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; @@ -342,9 +421,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. @@ -366,13 +447,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()), ) @@ -385,6 +461,7 @@ impl pallet_beefy_mmr::Config for Runtime { type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum; type LeafExtra = H256; type BeefyDataProvider = ParaHeadsRootProvider; + type WeightInfo = weights::pallet_beefy_mmr::WeightInfo; } parameter_types! { @@ -525,20 +602,20 @@ impl pallet_election_provider_multi_phase::MinerConfig for Runtime { type MaxWeight = OffchainSolutionWeightLimit; type Solution = NposCompactSolution16; type MaxVotesPerVoter = < - ::DataProvider - as - frame_election_provider_support::ElectionDataProvider - >::MaxVotesPerVoter; + ::DataProvider + as + frame_election_provider_support::ElectionDataProvider + >::MaxVotesPerVoter; type MaxWinners = MaxActiveValidators; // The unsigned submissions have to respect the weight of the submit_unsigned call, thus their // weight estimate function is wired to this call's weight. fn solution_weight(v: u32, t: u32, a: u32, d: u32) -> Weight { < - ::WeightInfo - as - pallet_election_provider_multi_phase::WeightInfo - >::submit_unsigned(v, t, a, d) + ::WeightInfo + as + pallet_election_provider_multi_phase::WeightInfo + >::submit_unsigned(v, t, a, d) } } @@ -559,7 +636,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; @@ -599,15 +676,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! { @@ -617,7 +716,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 @@ -641,7 +739,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; @@ -1229,11 +1327,11 @@ parameter_types! { 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; } @@ -1478,6 +1576,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; @@ -1585,7 +1685,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; @@ -1743,11 +1843,12 @@ 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] [pallet_balances, Balances] + [pallet_beefy_mmr, BeefyMmrLeaf] [pallet_conviction_voting, ConvictionVoting] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] [frame_election_provider_support, ElectionProviderBench::] @@ -1755,9 +1856,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] @@ -2013,7 +2116,7 @@ sp_api::impl_runtime_apis! { } } - #[api_version(4)] + #[api_version(5)] impl sp_consensus_beefy::BeefyApi for Runtime { fn beefy_genesis() -> Option { pallet_beefy::GenesisBlock::::get() @@ -2039,6 +2142,31 @@ sp_api::impl_runtime_apis! { ) } + 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, @@ -2049,6 +2177,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 { @@ -2337,6 +2476,14 @@ sp_api::impl_runtime_apis! { fn member_needs_delegate_migration(member: AccountId) -> bool { NominationPools::api_member_needs_delegate_migration(member) } + + fn member_total_balance(member: AccountId) -> Balance { + NominationPools::api_member_total_balance(member) + } + + fn pool_balance(pool_id: pallet_nomination_pools::PoolId) -> Balance { + NominationPools::api_pool_balance(pool_id) + } } impl pallet_staking_runtime_api::StakingApi for Runtime { @@ -2637,45 +2784,6 @@ sp_api::impl_runtime_apis! { } } -#[cfg(all(test, feature = "try-runtime"))] -mod remote_tests { - use super::*; - use frame_try_runtime::{runtime_decl_for_try_runtime::TryRuntime, UpgradeCheckSelect}; - use remote_externalities::{ - Builder, Mode, OfflineConfig, OnlineConfig, SnapshotConfig, Transport, - }; - use std::env::var; - - #[tokio::test] - async fn run_migrations() { - if var("RUN_MIGRATION_TESTS").is_err() { - return; - } - - sp_tracing::try_init_simple(); - let transport: Transport = - var("WS").unwrap_or("wss://westend-rpc.polkadot.io:443".to_string()).into(); - let maybe_state_snapshot: Option = var("SNAP").map(|s| s.into()).ok(); - let mut ext = Builder::::default() - .mode(if let Some(state_snapshot) = maybe_state_snapshot { - Mode::OfflineOrElseOnline( - OfflineConfig { state_snapshot: state_snapshot.clone() }, - OnlineConfig { - transport, - state_snapshot: Some(state_snapshot), - ..Default::default() - }, - ) - } else { - Mode::Online(OnlineConfig { transport, ..Default::default() }) - }) - .build() - .await - .unwrap(); - ext.execute_with(|| Runtime::on_runtime_upgrade(UpgradeCheckSelect::PreAndPost)); - } -} - mod clean_state_migration { use super::Runtime; #[cfg(feature = "try-runtime")] diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs index 4d5e2e946bce6e1cf26f061309b1a1000a3d1853..dc8103ab52c474a8f24b288add5b0cd9880265fc 100644 --- a/polkadot/runtime/westend/src/tests.rs +++ b/polkadot/runtime/westend/src/tests.rs @@ -99,3 +99,140 @@ fn check_treasury_pallet_id() { westend_runtime_constants::TREASURY_PALLET_ID ); } + +#[cfg(all(test, feature = "try-runtime"))] +mod remote_tests { + use super::*; + use frame_try_runtime::{runtime_decl_for_try_runtime::TryRuntime, UpgradeCheckSelect}; + use remote_externalities::{ + Builder, Mode, OfflineConfig, OnlineConfig, SnapshotConfig, Transport, + }; + use std::env::var; + + #[tokio::test] + async fn run_migrations() { + if var("RUN_MIGRATION_TESTS").is_err() { + return; + } + + sp_tracing::try_init_simple(); + let transport: Transport = + var("WS").unwrap_or("wss://westend-rpc.polkadot.io:443".to_string()).into(); + let maybe_state_snapshot: Option = var("SNAP").map(|s| s.into()).ok(); + let mut ext = Builder::::default() + .mode(if let Some(state_snapshot) = maybe_state_snapshot { + Mode::OfflineOrElseOnline( + OfflineConfig { state_snapshot: state_snapshot.clone() }, + OnlineConfig { + transport, + state_snapshot: Some(state_snapshot), + ..Default::default() + }, + ) + } else { + Mode::Online(OnlineConfig { transport, ..Default::default() }) + }) + .build() + .await + .unwrap(); + ext.execute_with(|| Runtime::on_runtime_upgrade(UpgradeCheckSelect::PreAndPost)); + } + + #[tokio::test] + async fn delegate_stake_migration() { + // Intended to be run only manually. + if var("RUN_MIGRATION_TESTS").is_err() { + return; + } + use frame_support::assert_ok; + sp_tracing::try_init_simple(); + + let transport: Transport = var("WS").unwrap_or("ws://127.0.0.1:9900".to_string()).into(); + let maybe_state_snapshot: Option = var("SNAP").map(|s| s.into()).ok(); + let mut ext = Builder::::default() + .mode(if let Some(state_snapshot) = maybe_state_snapshot { + Mode::OfflineOrElseOnline( + OfflineConfig { state_snapshot: state_snapshot.clone() }, + OnlineConfig { + transport, + state_snapshot: Some(state_snapshot), + pallets: vec![ + "staking".into(), + "system".into(), + "balances".into(), + "nomination-pools".into(), + "delegated-staking".into(), + ], + ..Default::default() + }, + ) + } else { + Mode::Online(OnlineConfig { transport, ..Default::default() }) + }) + .build() + .await + .unwrap(); + ext.execute_with(|| { + // create an account with some balance + let alice = AccountId::from([1u8; 32]); + use frame_support::traits::Currency; + let _ = Balances::deposit_creating(&alice, 100_000 * UNITS); + + // iterate over all pools + pallet_nomination_pools::BondedPools::::iter_keys().for_each(|k| { + if pallet_nomination_pools::Pallet::::api_pool_needs_delegate_migration(k) + { + assert_ok!( + pallet_nomination_pools::Pallet::::migrate_pool_to_delegate_stake( + RuntimeOrigin::signed(alice.clone()).into(), + k, + ) + ); + } + }); + + // member migration stats + let mut success = 0; + let mut direct_stakers = 0; + let mut unexpected_errors = 0; + + // iterate over all pool members + pallet_nomination_pools::PoolMembers::::iter_keys().for_each(|k| { + if pallet_nomination_pools::Pallet::::api_member_needs_delegate_migration( + k.clone(), + ) { + // reasons migrations can fail: + let is_direct_staker = pallet_staking::Bonded::::contains_key(&k); + + let migration = pallet_nomination_pools::Pallet::::migrate_delegation( + RuntimeOrigin::signed(alice.clone()).into(), + sp_runtime::MultiAddress::Id(k.clone()), + ); + + if is_direct_staker { + // if the member is a direct staker, the migration should fail until pool + // member unstakes all funds from pallet-staking. + direct_stakers += 1; + assert_eq!( + migration.unwrap_err(), + pallet_delegated_staking::Error::::AlreadyStaking.into() + ); + } else if migration.is_err() { + unexpected_errors += 1; + log::error!(target: "remote_test", "Unexpected error {:?} while migrating {:?}", migration.unwrap_err(), k); + } else { + success += 1; + } + } + }); + + log::info!( + target: "remote_test", + "Migration stats: success: {}, direct_stakers: {}, unexpected_errors: {}", + success, + direct_stakers, + unexpected_errors + ); + }); + } +} diff --git a/polkadot/runtime/westend/src/weights/mod.rs b/polkadot/runtime/westend/src/weights/mod.rs index f6a9008d71876726dda2ad240ecdb4588a1f82a3..cb6e2c85e3634af1127eb7ae48a9a7453b7b5eba 100644 --- a/polkadot/runtime/westend/src/weights/mod.rs +++ b/polkadot/runtime/westend/src/weights/mod.rs @@ -20,14 +20,17 @@ pub mod frame_system; pub mod pallet_asset_rate; pub mod pallet_bags_list; pub mod pallet_balances; +pub mod pallet_beefy_mmr; pub mod pallet_conviction_voting; pub mod pallet_election_provider_multi_phase; 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 +51,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 +58,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_beefy_mmr.rs b/polkadot/runtime/westend/src/weights/pallet_beefy_mmr.rs new file mode 100644 index 0000000000000000000000000000000000000000..5be207e3fcff484a789d209b3f3cdd7db7c49e15 --- /dev/null +++ b/polkadot/runtime/westend/src/weights/pallet_beefy_mmr.rs @@ -0,0 +1,89 @@ +// 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_beefy_mmr` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-08-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, 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_beefy_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_beefy_mmr`. +pub struct WeightInfo(PhantomData); +impl pallet_beefy_mmr::WeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn extract_validation_context() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 7_850_000 picoseconds. + Weight::from_parts(8_169_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `Mmr::Nodes` (r:1 w:0) + /// Proof: `Mmr::Nodes` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + fn read_peak() -> Weight { + // Proof Size summary in bytes: + // Measured: `201` + // Estimated: `3505` + // Minimum execution time: 6_852_000 picoseconds. + Weight::from_parts(7_448_000, 0) + .saturating_add(Weight::from_parts(0, 3505)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `Mmr::RootHash` (r:1 w:0) + /// Proof: `Mmr::RootHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `Mmr::NumberOfLeaves` (r:1 w:0) + /// Proof: `Mmr::NumberOfLeaves` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// The range of component `n` is `[2, 512]`. + fn n_items_proof_is_non_canonical(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `193` + // Estimated: `1517` + // Minimum execution time: 12_860_000 picoseconds. + Weight::from_parts(17_158_162, 0) + .saturating_add(Weight::from_parts(0, 1517)) + // Standard Error: 1_732 + .saturating_add(Weight::from_parts(1_489_410, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2)) + } +} 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_assigner_on_demand.rs b/polkadot/runtime/westend/src/weights/runtime_parachains_on_demand.rs similarity index 93% 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 1bd9fa31b81b29fc581475991115a86c7e4ecf5d..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,7 +14,7 @@ // 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-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` @@ -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,9 +45,9 @@ 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) diff --git a/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 9939f16aa29f84fb0df68f658fc8cef44c52eea3..e0c61c8e2bf2583733954469f5cff132a8f49406 100644 --- a/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-nbnwcyh-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024 // Executed Command: @@ -55,8 +55,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 24_815_000 picoseconds. - Weight::from_parts(25_098_000, 3593) + // Minimum execution time: 31_780_000 picoseconds. + Weight::from_parts(32_602_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -66,12 +66,12 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 51_268_000 picoseconds. - Weight::from_parts(51_857_000, 6196) + // Minimum execution time: 41_818_000 picoseconds. + Weight::from_parts(42_902_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `System::Account` (r:2 w:2) + /// Storage: `System::Account` (r:3 w:3) /// 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`) @@ -83,12 +83,12 @@ impl WeightInfo { /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn transfer_reserve_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `210` - // Estimated: `6196` - // Minimum execution time: 74_113_000 picoseconds. - Weight::from_parts(74_721_000, 6196) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(4)) + // Measured: `351` + // Estimated: `8799` + // Minimum execution time: 101_949_000 picoseconds. + Weight::from_parts(104_190_000, 8799) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `Benchmark::Override` (r:0 w:0) /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -105,16 +105,18 @@ impl WeightInfo { /// 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: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn initiate_reserve_withdraw() -> Weight { // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `3574` - // Minimum execution time: 28_919_000 picoseconds. - Weight::from_parts(29_703_000, 3574) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `351` + // Estimated: `6196` + // Minimum execution time: 70_123_000 picoseconds. + Weight::from_parts(72_564_000, 6196) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -122,8 +124,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 21_685_000 picoseconds. - Weight::from_parts(22_528_000, 3593) + // Minimum execution time: 31_868_000 picoseconds. + Weight::from_parts(32_388_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -133,27 +135,27 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 25_192_000 picoseconds. - Weight::from_parts(25_445_000, 3593) + // Minimum execution time: 24_532_000 picoseconds. + Weight::from_parts(25_166_000, 3593) .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: `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: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn deposit_reserve_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `3593` - // Minimum execution time: 49_349_000 picoseconds. - Weight::from_parts(50_476_000, 3593) + // Measured: `147` + // Estimated: `3612` + // Minimum execution time: 63_378_000 picoseconds. + Weight::from_parts(65_002_000, 3612) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -169,10 +171,10 @@ impl WeightInfo { /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn initiate_teleport() -> Weight { // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `3593` - // Minimum execution time: 51_386_000 picoseconds. - Weight::from_parts(52_141_000, 3593) + // Measured: `147` + // Estimated: `3612` + // Minimum execution time: 49_174_000 picoseconds. + Weight::from_parts(50_356_000, 3612) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } 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/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index 72174bda2340c46c7769c320c646c11556daf74c..862f5557a012a9bd1953607e774b36009c87d9e5 100644 --- a/polkadot/xcm/Cargo.toml +++ b/polkadot/xcm/Cargo.toml @@ -17,6 +17,7 @@ impl-trait-for-tuples = { workspace = true } log = { workspace = true } 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 = { default-features = true, optional = true, workspace = true } @@ -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/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 3941d104b81c6a5e4421841090c12282542af75f..8d0476b0e70d77f7cc1d63033392eb274dbb337c 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -35,9 +35,9 @@ use xcm_builder::{ 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 a7db183bcdbf89b2b642f2eb8eea9f87019f086d..83b35d19cf7eee67ef47f9af507d4a61b75fa9dc 100644 --- a/polkadot/xcm/procedural/Cargo.toml +++ b/polkadot/xcm/procedural/Cargo.toml @@ -21,4 +21,6 @@ Inflector = { workspace = true } [dev-dependencies] trybuild = { features = ["diff"], workspace = true } -xcm = { workspace = true, default-features = true } +# NOTE: we have to explicitly specify `std` because of trybuild +# https://github.com/paritytech/polkadot-sdk/pull/5167 +xcm = { workspace = true, default-features = true, features = ["std"] } 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 7702e2f9be07db04aafcd911a7fbb9fb2cdfb957..671f0181277ae905a0ab6f3d69bb13f0dc512616 100644 --- a/polkadot/xcm/xcm-builder/Cargo.toml +++ b/polkadot/xcm/xcm-builder/Cargo.toml @@ -22,13 +22,15 @@ sp-weights = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } pallet-transaction-payment = { workspace = true } +pallet-asset-conversion = { workspace = true } log = { workspace = true } # Polkadot dependencies polkadot-parachain-primitives = { workspace = true } [dev-dependencies] -primitive-types = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +primitive-types = { features = ["codec", "num-traits", "scale-info"], workspace = true } pallet-balances = { workspace = true, default-features = true } pallet-xcm = { workspace = true, default-features = true } pallet-salary = { workspace = true, default-features = true } @@ -43,6 +45,7 @@ default = ["std"] runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "pallet-asset-conversion/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-salary/runtime-benchmarks", @@ -59,8 +62,10 @@ std = [ "frame-support/std", "frame-system/std", "log/std", + "pallet-asset-conversion/std", "pallet-transaction-payment/std", "polkadot-parachain-primitives/std", + "primitive-types/std", "scale-info/std", "sp-arithmetic/std", "sp-io/std", diff --git a/polkadot/xcm/xcm-builder/src/asset_exchange/mod.rs b/polkadot/xcm/xcm-builder/src/asset_exchange/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..d42a443c9be1d57b3e12747ebde9b8a147d54b09 --- /dev/null +++ b/polkadot/xcm/xcm-builder/src/asset_exchange/mod.rs @@ -0,0 +1,22 @@ +// 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 . + +//! Adapters for the AssetExchanger config item. +//! +//! E.g. types that implement the [`xcm_executor::traits::AssetExchange`] trait. + +mod single_asset_adapter; +pub use single_asset_adapter::SingleAssetExchangeAdapter; diff --git a/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/adapter.rs b/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/adapter.rs new file mode 100644 index 0000000000000000000000000000000000000000..fa94ee5f1caaa1fa16a7568086a42edc82aafee1 --- /dev/null +++ b/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/adapter.rs @@ -0,0 +1,210 @@ +// 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 . + +//! Single asset exchange adapter. + +extern crate alloc; +use alloc::vec; +use core::marker::PhantomData; +use frame_support::{ensure, traits::tokens::fungibles}; +use pallet_asset_conversion::{QuotePrice, SwapCredit}; +use xcm::prelude::*; +use xcm_executor::{ + traits::{AssetExchange, MatchesFungibles}, + AssetsInHolding, +}; + +/// An adapter from [`pallet_asset_conversion::SwapCredit`] and +/// [`pallet_asset_conversion::QuotePrice`] to [`xcm_executor::traits::AssetExchange`]. +/// +/// This adapter takes just one fungible asset in `give` and allows only one fungible asset in +/// `want`. If you need to handle more assets in either `give` or `want`, then you should use +/// another type that implements [`xcm_executor::traits::AssetExchange`] or build your own. +/// +/// This adapter also only works for fungible assets. +/// +/// `exchange_asset` and `quote_exchange_price` will both return an error if there's +/// more than one asset in `give` or `want`. +pub struct SingleAssetExchangeAdapter( + PhantomData<(AssetConversion, Fungibles, Matcher, AccountId)>, +); +impl AssetExchange + for SingleAssetExchangeAdapter +where + AssetConversion: SwapCredit< + AccountId, + Balance = u128, + AssetKind = Fungibles::AssetId, + Credit = fungibles::Credit, + > + QuotePrice, + Fungibles: fungibles::Balanced, + Matcher: MatchesFungibles, +{ + fn exchange_asset( + _: Option<&Location>, + give: AssetsInHolding, + want: &Assets, + maximal: bool, + ) -> Result { + let mut give_iter = give.fungible_assets_iter(); + let give_asset = give_iter.next().ok_or_else(|| { + log::trace!( + target: "xcm::SingleAssetExchangeAdapter::exchange_asset", + "No fungible asset was in `give`.", + ); + give.clone() + })?; + ensure!(give_iter.next().is_none(), give.clone()); // We only support 1 asset in `give`. + ensure!(give.non_fungible_assets_iter().next().is_none(), give.clone()); // We don't allow non-fungible assets. + ensure!(want.len() == 1, give.clone()); // We only support 1 asset in `want`. + let want_asset = want.get(0).ok_or_else(|| give.clone())?; + let (give_asset_id, give_amount) = + Matcher::matches_fungibles(&give_asset).map_err(|error| { + log::trace!( + target: "xcm::SingleAssetExchangeAdapter::exchange_asset", + "Could not map XCM asset give {:?} to FRAME asset. Error: {:?}", + give_asset, + error, + ); + give.clone() + })?; + let (want_asset_id, want_amount) = + Matcher::matches_fungibles(&want_asset).map_err(|error| { + log::trace!( + target: "xcm::SingleAssetExchangeAdapter::exchange_asset", + "Could not map XCM asset want {:?} to FRAME asset. Error: {:?}", + want_asset, + error, + ); + give.clone() + })?; + + // We have to do this to convert the XCM assets into credit the pool can use. + let swap_asset = give_asset_id.clone().into(); + let credit_in = Fungibles::issue(give_asset_id, give_amount); + + // Do the swap. + let (credit_out, maybe_credit_change) = if maximal { + // If `maximal`, then we swap exactly `credit_in` to get as much of `want_asset_id` as + // we can, with a minimum of `want_amount`. + let credit_out = >::swap_exact_tokens_for_tokens( + vec![swap_asset, want_asset_id], + credit_in, + Some(want_amount), + ) + .map_err(|(credit_in, error)| { + log::error!( + target: "xcm::SingleAssetExchangeAdapter::exchange_asset", + "Could not perform the swap, error: {:?}.", + error + ); + drop(credit_in); + give.clone() + })?; + + // We don't have leftover assets if exchange was maximal. + (credit_out, None) + } else { + // If `minimal`, then we swap as little of `credit_in` as we can to get exactly + // `want_amount` of `want_asset_id`. + let (credit_out, credit_change) = + >::swap_tokens_for_exact_tokens( + vec![swap_asset, want_asset_id], + credit_in, + want_amount, + ) + .map_err(|(credit_in, error)| { + log::error!( + target: "xcm::SingleAssetExchangeAdapter::exchange_asset", + "Could not perform the swap, error: {:?}.", + error + ); + drop(credit_in); + give.clone() + })?; + + (credit_out, Some(credit_change)) + }; + + // We create an `AssetsInHolding` instance by putting in the resulting asset + // of the exchange. + let resulting_asset: Asset = (want_asset.id.clone(), credit_out.peek()).into(); + let mut result: AssetsInHolding = resulting_asset.into(); + + // If we have some leftover assets from the exchange, also put them in the result. + if let Some(credit_change) = maybe_credit_change { + let leftover_asset: Asset = (give_asset.id.clone(), credit_change.peek()).into(); + result.subsume(leftover_asset); + } + + Ok(result.into()) + } + + fn quote_exchange_price(give: &Assets, want: &Assets, maximal: bool) -> Option { + if give.len() != 1 || want.len() != 1 { + return None; + } // We only support 1 asset in `give` or `want`. + let give_asset = give.get(0)?; + let want_asset = want.get(0)?; + // We first match both XCM assets to the asset ID types `AssetConversion` can handle. + let (give_asset_id, give_amount) = Matcher::matches_fungibles(give_asset) + .map_err(|error| { + log::trace!( + target: "xcm::SingleAssetExchangeAdapter::quote_exchange_price", + "Could not map XCM asset {:?} to FRAME asset. Error: {:?}.", + give_asset, + error, + ); + () + }) + .ok()?; + let (want_asset_id, want_amount) = Matcher::matches_fungibles(want_asset) + .map_err(|error| { + log::trace!( + target: "xcm::SingleAssetExchangeAdapter::quote_exchange_price", + "Could not map XCM asset {:?} to FRAME asset. Error: {:?}.", + want_asset, + error, + ); + () + }) + .ok()?; + // We quote the price. + if maximal { + // The amount of `want` resulting from swapping `give`. + let resulting_want = + ::quote_price_exact_tokens_for_tokens( + give_asset_id, + want_asset_id, + give_amount, + true, // Include fee. + )?; + + Some((want_asset.id.clone(), resulting_want).into()) + } else { + // The `give` amount required to obtain `want`. + let necessary_give = + ::quote_price_tokens_for_exact_tokens( + give_asset_id, + want_asset_id, + want_amount, + true, // Include fee. + )?; + + Some((give_asset.id.clone(), necessary_give).into()) + } + } +} diff --git a/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs b/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs new file mode 100644 index 0000000000000000000000000000000000000000..4d9809e84f8821d120bd9f83e6f48eb24f7aa607 --- /dev/null +++ b/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs @@ -0,0 +1,370 @@ +// 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 . + +//! Mock to test [`SingleAssetExchangeAdapter`]. + +use core::marker::PhantomData; +use frame_support::{ + assert_ok, construct_runtime, derive_impl, ord_parameter_types, parameter_types, + traits::{ + fungible::{self, NativeFromLeft, NativeOrWithId}, + fungibles::Mutate, + tokens::imbalance::ResolveAssetTo, + AsEnsureOriginWithArg, Equals, Everything, Nothing, OriginTrait, PalletInfoAccess, + }, + PalletId, +}; +use sp_core::{ConstU128, ConstU32, Get}; +use sp_runtime::{ + traits::{AccountIdConversion, IdentityLookup, MaybeEquivalence, TryConvert, TryConvertInto}, + BuildStorage, Permill, +}; +use xcm::prelude::*; +use xcm_executor::{traits::ConvertLocation, XcmExecutor}; + +use crate::{FungibleAdapter, IsConcrete, MatchedConvertedConcreteId, StartsWith}; + +pub type Block = frame_system::mocking::MockBlock; +pub type AccountId = u64; +pub type Balance = u128; + +construct_runtime! { + pub struct Runtime { + System: frame_system, + Balances: pallet_balances, + AssetsPallet: pallet_assets::, + PoolAssets: pallet_assets::, + XcmPallet: pallet_xcm, + AssetConversion: pallet_asset_conversion, + } +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Runtime { + type Block = Block; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type AccountData = pallet_balances::AccountData; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type AccountStore = System; + type ExistentialDeposit = ConstU128<1>; +} + +pub type TrustBackedAssetsInstance = pallet_assets::Instance1; +pub type PoolAssetsInstance = pallet_assets::Instance2; + +#[derive_impl(pallet_assets::config_preludes::TestDefaultConfig)] +impl pallet_assets::Config for Runtime { + type Currency = Balances; + type Balance = Balance; + type AssetDeposit = ConstU128<1>; + type AssetAccountDeposit = ConstU128<10>; + type MetadataDepositBase = ConstU128<1>; + type MetadataDepositPerByte = ConstU128<1>; + type ApprovalDeposit = ConstU128<1>; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type Freezer = (); + type CallbackHandle = (); +} + +#[derive_impl(pallet_assets::config_preludes::TestDefaultConfig)] +impl pallet_assets::Config for Runtime { + type Currency = Balances; + type Balance = Balance; + type AssetDeposit = ConstU128<1>; + type AssetAccountDeposit = ConstU128<10>; + type MetadataDepositBase = ConstU128<1>; + type MetadataDepositPerByte = ConstU128<1>; + type ApprovalDeposit = ConstU128<1>; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type Freezer = (); + type CallbackHandle = (); +} + +/// Union fungibles implementation for `Assets` and `Balances`. +pub type NativeAndAssets = + fungible::UnionOf, AccountId>; + +parameter_types! { + pub const AssetConversionPalletId: PalletId = PalletId(*b"py/ascon"); + pub const Native: NativeOrWithId = NativeOrWithId::Native; + pub const LiquidityWithdrawalFee: Permill = Permill::from_percent(0); +} + +ord_parameter_types! { + pub const AssetConversionOrigin: AccountId = + AccountIdConversion::::into_account_truncating(&AssetConversionPalletId::get()); +} + +pub type PoolIdToAccountId = pallet_asset_conversion::AccountIdConverter< + AssetConversionPalletId, + (NativeOrWithId, NativeOrWithId), +>; + +impl pallet_asset_conversion::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type HigherPrecisionBalance = sp_core::U256; + type AssetKind = NativeOrWithId; + type Assets = NativeAndAssets; + type PoolId = (Self::AssetKind, Self::AssetKind); + type PoolLocator = pallet_asset_conversion::WithFirstAsset< + Native, + AccountId, + Self::AssetKind, + PoolIdToAccountId, + >; + type PoolAssetId = u32; + type PoolAssets = PoolAssets; + type PoolSetupFee = ConstU128<100>; // Asset class deposit fees are sufficient to prevent spam + type PoolSetupFeeAsset = Native; + type PoolSetupFeeTarget = ResolveAssetTo; + type LiquidityWithdrawalFee = LiquidityWithdrawalFee; + type LPFee = ConstU32<3>; + type PalletId = AssetConversionPalletId; + type MaxSwapPathLength = ConstU32<3>; + type MintMinLiquidity = ConstU128<100>; + type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + +/// We only alias local accounts. +pub type LocationToAccountId = AccountIndex64Aliases; + +parameter_types! { + pub HereLocation: Location = Here.into_location(); + pub WeightPerInstruction: Weight = Weight::from_parts(1, 1); + pub MaxInstructions: u32 = 100; + pub UniversalLocation: InteriorLocation = [GlobalConsensus(Polkadot), Parachain(1000)].into(); + pub TrustBackedAssetsPalletIndex: u8 = ::index() as u8; + pub TrustBackedAssetsPalletLocation: Location = PalletInstance(TrustBackedAssetsPalletIndex::get()).into(); +} + +/// Adapter for the native token. +pub type FungibleTransactor = FungibleAdapter< + // Use this implementation of the `fungible::*` traits. + // `Balances` is the name given to the balances pallet + Balances, + // This transactor deals with the native token. + IsConcrete, + // How to convert an XCM Location into a local account id. + // This is also something that's configured in the XCM executor. + LocationToAccountId, + // The type for account ids, only needed because `fungible` is generic over it. + AccountId, + // Not tracking teleports. + (), +>; + +pub type Weigher = crate::FixedWeightBounds; + +pub struct LocationToAssetId; +impl MaybeEquivalence> for LocationToAssetId { + fn convert(location: &Location) -> Option> { + let pallet_instance = TrustBackedAssetsPalletIndex::get(); + match location.unpack() { + (0, [PalletInstance(instance), GeneralIndex(index)]) + if *instance == pallet_instance => + Some(NativeOrWithId::WithId(*index as u32)), + (0, []) => Some(NativeOrWithId::Native), + _ => None, + } + } + + fn convert_back(asset_id: &NativeOrWithId) -> Option { + let pallet_instance = TrustBackedAssetsPalletIndex::get(); + Some(match asset_id { + NativeOrWithId::WithId(id) => + Location::new(0, [PalletInstance(pallet_instance), GeneralIndex((*id).into())]), + NativeOrWithId::Native => Location::new(0, []), + }) + } +} + +pub type PoolAssetsExchanger = crate::SingleAssetExchangeAdapter< + AssetConversion, + NativeAndAssets, + MatchedConvertedConcreteId< + NativeOrWithId, + Balance, + (StartsWith, Equals), + LocationToAssetId, + TryConvertInto, + >, + AccountId, +>; + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = (); + type AssetTransactor = FungibleTransactor; + type OriginConverter = (); + type IsReserve = (); + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + // This is not safe, you should use `crate::AllowTopLevelPaidExecutionFrom` in a + // production chain + type Barrier = crate::AllowUnpaidExecutionFrom; + type Weigher = Weigher; + type Trader = (); + type ResponseHandler = (); + type AssetTrap = (); + type AssetLocker = (); + type AssetExchanger = PoolAssetsExchanger; + type AssetClaims = (); + type SubscriptionService = (); + type PalletInstancesInfo = (); + type FeeManager = (); + type MaxAssetsIntoHolding = ConstU32<1>; + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = crate::FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); + type XcmRecorder = (); +} + +/// Simple converter from a [`Location`] with an [`AccountIndex64`] junction and no parent to a +/// `u64`. +pub struct AccountIndex64Aliases; +impl ConvertLocation for AccountIndex64Aliases { + fn convert_location(location: &Location) -> Option { + let index = match location.unpack() { + (0, [AccountIndex64 { index, network: None }]) => index, + _ => return None, + }; + Some((*index).into()) + } +} + +/// `Convert` implementation to convert from some a `Signed` (system) `Origin` into an +/// `AccountIndex64`. +/// +/// Typically used when configuring `pallet-xcm` in tests to allow `u64` accounts to dispatch an XCM +/// from an `AccountIndex64` origin. +pub struct SignedToAccountIndex64( + PhantomData<(RuntimeOrigin, AccountId, Network)>, +); +impl, Network: Get>> + TryConvert for SignedToAccountIndex64 +where + RuntimeOrigin::PalletsOrigin: From> + + TryInto, Error = RuntimeOrigin::PalletsOrigin>, +{ + fn try_convert(o: RuntimeOrigin) -> Result { + o.try_with_caller(|caller| match caller.try_into() { + Ok(frame_system::RawOrigin::Signed(who)) => + Ok(Junction::AccountIndex64 { network: Network::get(), index: who.into() }.into()), + Ok(other) => Err(other.into()), + Err(other) => Err(other), + }) + } +} + +parameter_types! { + pub const NoNetwork: Option = None; +} + +pub type LocalOriginToLocation = SignedToAccountIndex64; + +impl pallet_xcm::Config for Runtime { + // We turn off sending for these tests + type SendXcmOrigin = crate::EnsureXcmOrigin; + type XcmRouter = (); + // Anyone can execute XCM programs + type ExecuteXcmOrigin = crate::EnsureXcmOrigin; + // We execute any type of program + type XcmExecuteFilter = Everything; + // How we execute programs + type XcmExecutor = XcmExecutor; + // We don't allow teleports + type XcmTeleportFilter = Nothing; + // We don't allow reserve transfers + type XcmReserveTransferFilter = Nothing; + // Same weigher executor uses to weigh XCM programs + type Weigher = Weigher; + // Same universal location + type UniversalLocation = UniversalLocation; + // No version discovery needed + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 0; + type AdvertisedXcmVersion = frame_support::traits::ConstU32<3>; + type AdminOrigin = frame_system::EnsureRoot; + // No locking + type TrustedLockers = (); + type MaxLockers = frame_support::traits::ConstU32<0>; + type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + // How to turn locations into accounts + type SovereignAccountOf = LocationToAccountId; + // A currency to pay for things and its matcher, we are using the relay token + type Currency = Balances; + type CurrencyMatcher = crate::IsConcrete; + // Pallet benchmarks, no need for this recipe + type WeightInfo = pallet_xcm::TestWeightInfo; + // Runtime types + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; +} + +pub const INITIAL_BALANCE: Balance = 1_000_000_000; + +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(0, INITIAL_BALANCE), (1, INITIAL_BALANCE), (2, INITIAL_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + + let owner = 0; + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + assert_ok!(AssetsPallet::force_create(RuntimeOrigin::root(), 1, owner, false, 1,)); + assert_ok!(AssetsPallet::mint_into(1, &owner, INITIAL_BALANCE,)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(owner), + Box::new(NativeOrWithId::Native), + Box::new(NativeOrWithId::WithId(1)), + )); + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(owner), + Box::new(NativeOrWithId::Native), + Box::new(NativeOrWithId::WithId(1)), + 50_000_000, + 100_000_000, + 0, + 0, + owner, + )); + }); + ext +} diff --git a/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mod.rs b/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..2a47832923f7dadbbac5d2a0d496cdbc380aa7a2 --- /dev/null +++ b/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mod.rs @@ -0,0 +1,25 @@ +// 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 . + +//! SingleAssetExchangeAdapter. + +mod adapter; +pub use adapter::SingleAssetExchangeAdapter; + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; diff --git a/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/tests.rs b/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..83f57f32822f0305409250a3b221ebb5c9101e91 --- /dev/null +++ b/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/tests.rs @@ -0,0 +1,233 @@ +// 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 . + +//! Tests for the [`SingleAssetExchangeAdapter`] type. + +use super::mock::*; +use xcm::prelude::*; +use xcm_executor::{traits::AssetExchange, AssetsInHolding}; + +// ========== Happy path ========== + +/// Scenario: +/// Account #3 wants to use the local liquidity pool between two custom assets, +/// 1 and 2. +#[test] +fn maximal_exchange() { + new_test_ext().execute_with(|| { + let assets = PoolAssetsExchanger::exchange_asset( + None, + vec![([PalletInstance(2), GeneralIndex(1)], 10_000_000).into()].into(), + &vec![(Here, 2_000_000).into()].into(), + true, // Maximal + ) + .unwrap(); + let amount = get_amount_from_first_fungible(&assets); + assert_eq!(amount, 4_533_054); + }); +} + +#[test] +fn minimal_exchange() { + new_test_ext().execute_with(|| { + let assets = PoolAssetsExchanger::exchange_asset( + None, + vec![([PalletInstance(2), GeneralIndex(1)], 10_000_000).into()].into(), + &vec![(Here, 2_000_000).into()].into(), + false, // Minimal + ) + .unwrap(); + let (first_amount, second_amount) = get_amount_from_fungibles(&assets); + assert_eq!(first_amount, 2_000_000); + assert_eq!(second_amount, 5_820_795); + }); +} + +#[test] +fn maximal_quote() { + new_test_ext().execute_with(|| { + let assets = quote( + &([PalletInstance(2), GeneralIndex(1)], 10_000_000).into(), + &(Here, 2_000_000).into(), + true, + ) + .unwrap(); + let amount = get_amount_from_first_fungible(&assets.into()); + // The amount of the native token resulting from swapping all `10_000_000` of the custom + // token. + assert_eq!(amount, 4_533_054); + }); +} + +#[test] +fn minimal_quote() { + new_test_ext().execute_with(|| { + let assets = quote( + &([PalletInstance(2), GeneralIndex(1)], 10_000_000).into(), + &(Here, 2_000_000).into(), + false, + ) + .unwrap(); + let amount = get_amount_from_first_fungible(&assets.into()); + // The amount of the custom token needed to get `2_000_000` of the native token. + assert_eq!(amount, 4_179_205); + }); +} + +// ========== Unhappy path ========== + +#[test] +fn no_asset_in_give() { + new_test_ext().execute_with(|| { + assert!(PoolAssetsExchanger::exchange_asset( + None, + vec![].into(), + &vec![(Here, 2_000_000).into()].into(), + true + ) + .is_err()); + }); +} + +#[test] +fn more_than_one_asset_in_give() { + new_test_ext().execute_with(|| { + assert!(PoolAssetsExchanger::exchange_asset( + None, + vec![([PalletInstance(2), GeneralIndex(1)], 1).into(), (Here, 2).into()].into(), + &vec![(Here, 2_000_000).into()].into(), + true + ) + .is_err()); + }); +} + +#[test] +fn no_asset_in_want() { + new_test_ext().execute_with(|| { + assert!(PoolAssetsExchanger::exchange_asset( + None, + vec![([PalletInstance(2), GeneralIndex(1)], 10_000_000).into()].into(), + &vec![].into(), + true + ) + .is_err()); + }); +} + +#[test] +fn more_than_one_asset_in_want() { + new_test_ext().execute_with(|| { + assert!(PoolAssetsExchanger::exchange_asset( + None, + vec![([PalletInstance(2), GeneralIndex(1)], 10_000_000).into()].into(), + &vec![(Here, 2_000_000).into(), ([PalletInstance(2), GeneralIndex(1)], 1).into()] + .into(), + true + ) + .is_err()); + }); +} + +#[test] +fn give_asset_does_not_match() { + new_test_ext().execute_with(|| { + let nonexistent_asset_id = 1000; + assert!(PoolAssetsExchanger::exchange_asset( + None, + vec![([PalletInstance(2), GeneralIndex(nonexistent_asset_id)], 10_000_000).into()] + .into(), + &vec![(Here, 2_000_000).into()].into(), + true + ) + .is_err()); + }); +} + +#[test] +fn want_asset_does_not_match() { + new_test_ext().execute_with(|| { + let nonexistent_asset_id = 1000; + assert!(PoolAssetsExchanger::exchange_asset( + None, + vec![(Here, 2_000_000).into()].into(), + &vec![([PalletInstance(2), GeneralIndex(nonexistent_asset_id)], 10_000_000).into()] + .into(), + true + ) + .is_err()); + }); +} + +#[test] +fn exchange_fails() { + new_test_ext().execute_with(|| { + assert!(PoolAssetsExchanger::exchange_asset( + None, + vec![([PalletInstance(2), GeneralIndex(1)], 10_000_000).into()].into(), + // We're asking for too much of the native token... + &vec![(Here, 200_000_000).into()].into(), + false, // Minimal + ) + .is_err()); + }); +} + +#[test] +fn non_fungible_asset_in_give() { + new_test_ext().execute_with(|| { + assert!(PoolAssetsExchanger::exchange_asset( + None, + // Using `u64` here will give us a non-fungible instead of a fungible. + vec![([PalletInstance(2), GeneralIndex(2)], 10_000_000u64).into()].into(), + &vec![(Here, 10_000_000).into()].into(), + false, // Minimal + ) + .is_err()); + }); +} + +// ========== Helper functions ========== + +fn get_amount_from_first_fungible(assets: &AssetsInHolding) -> u128 { + let mut fungibles_iter = assets.fungible_assets_iter(); + let first_fungible = fungibles_iter.next().unwrap(); + let Fungible(amount) = first_fungible.fun else { + unreachable!("Asset should be fungible"); + }; + amount +} + +fn get_amount_from_fungibles(assets: &AssetsInHolding) -> (u128, u128) { + let mut fungibles_iter = assets.fungible_assets_iter(); + let first_fungible = fungibles_iter.next().unwrap(); + let Fungible(first_amount) = first_fungible.fun else { + unreachable!("Asset should be fungible"); + }; + let second_fungible = fungibles_iter.next().unwrap(); + let Fungible(second_amount) = second_fungible.fun else { + unreachable!("Asset should be fungible"); + }; + (first_amount, second_amount) +} + +fn quote(asset_1: &Asset, asset_2: &Asset, maximal: bool) -> Option { + PoolAssetsExchanger::quote_exchange_price( + &asset_1.clone().into(), + &asset_2.clone().into(), + maximal, + ) +} 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/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs index c3495601cd87518d1dc472ba5713fa51dbfe30f5..bec3bdcb05a0b0adeaabc13024be4d657bbdd807 100644 --- a/polkadot/xcm/xcm-builder/src/lib.rs +++ b/polkadot/xcm/xcm-builder/src/lib.rs @@ -35,6 +35,9 @@ pub use asset_conversion::{ AsPrefixedGeneralIndex, ConvertedConcreteId, MatchedConvertedConcreteId, }; +mod asset_exchange; +pub use asset_exchange::SingleAssetExchangeAdapter; + mod barriers; pub use barriers::{ AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, @@ -56,7 +59,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/test_utils.rs b/polkadot/xcm/xcm-builder/src/test_utils.rs index 37a49a1b3dc7e742c291e49274490dd20aa1ddee..90afb2c9a3d3e1fefa3db3d0ea81f9e5811d9b01 100644 --- a/polkadot/xcm/xcm-builder/src/test_utils.rs +++ b/polkadot/xcm/xcm-builder/src/test_utils.rs @@ -109,6 +109,10 @@ impl AssetExchange for TestAssetExchanger { ) -> Result { Ok(want.clone().into()) } + + fn quote_exchange_price(give: &Assets, _want: &Assets, _maximal: bool) -> Option { + Some(give.clone()) + } } pub struct TestPalletsInfo; diff --git a/polkadot/xcm/xcm-builder/src/tests/mock.rs b/polkadot/xcm/xcm-builder/src/tests/mock.rs index ac43d217ff3ff221becd89878e95772cf4000ded..9f42aee87c9fa44b0b73c93b0b4475c009dab26a 100644 --- a/polkadot/xcm/xcm-builder/src/tests/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/mock.rs @@ -695,6 +695,20 @@ impl AssetExchange for TestAssetExchange { EXCHANGE_ASSETS.with(|l| l.replace(have)); Ok(get) } + + fn quote_exchange_price(give: &Assets, want: &Assets, maximal: bool) -> Option { + let mut have = EXCHANGE_ASSETS.with(|l| l.borrow().clone()); + if !have.contains_assets(want) { + return None; + } + let get = if maximal { + have.saturating_take(give.clone().into()) + } else { + have.saturating_take(want.clone().into()) + }; + let result: Vec = get.fungible_assets_iter().collect(); + Some(result.into()) + } } pub struct SiblingPrefix; diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index 1daf5ae750cfbd0bb5a407eceb8d621023586fe0..74561e931e7e14931aeac42e73b0cd9cb8790b6b 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -809,7 +809,7 @@ impl XcmExecutor { }; let actual_weight = maybe_actual_weight.unwrap_or(weight); let surplus = weight.saturating_sub(actual_weight); - // We assume that the `Config::Weigher` will counts the `require_weight_at_most` + // We assume that the `Config::Weigher` will count the `require_weight_at_most` // for the estimate of how much weight this instruction will take. Now that we know // that it's less, we credit it. // @@ -858,14 +858,7 @@ impl XcmExecutor { let old_holding = self.holding.clone(); let result = Config::TransactionalProcessor::process(|| { let deposited = self.holding.saturating_take(assets); - for asset in deposited.into_assets_iter() { - Config::AssetTransactor::deposit_asset( - &asset, - &beneficiary, - Some(&self.context), - )?; - } - Ok(()) + self.deposit_assets_with_retry(&deposited, &beneficiary) }); if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() { self.holding = old_holding; @@ -890,9 +883,7 @@ impl XcmExecutor { // now take assets to deposit (excluding transport_fee) let deposited = self.holding.saturating_take(assets); - for asset in deposited.assets_iter() { - Config::AssetTransactor::deposit_asset(&asset, &dest, Some(&self.context))?; - } + self.deposit_assets_with_retry(&deposited, &dest)?; // Note that we pass `None` as `maybe_failed_bin` and drop any assets which // cannot be reanchored because we have already called `deposit_asset` on all // assets. @@ -1282,4 +1273,46 @@ impl XcmExecutor { }), } } + + /// Deposit `to_deposit` assets to `beneficiary`, without giving up on the first (transient) + /// error, and retrying once just in case one of the subsequently deposited assets satisfy some + /// requirement. + /// + /// Most common transient error is: `beneficiary` account does not yet exist and the first + /// asset(s) in the (sorted) list does not satisfy ED, but a subsequent one in the list does. + /// + /// This function can write into storage and also return an error at the same time, it should + /// always be called within a transactional context. + fn deposit_assets_with_retry( + &mut self, + to_deposit: &AssetsInHolding, + beneficiary: &Location, + ) -> Result<(), XcmError> { + let mut failed_deposits = Vec::with_capacity(to_deposit.len()); + + let mut deposit_result = Ok(()); + for asset in to_deposit.assets_iter() { + deposit_result = + Config::AssetTransactor::deposit_asset(&asset, &beneficiary, Some(&self.context)); + // if deposit failed for asset, mark it for retry after depositing the others. + if deposit_result.is_err() { + failed_deposits.push(asset); + } + } + if failed_deposits.len() == to_deposit.len() { + tracing::debug!( + target: "xcm::execute", + ?deposit_result, + "Deposit for each asset failed, returning the last error as there is no point in retrying any of them", + ); + return deposit_result; + } + tracing::trace!(target: "xcm::execute", ?failed_deposits, "Deposits to retry"); + + // retry previously failed deposits, this time short-circuiting on any error. + for asset in failed_deposits { + Config::AssetTransactor::deposit_asset(&asset, &beneficiary, Some(&self.context))?; + } + Ok(()) + } } diff --git a/polkadot/xcm/xcm-executor/src/traits/asset_exchange.rs b/polkadot/xcm/xcm-executor/src/traits/asset_exchange.rs index 432a7498ed4cf9b700649ed987c8050041e7de08..f4b7135d4206d1638e23260951ea78099e55fcc4 100644 --- a/polkadot/xcm/xcm-executor/src/traits/asset_exchange.rs +++ b/polkadot/xcm/xcm-executor/src/traits/asset_exchange.rs @@ -37,6 +37,27 @@ pub trait AssetExchange { want: &Assets, maximal: bool, ) -> Result; + + /// Handler for quoting the exchange price of two asset collections. + /// + /// It's useful before calling `exchange_asset`, to get some information on whether or not the + /// exchange will be successful. + /// + /// Arguments: + /// - `give` The asset(s) that are going to be given. + /// - `want` The asset(s) that are wanted. + /// - `maximal`: + /// - If `true`, then the return value is the resulting amount of `want` obtained by swapping + /// `give`. + /// - If `false`, then the return value is the required amount of `give` needed to get `want`. + /// + /// The return value is `Assets` since it comprises both which assets and how much of them. + /// + /// The relationship between this function and `exchange_asset` is the following: + /// - quote(give, want, maximal) = resulting_want -> exchange(give, resulting_want, maximal) ✅ + /// - quote(give, want, minimal) = required_give -> exchange(required_give_amount, want, + /// minimal) ✅ + fn quote_exchange_price(_give: &Assets, _want: &Assets, _maximal: bool) -> Option; } #[impl_trait_for_tuples::impl_for_tuples(30)] @@ -55,4 +76,14 @@ impl AssetExchange for Tuple { )* ); Err(give) } + + fn quote_exchange_price(give: &Assets, want: &Assets, maximal: bool) -> Option { + for_tuples!( #( + match Tuple::quote_exchange_price(give, want, maximal) { + Some(assets) => return Some(assets), + None => {} + } + )* ); + None + } } diff --git a/polkadot/xcm/xcm-runtime-apis/Cargo.toml b/polkadot/xcm/xcm-runtime-apis/Cargo.toml index 748d5af68a1fdee6c62873370d33387d55a06e6f..9ccca76c321cc031e0fcaf0a0f6486ea238f0068 100644 --- a/polkadot/xcm/xcm-runtime-apis/Cargo.toml +++ b/polkadot/xcm/xcm-runtime-apis/Cargo.toml @@ -31,7 +31,7 @@ pallet-assets = { workspace = true } xcm-executor = { workspace = true } frame-executive = { workspace = true } log = { workspace = true } -env_logger = { workspace = true } +sp-tracing = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs b/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs index 59ee17973805621ce360546afb0b1583abfbdc9a..e5dac7c7a04edaed341274d79690b09e7c987b42 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs @@ -41,7 +41,7 @@ use mock::{ // Parachain(2000) -------------------------------------------> Parachain(1000) #[test] fn fee_estimation_for_teleport() { - let _ = env_logger::builder().is_test(true).try_init(); + sp_tracing::init_for_tests(); let who = 1; // AccountId = u64. let balances = vec![(who, 100 + DeliveryFees::get() + ExistentialDeposit::get())]; let assets = vec![(1, who, 50)]; @@ -195,7 +195,7 @@ fn fee_estimation_for_teleport() { // Parachain(2000) -------------------------------------------> Parachain(1000) #[test] fn dry_run_reserve_asset_transfer() { - let _ = env_logger::builder().is_test(true).try_init(); + sp_tracing::init_for_tests(); let who = 1; // AccountId = u64. // Native token used for fees. let balances = vec![(who, DeliveryFees::get() + ExistentialDeposit::get())]; @@ -274,7 +274,7 @@ fn dry_run_reserve_asset_transfer() { #[test] fn dry_run_xcm() { - let _ = env_logger::builder().is_test(true).try_init(); + sp_tracing::init_for_tests(); let who = 1; // AccountId = u64. let transfer_amount = 100u128; // We need to build the XCM to weigh it and then build the real XCM that can pay for fees. 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/pr_3286.prdoc b/prdoc/1.15.0/pr_3286.prdoc similarity index 97% rename from prdoc/pr_3286.prdoc rename to prdoc/1.15.0/pr_3286.prdoc index 6ec3f6552a4a7369d1881e621e3070460d0b344f..3433f63f30295a57d8889eea12aedf731f8471cf 100644 --- a/prdoc/pr_3286.prdoc +++ b/prdoc/1.15.0/pr_3286.prdoc @@ -14,3 +14,4 @@ doc: crates: - name: pallet-assets + bump: patch diff --git a/prdoc/pr_4097.prdoc b/prdoc/1.15.0/pr_4097.prdoc similarity index 100% rename from prdoc/pr_4097.prdoc rename to prdoc/1.15.0/pr_4097.prdoc diff --git a/prdoc/pr_4522.prdoc b/prdoc/1.15.0/pr_4522.prdoc similarity index 100% rename from prdoc/pr_4522.prdoc rename to prdoc/1.15.0/pr_4522.prdoc diff --git a/prdoc/pr_4563.prdoc b/prdoc/1.15.0/pr_4563.prdoc similarity index 100% rename from prdoc/pr_4563.prdoc rename to prdoc/1.15.0/pr_4563.prdoc diff --git a/prdoc/pr_4566.prdoc b/prdoc/1.15.0/pr_4566.prdoc similarity index 100% rename from prdoc/pr_4566.prdoc rename to prdoc/1.15.0/pr_4566.prdoc diff --git a/prdoc/pr_4663.prdoc b/prdoc/1.15.0/pr_4663.prdoc similarity index 100% rename from prdoc/pr_4663.prdoc rename to prdoc/1.15.0/pr_4663.prdoc diff --git a/prdoc/pr_4738.prdoc b/prdoc/1.15.0/pr_4738.prdoc similarity index 100% rename from prdoc/pr_4738.prdoc rename to prdoc/1.15.0/pr_4738.prdoc diff --git a/prdoc/pr_4755.prdoc b/prdoc/1.15.0/pr_4755.prdoc similarity index 100% rename from prdoc/pr_4755.prdoc rename to prdoc/1.15.0/pr_4755.prdoc diff --git a/prdoc/pr_4777.prdoc b/prdoc/1.15.0/pr_4777.prdoc similarity index 100% rename from prdoc/pr_4777.prdoc rename to prdoc/1.15.0/pr_4777.prdoc diff --git a/prdoc/pr_4839.prdoc b/prdoc/1.15.0/pr_4839.prdoc similarity index 100% rename from prdoc/pr_4839.prdoc rename to prdoc/1.15.0/pr_4839.prdoc diff --git a/prdoc/pr_4840.prdoc b/prdoc/1.15.0/pr_4840.prdoc similarity index 100% rename from prdoc/pr_4840.prdoc rename to prdoc/1.15.0/pr_4840.prdoc diff --git a/prdoc/pr_4848.prdoc b/prdoc/1.15.0/pr_4848.prdoc similarity index 100% rename from prdoc/pr_4848.prdoc rename to prdoc/1.15.0/pr_4848.prdoc diff --git a/prdoc/pr_4863.prdoc b/prdoc/1.15.0/pr_4863.prdoc similarity index 100% rename from prdoc/pr_4863.prdoc rename to prdoc/1.15.0/pr_4863.prdoc diff --git a/prdoc/pr_4871.prdoc b/prdoc/1.15.0/pr_4871.prdoc similarity index 100% rename from prdoc/pr_4871.prdoc rename to prdoc/1.15.0/pr_4871.prdoc diff --git a/prdoc/pr_4885.prdoc b/prdoc/1.15.0/pr_4885.prdoc similarity index 100% rename from prdoc/pr_4885.prdoc rename to prdoc/1.15.0/pr_4885.prdoc diff --git a/prdoc/pr_4888.prdoc b/prdoc/1.15.0/pr_4888.prdoc similarity index 100% rename from prdoc/pr_4888.prdoc rename to prdoc/1.15.0/pr_4888.prdoc diff --git a/prdoc/pr_4902.prdoc b/prdoc/1.15.0/pr_4902.prdoc similarity index 100% rename from prdoc/pr_4902.prdoc rename to prdoc/1.15.0/pr_4902.prdoc diff --git a/prdoc/pr_4912.prdoc b/prdoc/1.15.0/pr_4912.prdoc similarity index 100% rename from prdoc/pr_4912.prdoc rename to prdoc/1.15.0/pr_4912.prdoc diff --git a/prdoc/pr_4922.prdoc b/prdoc/1.15.0/pr_4922.prdoc similarity index 100% rename from prdoc/pr_4922.prdoc rename to prdoc/1.15.0/pr_4922.prdoc diff --git a/prdoc/pr_4932.prdoc b/prdoc/1.15.0/pr_4932.prdoc similarity index 100% rename from prdoc/pr_4932.prdoc rename to prdoc/1.15.0/pr_4932.prdoc diff --git a/prdoc/pr_4935.prdoc b/prdoc/1.15.0/pr_4935.prdoc similarity index 100% rename from prdoc/pr_4935.prdoc rename to prdoc/1.15.0/pr_4935.prdoc diff --git a/prdoc/pr_4943.prdoc b/prdoc/1.15.0/pr_4943.prdoc similarity index 95% rename from prdoc/pr_4943.prdoc rename to prdoc/1.15.0/pr_4943.prdoc index 705325126060b8aa7eeab33ff2a03deaaa8b2919..a8db0f9e1ea10f59654c62122a79dfb69477f375 100644 --- a/prdoc/pr_4943.prdoc +++ b/prdoc/1.15.0/pr_4943.prdoc @@ -8,6 +8,6 @@ doc: 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: +crates: - name: frame-support - bump: patch \ No newline at end of file + bump: patch diff --git a/prdoc/pr_4972.prdoc b/prdoc/1.15.0/pr_4972.prdoc similarity index 100% rename from prdoc/pr_4972.prdoc rename to prdoc/1.15.0/pr_4972.prdoc diff --git a/prdoc/pr_4978.prdoc b/prdoc/1.15.0/pr_4978.prdoc similarity index 100% rename from prdoc/pr_4978.prdoc rename to prdoc/1.15.0/pr_4978.prdoc diff --git a/prdoc/1.15.0/pr_4997.prdoc b/prdoc/1.15.0/pr_4997.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..25620a7e63ea817e9009cf557748deb63d921f2e --- /dev/null +++ b/prdoc/1.15.0/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/1.15.0/pr_5011.prdoc similarity index 100% rename from prdoc/pr_5011.prdoc rename to prdoc/1.15.0/pr_5011.prdoc diff --git a/prdoc/1.15.0/pr_5040.prdoc b/prdoc/1.15.0/pr_5040.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..62b175c1d64806fc2a916811af8cf3845eb8051a --- /dev/null +++ b/prdoc/1.15.0/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/1.15.0/pr_5103.prdoc b/prdoc/1.15.0/pr_5103.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..b0f72bf531f183c7dc1bb4e0d57836778bd8d1b1 --- /dev/null +++ b/prdoc/1.15.0/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/1.15.0/pr_5153.prdoc b/prdoc/1.15.0/pr_5153.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..4f43b52d8edfbf033ffcb23c1a5aa8d529166763 --- /dev/null +++ b/prdoc/1.15.0/pr_5153.prdoc @@ -0,0 +1,12 @@ +title: "Grandpa: Ensure voting doesn't fail after a re-org" + +doc: + - audience: Node Operator + description: | + Ensures that a node is still able to vote with Grandpa, when a re-org happened that + changed the best chain. This ultimately prevents that a network may runs into a + potential finality stall. + +crates: + - name: sc-consensus-grandpa + bump: patch 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_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_4129.prdoc b/prdoc/pr_4129.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..dfcc9b9ef0307362d7be059271d370afd15cd7c1 --- /dev/null +++ b/prdoc/pr_4129.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: Update ForeignAssets from xcm::v3::Location to xcm::v4::Location + +doc: + - audience: + - Runtime Dev + - Runtime User + description: | + As a stepping stone for XCMv5, the foreign asset ids have been updated from v3::Location to v4::Location. + +crates: + - name: asset-hub-rococo-runtime + bump: minor + - name: asset-hub-westend-runtime + bump: minor diff --git a/prdoc/pr_4424.prdoc b/prdoc/pr_4424.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..7131ebfca274b40baa70fe582176143aa1bfacc0 --- /dev/null +++ b/prdoc/pr_4424.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: Coretime auto renewal + +doc: + - audience: Runtime User + description: | + With the additions in this PR, any task that utilizes a core that can be auto-renewed + can enable auto-renewal. The renewal is paid from the task's sovereign account. + The two new extrinsics for controlling auto-renewal are `enable_auto_renew` and + `disable_auto_renew`. + +crates: + - name: pallet-broker + bump: major + - name: coretime-rococo-runtime + bump: minor + - name: coretime-westend-runtime + bump: minor diff --git a/prdoc/pr_4460.prdoc b/prdoc/pr_4460.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..81636c3313fcff94418aa322e1d38fa2a5c9da29 --- /dev/null +++ b/prdoc/pr_4460.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: "xcm-executor: allow deposit of multiple assets if at least one of them satisfies ED" + +doc: + - audience: Runtime Dev + description: | + XCM programs that deposit assets to some new (empty) account will now succeed if at least + one of the deposited assets satisfies ED. Before this change, the requirement was that the + _first_ asset had to satisfy ED, but assets order can be changed during reanchoring so it + is not reliable. Now, ordering doesn't matter, any one(s) of them can satisfy ED for the + whole deposit to work. + - audience: Runtime User + description: | + XCM programs that deposit assets to some new (empty) account will now succeed if at least + one of the deposited assets satisfies ED. Before this change, the requirement was that the + _first_ asset had to satisfy ED, but assets order can be changed during reanchoring so it + is not reliable. Now, ordering doesn't matter, any one(s) of them can satisfy ED for the + whole deposit to work. + +crates: + - name: staging-xcm-executor + bump: patch diff --git a/prdoc/pr_4487.prdoc b/prdoc/pr_4487.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..fb2bab2a57a8916e890190ef0cb59d86aa1c9b19 --- /dev/null +++ b/prdoc/pr_4487.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 `pallet::getter` usage from pallet-election-provider-multi-phase + +doc: + - audience: Runtime Dev + description: | + This PR removes the `pallet::getter`s from `pallet-election-provider-multi-phase`. + The syntax `StorageItem::::get()` should be used instead. + +crates: + - name: pallet-election-provider-multi-phase + bump: minor + - name: pallet-election-provider-e2e-test + bump: minor 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_4527.prdoc b/prdoc/pr_4527.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..12056f87575b8a6d6a01a7e8727f05d25217a364 --- /dev/null +++ b/prdoc/pr_4527.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: Call implementation for `transfer_all` + +doc: + - audience: Runtime Dev + description: | + This PR introduces the `transfer_all` call for `pallet-assets`. + The parameters are analog to the same call in `pallet-balances`. + This change is expected to be backwards-compatible. + This change requires running benchmarkings to set accurate weights for + the call. + +crates: + - name: pallet-assets + bump: major + - name: asset-hub-rococo-runtime + bump: minor + - name: asset-hub-westend-runtime + 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_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_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_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_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_4822.prdoc b/prdoc/pr_4822.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..44f3e41d8d5afd3a2859eeb68d51eb2ad49de387 --- /dev/null +++ b/prdoc/pr_4822.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: Ensure as many as possible pool members can migrate to `DelegateStake` + +doc: + - audience: Runtime Dev + description: | + 1. Allows pool members to use their total balance while joining pool with `DelegateStake`. + 2. Gates call mutating pool or member in unmigrated state. + 3. Runtime apis for reading pool and member balance. + +crates: + - name: westend-runtime + bump: minor + - name: kitchensink-runtime + bump: patch + - name: pallet-delegated-staking + bump: patch + - name: pallet-nomination-pools + bump: minor + - name: sp-staking + bump: patch + - name: pallet-nomination-pools-runtime-api + bump: minor diff --git a/prdoc/pr_4845.prdoc b/prdoc/pr_4845.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..012d34ef090ebc73409f0bdd0155510b49286841 --- /dev/null +++ b/prdoc/pr_4845.prdoc @@ -0,0 +1,13 @@ +title: Make approval-distribution logic runnable on a separate thread + +doc: + - audience: Node Dev + description: | + Pass SubsystemSender trait inside approval-distribution instead of passing SubsystemContext everywhere. + + This allows us in the future to be able to run multiple approval-distribution instances on different workers. + + +crates: +- name: polkadot-approval-distribution + bump: minor 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_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_4937.prdoc b/prdoc/pr_4937.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..37b7bc3dda5943550a3e822b5ac3df8b83c4f8d7 --- /dev/null +++ b/prdoc/pr_4937.prdoc @@ -0,0 +1,21 @@ +title: "prospective-parachains rework: take II" + +doc: + - audience: Node Dev + description: | + Add back support for backing parachain forks. Once a candidate reaches the backing quorum, + validators use a shared way of picking the winning fork to back on-chain. This was done in + order to increase the likelihood that all backers will vote on the winning fork. + The functionality of backing unconnected candidates introduced by the previous rework is preserved. + +crates: + - name: polkadot-node-core-prospective-parachains + bump: minor + - name: polkadot-node-subsystem-types + bump: minor + - name: polkadot-node-subsystem-util + bump: minor + - name: polkadot-node-core-provisioner + bump: none + - name: polkadot-statement-distribution + bump: none 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_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_4963.prdoc b/prdoc/pr_4963.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..e274d2cbb689f80a9867afd096bc7797eec94288 --- /dev/null +++ b/prdoc/pr_4963.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-proxy + +doc: + - audience: Runtime Dev + description: | + This PR removed `pallet::getter`s from `pallet-proxy`s storage items. + When accessed inside the pallet, use the syntax `StorageItem::::get()`. + +crates: + - name: pallet-proxy + bump: minor \ No newline at end of file diff --git a/prdoc/pr_4967.prdoc b/prdoc/pr_4967.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..0ce4219daa1cf74b540135a52d5ac7877e921b38 --- /dev/null +++ b/prdoc/pr_4967.prdoc @@ -0,0 +1,28 @@ +# 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 balances pallet" + +doc: + - audience: Runtime Dev + description: | + This PR removes the `pallet::getter`s from `pallet-balances`. + The syntax `StorageItem::::get()` should be used instead. + +crates: + - name: pallet-balances + bump: patch + - name: pallet-staking + bump: patch + - name: pallet-treasury + bump: patch + - name: pallet-bounties + bump: patch + - name: pallet-conviction-voting + bump: patch + - name: pallet-democracy + bump: patch + - name: pallet-elections-phragmen + bump: patch + - name: pallet-referenda + bump: patch 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_4973.prdoc b/prdoc/pr_4973.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..20b8c94dd8a907366f7182984cb87e3bcbbd07e3 --- /dev/null +++ b/prdoc/pr_4973.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: "[pallet_contracts] Increase the weight of the deposit_event host function to limit the memory used by events." + +doc: + - audience: Runtime User + description: | + This PR updates the weight of the deposit_event host function by adding + a fixed ref_time of 60,000 picoseconds per byte. Given a block time of 2 seconds + and this specified ref_time, the total allocation size is 32MB. + +crates: + - name: pallet-contracts + bump: major 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_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_4998.prdoc b/prdoc/pr_4998.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..41e3886405cc7d7eaa6eb942ff246e5fde19dc83 --- /dev/null +++ b/prdoc/pr_4998.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: Ensure members can always exit the pool gracefully + +doc: + - audience: Runtime Dev + description: | + Ensures when a member wants to withdraw all funds but the pool is not able to provide all their funds, the member + can receive as much as possible and exit pool. Also handles cases where some extra funds held in member's account + is released when they are removed. + +crates: + - name: pallet-delegated-staking + bump: patch + - name: pallet-nomination-pools + bump: major + - name: sp-staking + bump: major + diff --git a/prdoc/pr_5029.prdoc b/prdoc/pr_5029.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..d446ddf274b8bef53aa129c2ade4ce2f1805fa78 --- /dev/null +++ b/prdoc/pr_5029.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: Backoff slow peers to avoid duplicate requests + +doc: + - audience: Node Dev + description: | + This PR introduces a backoff strategy mechanism. Whenever a peer disconnects with an inflight + block (or state) request, the peer is backed off for a period of time before receiving requests. + After several attempts, the peer is disconnected and banned. The strategy aims to offload + the pressure from peers that are slow to respond or overloaded. + +crates: +- name: sc-network-sync + bump: minor diff --git a/prdoc/pr_5036.prdoc b/prdoc/pr_5036.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..e9f21f823b64bf91264bb63d6a643853998ab900 --- /dev/null +++ b/prdoc/pr_5036.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: "[pallet_contracts] Modify the storage host function benchmarks to be run on an unbalanced storage trie" + +doc: + - audience: Runtime User + description: | + This PR modifies the storage host function benchmarks. Previously, they were run + on an empty storage trie. Now, they are run on an unbalanced storage trie + to reflect the worst-case scenario. This approach increases the storage host + function weights and decreases the probability of DoS attacks. + +crates: + - name: pallet-contracts + bump: patch diff --git a/prdoc/pr_5055.prdoc b/prdoc/pr_5055.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..2367bd5925f89256b703e68a5c4eb4fc4fdc599e --- /dev/null +++ b/prdoc/pr_5055.prdoc @@ -0,0 +1,11 @@ +title: Only log error in `UnixTime::now` call of the pallet-timestamp implementation if called at genesis + +doc: + - audience: Runtime Dev + description: | + This minor patch re-introduces a check to ensure that the `UnixTime::now` implementation in the timestamp only + logs an error if called at the genesis block. + +crates: +- name: pallet-timestamp + bump: minor diff --git a/prdoc/pr_5065.prdoc b/prdoc/pr_5065.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..11fca2ab71d66b97bd17b480843afba72e462067 --- /dev/null +++ b/prdoc/pr_5065.prdoc @@ -0,0 +1,65 @@ +# 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: Replace env_logger with sp_tracing + +doc: + - audience: Node Dev + description: | + This PR replaces env_logger with sp_tracing because of an issue with env_logger and gum #4660 + +crates: + - name: relay-utils + bump: none + - name: snowbridge-outbound-queue-merkle-tree + bump: patch + - name: polkadot-node-core-approval-voting + bump: patch + - name: polkadot-node-core-av-store + bump: patch + - name: polkadot-approval-distribution + bump: patch + - name: polkadot-availability-bitfield-distribution + bump: patch + - name: polkadot-collator-protocol + bump: patch + - name: polkadot-service + bump: patch + - name: polkadot-subsystem-bench + bump: none + - name: polkadot-node-subsystem-util + bump: none + - name: xcm-runtime-apis + bump: patch + - name: sc-executor + bump: patch + - name: sc-rpc + bump: patch + - name: sc-statement-store + bump: patch + - name: pallet-contracts + bump: patch + - name: pallet-mmr + bump: patch + - name: sp-tracing + bump: patch + - name: binary-merkle-tree + bump: patch + - name: frame-omni-bencher + bump: patch + - name: pallet-balances + bump: patch + - name: pallet-staking + bump: patch + - name: pallet-treasury + bump: patch + - name: pallet-bounties + bump: patch + - name: pallet-conviction-voting + bump: patch + - name: pallet-democracy + bump: patch + - name: pallet-elections-phragmen + bump: patch + - name: pallet-referenda + bump: patch \ No newline at end of file diff --git a/prdoc/pr_5067.prdoc b/prdoc/pr_5067.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..9a11f96b5104585aaad4f2c963ac6ebe0611f7b2 --- /dev/null +++ b/prdoc/pr_5067.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: Fix region nonfungible implementation + +doc: + - audience: Runtime User + description: | + PR fixes the issue with the current implementation where minting causes + the region coremask to be set to `Coremask::complete` regardless of the + actual coremask of the region. + +crates: +- name: pallet-broker + bump: major +- name: coretime-rococo-runtime + bump: patch +- name: coretime-westend-runtime + bump: patch \ No newline at end of file diff --git a/prdoc/pr_5074.prdoc b/prdoc/pr_5074.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..cddf15ffb47c9e7d56c729006ddd899821a2b309 --- /dev/null +++ b/prdoc/pr_5074.prdoc @@ -0,0 +1,33 @@ +title: "Snowbridge on Westend" + +doc: + - audience: Runtime Dev + description: | + Since Rococo is now deprecated, we need another testnet to detect bleeding-edge changes + to Substrate, Polkadot, BEEFY consensus protocols that could brick the bridge. + - audience: Runtime Dev + description: | + Like Rococo this PR enables the fast-runtime feature by default which is easier + for testing beefy stuff on westend-local. + +crates: + - name: asset-hub-westend-runtime + bump: patch + - name: bridge-hub-westend-runtime + bump: major + - name: bridge-hub-rococo-runtime + bump: patch + - name: testnet-parachains-constants + bump: patch + - name: bridge-hub-westend-emulated-chain + bump: minor + - name: bridge-hub-westend-integration-tests + bump: minor + - name: polkadot-parachain-bin + bump: patch + - name: westend-runtime + bump: patch + - name: polkadot-service + bump: patch + + diff --git a/prdoc/pr_5078.prdoc b/prdoc/pr_5078.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..1805a27c3f28a4d16160af055420a7023e2edfd8 --- /dev/null +++ b/prdoc/pr_5078.prdoc @@ -0,0 +1,34 @@ +title: Add possibility to inject non-authorities session-keys in genesis + +doc: + - audience: Runtime Dev + description: | + Allows to inject a set of registered session-keys in pallet-session that are not + part of the first initial set of validators +crates: +- name: pallet-session + bump: major +- name: parachains-runtimes-test-utils + bump: patch +- name: pallet-staking + bump: none +- name: pallet-collator-selection + bump: none +- name: pallet-root-offences + bump: none +- name: pallet-babe + bump: none +- name: pallet-staking + bump: none +- name: pallet-grandpa + bump: none +- name: pallet-collator-selection + bump: none +- name: pallet-beefy + bump: none +- name: pallet-beefy-mmr + bump: none +- name: pallet-root-offences + bump: none +- name: polkadot-parachain-bin + bump: none \ No newline at end of file diff --git a/prdoc/pr_5113.prdoc b/prdoc/pr_5113.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..64563f7a735d16a4e81c5123f95382dc2be12827 --- /dev/null +++ b/prdoc/pr_5113.prdoc @@ -0,0 +1,14 @@ +title: Make the candidate relay parent progression check more strict for elastic scaling + +doc: + - audience: Runtime Dev + description: | + Previously, the relay chain runtime was checking if the relay parent of a new candidate does + not move backwards from the latest included on-chain candidate. This was fine prior to elastic scaling. + We now need to also check that the relay parent progresses from the latest pending availability candidate, + as well as check the progression within the candidate chain in the inherent data. + Prospective-parachains is already doing this check but it's also needed in the runtime. + +crates: +- name: polkadot-runtime-parachains + 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/pr_5129.prdoc b/prdoc/pr_5129.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..beb7eb4d282d59fc9e4fa5a2779dcb52b107bbdb --- /dev/null +++ b/prdoc/pr_5129.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: Prevent finalized notification hoarding in beefy gadget + +doc: + - audience: Node Operator + description: | + This PR fixes the error message "Notification block pinning limit + reached." during warp sync. Finality notifications in BEEFY are now + constantly being consumed and don't keep blocks pinned for extended + periods of time. + +crates: + - name: sc-consensus-beefy + bump: minor diff --git a/prdoc/pr_5130.prdoc b/prdoc/pr_5130.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..c6a00505babcdf737e5823e71c84f6524a6c7f68 --- /dev/null +++ b/prdoc/pr_5130.prdoc @@ -0,0 +1,40 @@ +# 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 SingleAssetExchangeAdapter + +doc: + - audience: Runtime Dev + description: | + SingleAssetExchangeAdapter is an adapter in xcm-builder that can be used + to configure the AssetExchanger in XCM to use pallet-asset-conversion, + or any other type that implements the `SwapCredit` and `QuotePrice` traits. + It can be configured as follows: + ```rust + pub type AssetExchanger = SingleAssetExchangeAdapter< + // pallet-assets-conversion, as named in `construct_runtime`. + AssetConversion, + // The fungibles implementation that brings together all assets in pools. + // This may be created using `fungible::UnionOf` to mix the native token + // with more tokens. + Fungibles, + // The matcher for making sure which assets should be handled by this exchanger. + Matcher, + >; + ``` + It's called "single asset" since it will only allow exchanging one asset for another. + It will error out if more than one asset tries to be exchanged. + + Also, a new method was added to the `xcm_executor::traits::AssetExchange` trait: + `quote_exchange_price`. This is used to get the exchange price between two asset collections. + If you were using the trait, you now need to also implement this new function. + +crates: + - name: staging-xcm-executor + bump: major + - name: staging-xcm-builder + bump: minor + - name: pallet-asset-conversion + bump: minor + - name: cumulus-primitives-utility + bump: minor diff --git a/prdoc/pr_5132.prdoc b/prdoc/pr_5132.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..f23574e04b79f5bb2e6c6006ffb5aee0fb552135 --- /dev/null +++ b/prdoc/pr_5132.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 `from_mel` for `Footprint` + +doc: + - audience: Runtime Dev + description: | + This introduces a new way to generate the `Footprint` type by calculating the max encoded + length of some generic type. This allows you to generate a `Footprint` of a type without + actually constructing that type. + +crates: + - name: frame-support + bump: patch diff --git a/prdoc/pr_5142.prdoc b/prdoc/pr_5142.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..4083e5bf53cdb420cdb236e920b5e409b6c82149 --- /dev/null +++ b/prdoc/pr_5142.prdoc @@ -0,0 +1,26 @@ +# 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: "Move decompression to worker processes" + +doc: + - audience: Node Dev + description: | + Candidate validation subsystem performed the PVF code decompression as well as the PoV + decompression itself which might affect the subsystem main loop performance and required + it to run on the blocking threadpool. This change moves the decompression to PVF host + workers running synchronously in separate processes. + +crates: + - name: polkadot-node-core-candidate-validation + bump: patch + - name: polkadot-overseer + bump: patch + - name: polkadot-node-core-pvf + bump: major + - name: polkadot-node-core-pvf-common + bump: major + - name: polkadot-node-core-pvf-execute-worker + bump: patch + - name: polkadot-node-core-pvf-prepare-worker + bump: patch diff --git a/prdoc/pr_5173.prdoc b/prdoc/pr_5173.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..81ddcd9578ba164a0615e846c3ae4ca2f66ab1e6 --- /dev/null +++ b/prdoc/pr_5173.prdoc @@ -0,0 +1,39 @@ +title: "Umbrella crate: exclude chain-specific crates" + +doc: + - audience: Runtime Dev + description: | + The `polkadot-sdk` umbrella crate does now not contain chain-specific crates. The reasoning is + that the SDK should be mostly chain-agnostic. Please check out + [psvm](https://github.com/paritytech/psvm) to select matching version numbers for chain- + specific crates. + +crates: + - name: polkadot-sdk + bump: major + - name: rococo-runtime-constants + bump: none + - name: westend-runtime-constants + bump: none + - name: bp-asset-hub-rococo + bump: none + - name: bp-asset-hub-westend + bump: none + - name: bp-bridge-hub-cumulus + bump: none + - name: bp-bridge-hub-kusama + bump: none + - name: bp-bridge-hub-polkadot + bump: none + - name: bp-bridge-hub-rococo + bump: none + - name: bp-bridge-hub-westend + bump: none + - name: bp-kusama + bump: none + - name: bp-polkadot-bulletin + bump: none + - name: bp-rococo + bump: none + - name: bp-westend + bump: none diff --git a/prdoc/pr_5174.prdoc b/prdoc/pr_5174.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..2c7a6983377cf9dea5883029b3b5ef8f81feb778 --- /dev/null +++ b/prdoc/pr_5174.prdoc @@ -0,0 +1,10 @@ +title: "Wasm-builder: Set the `resolver` version to `2`" + +doc: + - audience: Runtime Dev + description: | + Set the `resolver` version to `2` in the generated `Cargo.toml`. + +crates: + - name: substrate-wasm-builder + bump: patch diff --git a/prdoc/pr_5188.prdoc b/prdoc/pr_5188.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..b2ab9ff6653b6abcf8b1c125d527a51d11ff88e3 --- /dev/null +++ b/prdoc/pr_5188.prdoc @@ -0,0 +1,32 @@ +# 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 benchmarks for BEEFY fork voting + +doc: + - audience: + - Runtime Dev + - Runtime User + description: | + This PR adds benchmarks for `report_fork_voting` and `report_future_voting` extrinsics to `pallet-beefy`. + `report_future_voting` can be called now. `report_fork_voting` can't be called yet. Even though we have added + the formula for computing its weight, we still use `Weight::MAX`. We will set the proper weight in a future PR. + In order to do this we need to also check that the ancestry proof is optimal. + The PR adds a `WeightInfo` associated trait to the `pallet_beefy_mmr::Config` and defines benchmarks for + `pallet_beefy_mmr`. + +crates: + - name: pallet-mmr + bump: minor + - name: sp-mmr-primitives + bump: minor + - name: sp-consensus-beefy + bump: minor + - name: rococo-runtime + bump: minor + - name: pallet-beefy + bump: major + - name: pallet-beefy-mmr + bump: major + - name: westend-runtime + bump: minor diff --git a/prdoc/pr_5195.prdoc b/prdoc/pr_5195.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..cfd435fa289d00ed4487c0b0baacbad14f777075 --- /dev/null +++ b/prdoc/pr_5195.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: Bump Aura authoring duration to 2s. + +doc: + - audience: Node Dev + description: | + This PR bumps the Aura authoring duration in the asynchronous backing + guide and the polkadot-parachain service file to 2s in order to make + better use of the provided coretime. + +crates: + - name: polkadot-parachain-bin + bump: patch diff --git a/prdoc/pr_5196.prdoc b/prdoc/pr_5196.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..3ed4fbdff3f33b1dd4bab3153e67c657408bab15 --- /dev/null +++ b/prdoc/pr_5196.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: Bring benchmark inline with reference machine used for weights + +doc: + - audience: Node Operator + description: | + - BLAKE2-256 reference values were too low(~30%) when compared with the machine used for generating + the weights, so it was brought in sync with results on the reference hardware recommended here: + https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware + - SR25519-Verify reference values were too low(~10%) when compared with the machine used for generating + the weights, so it was brought in sync with results on the reference hardware recommended here: + https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware + - Validators where the `BLAKE2-256` and `SR25519-Verify` were barely passing, might received the + warning that they are not compliant anymore, this should not be treated as critical, but they + should take the necessary steps to become compliant in the near/mid-term future. + - Note!: The reference hardware requirements have not been increased we just fixed the benchmark which + was wrongly reporting lower spec HW as being compliant. + +crates: + - name: frame-benchmarking-cli + bump: minor diff --git a/prdoc/pr_5197.prdoc b/prdoc/pr_5197.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..40e25cf70dd1186e5470d7619b509bc6e0095447 --- /dev/null +++ b/prdoc/pr_5197.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: Prevent `ConsensusReset` by tolerating runtime API errors in BEEFY + +doc: + - audience: Node Operator + description: | + After warp sync, the BEEFY worker was trying to execute runtime calls on + blocks which had their state already pruned. This led to an error and restarting + of the beefy subsystem in a loop. After this PR, the worker tolerates call errors and therefore prevents this + worker restart loop. + +crates: + - name: sc-consensus-beefy + bump: minor diff --git a/prdoc/pr_5205.prdoc b/prdoc/pr_5205.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..48abfe50ca2411966820bfa1b28339224a90a509 --- /dev/null +++ b/prdoc/pr_5205.prdoc @@ -0,0 +1,18 @@ +title: Enable ChainSpec API for polkadot-parachain + +doc: + - audience: + - Runtime Dev + - Node Dev + description: | + The substrate service-builder now includes the entire rpc v2 API. + The chainspec API was previously defined as rpc extension where for instance chains would need to enable it explicitly. + At the same time, this paves the way for implementing in the future a `chainSpec_v1_getSpec` + method that can extract the chainSpec of any chain (including parachains) for the use with lightclients. + For more info about the `chainSpec`, please see the specification: https://github.com/paritytech/json-rpc-interface-spec/blob/main/src/api/chainSpec.md. + +crates: + - name: sc-service + bump: patch + - name: polkadot-rpc + bump: patch diff --git a/prdoc/pr_5214.prdoc b/prdoc/pr_5214.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..4dc8b28c59485d95553362a74a61abb07dcaa778 --- /dev/null +++ b/prdoc/pr_5214.prdoc @@ -0,0 +1,11 @@ +title: make polkadot-parachain startup errors pretty + +doc: + - audience: Node Operator + description: | + Changed the format of how polkadot-parachain prints the startup errors to include + the full displayable context. + +crates: + - name: polkadot-parachain-bin + bump: minor diff --git a/prdoc/pr_5240.prdoc b/prdoc/pr_5240.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..3622a6ada76b47da1b8d72b149918e9661faacbb --- /dev/null +++ b/prdoc/pr_5240.prdoc @@ -0,0 +1,12 @@ +title: Warn on empty public-addr when starting a validator node + +doc: + - audience: Node Operator + description: | + This PR shows a warning when the `--public-addr` CLI parameter is missing for validators. + In the future, we'll transform this warning into a hard failure. + Validators are encouraged to provide this parameter for better availability over the network. + +crates: + - name: sc-cli + bump: patch diff --git a/prdoc/pr_5250.prdoc b/prdoc/pr_5250.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..2cac6b2383e34ac80a8bc995943738a3c05b57e6 --- /dev/null +++ b/prdoc/pr_5250.prdoc @@ -0,0 +1,12 @@ +title: Export `MetricsService` and add public constructor to `RpcHandlers` + +doc: + - audience: Node Dev + description: | + `sc-service` was missing just a couple of things in public API in order to make it possible to recreate its + `spawn_tasks`, specifically `MetricsService` struct and `RpcHandlers` didn't have public constructor, which were + both finally addressed. + +crates: + - name: sc-service + bump: patch diff --git a/prdoc/pr_5257.prdoc b/prdoc/pr_5257.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..7a4cff671af0d8c4e242ca152aaa75df09c56cb9 --- /dev/null +++ b/prdoc/pr_5257.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: Enable proof-recording in benchmarking + +doc: + - audience: Runtime Dev + description: | + We now enable proof recording in the timing benchmarks. This affects the standalone `frame-omni-bencher` as well + as the integrated benchmarking commands of the node. For parachains on recent versions of polkadot-sdk this is the + correct default setting, since PoV-reclaim requires proof recording to be enabled on block import. + This comes with a slight increase in timing weight due to the additional overhead. Relay- or solo-chains + which do not need proof recording can restore the old behaviour by passing `--disable-proof-recording` to the + benchmarking command. + + In addition, the `ProofSizeExt` extension is available during benchmarking. + +crates: + - name: frame-benchmarking-cli + bump: minor \ No newline at end of file diff --git a/prdoc/pr_5273.prdoc b/prdoc/pr_5273.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..981172c6c13fa98be6ba3e30535ac37d40eb4a55 --- /dev/null +++ b/prdoc/pr_5273.prdoc @@ -0,0 +1,10 @@ +title: Fix storage weight reclaim bug. + +doc: + - audience: Runtime Dev + description: | + A bug in storage weight reclaim signed extension is fixed. The bug was causing an underestimate of the proof size when the post dispatch info was underestimating the proof size and the pre dispatch info was overestimating the proof size at the same time. + +crates: + - name: cumulus-primitives-storage-weight-reclaim + bump: patch diff --git a/prdoc/pr_5281.prdoc b/prdoc/pr_5281.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..60feab412affd84a930ba06f4dd5fbb1fa471af9 --- /dev/null +++ b/prdoc/pr_5281.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: PoV-Reclaim - Set `BlockWeight` to node-side PoV size if mismatch is detected + +doc: + - audience: Runtime Dev + description: | + After this change, the `StorageWeightReclaim` `SignedExtension` will check the node-side PoV size after every + extrinsic. If we detect a case where the returned proof size is higher than the `BlockWeight` value of the + runtime, we set `BlockWeight` to the size returned from the node. + +crates: + - name: cumulus-primitives-storage-weight-reclaim + bump: patch + - name: frame-system + bump: minor diff --git a/prdoc/pr_5284.prdoc b/prdoc/pr_5284.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..a3244a82c86092b3f9feb82b5c3b838c41bfe470 --- /dev/null +++ b/prdoc/pr_5284.prdoc @@ -0,0 +1,7 @@ +title: Minor clean up +author: conr2d +topic: runtime + +crates: + - name: sp-runtime + bump: none diff --git a/prdoc/pr_5321.prdoc b/prdoc/pr_5321.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..97f75d28dd521ee8a01384af5df5b20047f4465f --- /dev/null +++ b/prdoc/pr_5321.prdoc @@ -0,0 +1,11 @@ +title: fix availability-distribution Jaeger spans memory leak + +doc: + - audience: Node Dev + description: | + Fixes a memory leak which caused the Jaeger span storage in availability-distribution to never be pruned and therefore increasing indefinitely. + This was caused by improper handling of finalized heads. More info in https://github.com/paritytech/polkadot-sdk/issues/5258 + +crates: + - name: polkadot-availability-distribution + bump: patch diff --git a/prdoc/pr_5356.prdoc b/prdoc/pr_5356.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..a306be335440735fdc088d4a506f275e65ff2a73 --- /dev/null +++ b/prdoc/pr_5356.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: Fix OurViewChange small race + +doc: + - audience: Node Dev + description: | + Always queue OurViewChange event before we send view changes to our peers, because otherwise we risk + the peers sending us a message that can be processed by our subsystems before OurViewChange. + Normally, this is not really a problem because the latency of the ViewChange we send to our peers + is way higher than that of our subsystem processing OurViewChange, however on testnets like versi + where CPUs are sometimes overcommitted this race gets triggered occasionally, so let's fix it by + sending the messages in the right order. + +crates: + - name: polkadot-network-bridge + bump: minor diff --git a/prdoc/pr_5359.prdoc b/prdoc/pr_5359.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..bf059129a4362473fb9de83613b1a8ddde88f575 --- /dev/null +++ b/prdoc/pr_5359.prdoc @@ -0,0 +1,21 @@ +title: Make ticket non-optional and add ensure_successful method to Consideration trait + +doc: + - audience: Runtime Dev + description: | + Make ticket non-optional and add ensure_successful method to Consideration trait. + + Reverts the optional return ticket type for the new function introduced in + [polkadot-sdk/4596](https://github.com/paritytech/polkadot-sdk/pull/4596) and adds a helper + `ensure_successful` function for the runtime benchmarks. + Since the existing FRAME pallet represents zero cost with a zero balance type rather than + `None` in an option, maintaining the ticket type as a non-optional balance is beneficial + for backward compatibility and helps avoid unnecessary migrations. + +crates: + - name: frame-support + bump: major + - name: pallet-preimage + bump: major + - name: pallet-balances + bump: patch diff --git a/prdoc/pr_5360.prdoc b/prdoc/pr_5360.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..4b07f30bfd09d4835c998e447e86b0ef4b26acae --- /dev/null +++ b/prdoc/pr_5360.prdoc @@ -0,0 +1,3 @@ +crates: + - name: sc-service + bump: none 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/generate-umbrella.py b/scripts/generate-umbrella.py index 0bdf160e63b176c6981ec18d8b72ee8782dd0e8b..3293c30bc828ea8f53522f238d14808db154ee55 100644 --- a/scripts/generate-umbrella.py +++ b/scripts/generate-umbrella.py @@ -5,10 +5,10 @@ Creates the Polkadot-SDK umbrella crate that re-exports all other crates. This re-creates the `umbrella/` folder. Ensure that it does not contain any changes you want to keep. Usage: - python3 polkadot-sdk-umbrella-crate.py --sdk --version + python3 generate-umbrella.py --sdk --version Example: - python3 polkadot-sdk-umbrella-crate.py --sdk ../polkadot-sdk --version 1.11.0 + python3 generate-umbrella.py --sdk .. --version 1.11.0 """ import argparse @@ -24,12 +24,13 @@ Crate names that should be excluded from the umbrella crate. """ def exclude(crate): name = crate.name - if crate.metadata.get("polkadot-sdk.skip-umbrella", False): + if crate.metadata.get("polkadot-sdk.exclude-from-umbrella", False): return True # No fuzzers or examples: if "example" in name or name.endswith("fuzzer"): return True + # No runtime crates: if name.endswith("-runtime"): # Note: this is a bit hacky. We should use custom crate metadata instead. 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/scripts/update-ui-tests.sh b/scripts/update-ui-tests.sh index dedee8e641f8a88ef7af36fecc3672944c2f477c..d363e51e40414c8272a4266444f381efd472ec25 100755 --- a/scripts/update-ui-tests.sh +++ b/scripts/update-ui-tests.sh @@ -38,3 +38,4 @@ $RUSTUP_RUN cargo test --manifest-path substrate/primitives/runtime-interface/Ca $RUSTUP_RUN cargo test -p sp-api-test ui $RUSTUP_RUN cargo test -p frame-election-provider-solution-type ui $RUSTUP_RUN cargo test -p frame-support-test --features=no-metadata-docs,try-runtime,experimental ui +$RUSTUP_RUN cargo test -p xcm-procedural ui diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index 6b061955184ea3ef982352011733616a9bb0520a..88ea908abc23a9f270268c6c7911837c2547256b 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -5,7 +5,7 @@ authors.workspace = true description = "Substrate node integration benchmarks." edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true publish = false 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 ab665f0792a46814343bb39f7497ae925bbe8e68..5b827c9d718fefecf3c27d23f9c9e4274c321f64 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -7,7 +7,7 @@ build = "build.rs" edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" default-run = "substrate-node" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true publish = false @@ -71,6 +71,7 @@ wait-timeout = { workspace = true } wat = { workspace = true } serde_json = { workspace = true, default-features = true } 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 = { workspace = true } 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 b63e5ff549ef9d0a5742e26fe03a6167821cc97e..a2e52837d88222b18c42996bd13d400c97d4e920 100644 --- a/substrate/bin/node/cli/tests/res/default_genesis_config.json +++ b/substrate/bin/node/cli/tests/res/default_genesis_config.json @@ -34,7 +34,9 @@ "maxNominatorCount": null }, "session": { - "keys": [] + "keys": [], + "nonAuthorityKeys": [] + }, "democracy": {}, "council": { diff --git a/substrate/bin/node/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index 68769ffb4fa44794d98bfd56657d8cb7219f8a7c..6c8a4e59f68d7e2c848463361755b51eeecac668 100644 --- a/substrate/bin/node/inspect/Cargo.toml +++ b/substrate/bin/node/inspect/Cargo.toml @@ -5,7 +5,7 @@ authors.workspace = true description = "Substrate node block inspection tool." edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true [lints] diff --git a/substrate/bin/node/primitives/Cargo.toml b/substrate/bin/node/primitives/Cargo.toml index de295fd59d45a73fee8736259ed91038dd2d40aa..87271439921a0530675a6d3e8a68801411e9f501 100644 --- a/substrate/bin/node/primitives/Cargo.toml +++ b/substrate/bin/node/primitives/Cargo.toml @@ -5,7 +5,7 @@ authors.workspace = true description = "Substrate node low-level primitives." edition.workspace = true license = "Apache-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true publish = false diff --git a/substrate/bin/node/rpc/Cargo.toml b/substrate/bin/node/rpc/Cargo.toml index fa1e96e67e98250a1c3da6b6298307f00cb85acb..d85998e3c87b05bd6821a1769320e602bee7d6ee 100644 --- a/substrate/bin/node/rpc/Cargo.toml +++ b/substrate/bin/node/rpc/Cargo.toml @@ -5,7 +5,7 @@ authors.workspace = true description = "Substrate node rpc methods." edition.workspace = true license = "Apache-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true publish = false @@ -32,7 +32,6 @@ 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 } diff --git a/substrate/bin/node/rpc/src/lib.rs b/substrate/bin/node/rpc/src/lib.rs index 52cd7f9561d2a9e8287e85e1fdc7dc80f4bf5a3f..c55e03ee9d6f376b81519186e1335478fd893878 100644 --- a/substrate/bin/node/rpc/src/lib.rs +++ b/substrate/bin/node/rpc/src/lib.rs @@ -160,7 +160,6 @@ where mixnet::MixnetApiServer, statement::StatementApiServer, }; - use sc_rpc_spec_v2::chain_spec::{ChainSpec, ChainSpecApiServer}; use sc_sync_state_rpc::{SyncState, SyncStateApiServer}; use substrate_frame_rpc_system::{System, SystemApiServer}; use substrate_state_trie_migration_rpc::{StateMigration, StateMigrationApiServer}; @@ -176,11 +175,6 @@ where finality_provider, } = grandpa; - let chain_name = chain_spec.name().to_string(); - let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"); - let properties = chain_spec.properties(); - io.merge(ChainSpec::new(chain_name, genesis_hash, properties).into_rpc())?; - io.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?; // Making synchronous calls in light client freezes the browser currently, // more context: https://github.com/paritytech/substrate/pull/3480 diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index c1c470f1dcd6dfc7bf755d25609c68d6cb18fa03..2ad655883916dbfc189b8c66f81d79db55921e48 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -6,7 +6,7 @@ description = "Substrate node kitchensink runtime." edition.workspace = true build = "build.rs" license = "Apache-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true publish = false diff --git a/substrate/bin/node/runtime/src/impls.rs b/substrate/bin/node/runtime/src/impls.rs index 6c121fad624b2c6be3b6a22813b6d56f57952526..43e7a766e0e80c78f46f8f38772b90654e3aae19 100644 --- a/substrate/bin/node/runtime/src/impls.rs +++ b/substrate/bin/node/runtime/src/impls.rs @@ -63,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 @@ -74,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 a1896325ee936f2427dd6bc26f359195fc5c81bd..ea9a66862d64fe79cced6bd1deac8deb27814f4b 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -69,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; @@ -78,6 +79,7 @@ use pallet_nis::WithMaximumOf; use pallet_session::historical as pallet_session_historical; // Can't use `FungibleAdapter` here until Treasury pallet migrates to fungibles // +use pallet_broker::TaskId; #[allow(deprecated)] pub use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustment}; use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo}; @@ -96,8 +98,8 @@ use sp_runtime::{ curve::PiecewiseLinear, generic, impl_opaque_keys, traits::{ - self, AccountIdConversion, BlakeTwo256, Block as BlockT, Bounded, ConvertInto, NumberFor, - OpaqueKeys, SaturatedConversion, StaticLookup, + self, AccountIdConversion, BlakeTwo256, Block as BlockT, Bounded, ConvertInto, + MaybeConvert, NumberFor, OpaqueKeys, SaturatedConversion, StaticLookup, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, FixedPointNumber, FixedU128, Perbill, Percent, Permill, Perquintill, @@ -123,7 +125,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; @@ -189,7 +191,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); @@ -574,22 +576,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, >; } @@ -859,7 +853,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; @@ -1605,6 +1599,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! { @@ -1616,6 +1612,7 @@ impl pallet_beefy_mmr::Config for Runtime { type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum; type LeafExtra = Vec; type BeefyDataProvider = (); + type WeightInfo = (); } parameter_types! { @@ -1703,12 +1700,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< @@ -2117,6 +2117,15 @@ impl CoretimeInterface for CoretimeProvider { } } +pub struct SovereignAccountOf; +// Dummy implementation which converts `TaskId` to `AccountId`. +impl MaybeConvert for SovereignAccountOf { + fn maybe_convert(task: TaskId) -> Option { + let mut account: [u8; 32] = [0; 32]; + account[..4].copy_from_slice(&task.to_le_bytes()); + Some(account.into()) + } +} impl pallet_broker::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; @@ -2129,6 +2138,8 @@ impl pallet_broker::Config for Runtime { type WeightInfo = (); type PalletId = BrokerPalletId; type AdminOrigin = EnsureRoot; + type SovereignAccountOf = SovereignAccountOf; + type MaxAutoRenewals = ConstU32<10>; type PriceAdapter = pallet_broker::CenterTargetPrice; } @@ -2257,9 +2268,6 @@ mod runtime { #[runtime::pallet_index(7)] pub type TransactionPayment = pallet_transaction_payment::Pallet; - #[runtime::pallet_index(8)] - pub type AssetTxPayment = pallet_asset_tx_payment::Pallet; - #[runtime::pallet_index(9)] pub type AssetConversionTxPayment = pallet_asset_conversion_tx_payment::Pallet; @@ -2578,6 +2586,7 @@ mod benches { [pallet_babe, Babe] [pallet_bags_list, VoterList] [pallet_balances, Balances] + [pallet_beefy_mmr, MmrLeaf] [pallet_bounties, Bounties] [pallet_broker, Broker] [pallet_child_bounties, ChildBounties] @@ -2775,6 +2784,14 @@ impl_runtime_apis! { fn member_needs_delegate_migration(member: AccountId) -> bool { NominationPools::api_member_needs_delegate_migration(member) } + + fn member_total_balance(member: AccountId) -> Balance { + NominationPools::api_member_total_balance(member) + } + + fn pool_balance(pool_id: pallet_nomination_pools::PoolId) -> Balance { + NominationPools::api_pool_balance(pool_id) + } } impl pallet_staking_runtime_api::StakingApi for Runtime { @@ -3036,7 +3053,7 @@ impl_runtime_apis! { } } - #[api_version(4)] + #[api_version(5)] impl sp_consensus_beefy::BeefyApi for Runtime { fn beefy_genesis() -> Option { pallet_beefy::GenesisBlock::::get() @@ -3062,6 +3079,31 @@ impl_runtime_apis! { ) } + 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, @@ -3070,6 +3112,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 90c9ee0555cf496dcc371b4f697e64855b6d79f0..a5cec856717f676898b883954dafedecf900759f 100644 --- a/substrate/bin/node/testing/Cargo.toml +++ b/substrate/bin/node/testing/Cargo.toml @@ -5,7 +5,7 @@ authors.workspace = true description = "Test utilities for Substrate node." edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true publish = false diff --git a/substrate/bin/node/testing/src/genesis.rs b/substrate/bin/node/testing/src/genesis.rs index c79612d68444c8bd64ad18c3b0a74ceed176eff8..7f5364744c667f711a5e2c32e20636e904ee02c2 100644 --- a/substrate/bin/node/testing/src/genesis.rs +++ b/substrate/bin/node/testing/src/genesis.rs @@ -54,6 +54,7 @@ pub fn config_endowed(extra_endowed: Vec) -> RuntimeGenesisConfig { (bob(), eve(), session_keys_from_seed(Ed25519Keyring::Bob.into())), (charlie(), ferdie(), session_keys_from_seed(Ed25519Keyring::Charlie.into())), ], + ..Default::default() }, staking: StakingConfig { stakers: vec![ diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index 083f2191f3c5a9a9b3b41639ed20808173d3a3a4..070cf13091756449239894ba6c811a9c21456330 100644 --- a/substrate/bin/utils/chain-spec-builder/Cargo.toml +++ b/substrate/bin/utils/chain-spec-builder/Cargo.toml @@ -5,7 +5,7 @@ authors.workspace = true edition.workspace = true build = "build.rs" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true publish = true description = "Utility for building chain-specification files for Substrate-based runtimes based on `sp-genesis-builder`" diff --git a/substrate/bin/utils/subkey/Cargo.toml b/substrate/bin/utils/subkey/Cargo.toml index 5aa013097c150add192d25c2b658c61720e39bd8..72677a2bd43df4116d18c106e20abfbe35e4e5fb 100644 --- a/substrate/bin/utils/subkey/Cargo.toml +++ b/substrate/bin/utils/subkey/Cargo.toml @@ -5,7 +5,7 @@ authors.workspace = true description = "Generate and restore keys for Substrate based chains such as Polkadot, Kusama and a growing number of parachains and Substrate based projects." edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true readme = "README.md" diff --git a/substrate/client/allocator/Cargo.toml b/substrate/client/allocator/Cargo.toml index 5a3b05aa8a98d8366433d574e158a8cd9a2f3a64..a8b3bdc864c9ae2ce1e10a3e24bd4d5255058522 100644 --- a/substrate/client/allocator/Cargo.toml +++ b/substrate/client/allocator/Cargo.toml @@ -4,7 +4,7 @@ version = "23.0.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true description = "Collection of allocator implementations." documentation = "https://docs.rs/sc-allocator" diff --git a/substrate/client/api/Cargo.toml b/substrate/client/api/Cargo.toml index a64ee3ab4ce1944672ec87aac34119720834ef59..670c746844672cc531174c18ad2ede216df0ba44 100644 --- a/substrate/client/api/Cargo.toml +++ b/substrate/client/api/Cargo.toml @@ -4,7 +4,7 @@ version = "28.0.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true description = "Substrate client interfaces." documentation = "https://docs.rs/sc-client-api" diff --git a/substrate/client/authority-discovery/Cargo.toml b/substrate/client/authority-discovery/Cargo.toml index 309c9c542a0b10fa8c7fbff14a07c5622634e8f2..09381ec6b553d3f574d488068e991fdbca7e6348 100644 --- a/substrate/client/authority-discovery/Cargo.toml +++ b/substrate/client/authority-discovery/Cargo.toml @@ -5,7 +5,7 @@ authors.workspace = true edition.workspace = true build = "build.rs" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true description = "Substrate authority discovery." readme = "README.md" 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/worker.rs b/substrate/client/authority-discovery/src/worker.rs index 1f1cce160786c9ea423fbe764ecaac69232235ca..6f4fbac77e05982042ad7bad7ed337f8f1170cac 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,16 +34,17 @@ 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, trace}; 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, + config::DEFAULT_KADEMLIA_REPLICATION_FACTOR, event::DhtEvent, multiaddr, KademliaKey, + Multiaddr, NetworkDHTProvider, NetworkSigner, NetworkStateInfo, }; use sc_network_types::{multihash::Code, PeerId}; use schema::PeerSignature; @@ -62,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; @@ -159,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, @@ -168,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] @@ -283,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(), } } @@ -392,10 +416,12 @@ where }) .collect::>(); - debug!( - target: LOG_TARGET, - "Publishing authority DHT record peer_id='{local_peer_id}' addresses='{addresses:?}'", - ); + if !addresses.is_empty() { + debug!( + target: LOG_TARGET, + "Publishing authority DHT record peer_id='{local_peer_id}' with addresses='{addresses:?}'", + ); + } // The address must include the local peer id. addresses @@ -413,6 +439,17 @@ where Role::Discover => return Ok(()), }; + let addresses = serialize_addresses(self.addresses_to_publish()); + if addresses.is_empty() { + trace!( + target: LOG_TARGET, + "No addresses to publish. Skipping publication." + ); + + self.publish_interval.set_to_start(); + return Ok(()) + } + let keys = Worker::::get_own_public_keys_within_authority_set( key_store.clone(), @@ -435,8 +472,6 @@ where self.query_interval.set_to_start(); } - let addresses = serialize_addresses(self.addresses_to_publish()); - if let Some(metrics) = &self.metrics { metrics.publish.inc(); metrics @@ -444,7 +479,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::>(); @@ -495,12 +530,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 @@ -538,16 +578,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); } }, @@ -651,6 +687,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(()) } @@ -701,67 +762,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 @@ -772,6 +854,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) @@ -838,9 +982,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) @@ -876,7 +1032,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/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 e3ae80e14f6ffd3f554f59f3debb45a3b0c04431..cc2e0d8d04dfef0a0ea122a954c3f62dde658e6d 100644 --- a/substrate/client/basic-authorship/Cargo.toml +++ b/substrate/client/basic-authorship/Cargo.toml @@ -4,7 +4,7 @@ version = "0.34.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true description = "Basic implementation of block-authoring logic." readme = "README.md" diff --git a/substrate/client/block-builder/Cargo.toml b/substrate/client/block-builder/Cargo.toml index 47e3fc39c289997bdcdfa094ce65193295ab0220..08392e18227f93a2fec12ee7796433c68d4122c8 100644 --- a/substrate/client/block-builder/Cargo.toml +++ b/substrate/client/block-builder/Cargo.toml @@ -4,7 +4,7 @@ version = "0.33.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true description = "Substrate block builder" readme = "README.md" diff --git a/substrate/client/chain-spec/Cargo.toml b/substrate/client/chain-spec/Cargo.toml index b3cd4bd57db86c0384c56316315550edda962f24..2e885240936fe94fcdd408a56e512eec2cf46f5a 100644 --- a/substrate/client/chain-spec/Cargo.toml +++ b/substrate/client/chain-spec/Cargo.toml @@ -4,7 +4,7 @@ version = "28.0.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true description = "Substrate chain configurations." readme = "README.md" diff --git a/substrate/client/chain-spec/derive/Cargo.toml b/substrate/client/chain-spec/derive/Cargo.toml index 4ab8c849cc7feb6368c5f74fbbd77703434b7675..ccd898447beaca06db3f2d561bab7f8cb6244954 100644 --- a/substrate/client/chain-spec/derive/Cargo.toml +++ b/substrate/client/chain-spec/derive/Cargo.toml @@ -4,7 +4,7 @@ version = "11.0.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true description = "Macros to derive chain spec extension traits implementation." diff --git a/substrate/client/chain-spec/src/chain_spec.rs b/substrate/client/chain-spec/src/chain_spec.rs index 5f90f549e02262e97c3ae8ea82941838faa5e2f7..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, diff --git a/substrate/client/chain-spec/src/lib.rs b/substrate/client/chain-spec/src/lib.rs index c43f9e89b8a993f6a349b3eb612b41346acc62ec..5451428d34811bfa54cb87a767d8434b5f4b7524 100644 --- a/substrate/client/chain-spec/src/lib.rs +++ b/substrate/client/chain-spec/src/lib.rs @@ -172,6 +172,12 @@ //! //! //! +//! The main purpose of the `RuntimeGenesisConfig` patch is to: +//! - minimize the maintenance effort when RuntimeGenesisConfig is changed in the future (e.g. new +//! pallets added to the runtime or pallet's genesis config changed), +//! - increase the readability - it only contains the relevant fields, +//! - allow to apply numerous changes in distinct domains (e.g. for zombienet). +//! //! For production or long-lasting blockchains, using the `raw` format in the chain specification is //! recommended. Only the `raw` format guarantees that storage root hash will remain unchanged when //! the `RuntimeGenesisConfig` format changes due to software upgrade. diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 1e4017c23af231baf0946ed26cc37e7767276cbb..b7d29aebc3d77d59eedd9e460ecf1b850c86b700 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -5,7 +5,7 @@ authors.workspace = true description = "Substrate CLI interface." edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true readme = "README.md" diff --git a/substrate/client/cli/src/config.rs b/substrate/client/cli/src/config.rs index 783c9313121fef1a199705e8a6508688e51b67ca..406d1fb264ddfafdbabdfe8c5413bc194f2514a4 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, }, @@ -172,7 +172,7 @@ pub trait CliConfiguration: Sized { node_key: NodeKeyConfig, default_listen_port: u16, ) -> Result { - Ok(if let Some(network_params) = self.network_params() { + let network_config = if let Some(network_params) = self.network_params() { network_params.network_config( chain_spec, is_dev, @@ -185,7 +185,13 @@ pub trait CliConfiguration: Sized { ) } else { NetworkConfiguration::new(node_name, client_id, node_key, Some(net_config_dir)) - }) + }; + + // TODO: Return error here in the next release: + // https://github.com/paritytech/polkadot-sdk/issues/5266 + // if is_validator && network_config.public_addresses.is_empty() {} + + Ok(network_config) } /// Get the keystore configuration. @@ -550,7 +556,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, }) } @@ -639,6 +644,14 @@ pub trait CliConfiguration: Sized { logger.init()?; + if config.role.is_authority() && config.network.public_addresses.is_empty() { + warn!( + "WARNING: No public address specified, validator node may not be reachable. + Consider setting `--public-addr` to the public IP address of this node. + This will become a hard requirement in future versions." + ); + } + match fdlimit::raise_fd_limit() { Ok(fdlimit::Outcome::LimitRaised { to, .. }) => if to < RECOMMENDED_OPEN_FILE_DESCRIPTOR_LIMIT { 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 3a3d7ae18d711e0c9b952e4f1383ae8ecb28fbc3..98e8ad676be3c9b64aafdc96b08434c0462de62c 100644 --- a/substrate/client/consensus/aura/Cargo.toml +++ b/substrate/client/consensus/aura/Cargo.toml @@ -5,7 +5,7 @@ authors.workspace = true description = "Aura consensus algorithm for substrate" edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true readme = "README.md" diff --git a/substrate/client/consensus/babe/Cargo.toml b/substrate/client/consensus/babe/Cargo.toml index bba60bc45ea50d5c14b2d6a742de690ea95c98d6..af55e72a9b7eed54a956f2c283c06fab0b494294 100644 --- a/substrate/client/consensus/babe/Cargo.toml +++ b/substrate/client/consensus/babe/Cargo.toml @@ -5,7 +5,7 @@ authors.workspace = true description = "BABE consensus algorithm for substrate" edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true documentation = "https://docs.rs/sc-consensus-babe" readme = "README.md" diff --git a/substrate/client/consensus/babe/rpc/Cargo.toml b/substrate/client/consensus/babe/rpc/Cargo.toml index 1ef049c3dbcc412ae94bc849b066e2ff154ae57c..ce5b1baec0b57700b5831a5d86eabd62a841c237 100644 --- a/substrate/client/consensus/babe/rpc/Cargo.toml +++ b/substrate/client/consensus/babe/rpc/Cargo.toml @@ -5,7 +5,7 @@ authors.workspace = true description = "RPC extensions for the BABE consensus algorithm" edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true readme = "README.md" diff --git a/substrate/client/consensus/beefy/Cargo.toml b/substrate/client/consensus/beefy/Cargo.toml index b2031e0d1e077ef1d793faf570698499487aa4b2..900a44b95e0442159c3efb42965cc256d5998e9c 100644 --- a/substrate/client/consensus/beefy/Cargo.toml +++ b/substrate/client/consensus/beefy/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" repository.workspace = true description = "BEEFY Client gadget for substrate" -homepage = "https://substrate.io" +homepage.workspace = true [lints] workspace = true diff --git a/substrate/client/consensus/beefy/rpc/Cargo.toml b/substrate/client/consensus/beefy/rpc/Cargo.toml index 7869f5a336b1135bb471fc584b8f826e17fb9d02..e1956dacf396125c8b7a08a2e43da5d6b75b43b7 100644 --- a/substrate/client/consensus/beefy/rpc/Cargo.toml +++ b/substrate/client/consensus/beefy/rpc/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" repository.workspace = true description = "RPC for the BEEFY Client gadget for substrate" -homepage = "https://substrate.io" +homepage.workspace = true [lints] workspace = true diff --git a/substrate/client/consensus/beefy/rpc/src/lib.rs b/substrate/client/consensus/beefy/rpc/src/lib.rs index 66102eeb35c897a7bff4e50a12da1b90754eeeaa..83477d223dd2d1cc043f8d63ef0a6f3057b87436 100644 --- a/substrate/client/consensus/beefy/rpc/src/lib.rs +++ b/substrate/client/consensus/beefy/rpc/src/lib.rs @@ -24,7 +24,10 @@ use parking_lot::RwLock; use sp_consensus_beefy::AuthorityIdBound; use std::sync::Arc; -use sc_rpc::{utils::pipe_from_stream, SubscriptionTaskExecutor}; +use sc_rpc::{ + utils::{BoundedVecDeque, PendingSubscription}, + SubscriptionTaskExecutor, +}; use sp_application_crypto::RuntimeAppPublic; use sp_runtime::traits::Block as BlockT; @@ -145,7 +148,10 @@ where .subscribe(100_000) .map(|vfp| notification::EncodedVersionedFinalityProof::new::(vfp)); - sc_rpc::utils::spawn_subscription_task(&self.executor, pipe_from_stream(pending, stream)); + sc_rpc::utils::spawn_subscription_task( + &self.executor, + PendingSubscription::from(pending).pipe_from_stream(stream, BoundedVecDeque::default()), + ); } async fn latest_finalized(&self) -> Result { 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 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/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index a47bfe1dbe24056237a5aa87a3266270b54877ef..30cdd494905f2881bb4b6acd4aa9c081e7e95847 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -32,13 +32,14 @@ use crate::{ metrics::register_metrics, }; use futures::{stream::Fuse, FutureExt, StreamExt}; -use log::{debug, error, info, warn}; +use log::{debug, error, info, trace, warn}; use parking_lot::Mutex; use prometheus_endpoint::Registry; -use sc_client_api::{Backend, BlockBackend, BlockchainEvents, FinalityNotifications, Finalizer}; +use sc_client_api::{Backend, BlockBackend, BlockchainEvents, FinalityNotification, Finalizer}; use sc_consensus::BlockImport; use sc_network::{NetworkRequest, NotificationService, ProtocolName}; use sc_network_gossip::{GossipEngine, Network as GossipNetwork, Syncing as GossipSyncing}; +use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver}; use sp_api::ProvideRuntimeApi; use sp_blockchain::{Backend as BlockchainBackend, HeaderBackend}; use sp_consensus::{Error as ConsensusError, SyncOracle}; @@ -49,7 +50,9 @@ use sp_keystore::KeystorePtr; use sp_runtime::traits::{Block, Header as HeaderT, NumberFor, Zero}; use std::{ collections::{BTreeMap, VecDeque}, + future::Future, marker::PhantomData, + pin::Pin, sync::Arc, time::Duration, }; @@ -87,6 +90,8 @@ const LOG_TARGET: &str = "beefy"; const HEADER_SYNC_DELAY: Duration = Duration::from_secs(60); +type FinalityNotifications = + sc_utils::mpsc::TracingUnboundedReceiver>; /// A convenience BEEFY client trait that defines all the type bounds a BEEFY client /// has to satisfy. Ideally that should actually be a trait alias. Unfortunately as /// of today, Rust does not allow a type alias to be used as a trait bound. Tracking @@ -446,7 +451,8 @@ where state.set_best_grandpa(best_grandpa.clone()); // Overwrite persisted data with newly provided `min_block_delta`. state.set_min_block_delta(min_block_delta); - debug!(target: LOG_TARGET, "🥩 Loading BEEFY voter state from db: {:?}.", state); + debug!(target: LOG_TARGET, "🥩 Loading BEEFY voter state from db."); + trace!(target: LOG_TARGET, "🥩 Loaded state: {:?}.", state); // Make sure that all the headers that we need have been synced. let mut new_sessions = vec![]; @@ -484,6 +490,30 @@ where } } +/// Finality notification for consumption by BEEFY worker. +/// This is a stripped down version of `sc_client_api::FinalityNotification` which does not keep +/// blocks pinned. +struct UnpinnedFinalityNotification { + /// Finalized block header hash. + pub hash: B::Hash, + /// Finalized block header. + pub header: B::Header, + /// Path from the old finalized to new finalized parent (implicitly finalized blocks). + /// + /// This maps to the range `(old_finalized, new_finalized)`. + pub tree_route: Arc<[B::Hash]>, +} + +impl From> for UnpinnedFinalityNotification { + fn from(value: FinalityNotification) -> Self { + UnpinnedFinalityNotification { + hash: value.hash, + header: value.header, + tree_route: value.tree_route, + } + } +} + /// Start the BEEFY gadget. /// /// This is a thin shim around running and awaiting a BEEFY worker. @@ -525,10 +555,13 @@ pub async fn start_beefy_gadget( let metrics = register_metrics(prometheus_registry.clone()); + let mut block_import_justif = links.from_block_import_justif_stream.subscribe(100_000).fuse(); + // Subscribe to finality notifications and justifications before waiting for runtime pallet and // reuse the streams, so we don't miss notifications while waiting for pallet to be available. - let mut finality_notifications = client.finality_notification_stream().fuse(); - let mut block_import_justif = links.from_block_import_justif_stream.subscribe(100_000).fuse(); + let finality_notifications = client.finality_notification_stream(); + let (mut transformer, mut finality_notifications) = + finality_notification_transformer_future(finality_notifications); let known_peers = Arc::new(Mutex::new(KnownPeers::new())); // Default votes filter is to discard everything. @@ -582,7 +615,11 @@ pub async fn start_beefy_gadget( _ = &mut beefy_comms.gossip_engine => { error!(target: LOG_TARGET, "🥩 Gossip engine has unexpectedly terminated."); return - } + }, + _ = &mut transformer => { + error!(target: LOG_TARGET, "🥩 Finality notification transformer task has unexpectedly terminated."); + return + }, }; let worker = worker_builder.build( @@ -594,30 +631,54 @@ pub async fn start_beefy_gadget( is_authority, ); - match futures::future::select( - Box::pin(worker.run(&mut block_import_justif, &mut finality_notifications)), - Box::pin(on_demand_justifications_handler.run()), - ) - .await - { - // On `ConsensusReset` error, just reinit and restart voter. - futures::future::Either::Left(((error::Error::ConsensusReset, reuse_comms), _)) => { - error!(target: LOG_TARGET, "🥩 Error: {:?}. Restarting voter.", error::Error::ConsensusReset); - beefy_comms = reuse_comms; - continue; - }, - // On other errors, bring down / finish the task. - futures::future::Either::Left(((worker_err, _), _)) => { - error!(target: LOG_TARGET, "🥩 Error: {:?}. Terminating.", worker_err) + futures::select! { + result = worker.run(&mut block_import_justif, &mut finality_notifications).fuse() => { + match result { + (error::Error::ConsensusReset, reuse_comms) => { + error!(target: LOG_TARGET, "🥩 Error: {:?}. Restarting voter.", error::Error::ConsensusReset); + beefy_comms = reuse_comms; + continue; + }, + (err, _) => { + error!(target: LOG_TARGET, "🥩 Error: {:?}. Terminating.", err) + } + } }, - futures::future::Either::Right((odj_handler_err, _)) => { - error!(target: LOG_TARGET, "🥩 Error: {:?}. Terminating.", odj_handler_err) + odj_handler_error = on_demand_justifications_handler.run().fuse() => { + error!(target: LOG_TARGET, "🥩 Error: {:?}. Terminating.", odj_handler_error) }, - }; + _ = &mut transformer => { + error!(target: LOG_TARGET, "🥩 Finality notification transformer task has unexpectedly terminated."); + } + } return; } } +/// Produce a future that transformes finality notifications into a struct that does not keep blocks +/// pinned. +fn finality_notification_transformer_future( + mut finality_notifications: sc_client_api::FinalityNotifications, +) -> ( + Pin + Sized>>>, + Fuse>>, +) +where + B: Block, +{ + let (tx, rx) = tracing_unbounded("beefy-notification-transformer-channel", 10000); + let transformer_fut = async move { + while let Some(notification) = finality_notifications.next().await { + debug!(target: LOG_TARGET, "🥩 Transforming grandpa notification. #{}({:?})", notification.header.number(), notification.hash); + if let Err(err) = tx.unbounded_send(UnpinnedFinalityNotification::from(notification)) { + error!(target: LOG_TARGET, "🥩 Unable to send transformed notification. Shutting down. err = {}", err); + return + }; + } + }; + (Box::pin(transformer_fut.fuse()), rx.fuse()) +} + /// Waits until the parent header of `current` is available and returns it. /// /// When the node uses GRANDPA warp sync it initially downloads only the mandatory GRANDPA headers. diff --git a/substrate/client/consensus/beefy/src/tests.rs b/substrate/client/consensus/beefy/src/tests.rs index d8f5b39dbbaaacc3094bcef31dfd8af618917990..4b1dd447320bffdc5736a0a8983c47c68295904a 100644 --- a/substrate/client/consensus/beefy/src/tests.rs +++ b/substrate/client/consensus/beefy/src/tests.rs @@ -30,13 +30,17 @@ use crate::{ request_response::{on_demand_justifications_protocol_config, BeefyJustifsRequestHandler}, }, error::Error, - gossip_protocol_name, + finality_notification_transformer_future, gossip_protocol_name, justification::*, wait_for_runtime_pallet, worker::PersistedState, - BeefyRPCLinks, BeefyVoterLinks, BeefyWorkerBuilder, KnownPeers, + BeefyRPCLinks, BeefyVoterLinks, BeefyWorkerBuilder, KnownPeers, UnpinnedFinalityNotification, +}; +use futures::{ + future, + stream::{Fuse, FuturesUnordered}, + Future, FutureExt, StreamExt, }; -use futures::{future, stream::FuturesUnordered, Future, FutureExt, StreamExt}; use parking_lot::Mutex; use sc_block_builder::BlockBuilderBuilder; use sc_client_api::{Backend as BackendT, BlockchainEvents, FinalityNotifications, HeaderBackend}; @@ -49,7 +53,7 @@ use sc_network_test::{ Block, BlockImportAdapter, FullPeerConfig, PassThroughVerifier, Peer, PeersClient, PeersFullClient, TestNetFactory, }; -use sc_utils::notification::NotificationReceiver; +use sc_utils::{mpsc::TracingUnboundedReceiver, notification::NotificationReceiver}; use serde::{Deserialize, Serialize}; use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_application_crypto::key_types::BEEFY as BEEFY_KEY_TYPE; @@ -371,7 +375,7 @@ pub(crate) fn create_beefy_keystore(authority: &BeefyKeyring) -> Ke async fn voter_init_setup( net: &mut BeefyTestNet, - finality: &mut futures::stream::Fuse>, + finality: &mut futures::stream::Fuse>, api: &TestApi, ) -> Result, Error> { let backend = net.peer(0).client().as_backend(); @@ -391,6 +395,15 @@ async fn voter_init_setup( .await } +fn start_finality_worker( + finality: FinalityNotifications, +) -> Fuse>> { + let (transformer, finality_notifications) = finality_notification_transformer_future(finality); + let tokio_handle = tokio::runtime::Handle::current(); + tokio_handle.spawn(transformer); + finality_notifications +} + // Spawns beefy voters. Returns a future to spawn on the runtime. fn initialize_beefy( net: &mut BeefyTestNet, @@ -1020,13 +1033,17 @@ async fn should_initialize_voter_at_genesis() { // push 15 blocks with `AuthorityChange` digests every 10 blocks let hashes = net.generate_blocks_and_sync(15, 10, &validator_set, false).await; - let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); + let finality = net.peer(0).client().as_client().finality_notification_stream(); + + let mut finality_notifications = start_finality_worker(finality); + // finalize 13 without justifications net.peer(0).client().as_client().finalize_block(hashes[13], None).unwrap(); let api = TestApi::with_validator_set(&validator_set); // load persistent state - nothing in DB, should init at genesis - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); + let persisted_state = + voter_init_setup(&mut net, &mut finality_notifications, &api).await.unwrap(); // Test initialization at session boundary. // verify voter initialized with two sessions starting at blocks 1 and 10 @@ -1061,14 +1078,18 @@ async fn should_initialize_voter_at_custom_genesis() { // push 15 blocks with `AuthorityChange` digests every 15 blocks let hashes = net.generate_blocks_and_sync(15, 15, &validator_set, false).await; - let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); + let finality = net.peer(0).client().as_client().finality_notification_stream(); + + let mut finality_notifications = start_finality_worker(finality); + // finalize 3, 5, 8 without justifications net.peer(0).client().as_client().finalize_block(hashes[3], None).unwrap(); net.peer(0).client().as_client().finalize_block(hashes[5], None).unwrap(); net.peer(0).client().as_client().finalize_block(hashes[8], None).unwrap(); // load persistent state - nothing in DB, should init at genesis - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); + let persisted_state = + voter_init_setup(&mut net, &mut finality_notifications, &api).await.unwrap(); // Test initialization at session boundary. // verify voter initialized with single session starting at block `custom_pallet_genesis` (7) @@ -1098,7 +1119,8 @@ async fn should_initialize_voter_at_custom_genesis() { net.peer(0).client().as_client().finalize_block(hashes[10], None).unwrap(); // load persistent state - state preset in DB, but with different pallet genesis - let new_persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); + let new_persisted_state = + voter_init_setup(&mut net, &mut finality_notifications, &api).await.unwrap(); // verify voter initialized with single session starting at block `new_pallet_genesis` (10) let sessions = new_persisted_state.voting_oracle().sessions(); @@ -1129,7 +1151,9 @@ async fn should_initialize_voter_when_last_final_is_session_boundary() { // push 15 blocks with `AuthorityChange` digests every 10 blocks let hashes = net.generate_blocks_and_sync(15, 10, &validator_set, false).await; - let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); + let finality = net.peer(0).client().as_client().finality_notification_stream(); + + let mut finality_notifications = start_finality_worker(finality); // finalize 13 without justifications net.peer(0).client().as_client().finalize_block(hashes[13], None).unwrap(); @@ -1153,7 +1177,8 @@ async fn should_initialize_voter_when_last_final_is_session_boundary() { let api = TestApi::with_validator_set(&validator_set); // load persistent state - nothing in DB, should init at session boundary - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); + let persisted_state = + voter_init_setup(&mut net, &mut finality_notifications, &api).await.unwrap(); // verify voter initialized with single session starting at block 10 assert_eq!(persisted_state.voting_oracle().sessions().len(), 1); @@ -1183,7 +1208,9 @@ async fn should_initialize_voter_at_latest_finalized() { // push 15 blocks with `AuthorityChange` digests every 10 blocks let hashes = net.generate_blocks_and_sync(15, 10, &validator_set, false).await; - let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); + let finality = net.peer(0).client().as_client().finality_notification_stream(); + + let mut finality_notifications = start_finality_worker(finality); // finalize 13 without justifications net.peer(0).client().as_client().finalize_block(hashes[13], None).unwrap(); @@ -1206,7 +1233,8 @@ async fn should_initialize_voter_at_latest_finalized() { let api = TestApi::with_validator_set(&validator_set); // load persistent state - nothing in DB, should init at last BEEFY finalized - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); + let persisted_state = + voter_init_setup(&mut net, &mut finality_notifications, &api).await.unwrap(); // verify voter initialized with single session starting at block 12 assert_eq!(persisted_state.voting_oracle().sessions().len(), 1); @@ -1239,12 +1267,15 @@ async fn should_initialize_voter_at_custom_genesis_when_state_unavailable() { // push 30 blocks with `AuthorityChange` digests every 5 blocks let hashes = net.generate_blocks_and_sync(30, 5, &validator_set, false).await; - let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); + let finality = net.peer(0).client().as_client().finality_notification_stream(); + + let mut finality_notifications = start_finality_worker(finality); // finalize 30 without justifications net.peer(0).client().as_client().finalize_block(hashes[30], None).unwrap(); // load persistent state - nothing in DB, should init at genesis - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); + let persisted_state = + voter_init_setup(&mut net, &mut finality_notifications, &api).await.unwrap(); // Test initialization at session boundary. // verify voter initialized with all sessions pending, first one starting at block 5 (start of @@ -1282,14 +1313,18 @@ async fn should_catch_up_when_loading_saved_voter_state() { // push 30 blocks with `AuthorityChange` digests every 10 blocks let hashes = net.generate_blocks_and_sync(30, 10, &validator_set, false).await; - let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); + let finality = net.peer(0).client().as_client().finality_notification_stream(); + + let mut finality_notifications = start_finality_worker(finality); + // finalize 13 without justifications net.peer(0).client().as_client().finalize_block(hashes[13], None).unwrap(); let api = TestApi::with_validator_set(&validator_set); // load persistent state - nothing in DB, should init at genesis - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); + let persisted_state = + voter_init_setup(&mut net, &mut finality_notifications, &api).await.unwrap(); // Test initialization at session boundary. // verify voter initialized with two sessions starting at blocks 1 and 10 @@ -1316,7 +1351,8 @@ async fn should_catch_up_when_loading_saved_voter_state() { // finalize 25 without justifications net.peer(0).client().as_client().finalize_block(hashes[25], None).unwrap(); // load persistent state - state preset in DB - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); + let persisted_state = + voter_init_setup(&mut net, &mut finality_notifications, &api).await.unwrap(); // Verify voter initialized with old sessions plus a new one starting at block 20. // There shouldn't be any duplicates. diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 4a9f7a2d0e3b0afd6d8ed8b6f3237fcd1c209a49..3c7f3b1b6efab377ed13ea91f33b80f8d541c109 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -29,14 +29,14 @@ use crate::{ metric_inc, metric_set, metrics::VoterMetrics, round::{Rounds, VoteImportResult}, - BeefyComms, BeefyVoterLinks, LOG_TARGET, + BeefyComms, BeefyVoterLinks, UnpinnedFinalityNotification, LOG_TARGET, }; use sp_application_crypto::RuntimeAppPublic; use codec::{Codec, Decode, DecodeAll, Encode}; use futures::{stream::Fuse, FutureExt, StreamExt}; use log::{debug, error, info, trace, warn}; -use sc_client_api::{Backend, FinalityNotification, FinalityNotifications, HeaderBackend}; +use sc_client_api::{Backend, HeaderBackend}; use sc_utils::notification::NotificationReceiver; use sp_api::ProvideRuntimeApi; use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; @@ -447,24 +447,29 @@ where fn handle_finality_notification( &mut self, - notification: &FinalityNotification, + notification: &UnpinnedFinalityNotification, ) -> Result<(), Error> { let header = ¬ification.header; debug!( target: LOG_TARGET, "🥩 Finality notification: header(number {:?}, hash {:?}) tree_route {:?}", header.number(), - header.hash(), + notification.hash, notification.tree_route, ); - self.runtime - .runtime_api() - .beefy_genesis(header.hash()) - .ok() - .flatten() - .filter(|genesis| *genesis == self.persisted_state.pallet_genesis) - .ok_or(Error::ConsensusReset)?; + match self.runtime.runtime_api().beefy_genesis(notification.hash) { + Ok(Some(genesis)) if genesis != self.persisted_state.pallet_genesis => { + debug!(target: LOG_TARGET, "🥩 ConsensusReset detected. Expected genesis: {}, found genesis: {}", self.persisted_state.pallet_genesis, genesis); + return Err(Error::ConsensusReset) + }, + Ok(_) => {}, + Err(api_error) => { + // This can happen in case the block was already pruned. + // Mostly after warp sync when finality notifications are piled up. + debug!(target: LOG_TARGET, "🥩 Unable to check beefy genesis: {}", api_error); + }, + } let mut new_session_added = false; if *header.number() > self.best_grandpa_block() { @@ -845,7 +850,7 @@ where block_import_justif: &mut Fuse< NotificationReceiver>, >, - finality_notifications: &mut Fuse>, + finality_notifications: &mut Fuse>, ) -> (Error, BeefyComms) { info!( target: LOG_TARGET, diff --git a/substrate/client/consensus/common/Cargo.toml b/substrate/client/consensus/common/Cargo.toml index a6f59e600f269c67ab87f295c268f3d185dafcf4..77cd50ad784bb5e055480466036e573b9ec7cbc8 100644 --- a/substrate/client/consensus/common/Cargo.toml +++ b/substrate/client/consensus/common/Cargo.toml @@ -4,7 +4,7 @@ version = "0.33.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true description = "Collection of common consensus specific implementations for Substrate (client)" readme = "README.md" diff --git a/substrate/client/consensus/common/src/import_queue.rs b/substrate/client/consensus/common/src/import_queue.rs index 35fc8ad4a402e72d9f6c8d110a468bea5f3c5195..1baa67398a49c3461a2d4f85d9c23de3191e9c22 100644 --- a/substrate/client/consensus/common/src/import_queue.rs +++ b/substrate/client/consensus/common/src/import_queue.rs @@ -225,7 +225,7 @@ pub async fn import_single_block>( import_handle: &mut impl BlockImport, block_origin: BlockOrigin, block: IncomingBlock, - verifier: &mut V, + verifier: &V, ) -> BlockImportResult { match verify_single_block_metered(import_handle, block_origin, block, verifier, None).await? { SingleBlockVerificationOutcome::Imported(import_status) => Ok(import_status), @@ -295,7 +295,7 @@ pub(crate) async fn verify_single_block_metered>( import_handle: &impl BlockImport, block_origin: BlockOrigin, block: IncomingBlock, - verifier: &mut V, + verifier: &V, metrics: Option<&Metrics>, ) -> Result, BlockImportError> { let peer = block.origin; 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 05f2b252796146f62ba7c258b208fa4c2eb4a3d1..6a307acb2517dcff8a15abf37437be53bcab4280 100644 --- a/substrate/client/consensus/common/src/import_queue/basic_queue.rs +++ b/substrate/client/consensus/common/src/import_queue/basic_queue.rs @@ -222,7 +222,7 @@ mod worker_messages { /// Returns when `block_import` ended. async fn block_import_process( mut block_import: BoxBlockImport, - mut verifier: impl Verifier, + verifier: impl Verifier, mut result_sender: BufferedLinkSender, mut block_import_receiver: TracingUnboundedReceiver>, metrics: Option, @@ -241,8 +241,7 @@ async fn block_import_process( }; let res = - import_many_blocks(&mut block_import, origin, blocks, &mut verifier, metrics.clone()) - .await; + import_many_blocks(&mut block_import, origin, blocks, &verifier, metrics.clone()).await; result_sender.blocks_processed(res.imported, res.block_count, res.results); } @@ -388,7 +387,7 @@ async fn import_many_blocks>( import_handle: &mut BoxBlockImport, blocks_origin: BlockOrigin, blocks: Vec>, - verifier: &mut V, + verifier: &V, metrics: Option, ) -> ImportManyBlocksResult { let count = blocks.len(); diff --git a/substrate/client/consensus/epochs/Cargo.toml b/substrate/client/consensus/epochs/Cargo.toml index 127cc9ebec207b27f9bf2f54c9e07184b290ebae..c51671d6d75d83ddfe4d7644428ab9b4122a7d1d 100644 --- a/substrate/client/consensus/epochs/Cargo.toml +++ b/substrate/client/consensus/epochs/Cargo.toml @@ -5,7 +5,7 @@ authors.workspace = true description = "Generic epochs-based utilities for consensus" edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true readme = "README.md" diff --git a/substrate/client/consensus/grandpa/Cargo.toml b/substrate/client/consensus/grandpa/Cargo.toml index e49c7c9f0d7a93e727453592d7f300d54bc96acf..65ba39d34c214014c0a2f29e67fbe211e4763b25 100644 --- a/substrate/client/consensus/grandpa/Cargo.toml +++ b/substrate/client/consensus/grandpa/Cargo.toml @@ -4,7 +4,7 @@ version = "0.19.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true description = "Integration of the GRANDPA finality gadget into substrate." documentation = "https://docs.rs/sc-consensus-grandpa" diff --git a/substrate/client/consensus/grandpa/rpc/Cargo.toml b/substrate/client/consensus/grandpa/rpc/Cargo.toml index 0215fe2e3e64244ac5143dff0b18237fedc23bba..86513ac5df153f600f898bffa88513bd19d263e4 100644 --- a/substrate/client/consensus/grandpa/rpc/Cargo.toml +++ b/substrate/client/consensus/grandpa/rpc/Cargo.toml @@ -7,7 +7,7 @@ repository.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" readme = "README.md" -homepage = "https://substrate.io" +homepage.workspace = true [lints] workspace = true diff --git a/substrate/client/consensus/grandpa/rpc/src/lib.rs b/substrate/client/consensus/grandpa/rpc/src/lib.rs index 430525019dfb9ad9fec903d5e93f5ab3e5cb1a88..a41b142990899afaa71a16c78c8c696d7b96d46b 100644 --- a/substrate/client/consensus/grandpa/rpc/src/lib.rs +++ b/substrate/client/consensus/grandpa/rpc/src/lib.rs @@ -38,7 +38,10 @@ use finality::{EncodedFinalityProof, RpcFinalityProofProvider}; use notification::JustificationNotification; use report::{ReportAuthoritySet, ReportVoterState, ReportedRoundStates}; use sc_consensus_grandpa::GrandpaJustificationStream; -use sc_rpc::{utils::pipe_from_stream, SubscriptionTaskExecutor}; +use sc_rpc::{ + utils::{BoundedVecDeque, PendingSubscription}, + SubscriptionTaskExecutor, +}; use sp_runtime::traits::{Block as BlockT, NumberFor}; /// Provides RPC methods for interacting with GRANDPA. @@ -108,7 +111,10 @@ where }, ); - sc_rpc::utils::spawn_subscription_task(&self.executor, pipe_from_stream(pending, stream)); + sc_rpc::utils::spawn_subscription_task( + &self.executor, + PendingSubscription::from(pending).pipe_from_stream(stream, BoundedVecDeque::default()), + ); } async fn prove_finality( diff --git a/substrate/client/consensus/grandpa/src/environment.rs b/substrate/client/consensus/grandpa/src/environment.rs index 6199e8a97d990388b518d5d5404bfca789142310..a618b7ff07ad8f5411b54d63b98faf44a0d169ad 100644 --- a/substrate/client/consensus/grandpa/src/environment.rs +++ b/substrate/client/consensus/grandpa/src/environment.rs @@ -1214,14 +1214,20 @@ where .header(target_hash)? .expect("Header known to exist after `finality_target` call; qed"), Err(err) => { - warn!( + debug!( target: LOG_TARGET, "Encountered error finding best chain containing {:?}: couldn't find target block: {}", block, err, ); - return Ok(None) + // NOTE: in case the given `SelectChain` doesn't provide any block we fallback to using + // the given base block provided by the GRANDPA voter. + // + // For example, `LongestChain` will error if the given block to use as base isn't part + // of the best chain (as defined by `LongestChain`), which could happen if there was a + // re-org. + base_header.clone() }, }; diff --git a/substrate/client/consensus/grandpa/src/tests.rs b/substrate/client/consensus/grandpa/src/tests.rs index 14708cc89e890bd3fe7963589010896f78bb6ab1..2aa1b5f6ee1b268e5c80ff557e203964f496debf 100644 --- a/substrate/client/consensus/grandpa/src/tests.rs +++ b/substrate/client/consensus/grandpa/src/tests.rs @@ -1820,6 +1820,116 @@ async fn grandpa_environment_checks_if_best_block_is_descendent_of_finality_targ ); } +// This is a regression test for an issue that was triggered by a reorg +// - https://github.com/paritytech/polkadot-sdk/issues/3487 +// - https://github.com/humanode-network/humanode/issues/1104 +#[tokio::test] +async fn grandpa_environment_uses_round_base_block_for_voting_if_finality_target_errors() { + use finality_grandpa::voter::Environment; + use sp_consensus::SelectChain; + + let peers = &[Ed25519Keyring::Alice]; + let voters = make_ids(peers); + + let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0); + let peer = net.peer(0); + let network_service = peer.network_service().clone(); + let sync_service = peer.sync_service().clone(); + let notification_service = + peer.take_notification_service(&grandpa_protocol_name::NAME.into()).unwrap(); + let link = peer.data.lock().take().unwrap(); + let client = peer.client().as_client().clone(); + let select_chain = sc_consensus::LongestChain::new(peer.client().as_backend()); + + // create a chain that is 10 blocks long + peer.push_blocks(10, false); + + let env = test_environment_with_select_chain( + &link, + None, + network_service.clone(), + sync_service, + notification_service, + select_chain.clone(), + VotingRulesBuilder::default().build(), + ); + + let hashof7 = client.expect_block_hash_from_id(&BlockId::Number(7)).unwrap(); + let hashof8_a = client.expect_block_hash_from_id(&BlockId::Number(8)).unwrap(); + + // finalize the 7th block + peer.client().finalize_block(hashof7, None, false).unwrap(); + + assert_eq!(peer.client().info().finalized_hash, hashof7); + + // simulate completed grandpa round + env.completed( + 1, + finality_grandpa::round::State { + prevote_ghost: Some((hashof8_a, 8)), + finalized: Some((hashof7, 7)), + estimate: Some((hashof8_a, 8)), + completable: true, + }, + Default::default(), + &finality_grandpa::HistoricalVotes::new(), + ) + .unwrap(); + + // check simulated last completed round + assert_eq!( + env.voter_set_state.read().last_completed_round().state, + finality_grandpa::round::State { + prevote_ghost: Some((hashof8_a, 8)), + finalized: Some((hashof7, 7)), + estimate: Some((hashof8_a, 8)), + completable: true + } + ); + + // `hashof8_a` should be finalized next, `best_chain_containing` should return `hashof8_a` + assert_eq!(env.best_chain_containing(hashof8_a).await.unwrap().unwrap().0, hashof8_a); + + // simulate reorg on block 8 by creating a fork starting at block 7 that is 10 blocks long + peer.generate_blocks_at( + BlockId::Number(7), + 10, + BlockOrigin::File, + |mut builder| { + builder.push_deposit_log_digest_item(DigestItem::Other(vec![1])).unwrap(); + builder.build().unwrap().block + }, + false, + false, + true, + ForkChoiceStrategy::LongestChain, + ); + + // check that new best chain is on longest chain + assert_eq!(env.select_chain.best_chain().await.unwrap().number, 17); + + // verify that last completed round has `prevote_ghost` and `estimate` blocks related to + // `hashof8_a` + assert_eq!( + env.voter_set_state.read().last_completed_round().state, + finality_grandpa::round::State { + prevote_ghost: Some((hashof8_a, 8)), + finalized: Some((hashof7, 7)), + estimate: Some((hashof8_a, 8)), + completable: true + } + ); + + // `hashof8_a` should be finalized next, `best_chain_containing` should still return `hashof8_a` + assert_eq!(env.best_chain_containing(hashof8_a).await.unwrap().unwrap().0, hashof8_a); + + // simulate finalization of the `hashof8_a` block + peer.client().finalize_block(hashof8_a, None, false).unwrap(); + + // check that best chain is reorged back + assert_eq!(env.select_chain.best_chain().await.unwrap().number, 10); +} + #[tokio::test] async fn grandpa_environment_never_overwrites_round_voter_state() { use finality_grandpa::voter::Environment; diff --git a/substrate/client/consensus/manual-seal/Cargo.toml b/substrate/client/consensus/manual-seal/Cargo.toml index 3d74eda8fa01f838b063c134163a61a8d98af081..49111434015af9cbba80a091102259a781972853 100644 --- a/substrate/client/consensus/manual-seal/Cargo.toml +++ b/substrate/client/consensus/manual-seal/Cargo.toml @@ -5,7 +5,7 @@ authors.workspace = true description = "Manual sealing engine for Substrate" edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true readme = "README.md" diff --git a/substrate/client/consensus/pow/Cargo.toml b/substrate/client/consensus/pow/Cargo.toml index f2a071ec25c2c3fb97e64229e2fac662532d5969..bc89deb0b50d60d2872cc73aba7705f360b53381 100644 --- a/substrate/client/consensus/pow/Cargo.toml +++ b/substrate/client/consensus/pow/Cargo.toml @@ -5,7 +5,7 @@ authors.workspace = true description = "PoW consensus algorithm for substrate" edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true readme = "README.md" diff --git a/substrate/client/consensus/slots/Cargo.toml b/substrate/client/consensus/slots/Cargo.toml index 2b795b13f8e338d6ed982ef2bd261e76336e683d..cc39575efe82806bbf86c2d34f993a9d961af18a 100644 --- a/substrate/client/consensus/slots/Cargo.toml +++ b/substrate/client/consensus/slots/Cargo.toml @@ -6,7 +6,7 @@ description = "Generic slots-based utilities for consensus" edition.workspace = true build = "build.rs" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true readme = "README.md" diff --git a/substrate/client/db/Cargo.toml b/substrate/client/db/Cargo.toml index c8372701ac3290377ae54f0aed7c7eb8ed781511..5725155579fc70450afad9ff46580afc721d2ea0 100644 --- a/substrate/client/db/Cargo.toml +++ b/substrate/client/db/Cargo.toml @@ -4,7 +4,7 @@ version = "0.35.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true description = "Client backend that uses RocksDB database as storage." readme = "README.md" diff --git a/substrate/client/db/src/bench.rs b/substrate/client/db/src/bench.rs index 32503cf63c0ad7eeae1ab502d38b09aa210d9bc9..3d590bd2bb76ea7c574363566e6f5b3f4782f699 100644 --- a/substrate/client/db/src/bench.rs +++ b/substrate/client/db/src/bench.rs @@ -179,6 +179,11 @@ impl BenchmarkingState { Ok(state) } + /// Get the proof recorder for this state + pub fn recorder(&self) -> Option> { + self.proof_recorder.clone() + } + fn reopen(&self) -> Result<(), String> { *self.state.borrow_mut() = None; let db = match self.db.take() { diff --git a/substrate/client/db/src/lib.rs b/substrate/client/db/src/lib.rs index e95cd9e4ad5fd3e527f3f870aaf40948b238c9a2..ba0cbc09d53dad38939efd4017da27ecd48f213a 100644 --- a/substrate/client/db/src/lib.rs +++ b/substrate/client/db/src/lib.rs @@ -2613,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, @@ -3112,6 +3141,123 @@ pub(crate) mod tests { } } + #[test] + 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 genesis_number = 0; + let genesis_hash = + insert_header(&backend, genesis_number, Default::default(), 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, + ); + + let a4_number = 4; + let a4_hash = + insert_disconnected_header(&backend, a4_number, a3_hash, H256::from([2; 32]), true); + { + 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 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 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 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 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 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); @@ -3156,6 +3302,15 @@ pub(crate) mod tests { assert_eq!(displaced_a3.displaced_leaves, vec![]); assert_eq!(displaced_a3.displaced_blocks, vec![]); } + { + // 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![]); + } // fork from genesis: 2 prong. let b1_number = 1; diff --git a/substrate/client/executor/Cargo.toml b/substrate/client/executor/Cargo.toml index c10c60822ff8dbec0b3ac800a1c3c2b0a3d8b0d8..ca78afd470681227c07a2fad61bcc5b945d01e94 100644 --- a/substrate/client/executor/Cargo.toml +++ b/substrate/client/executor/Cargo.toml @@ -4,7 +4,7 @@ version = "0.32.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true description = "A crate that provides means of executing/dispatching calls into the runtime." documentation = "https://docs.rs/sc-executor" @@ -51,7 +51,6 @@ tracing-subscriber = { workspace = true } 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 } diff --git a/substrate/client/executor/benches/bench.rs b/substrate/client/executor/benches/bench.rs index 86c769f88811b9d004e373ac22a166ae84416df2..4cde8c2a4a64678bc43b2c6001a105249e94453c 100644 --- a/substrate/client/executor/benches/bench.rs +++ b/substrate/client/executor/benches/bench.rs @@ -147,7 +147,7 @@ fn run_benchmark( } fn bench_call_instance(c: &mut Criterion) { - let _ = env_logger::try_init(); + sp_tracing::try_init_simple(); let strategies = [ ( diff --git a/substrate/client/executor/common/Cargo.toml b/substrate/client/executor/common/Cargo.toml index e985c75ca908a669f0ff7e6cc7368269e0814343..58fb0b423f24235a0ddd277b3feaca5c193482d2 100644 --- a/substrate/client/executor/common/Cargo.toml +++ b/substrate/client/executor/common/Cargo.toml @@ -4,7 +4,7 @@ version = "0.29.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true description = "A set of common definitions that are needed for defining execution engines." documentation = "https://docs.rs/sc-executor-common/" diff --git a/substrate/client/executor/polkavm/Cargo.toml b/substrate/client/executor/polkavm/Cargo.toml index 8b849209a07cf17838c89e32cc53fcb80fe3c6ab..941c830ba16a29204e81c4e5c1db1b3e154b5b25 100644 --- a/substrate/client/executor/polkavm/Cargo.toml +++ b/substrate/client/executor/polkavm/Cargo.toml @@ -4,7 +4,7 @@ version = "0.29.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true description = "PolkaVM executor for Substrate" readme = "README.md" diff --git a/substrate/client/executor/runtime-test/Cargo.toml b/substrate/client/executor/runtime-test/Cargo.toml index d132f47ff877f3c05580326e832a72c34676f7da..5ab92cbb9332dace3f4da65f4c4abcc91b60d2ab 100644 --- a/substrate/client/executor/runtime-test/Cargo.toml +++ b/substrate/client/executor/runtime-test/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true build = "build.rs" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" publish = false -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true [lints] diff --git a/substrate/client/executor/wasmtime/Cargo.toml b/substrate/client/executor/wasmtime/Cargo.toml index e58b19bb12431a3ffb5b9fc77526b523e7cf4863..ef8e5da876aa606e32790e9e8eb0ffb077ce2174 100644 --- a/substrate/client/executor/wasmtime/Cargo.toml +++ b/substrate/client/executor/wasmtime/Cargo.toml @@ -4,7 +4,7 @@ version = "0.29.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true description = "Defines a `WasmRuntime` that uses the Wasmtime JIT to execute." readme = "README.md" diff --git a/substrate/client/informant/Cargo.toml b/substrate/client/informant/Cargo.toml index 9da2296deee3c2cdec7d2ba2ef7d2958dc03d86c..87a4be320d689d984f0b8ac94c12f78fda84eaa8 100644 --- a/substrate/client/informant/Cargo.toml +++ b/substrate/client/informant/Cargo.toml @@ -5,7 +5,7 @@ authors.workspace = true description = "Substrate informant." edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" +homepage.workspace = true repository.workspace = true readme = "README.md" @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -ansi_term = { workspace = true } +console = { workspace = true } futures = { workspace = true } futures-timer = { workspace = true } log = { 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